mirror of
https://github.com/httprunner/httprunner.git
synced 2026-09-07 08:27:35 +08:00
refactor: move action options
This commit is contained in:
+49
-118
@@ -14,78 +14,8 @@ import (
|
||||
"github.com/httprunner/httprunner/v5/uixt/option"
|
||||
)
|
||||
|
||||
type ActionMethod string
|
||||
|
||||
const (
|
||||
ACTION_LOG ActionMethod = "log"
|
||||
ACTION_AppInstall ActionMethod = "install"
|
||||
ACTION_AppUninstall ActionMethod = "uninstall"
|
||||
ACTION_WebLoginNoneUI ActionMethod = "login_none_ui"
|
||||
ACTION_AppClear ActionMethod = "app_clear"
|
||||
ACTION_AppStart ActionMethod = "app_start"
|
||||
ACTION_AppLaunch ActionMethod = "app_launch" // 启动 app 并堵塞等待 app 首屏加载完成
|
||||
ACTION_AppTerminate ActionMethod = "app_terminate"
|
||||
ACTION_AppStop ActionMethod = "app_stop"
|
||||
ACTION_ScreenShot ActionMethod = "screenshot"
|
||||
ACTION_Sleep ActionMethod = "sleep"
|
||||
ACTION_SleepMS ActionMethod = "sleep_ms"
|
||||
ACTION_SleepRandom ActionMethod = "sleep_random"
|
||||
ACTION_SetIme ActionMethod = "set_ime"
|
||||
ACTION_GetSource ActionMethod = "get_source"
|
||||
ACTION_GetForegroundApp ActionMethod = "get_foreground_app"
|
||||
ACTION_CallFunction ActionMethod = "call_function"
|
||||
|
||||
// UI handling
|
||||
ACTION_Home ActionMethod = "home"
|
||||
ACTION_TapXY ActionMethod = "tap_xy"
|
||||
ACTION_TapAbsXY ActionMethod = "tap_abs_xy"
|
||||
ACTION_TapByOCR ActionMethod = "tap_ocr"
|
||||
ACTION_TapByCV ActionMethod = "tap_cv"
|
||||
ACTION_DoubleTapXY ActionMethod = "double_tap_xy"
|
||||
ACTION_Swipe ActionMethod = "swipe"
|
||||
ACTION_Drag ActionMethod = "drag"
|
||||
ACTION_Input ActionMethod = "input"
|
||||
ACTION_Back ActionMethod = "back"
|
||||
ACTION_KeyCode ActionMethod = "keycode"
|
||||
ACTION_AIAction ActionMethod = "ai_action" // action with ai
|
||||
ACTION_TapBySelector ActionMethod = "tap_by_selector"
|
||||
ACTION_HoverBySelector ActionMethod = "hover_by_selector"
|
||||
ACTION_WebCloseTab ActionMethod = "web_close_tab"
|
||||
ACTION_SecondaryClick ActionMethod = "secondary_click"
|
||||
ACTION_SecondaryClickBySelector ActionMethod = "secondary_click_by_selector"
|
||||
ACTION_GetElementTextBySelector ActionMethod = "get_element_text_by_selector"
|
||||
|
||||
// custom actions
|
||||
ACTION_SwipeToTapApp ActionMethod = "swipe_to_tap_app" // swipe left & right to find app and tap
|
||||
ACTION_SwipeToTapText ActionMethod = "swipe_to_tap_text" // swipe up & down to find text and tap
|
||||
ACTION_SwipeToTapTexts ActionMethod = "swipe_to_tap_texts" // swipe up & down to find text and tap
|
||||
ACTION_ClosePopups ActionMethod = "close_popups"
|
||||
ACTION_EndToEndDelay ActionMethod = "live_e2e"
|
||||
ACTION_InstallApp ActionMethod = "install_app"
|
||||
ACTION_UninstallApp ActionMethod = "uninstall_app"
|
||||
ACTION_DownloadApp ActionMethod = "download_app"
|
||||
)
|
||||
|
||||
const (
|
||||
// UI validation
|
||||
// selectors
|
||||
SelectorName string = "ui_name"
|
||||
SelectorLabel string = "ui_label"
|
||||
SelectorOCR string = "ui_ocr"
|
||||
SelectorImage string = "ui_image"
|
||||
SelectorAI string = "ui_ai" // ui query with ai
|
||||
SelectorForegroundApp string = "ui_foreground_app"
|
||||
SelectorSelector string = "ui_selector"
|
||||
// assertions
|
||||
AssertionEqual string = "equal"
|
||||
AssertionNotEqual string = "not_equal"
|
||||
AssertionExists string = "exists"
|
||||
AssertionNotExists string = "not_exists"
|
||||
AssertionAI string = "ai_assert" // assert with ai
|
||||
)
|
||||
|
||||
type MobileAction struct {
|
||||
Method ActionMethod `json:"method,omitempty" yaml:"method,omitempty"`
|
||||
Method option.ActionMethod `json:"method,omitempty" yaml:"method,omitempty"`
|
||||
Params interface{} `json:"params,omitempty" yaml:"params,omitempty"`
|
||||
Fn func() `json:"-" yaml:"-"` // used for function action, not serialized
|
||||
Options *option.ActionOptions `json:"options,omitempty" yaml:"options,omitempty"`
|
||||
@@ -102,6 +32,7 @@ func (ma MobileAction) GetOptions() []option.ActionOption {
|
||||
return actionOptionList
|
||||
}
|
||||
|
||||
// TODO: merge to uixt MCP Server
|
||||
func (dExt *XTDriver) DoAction(action MobileAction) (err error) {
|
||||
actionStartTime := time.Now()
|
||||
defer func() {
|
||||
@@ -119,7 +50,7 @@ func (dExt *XTDriver) DoAction(action MobileAction) (err error) {
|
||||
}()
|
||||
|
||||
switch action.Method {
|
||||
case ACTION_WebLoginNoneUI:
|
||||
case option.ACTION_WebLoginNoneUI:
|
||||
if len(action.Params.([]interface{})) == 4 {
|
||||
driver, ok := dExt.IDriver.(*BrowserDriver)
|
||||
if !ok {
|
||||
@@ -129,53 +60,53 @@ func (dExt *XTDriver) DoAction(action MobileAction) (err error) {
|
||||
_, err = driver.LoginNoneUI(params[0].(string), params[1].(string), params[2].(string), params[3].(string))
|
||||
return err
|
||||
}
|
||||
return fmt.Errorf("invalid %s params: %v", ACTION_WebLoginNoneUI, action.Params)
|
||||
case ACTION_AppInstall:
|
||||
return fmt.Errorf("invalid %s params: %v", option.ACTION_WebLoginNoneUI, action.Params)
|
||||
case option.ACTION_AppInstall:
|
||||
if app, ok := action.Params.(string); ok {
|
||||
if err = dExt.GetDevice().Install(app,
|
||||
option.WithRetryTimes(action.MaxRetryTimes)); err != nil {
|
||||
return errors.Wrap(err, "failed to install app")
|
||||
}
|
||||
}
|
||||
case ACTION_AppUninstall:
|
||||
case option.ACTION_AppUninstall:
|
||||
if packageName, ok := action.Params.(string); ok {
|
||||
if err = dExt.GetDevice().Uninstall(packageName); err != nil {
|
||||
return errors.Wrap(err, "failed to uninstall app")
|
||||
}
|
||||
}
|
||||
case ACTION_AppClear:
|
||||
case option.ACTION_AppClear:
|
||||
if packageName, ok := action.Params.(string); ok {
|
||||
if err = dExt.AppClear(packageName); err != nil {
|
||||
return errors.Wrap(err, "failed to clear app")
|
||||
}
|
||||
}
|
||||
case ACTION_AppLaunch:
|
||||
case option.ACTION_AppLaunch:
|
||||
if bundleId, ok := action.Params.(string); ok {
|
||||
return dExt.AppLaunch(bundleId)
|
||||
}
|
||||
return fmt.Errorf("invalid %s params, should be bundleId(string), got %v",
|
||||
ACTION_AppLaunch, action.Params)
|
||||
case ACTION_SwipeToTapApp:
|
||||
option.ACTION_AppLaunch, action.Params)
|
||||
case option.ACTION_SwipeToTapApp:
|
||||
if appName, ok := action.Params.(string); ok {
|
||||
return dExt.SwipeToTapApp(appName, action.GetOptions()...)
|
||||
}
|
||||
return fmt.Errorf("invalid %s params, should be app name(string), got %v",
|
||||
ACTION_SwipeToTapApp, action.Params)
|
||||
case ACTION_SwipeToTapText:
|
||||
option.ACTION_SwipeToTapApp, action.Params)
|
||||
case option.ACTION_SwipeToTapText:
|
||||
if text, ok := action.Params.(string); ok {
|
||||
return dExt.SwipeToTapTexts([]string{text}, action.GetOptions()...)
|
||||
}
|
||||
return fmt.Errorf("invalid %s params, should be app text(string), got %v",
|
||||
ACTION_SwipeToTapText, action.Params)
|
||||
case ACTION_SwipeToTapTexts:
|
||||
option.ACTION_SwipeToTapText, action.Params)
|
||||
case option.ACTION_SwipeToTapTexts:
|
||||
if texts, ok := action.Params.([]string); ok {
|
||||
return dExt.SwipeToTapTexts(texts, action.GetOptions()...)
|
||||
}
|
||||
if texts, err := builtin.ConvertToStringSlice(action.Params); err == nil {
|
||||
return dExt.SwipeToTapTexts(texts, action.GetOptions()...)
|
||||
}
|
||||
return fmt.Errorf("invalid %s params: %v", ACTION_SwipeToTapTexts, action.Params)
|
||||
case ACTION_AppTerminate:
|
||||
return fmt.Errorf("invalid %s params: %v", option.ACTION_SwipeToTapTexts, action.Params)
|
||||
case option.ACTION_AppTerminate:
|
||||
if bundleId, ok := action.Params.(string); ok {
|
||||
success, err := dExt.AppTerminate(bundleId)
|
||||
if err != nil {
|
||||
@@ -187,9 +118,9 @@ func (dExt *XTDriver) DoAction(action MobileAction) (err error) {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("app_terminate params should be bundleId(string), got %v", action.Params)
|
||||
case ACTION_Home:
|
||||
case option.ACTION_Home:
|
||||
return dExt.Home()
|
||||
case ACTION_SecondaryClick:
|
||||
case option.ACTION_SecondaryClick:
|
||||
if params, err := builtin.ConvertToFloat64Slice(action.Params); err == nil {
|
||||
if len(params) != 2 {
|
||||
return fmt.Errorf("invalid tap location params: %v", params)
|
||||
@@ -197,23 +128,23 @@ func (dExt *XTDriver) DoAction(action MobileAction) (err error) {
|
||||
x, y := params[0], params[1]
|
||||
return dExt.SecondaryClick(x, y)
|
||||
}
|
||||
return fmt.Errorf("invalid %s params: %v", ACTION_SecondaryClick, action.Params)
|
||||
case ACTION_HoverBySelector:
|
||||
return fmt.Errorf("invalid %s params: %v", option.ACTION_SecondaryClick, action.Params)
|
||||
case option.ACTION_HoverBySelector:
|
||||
if selector, ok := action.Params.(string); ok {
|
||||
return dExt.HoverBySelector(selector, action.GetOptions()...)
|
||||
}
|
||||
return fmt.Errorf("invalid %s params: %v", ACTION_HoverBySelector, action.Params)
|
||||
case ACTION_TapBySelector:
|
||||
return fmt.Errorf("invalid %s params: %v", option.ACTION_HoverBySelector, action.Params)
|
||||
case option.ACTION_TapBySelector:
|
||||
if selector, ok := action.Params.(string); ok {
|
||||
return dExt.TapBySelector(selector, action.GetOptions()...)
|
||||
}
|
||||
return fmt.Errorf("invalid %s params: %v", ACTION_TapBySelector, action.Params)
|
||||
case ACTION_SecondaryClickBySelector:
|
||||
return fmt.Errorf("invalid %s params: %v", option.ACTION_TapBySelector, action.Params)
|
||||
case option.ACTION_SecondaryClickBySelector:
|
||||
if selector, ok := action.Params.(string); ok {
|
||||
return dExt.SecondaryClickBySelector(selector, action.GetOptions()...)
|
||||
}
|
||||
return fmt.Errorf("invalid %s params: %v", ACTION_SecondaryClickBySelector, action.Params)
|
||||
case ACTION_WebCloseTab:
|
||||
return fmt.Errorf("invalid %s params: %v", option.ACTION_SecondaryClickBySelector, action.Params)
|
||||
case option.ACTION_WebCloseTab:
|
||||
if param, ok := action.Params.(json.Number); ok {
|
||||
paramInt64, _ := param.Int64()
|
||||
return dExt.IDriver.(*BrowserDriver).CloseTab(int(paramInt64))
|
||||
@@ -223,7 +154,7 @@ func (dExt *XTDriver) DoAction(action MobileAction) (err error) {
|
||||
return dExt.IDriver.(*BrowserDriver).CloseTab(action.Params.(int))
|
||||
}
|
||||
// return fmt.Errorf("invalid %s params: %v", ACTION_WebCloseTab, action.Params)
|
||||
case ACTION_SetIme:
|
||||
case option.ACTION_SetIme:
|
||||
if ime, ok := action.Params.(string); ok {
|
||||
err = dExt.SetIme(ime)
|
||||
if err != nil {
|
||||
@@ -231,7 +162,7 @@ func (dExt *XTDriver) DoAction(action MobileAction) (err error) {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
case ACTION_GetSource:
|
||||
case option.ACTION_GetSource:
|
||||
if packageName, ok := action.Params.(string); ok {
|
||||
_, err = dExt.Source(option.WithProcessName(packageName))
|
||||
if err != nil {
|
||||
@@ -239,7 +170,7 @@ func (dExt *XTDriver) DoAction(action MobileAction) (err error) {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
case ACTION_TapXY:
|
||||
case option.ACTION_TapXY:
|
||||
if params, err := builtin.ConvertToFloat64Slice(action.Params); err == nil {
|
||||
// relative x,y of window size: [0.5, 0.5]
|
||||
if len(params) != 2 {
|
||||
@@ -248,8 +179,8 @@ func (dExt *XTDriver) DoAction(action MobileAction) (err error) {
|
||||
x, y := params[0], params[1]
|
||||
return dExt.TapXY(x, y, action.GetOptions()...)
|
||||
}
|
||||
return fmt.Errorf("invalid %s params: %v", ACTION_TapXY, action.Params)
|
||||
case ACTION_TapAbsXY:
|
||||
return fmt.Errorf("invalid %s params: %v", option.ACTION_TapXY, action.Params)
|
||||
case option.ACTION_TapAbsXY:
|
||||
if params, err := builtin.ConvertToFloat64Slice(action.Params); err == nil {
|
||||
// absolute coordinates x,y of window size: [100, 300]
|
||||
if len(params) != 2 {
|
||||
@@ -258,19 +189,19 @@ func (dExt *XTDriver) DoAction(action MobileAction) (err error) {
|
||||
x, y := params[0], params[1]
|
||||
return dExt.TapAbsXY(x, y, action.GetOptions()...)
|
||||
}
|
||||
return fmt.Errorf("invalid %s params: %v", ACTION_TapAbsXY, action.Params)
|
||||
case ACTION_TapByOCR:
|
||||
return fmt.Errorf("invalid %s params: %v", option.ACTION_TapAbsXY, action.Params)
|
||||
case option.ACTION_TapByOCR:
|
||||
if ocrText, ok := action.Params.(string); ok {
|
||||
return dExt.TapByOCR(ocrText, action.GetOptions()...)
|
||||
}
|
||||
return fmt.Errorf("invalid %s params: %v", ACTION_TapByOCR, action.Params)
|
||||
case ACTION_TapByCV:
|
||||
return fmt.Errorf("invalid %s params: %v", option.ACTION_TapByOCR, action.Params)
|
||||
case option.ACTION_TapByCV:
|
||||
actionOptions := option.NewActionOptions(action.GetOptions()...)
|
||||
if len(actionOptions.ScreenShotWithUITypes) > 0 {
|
||||
return dExt.TapByCV(action.GetOptions()...)
|
||||
}
|
||||
return fmt.Errorf("invalid %s params: %v", ACTION_TapByCV, action.Params)
|
||||
case ACTION_DoubleTapXY:
|
||||
return fmt.Errorf("invalid %s params: %v", option.ACTION_TapByCV, action.Params)
|
||||
case option.ACTION_DoubleTapXY:
|
||||
if params, err := builtin.ConvertToFloat64Slice(action.Params); err == nil {
|
||||
// relative x,y of window size: [0.5, 0.5]
|
||||
if len(params) != 2 {
|
||||
@@ -279,20 +210,20 @@ func (dExt *XTDriver) DoAction(action MobileAction) (err error) {
|
||||
x, y := params[0], params[1]
|
||||
return dExt.DoubleTap(x, y)
|
||||
}
|
||||
return fmt.Errorf("invalid %s params: %v", ACTION_DoubleTapXY, action.Params)
|
||||
case ACTION_Swipe:
|
||||
return fmt.Errorf("invalid %s params: %v", option.ACTION_DoubleTapXY, action.Params)
|
||||
case option.ACTION_Swipe:
|
||||
params := action.Params
|
||||
swipeAction := prepareSwipeAction(dExt, params, action.GetOptions()...)
|
||||
return swipeAction(dExt)
|
||||
case ACTION_Input:
|
||||
case option.ACTION_Input:
|
||||
// input text on current active element
|
||||
// append \n to send text with enter
|
||||
// send \b\b\b to delete 3 chars
|
||||
param := fmt.Sprintf("%v", action.Params)
|
||||
return dExt.Input(param)
|
||||
case ACTION_Back:
|
||||
case option.ACTION_Back:
|
||||
return dExt.Back()
|
||||
case ACTION_Sleep:
|
||||
case option.ACTION_Sleep:
|
||||
if param, ok := action.Params.(json.Number); ok {
|
||||
seconds, _ := param.Float64()
|
||||
time.Sleep(time.Duration(seconds*1000) * time.Millisecond)
|
||||
@@ -315,7 +246,7 @@ func (dExt *XTDriver) DoAction(action MobileAction) (err error) {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("invalid sleep params: %v(%T)", action.Params, action.Params)
|
||||
case ACTION_SleepMS:
|
||||
case option.ACTION_SleepMS:
|
||||
if param, ok := action.Params.(json.Number); ok {
|
||||
milliseconds, _ := param.Int64()
|
||||
time.Sleep(time.Duration(milliseconds) * time.Millisecond)
|
||||
@@ -328,29 +259,29 @@ func (dExt *XTDriver) DoAction(action MobileAction) (err error) {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("invalid sleep ms params: %v(%T)", action.Params, action.Params)
|
||||
case ACTION_SleepRandom:
|
||||
case option.ACTION_SleepRandom:
|
||||
if params, err := builtin.ConvertToFloat64Slice(action.Params); err == nil {
|
||||
sleepStrict(time.Now(), getSimulationDuration(params))
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("invalid sleep random params: %v(%T)", action.Params, action.Params)
|
||||
case ACTION_ScreenShot:
|
||||
case option.ACTION_ScreenShot:
|
||||
// take screenshot
|
||||
log.Info().Msg("take screenshot for current screen")
|
||||
_, err := dExt.GetScreenResult(action.GetScreenShotOptions()...)
|
||||
return err
|
||||
case ACTION_ClosePopups:
|
||||
case option.ACTION_ClosePopups:
|
||||
return dExt.ClosePopupsHandler()
|
||||
case ACTION_CallFunction:
|
||||
case option.ACTION_CallFunction:
|
||||
if funcDesc, ok := action.Params.(string); ok {
|
||||
return dExt.Call(funcDesc, action.Fn, action.GetOptions()...)
|
||||
}
|
||||
return fmt.Errorf("invalid function description: %v", action.Params)
|
||||
case ACTION_AIAction:
|
||||
case option.ACTION_AIAction:
|
||||
if prompt, ok := action.Params.(string); ok {
|
||||
return dExt.AIAction(prompt, action.GetOptions()...)
|
||||
}
|
||||
return fmt.Errorf("invalid %s params: %v", ACTION_AIAction, action.Params)
|
||||
return fmt.Errorf("invalid %s params: %v", option.ACTION_AIAction, action.Params)
|
||||
default:
|
||||
log.Warn().Str("action", string(action.Method)).Msg("action not implemented")
|
||||
return errors.Wrapf(code.InvalidCaseError,
|
||||
|
||||
Reference in New Issue
Block a user