From 4ff2692f0299a74985111f991e390ad1622f0887 Mon Sep 17 00:00:00 2001 From: "lilong.129" Date: Sun, 25 May 2025 00:09:25 +0800 Subject: [PATCH] refactor: move action options --- compat.go | 7 +- internal/version/VERSION | 2 +- step_ui.go | 126 ++++++++++++------------- summary.go | 14 +-- uixt/android_driver_adb.go | 8 +- uixt/android_driver_uia2.go | 8 +- uixt/browser_driver.go | 6 +- uixt/driver_action.go | 167 ++++++++++------------------------ uixt/driver_ext_screenshot.go | 6 +- uixt/driver_handler.go | 10 +- uixt/driver_utils.go | 24 ++--- uixt/harmony_driver_hdc.go | 4 +- uixt/ios_driver_wda.go | 6 +- uixt/option/action.go | 70 ++++++++++++++ uixt/sdk.go | 2 +- 15 files changed, 230 insertions(+), 230 deletions(-) diff --git a/compat.go b/compat.go index ba924c54..4c491df0 100644 --- a/compat.go +++ b/compat.go @@ -8,7 +8,6 @@ import ( "github.com/httprunner/httprunner/v5/code" "github.com/httprunner/httprunner/v5/internal/builtin" - "github.com/httprunner/httprunner/v5/uixt" "github.com/httprunner/httprunner/v5/uixt/option" ) @@ -138,17 +137,17 @@ func convertCompatMobileStep(mobileUI *MobileUI) { ma := mobileUI.Actions[i] actionOptions := option.NewActionOptions(ma.GetOptions()...) // append tap_cv params to screenshot_with_ui_types option - if ma.Method == uixt.ACTION_TapByCV { + if ma.Method == option.ACTION_TapByCV { uiTypes, _ := builtin.ConvertToStringSlice(ma.Params) ma.ActionOptions.ScreenShotWithUITypes = append(ma.ActionOptions.ScreenShotWithUITypes, uiTypes...) ma.ActionOptions.ScreenShotWithUpload = true } // set default max_retry_times to 10 for swipe_to_tap_texts - if ma.Method == uixt.ACTION_SwipeToTapTexts && actionOptions.MaxRetryTimes == 0 { + if ma.Method == option.ACTION_SwipeToTapTexts && actionOptions.MaxRetryTimes == 0 { ma.ActionOptions.MaxRetryTimes = 10 } // set default max_retry_times to 10 for swipe_to_tap_text - if ma.Method == uixt.ACTION_SwipeToTapText && actionOptions.MaxRetryTimes == 0 { + if ma.Method == option.ACTION_SwipeToTapText && actionOptions.MaxRetryTimes == 0 { ma.ActionOptions.MaxRetryTimes = 10 } mobileUI.Actions[i] = ma diff --git a/internal/version/VERSION b/internal/version/VERSION index 5f27b6fe..2ff7b1e4 100644 --- a/internal/version/VERSION +++ b/internal/version/VERSION @@ -1 +1 @@ -v5.0.0-beta-2505242351 +v5.0.0-beta-2505250015 diff --git a/step_ui.go b/step_ui.go index ae3c2217..9611f6dd 100644 --- a/step_ui.go +++ b/step_ui.go @@ -67,9 +67,9 @@ func (s *StepMobile) Serial(serial string) *StepMobile { return s } -func (s *StepMobile) Log(actionName uixt.ActionMethod) *StepMobile { +func (s *StepMobile) Log(actionName option.ActionMethod) *StepMobile { s.obj().Actions = append(s.obj().Actions, uixt.MobileAction{ - Method: uixt.ACTION_LOG, + Method: option.ACTION_LOG, Params: actionName, }) return s @@ -77,7 +77,7 @@ func (s *StepMobile) Log(actionName uixt.ActionMethod) *StepMobile { func (s *StepMobile) InstallApp(path string) *StepMobile { s.obj().Actions = append(s.obj().Actions, uixt.MobileAction{ - Method: uixt.ACTION_AppInstall, + Method: option.ACTION_AppInstall, Params: path, }) return s @@ -85,7 +85,7 @@ func (s *StepMobile) InstallApp(path string) *StepMobile { func (s *StepMobile) WebLoginNoneUI(packageName, phoneNumber string, captcha, password string) *StepMobile { s.obj().Actions = append(s.obj().Actions, uixt.MobileAction{ - Method: uixt.ACTION_WebLoginNoneUI, + Method: option.ACTION_WebLoginNoneUI, Params: []string{packageName, phoneNumber, captcha, password}, }) return s @@ -93,7 +93,7 @@ func (s *StepMobile) WebLoginNoneUI(packageName, phoneNumber string, captcha, pa func (s *StepMobile) AppLaunch(bundleId string) *StepMobile { s.obj().Actions = append(s.obj().Actions, uixt.MobileAction{ - Method: uixt.ACTION_AppLaunch, + Method: option.ACTION_AppLaunch, Params: bundleId, }) return s @@ -101,7 +101,7 @@ func (s *StepMobile) AppLaunch(bundleId string) *StepMobile { func (s *StepMobile) AppTerminate(bundleId string) *StepMobile { s.obj().Actions = append(s.obj().Actions, uixt.MobileAction{ - Method: uixt.ACTION_AppTerminate, + Method: option.ACTION_AppTerminate, Params: bundleId, }) return s @@ -109,7 +109,7 @@ func (s *StepMobile) AppTerminate(bundleId string) *StepMobile { func (s *StepMobile) Home() *StepMobile { s.obj().Actions = append(s.obj().Actions, uixt.MobileAction{ - Method: uixt.ACTION_Home, + Method: option.ACTION_Home, Params: nil, }) return s @@ -120,7 +120,7 @@ func (s *StepMobile) Home() *StepMobile { // else, X & Y will be considered as absolute coordinates func (s *StepMobile) TapXY(x, y float64, opts ...option.ActionOption) *StepMobile { action := uixt.MobileAction{ - Method: uixt.ACTION_TapXY, + Method: option.ACTION_TapXY, Params: []float64{x, y}, Options: option.NewActionOptions(opts...), } @@ -132,7 +132,7 @@ func (s *StepMobile) TapXY(x, y float64, opts ...option.ActionOption) *StepMobil // TapAbsXY taps the point {X,Y}, X & Y is absolute coordinates func (s *StepMobile) TapAbsXY(x, y float64, opts ...option.ActionOption) *StepMobile { action := uixt.MobileAction{ - Method: uixt.ACTION_TapAbsXY, + Method: option.ACTION_TapAbsXY, Params: []float64{x, y}, Options: option.NewActionOptions(opts...), } @@ -144,7 +144,7 @@ func (s *StepMobile) TapAbsXY(x, y float64, opts ...option.ActionOption) *StepMo // TapByOCR taps on the target element by OCR recognition func (s *StepMobile) TapByOCR(ocrText string, opts ...option.ActionOption) *StepMobile { action := uixt.MobileAction{ - Method: uixt.ACTION_TapByOCR, + Method: option.ACTION_TapByOCR, Params: ocrText, Options: option.NewActionOptions(opts...), } @@ -156,7 +156,7 @@ func (s *StepMobile) TapByOCR(ocrText string, opts ...option.ActionOption) *Step // TapByCV taps on the target element by CV recognition func (s *StepMobile) TapByCV(imagePath string, opts ...option.ActionOption) *StepMobile { action := uixt.MobileAction{ - Method: uixt.ACTION_TapByCV, + Method: option.ACTION_TapByCV, Params: imagePath, Options: option.NewActionOptions(opts...), } @@ -168,7 +168,7 @@ func (s *StepMobile) TapByCV(imagePath string, opts ...option.ActionOption) *Ste // TapByUITypes taps on the target element specified by uiTypes, the higher the uiTypes, the higher the priority func (s *StepMobile) TapByUITypes(opts ...option.ActionOption) *StepMobile { action := uixt.MobileAction{ - Method: uixt.ACTION_TapByCV, + Method: option.ACTION_TapByCV, Options: option.NewActionOptions(opts...), } @@ -179,7 +179,7 @@ func (s *StepMobile) TapByUITypes(opts ...option.ActionOption) *StepMobile { // AIAction do actions with VLM func (s *StepMobile) AIAction(prompt string, opts ...option.ActionOption) *StepMobile { action := uixt.MobileAction{ - Method: uixt.ACTION_AIAction, + Method: option.ACTION_AIAction, Params: prompt, Options: option.NewActionOptions(opts...), } @@ -191,7 +191,7 @@ func (s *StepMobile) AIAction(prompt string, opts ...option.ActionOption) *StepM // DoubleTapXY double taps the point {X,Y}, X & Y is percentage of coordinates func (s *StepMobile) DoubleTapXY(x, y float64, opts ...option.ActionOption) *StepMobile { s.obj().Actions = append(s.obj().Actions, uixt.MobileAction{ - Method: uixt.ACTION_DoubleTapXY, + Method: option.ACTION_DoubleTapXY, Params: []float64{x, y}, Options: option.NewActionOptions(opts...), }) @@ -200,7 +200,7 @@ func (s *StepMobile) DoubleTapXY(x, y float64, opts ...option.ActionOption) *Ste func (s *StepMobile) Back() *StepMobile { action := uixt.MobileAction{ - Method: uixt.ACTION_Back, + Method: option.ACTION_Back, Params: nil, Options: nil, } @@ -212,7 +212,7 @@ func (s *StepMobile) Back() *StepMobile { // Swipe drags from [sx, sy] to [ex, ey] func (s *StepMobile) Swipe(sx, sy, ex, ey float64, opts ...option.ActionOption) *StepMobile { action := uixt.MobileAction{ - Method: uixt.ACTION_Swipe, + Method: option.ACTION_Swipe, Params: []float64{sx, sy, ex, ey}, Options: option.NewActionOptions(opts...), } @@ -223,7 +223,7 @@ func (s *StepMobile) Swipe(sx, sy, ex, ey float64, opts ...option.ActionOption) func (s *StepMobile) SwipeUp(opts ...option.ActionOption) *StepMobile { action := uixt.MobileAction{ - Method: uixt.ACTION_Swipe, + Method: option.ACTION_Swipe, Params: "up", Options: option.NewActionOptions(opts...), } @@ -234,7 +234,7 @@ func (s *StepMobile) SwipeUp(opts ...option.ActionOption) *StepMobile { func (s *StepMobile) SwipeDown(opts ...option.ActionOption) *StepMobile { action := uixt.MobileAction{ - Method: uixt.ACTION_Swipe, + Method: option.ACTION_Swipe, Params: "down", Options: option.NewActionOptions(opts...), } @@ -245,7 +245,7 @@ func (s *StepMobile) SwipeDown(opts ...option.ActionOption) *StepMobile { func (s *StepMobile) SwipeLeft(opts ...option.ActionOption) *StepMobile { action := uixt.MobileAction{ - Method: uixt.ACTION_Swipe, + Method: option.ACTION_Swipe, Params: "left", Options: option.NewActionOptions(opts...), } @@ -256,7 +256,7 @@ func (s *StepMobile) SwipeLeft(opts ...option.ActionOption) *StepMobile { func (s *StepMobile) SwipeRight(opts ...option.ActionOption) *StepMobile { action := uixt.MobileAction{ - Method: uixt.ACTION_Swipe, + Method: option.ACTION_Swipe, Params: "right", Options: option.NewActionOptions(opts...), } @@ -267,7 +267,7 @@ func (s *StepMobile) SwipeRight(opts ...option.ActionOption) *StepMobile { func (s *StepMobile) SwipeToTapApp(appName string, opts ...option.ActionOption) *StepMobile { action := uixt.MobileAction{ - Method: uixt.ACTION_SwipeToTapApp, + Method: option.ACTION_SwipeToTapApp, Params: appName, Options: option.NewActionOptions(opts...), } @@ -278,7 +278,7 @@ func (s *StepMobile) SwipeToTapApp(appName string, opts ...option.ActionOption) func (s *StepMobile) SwipeToTapText(text string, opts ...option.ActionOption) *StepMobile { action := uixt.MobileAction{ - Method: uixt.ACTION_SwipeToTapText, + Method: option.ACTION_SwipeToTapText, Params: text, Options: option.NewActionOptions(opts...), } @@ -289,7 +289,7 @@ func (s *StepMobile) SwipeToTapText(text string, opts ...option.ActionOption) *S func (s *StepMobile) SwipeToTapTexts(texts interface{}, opts ...option.ActionOption) *StepMobile { action := uixt.MobileAction{ - Method: uixt.ACTION_SwipeToTapTexts, + Method: option.ACTION_SwipeToTapTexts, Params: texts, Options: option.NewActionOptions(opts...), } @@ -300,7 +300,7 @@ func (s *StepMobile) SwipeToTapTexts(texts interface{}, opts ...option.ActionOpt func (s *StepMobile) SecondaryClick(x, y float64, options ...option.ActionOption) *StepMobile { action := uixt.MobileAction{ - Method: uixt.ACTION_SecondaryClick, + Method: option.ACTION_SecondaryClick, Params: []float64{x, y}, Options: option.NewActionOptions(options...), } @@ -310,7 +310,7 @@ func (s *StepMobile) SecondaryClick(x, y float64, options ...option.ActionOption func (s *StepMobile) SecondaryClickBySelector(selector string, options ...option.ActionOption) *StepMobile { action := uixt.MobileAction{ - Method: uixt.ACTION_SecondaryClickBySelector, + Method: option.ACTION_SecondaryClickBySelector, Params: selector, Options: option.NewActionOptions(options...), } @@ -320,7 +320,7 @@ func (s *StepMobile) SecondaryClickBySelector(selector string, options ...option func (s *StepMobile) HoverBySelector(selector string, options ...option.ActionOption) *StepMobile { action := uixt.MobileAction{ - Method: uixt.ACTION_HoverBySelector, + Method: option.ACTION_HoverBySelector, Params: selector, Options: option.NewActionOptions(options...), } @@ -330,7 +330,7 @@ func (s *StepMobile) HoverBySelector(selector string, options ...option.ActionOp func (s *StepMobile) TapBySelector(selector string, options ...option.ActionOption) *StepMobile { action := uixt.MobileAction{ - Method: uixt.ACTION_TapBySelector, + Method: option.ACTION_TapBySelector, Params: selector, Options: option.NewActionOptions(options...), } @@ -340,7 +340,7 @@ func (s *StepMobile) TapBySelector(selector string, options ...option.ActionOpti func (s *StepMobile) WebCloseTab(idx int, options ...option.ActionOption) *StepMobile { action := uixt.MobileAction{ - Method: uixt.ACTION_WebCloseTab, + Method: option.ACTION_WebCloseTab, Params: idx, Options: option.NewActionOptions(options...), } @@ -350,7 +350,7 @@ func (s *StepMobile) WebCloseTab(idx int, options ...option.ActionOption) *StepM func (s *StepMobile) GetElementTextBySelector(selector string, options ...option.ActionOption) *StepMobile { action := uixt.MobileAction{ - Method: uixt.ACTION_GetElementTextBySelector, + Method: option.ACTION_GetElementTextBySelector, Params: selector, Options: option.NewActionOptions(options...), } @@ -360,7 +360,7 @@ func (s *StepMobile) GetElementTextBySelector(selector string, options ...option func (s *StepMobile) Input(text string, opts ...option.ActionOption) *StepMobile { action := uixt.MobileAction{ - Method: uixt.ACTION_Input, + Method: option.ACTION_Input, Params: text, Options: option.NewActionOptions(opts...), } @@ -372,7 +372,7 @@ func (s *StepMobile) Input(text string, opts ...option.ActionOption) *StepMobile // Sleep specify sleep seconds after last action func (s *StepMobile) Sleep(nSeconds float64, startTime ...time.Time) *StepMobile { action := uixt.MobileAction{ - Method: uixt.ACTION_Sleep, + Method: option.ACTION_Sleep, Params: nSeconds, Options: nil, } @@ -388,7 +388,7 @@ func (s *StepMobile) Sleep(nSeconds float64, startTime ...time.Time) *StepMobile func (s *StepMobile) SleepMS(nMilliseconds int64, startTime ...time.Time) *StepMobile { action := uixt.MobileAction{ - Method: uixt.ACTION_SleepMS, + Method: option.ACTION_SleepMS, Params: nMilliseconds, Options: nil, } @@ -408,7 +408,7 @@ func (s *StepMobile) SleepMS(nMilliseconds int64, startTime ...time.Time) *StepM // 2. [min1, max1, weight1, min2, max2, weight2, ...] : weight is the probability of the time range func (s *StepMobile) SleepRandom(params ...float64) *StepMobile { s.obj().Actions = append(s.obj().Actions, uixt.MobileAction{ - Method: uixt.ACTION_SleepRandom, + Method: option.ACTION_SleepRandom, Params: params, Options: nil, }) @@ -417,7 +417,7 @@ func (s *StepMobile) SleepRandom(params ...float64) *StepMobile { func (s *StepMobile) EndToEndDelay(opts ...option.ActionOption) *StepMobile { s.obj().Actions = append(s.obj().Actions, uixt.MobileAction{ - Method: uixt.ACTION_EndToEndDelay, + Method: option.ACTION_EndToEndDelay, Params: nil, Options: option.NewActionOptions(opts...), }) @@ -426,7 +426,7 @@ func (s *StepMobile) EndToEndDelay(opts ...option.ActionOption) *StepMobile { func (s *StepMobile) ScreenShot(opts ...option.ActionOption) *StepMobile { s.obj().Actions = append(s.obj().Actions, uixt.MobileAction{ - Method: uixt.ACTION_ScreenShot, + Method: option.ACTION_ScreenShot, Params: nil, Options: option.NewActionOptions(opts...), }) @@ -440,7 +440,7 @@ func (s *StepMobile) DisableAutoPopupHandler() *StepMobile { func (s *StepMobile) ClosePopups(opts ...option.ActionOption) *StepMobile { s.obj().Actions = append(s.obj().Actions, uixt.MobileAction{ - Method: uixt.ACTION_ClosePopups, + Method: option.ACTION_ClosePopups, Params: nil, Options: option.NewActionOptions(opts...), }) @@ -449,7 +449,7 @@ func (s *StepMobile) ClosePopups(opts ...option.ActionOption) *StepMobile { func (s *StepMobile) Call(name string, fn func(), opts ...option.ActionOption) *StepMobile { s.obj().Actions = append(s.obj().Actions, uixt.MobileAction{ - Method: uixt.ACTION_CallFunction, + Method: option.ACTION_CallFunction, Params: name, // function description Fn: fn, Options: option.NewActionOptions(opts...), @@ -493,8 +493,8 @@ type StepMobileUIValidation struct { func (s *StepMobileUIValidation) AssertNameExists(expectedName string, msg ...string) *StepMobileUIValidation { v := Validator{ - Check: uixt.SelectorName, - Assert: uixt.AssertionExists, + Check: option.SelectorName, + Assert: option.AssertionExists, Expect: expectedName, } if len(msg) > 0 { @@ -508,8 +508,8 @@ func (s *StepMobileUIValidation) AssertNameExists(expectedName string, msg ...st func (s *StepMobileUIValidation) AssertNameNotExists(expectedName string, msg ...string) *StepMobileUIValidation { v := Validator{ - Check: uixt.SelectorName, - Assert: uixt.AssertionNotExists, + Check: option.SelectorName, + Assert: option.AssertionNotExists, Expect: expectedName, } if len(msg) > 0 { @@ -523,8 +523,8 @@ func (s *StepMobileUIValidation) AssertNameNotExists(expectedName string, msg .. func (s *StepMobileUIValidation) AssertLabelExists(expectedLabel string, msg ...string) *StepMobileUIValidation { v := Validator{ - Check: uixt.SelectorLabel, - Assert: uixt.AssertionExists, + Check: option.SelectorLabel, + Assert: option.AssertionExists, Expect: expectedLabel, } if len(msg) > 0 { @@ -538,8 +538,8 @@ func (s *StepMobileUIValidation) AssertLabelExists(expectedLabel string, msg ... func (s *StepMobileUIValidation) AssertLabelNotExists(expectedLabel string, msg ...string) *StepMobileUIValidation { v := Validator{ - Check: uixt.SelectorLabel, - Assert: uixt.AssertionNotExists, + Check: option.SelectorLabel, + Assert: option.AssertionNotExists, Expect: expectedLabel, } if len(msg) > 0 { @@ -553,8 +553,8 @@ func (s *StepMobileUIValidation) AssertLabelNotExists(expectedLabel string, msg func (s *StepMobileUIValidation) AssertOCRExists(expectedText string, msg ...string) *StepMobileUIValidation { v := Validator{ - Check: uixt.SelectorOCR, - Assert: uixt.AssertionExists, + Check: option.SelectorOCR, + Assert: option.AssertionExists, Expect: expectedText, } if len(msg) > 0 { @@ -568,8 +568,8 @@ func (s *StepMobileUIValidation) AssertOCRExists(expectedText string, msg ...str func (s *StepMobileUIValidation) AssertOCRNotExists(expectedText string, msg ...string) *StepMobileUIValidation { v := Validator{ - Check: uixt.SelectorOCR, - Assert: uixt.AssertionNotExists, + Check: option.SelectorOCR, + Assert: option.AssertionNotExists, Expect: expectedText, } if len(msg) > 0 { @@ -583,8 +583,8 @@ func (s *StepMobileUIValidation) AssertOCRNotExists(expectedText string, msg ... func (s *StepMobileUIValidation) AssertImageExists(expectedImagePath string, msg ...string) *StepMobileUIValidation { v := Validator{ - Check: uixt.SelectorImage, - Assert: uixt.AssertionExists, + Check: option.SelectorImage, + Assert: option.AssertionExists, Expect: expectedImagePath, } if len(msg) > 0 { @@ -598,8 +598,8 @@ func (s *StepMobileUIValidation) AssertImageExists(expectedImagePath string, msg func (s *StepMobileUIValidation) AssertImageNotExists(expectedImagePath string, msg ...string) *StepMobileUIValidation { v := Validator{ - Check: uixt.SelectorImage, - Assert: uixt.AssertionNotExists, + Check: option.SelectorImage, + Assert: option.AssertionNotExists, Expect: expectedImagePath, } if len(msg) > 0 { @@ -613,8 +613,8 @@ func (s *StepMobileUIValidation) AssertImageNotExists(expectedImagePath string, func (s *StepMobileUIValidation) AssertAI(prompt string, msg ...string) *StepMobileUIValidation { v := Validator{ - Check: uixt.SelectorAI, - Assert: uixt.AssertionAI, + Check: option.SelectorAI, + Assert: option.AssertionAI, Expect: prompt, } if len(msg) > 0 { @@ -628,8 +628,8 @@ func (s *StepMobileUIValidation) AssertAI(prompt string, msg ...string) *StepMob func (s *StepMobileUIValidation) AssertAppInForeground(packageName string, msg ...string) *StepMobileUIValidation { v := Validator{ - Check: uixt.SelectorForegroundApp, - Assert: uixt.AssertionEqual, + Check: option.SelectorForegroundApp, + Assert: option.AssertionEqual, Expect: packageName, } if len(msg) > 0 { @@ -643,8 +643,8 @@ func (s *StepMobileUIValidation) AssertAppInForeground(packageName string, msg . func (s *StepMobileUIValidation) AssertAppNotInForeground(packageName string, msg ...string) *StepMobileUIValidation { v := Validator{ - Check: uixt.SelectorForegroundApp, - Assert: uixt.AssertionNotEqual, + Check: option.SelectorForegroundApp, + Assert: option.AssertionNotEqual, Expect: packageName, } if len(msg) > 0 { @@ -739,7 +739,7 @@ func runStepMobileUI(s *SessionRunner, step IStep) (stepResult *StepResult, err startTime := time.Now() actionResult := &ActionResult{ MobileAction: uixt.MobileAction{ - Method: uixt.ACTION_GetForegroundApp, + Method: option.ACTION_GetForegroundApp, Params: "[ForDebug] check foreground app", }, StartTime: startTime.Unix(), @@ -758,7 +758,7 @@ func runStepMobileUI(s *SessionRunner, step IStep) (stepResult *StepResult, err startTime := time.Now() actionResult := &ActionResult{ MobileAction: uixt.MobileAction{ - Method: uixt.ACTION_ClosePopups, + Method: option.ACTION_ClosePopups, Params: "[ForDebug] close popups handler", }, StartTime: startTime.Unix(), @@ -802,9 +802,9 @@ func runStepMobileUI(s *SessionRunner, step IStep) (stepResult *StepResult, err } // stat uixt action - if action.Method == uixt.ACTION_LOG { + if action.Method == option.ACTION_LOG { log.Info().Interface("action", action.Params).Msg("stat uixt action") - actionMethod := uixt.ActionMethod(action.Params.(string)) + actionMethod := option.ActionMethod(action.Params.(string)) s.summary.Stat.Actions[actionMethod]++ continue } diff --git a/summary.go b/summary.go index 8fb89557..d1dc1244 100644 --- a/summary.go +++ b/summary.go @@ -15,7 +15,7 @@ import ( "github.com/httprunner/httprunner/v5/internal/builtin" "github.com/httprunner/httprunner/v5/internal/config" "github.com/httprunner/httprunner/v5/internal/version" - "github.com/httprunner/httprunner/v5/uixt" + "github.com/httprunner/httprunner/v5/uixt/option" ) func NewSummary() *Summary { @@ -28,7 +28,7 @@ func NewSummary() *Summary { Success: true, Stat: &Stat{ TestSteps: TestStepStat{ - Actions: make(map[uixt.ActionMethod]int), + Actions: make(map[option.ActionMethod]int), }, }, Time: &TestCaseTime{ @@ -146,10 +146,10 @@ type TestCaseStat struct { } type TestStepStat struct { - Total int `json:"total" yaml:"total"` - Successes int `json:"successes" yaml:"successes"` - Failures int `json:"failures" yaml:"failures"` - Actions map[uixt.ActionMethod]int `json:"actions" yaml:"actions"` // record action stats + Total int `json:"total" yaml:"total"` + Successes int `json:"successes" yaml:"successes"` + Failures int `json:"failures" yaml:"failures"` + Actions map[option.ActionMethod]int `json:"actions" yaml:"actions"` // record action stats } type TestCaseTime struct { @@ -167,7 +167,7 @@ func NewCaseSummary() *TestCaseSummary { return &TestCaseSummary{ Success: true, Stat: &TestStepStat{ - Actions: make(map[uixt.ActionMethod]int), + Actions: make(map[option.ActionMethod]int), }, Time: &TestCaseTime{ StartAt: time.Now(), diff --git a/uixt/android_driver_adb.go b/uixt/android_driver_adb.go index bdc7035c..21b8ea01 100644 --- a/uixt/android_driver_adb.go +++ b/uixt/android_driver_adb.go @@ -312,7 +312,7 @@ func (ad *ADBDriver) TapAbsXY(x, y float64, opts ...option.ActionOption) error { if err != nil { return err } - defer postHandler(ad, ACTION_TapAbsXY, actionOptions) + defer postHandler(ad, option.ACTION_TapAbsXY, actionOptions) // adb shell input tap x y xStr := fmt.Sprintf("%.1f", x) @@ -331,7 +331,7 @@ func (ad *ADBDriver) DoubleTap(x, y float64, opts ...option.ActionOption) error if err != nil { return err } - defer postHandler(ad, ACTION_DoubleTapXY, actionOptions) + defer postHandler(ad, option.ACTION_DoubleTapXY, actionOptions) // adb shell input tap x y xStr := fmt.Sprintf("%.1f", x) @@ -380,7 +380,7 @@ func (ad *ADBDriver) Drag(fromX, fromY, toX, toY float64, opts ...option.ActionO if err != nil { return err } - defer postHandler(ad, ACTION_Drag, actionOptions) + defer postHandler(ad, option.ACTION_Drag, actionOptions) duration := 200.0 if actionOptions.Duration > 0 { @@ -412,7 +412,7 @@ func (ad *ADBDriver) Swipe(fromX, fromY, toX, toY float64, opts ...option.Action if err != nil { return err } - defer postHandler(ad, ACTION_Swipe, actionOptions) + defer postHandler(ad, option.ACTION_Swipe, actionOptions) // adb shell input swipe fromX fromY toX toY _, err = ad.runShellCommand( diff --git a/uixt/android_driver_uia2.go b/uixt/android_driver_uia2.go index 320250cf..e7c12573 100644 --- a/uixt/android_driver_uia2.go +++ b/uixt/android_driver_uia2.go @@ -262,7 +262,7 @@ func (ud *UIA2Driver) DoubleTap(x, y float64, opts ...option.ActionOption) error if err != nil { return err } - defer postHandler(ud, ACTION_DoubleTapXY, actionOptions) + defer postHandler(ud, option.ACTION_DoubleTapXY, actionOptions) data := map[string]interface{}{ "actions": []interface{}{ @@ -304,7 +304,7 @@ func (ud *UIA2Driver) TapAbsXY(x, y float64, opts ...option.ActionOption) error if err != nil { return err } - defer postHandler(ud, ACTION_TapAbsXY, actionOptions) + defer postHandler(ud, option.ACTION_TapAbsXY, actionOptions) duration := 100.0 if actionOptions.PressDuration > 0 { @@ -367,7 +367,7 @@ func (ud *UIA2Driver) Drag(fromX, fromY, toX, toY float64, opts ...option.Action if err != nil { return err } - defer postHandler(ud, ACTION_Drag, actionOptions) + defer postHandler(ud, option.ACTION_Drag, actionOptions) data := map[string]interface{}{ "startX": fromX, @@ -398,7 +398,7 @@ func (ud *UIA2Driver) Swipe(fromX, fromY, toX, toY float64, opts ...option.Actio if err != nil { return err } - defer postHandler(ud, ACTION_Swipe, actionOptions) + defer postHandler(ud, option.ACTION_Swipe, actionOptions) duration := 200.0 if actionOptions.PressDuration > 0 { diff --git a/uixt/browser_driver.go b/uixt/browser_driver.go index bdf09e5d..d074eb9d 100644 --- a/uixt/browser_driver.go +++ b/uixt/browser_driver.go @@ -119,7 +119,7 @@ func (wd *BrowserDriver) Drag(fromX, fromY, toX, toY float64, options ...option. if err != nil { return err } - defer postHandler(wd, ACTION_Drag, actionOptions) + defer postHandler(wd, option.ACTION_Drag, actionOptions) data := map[string]interface{}{ "from_x": fromX, @@ -518,7 +518,7 @@ func (wd *BrowserDriver) TapFloat(x, y float64, opts ...option.ActionOption) err if err != nil { return err } - defer postHandler(wd, ACTION_TapAbsXY, actionOptions) + defer postHandler(wd, option.ACTION_TapAbsXY, actionOptions) duration := 0.1 if actionOptions.Duration > 0 { @@ -542,7 +542,7 @@ func (wd *BrowserDriver) DoubleTap(x, y float64, options ...option.ActionOption) if err != nil { return err } - defer postHandler(wd, ACTION_DoubleTapXY, actionOptions) + defer postHandler(wd, option.ACTION_DoubleTapXY, actionOptions) data := map[string]interface{}{ "x": x, diff --git a/uixt/driver_action.go b/uixt/driver_action.go index 810b7233..f39cb1c2 100644 --- a/uixt/driver_action.go +++ b/uixt/driver_action.go @@ -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, diff --git a/uixt/driver_ext_screenshot.go b/uixt/driver_ext_screenshot.go index d0e66b19..17f3eabe 100644 --- a/uixt/driver_ext_screenshot.go +++ b/uixt/driver_ext_screenshot.go @@ -322,7 +322,7 @@ func compressImageBuffer(raw *bytes.Buffer) (compressed *bytes.Buffer, err error } // MarkUIOperation add operation mark for UI operation -func MarkUIOperation(driver IDriver, actionType ActionMethod, actionCoordinates []float64) error { +func MarkUIOperation(driver IDriver, actionType option.ActionMethod, actionCoordinates []float64) error { if actionType == "" || len(actionCoordinates) == 0 { return nil } @@ -341,14 +341,14 @@ func MarkUIOperation(driver IDriver, actionType ActionMethod, actionCoordinates fmt.Sprintf("action_%s_pre_%s.png", timestamp, actionType), ) - if actionType == ACTION_TapAbsXY || actionType == ACTION_DoubleTapXY { + if actionType == option.ACTION_TapAbsXY || actionType == option.ACTION_DoubleTapXY { if len(actionCoordinates) != 2 { return fmt.Errorf("invalid tap action coordinates: %v", actionCoordinates) } x, y := actionCoordinates[0], actionCoordinates[1] point := image.Point{X: int(x), Y: int(y)} err = SaveImageWithCircleMarker(compressedBufSource, point, imagePath) - } else if actionType == ACTION_Swipe || actionType == ACTION_Drag { + } else if actionType == option.ACTION_Swipe || actionType == option.ACTION_Drag { if len(actionCoordinates) != 4 { return fmt.Errorf("invalid swipe action coordinates: %v", actionCoordinates) } diff --git a/uixt/driver_handler.go b/uixt/driver_handler.go index e6ffa464..e34da4f3 100644 --- a/uixt/driver_handler.go +++ b/uixt/driver_handler.go @@ -51,7 +51,7 @@ func preHandler_TapAbsXY(driver IDriver, options *option.ActionOptions, rawX, ra // mark UI operation if options.PreMarkOperation { - if markErr := MarkUIOperation(driver, ACTION_TapAbsXY, []float64{x, y}); markErr != nil { + if markErr := MarkUIOperation(driver, option.ACTION_TapAbsXY, []float64{x, y}); markErr != nil { log.Warn().Err(markErr).Msg("Failed to mark tap operation") } } @@ -71,7 +71,7 @@ func preHandler_DoubleTap(driver IDriver, options *option.ActionOptions, rawX, r // mark UI operation if options.PreMarkOperation { - if markErr := MarkUIOperation(driver, ACTION_DoubleTapXY, []float64{x, y}); markErr != nil { + if markErr := MarkUIOperation(driver, option.ACTION_DoubleTapXY, []float64{x, y}); markErr != nil { log.Warn().Err(markErr).Msg("Failed to mark double tap operation") } } @@ -90,7 +90,7 @@ func preHandler_Drag(driver IDriver, options *option.ActionOptions, rawFomX, raw // mark UI operation if options.PreMarkOperation { - if markErr := MarkUIOperation(driver, ACTION_Drag, []float64{fromX, fromY, toX, toY}); markErr != nil { + if markErr := MarkUIOperation(driver, option.ACTION_Drag, []float64{fromX, fromY, toX, toY}); markErr != nil { log.Warn().Err(markErr).Msg("Failed to mark drag operation") } } @@ -109,7 +109,7 @@ func preHandler_Swipe(driver IDriver, options *option.ActionOptions, rawFomX, ra // save screenshot before action and mark UI operation if options.PreMarkOperation { - if markErr := MarkUIOperation(driver, ACTION_Swipe, []float64{fromX, fromY, toX, toY}); markErr != nil { + if markErr := MarkUIOperation(driver, option.ACTION_Swipe, []float64{fromX, fromY, toX, toY}); markErr != nil { log.Warn().Err(markErr).Msg("Failed to mark swipe operation") } } @@ -117,7 +117,7 @@ func preHandler_Swipe(driver IDriver, options *option.ActionOptions, rawFomX, ra return fromX, fromY, toX, toY, nil } -func postHandler(driver IDriver, actionType ActionMethod, options *option.ActionOptions) error { +func postHandler(driver IDriver, actionType option.ActionMethod, options *option.ActionOptions) error { // save screenshot after action if options.PostMarkOperation { // get compressed screenshot buffer diff --git a/uixt/driver_utils.go b/uixt/driver_utils.go index 162b6d97..cc3b9e92 100644 --- a/uixt/driver_utils.go +++ b/uixt/driver_utils.go @@ -130,23 +130,23 @@ func (dExt *XTDriver) assertOCR(text, assert string) error { opts = append(opts, option.WithScreenShotFileName(fmt.Sprintf("assert_ocr_%s", text))) switch assert { - case AssertionEqual: + case option.AssertionEqual: _, err := dExt.FindScreenText(text, opts...) if err != nil { return errors.Wrap(err, "assert ocr equal failed") } - case AssertionNotEqual: + case option.AssertionNotEqual: _, err := dExt.FindScreenText(text, opts...) if err == nil { return errors.New("assert ocr not equal failed") } - case AssertionExists: + case option.AssertionExists: opts = append(opts, option.WithRegex(true)) _, err := dExt.FindScreenText(text, opts...) if err != nil { return errors.Wrap(err, "assert ocr exists failed") } - case AssertionNotExists: + case option.AssertionNotExists: opts = append(opts, option.WithRegex(true)) _, err := dExt.FindScreenText(text, opts...) if err == nil { @@ -166,11 +166,11 @@ func (dExt *XTDriver) assertForegroundApp(appName, assert string) error { } switch assert { - case AssertionEqual: + case option.AssertionEqual: if app.PackageName != appName { return errors.Wrap(err, "assert foreground app equal failed") } - case AssertionNotEqual: + case option.AssertionNotEqual: if app.PackageName == appName { return errors.New("assert foreground app not equal failed") } @@ -186,12 +186,12 @@ func (dExt *XTDriver) assertSelector(selector, assert string) error { return errors.New("assert selector only supports browser driver") } switch assert { - case AssertionExists: + case option.AssertionExists: _, err := driver.IsElementExistBySelector(selector) if err != nil { return errors.Wrap(err, "assert ocr exists failed") } - case AssertionNotExists: + case option.AssertionNotExists: _, err := driver.IsElementExistBySelector(selector) if err == nil { return errors.New("assert ocr not exists failed") @@ -204,13 +204,13 @@ func (dExt *XTDriver) assertSelector(selector, assert string) error { func (dExt *XTDriver) DoValidation(check, assert, expected string, message ...string) (err error) { switch check { - case SelectorOCR: + case option.SelectorOCR: err = dExt.assertOCR(expected, assert) - case SelectorAI: + case option.SelectorAI: err = dExt.AIAssert(assert) - case SelectorForegroundApp: + case option.SelectorForegroundApp: err = dExt.assertForegroundApp(expected, assert) - case SelectorSelector: + case option.SelectorSelector: err = dExt.assertSelector(expected, assert) default: return fmt.Errorf("validator %s not implemented", check) diff --git a/uixt/harmony_driver_hdc.go b/uixt/harmony_driver_hdc.go index 8a578c01..046ac10d 100644 --- a/uixt/harmony_driver_hdc.go +++ b/uixt/harmony_driver_hdc.go @@ -159,7 +159,7 @@ func (hd *HDCDriver) TapAbsXY(x, y float64, opts ...option.ActionOption) error { if err != nil { return err } - defer postHandler(hd, ACTION_TapAbsXY, actionOptions) + defer postHandler(hd, option.ACTION_TapAbsXY, actionOptions) if actionOptions.Identifier != "" { startTime := int(time.Now().UnixMilli()) @@ -191,7 +191,7 @@ func (hd *HDCDriver) Swipe(fromX, fromY, toX, toY float64, opts ...option.Action if err != nil { return err } - defer postHandler(hd, ACTION_Swipe, actionOptions) + defer postHandler(hd, option.ACTION_Swipe, actionOptions) duration := 200 if actionOptions.PressDuration > 0 { diff --git a/uixt/ios_driver_wda.go b/uixt/ios_driver_wda.go index 3595a667..d3c649e9 100644 --- a/uixt/ios_driver_wda.go +++ b/uixt/ios_driver_wda.go @@ -602,7 +602,7 @@ func (wd *WDADriver) TapAbsXY(x, y float64, opts ...option.ActionOption) error { if err != nil { return err } - defer postHandler(wd, ACTION_TapAbsXY, actionOptions) + defer postHandler(wd, option.ACTION_TapAbsXY, actionOptions) data := map[string]interface{}{ "x": x, @@ -627,7 +627,7 @@ func (wd *WDADriver) DoubleTap(x, y float64, opts ...option.ActionOption) error if err != nil { return err } - defer postHandler(wd, ACTION_DoubleTapXY, actionOptions) + defer postHandler(wd, option.ACTION_DoubleTapXY, actionOptions) data := map[string]interface{}{ "x": x, @@ -664,7 +664,7 @@ func (wd *WDADriver) Drag(fromX, fromY, toX, toY float64, opts ...option.ActionO if err != nil { return err } - defer postHandler(wd, ACTION_Drag, actionOptions) + defer postHandler(wd, option.ACTION_Drag, actionOptions) data := map[string]interface{}{ "fromX": math.Round(fromX*10) / 10, diff --git a/uixt/option/action.go b/uixt/option/action.go index ac3ca847..90de943a 100644 --- a/uixt/option/action.go +++ b/uixt/option/action.go @@ -8,6 +8,76 @@ import ( "github.com/rs/zerolog/log" ) +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 ActionOptions struct { Context context.Context `json:"-" yaml:"-"` // log diff --git a/uixt/sdk.go b/uixt/sdk.go index fd282699..3bc557ed 100644 --- a/uixt/sdk.go +++ b/uixt/sdk.go @@ -94,7 +94,7 @@ func convertActionToCallToolRequest(action MobileAction) (mcp.CallToolRequest, e return mcp.CallToolRequest{}, nil } -func (dExt *XTDriver) DoAction2(action MobileAction) (err error) { +func (dExt *XTDriver) ExecuteAction(action MobileAction) (err error) { // convert action to call tool request req, err := convertActionToCallToolRequest(action) if err != nil {