From 6ec187d995f6f39d6f3f2143753e1325d44e879f Mon Sep 17 00:00:00 2001 From: "xucong.053" Date: Thu, 13 Oct 2022 14:17:24 +0800 Subject: [PATCH 1/3] feat: input params by funcion in ui automation --- hrp/internal/builtin/function.go | 5 +++++ hrp/pkg/uixt/ext.go | 8 ++++++++ hrp/step.go | 1 + hrp/step_mobile_ui.go | 7 +++++++ 4 files changed, 21 insertions(+) diff --git a/hrp/internal/builtin/function.go b/hrp/internal/builtin/function.go index a5b3c36f..00d01d97 100644 --- a/hrp/internal/builtin/function.go +++ b/hrp/internal/builtin/function.go @@ -28,6 +28,7 @@ var Functions = map[string]interface{}{ "md5": MD5, // call with one argument "parameterize": loadFromCSV, "P": loadFromCSV, + "split_by_comma": splitByComma, // call with one argument "environ": os.Getenv, "ENV": os.Getenv, "load_ws_message": loadMessage, @@ -225,3 +226,7 @@ func multipartContentType(w *TFormDataWriter) string { } return w.Writer.FormDataContentType() } + +func splitByComma(s string) []string { + return strings.Split(s, ",") +} diff --git a/hrp/pkg/uixt/ext.go b/hrp/pkg/uixt/ext.go index 25a3bb44..276b6946 100644 --- a/hrp/pkg/uixt/ext.go +++ b/hrp/pkg/uixt/ext.go @@ -67,6 +67,7 @@ type MobileAction struct { Identifier string `json:"identifier,omitempty" yaml:"identifier,omitempty"` // used to identify the action in log MaxRetryTimes int `json:"max_retry_times,omitempty" yaml:"max_retry_times,omitempty"` // max retry times Direction interface{} `json:"direction,omitempty" yaml:"direction,omitempty"` // used by swipe to tap text or app + Function string `json:"function,omitempty" yaml:"function,omitempty"` // used to replace params Index int `json:"index,omitempty" yaml:"index,omitempty"` // index of the target element, should start from 1 Timeout int `json:"timeout,omitempty" yaml:"timeout,omitempty"` // TODO: wait timeout in seconds for mobile action IgnoreNotFoundError bool `json:"ignore_NotFoundError,omitempty" yaml:"ignore_NotFoundError,omitempty"` // ignore error if target element not found @@ -89,6 +90,13 @@ func WithIndex(index int) ActionOption { } } +// WithFunction replaces params +func WithFunction(function string) ActionOption { + return func(o *MobileAction) { + o.Function = function + } +} + // WithDirection inputs direction (up, down, left, right) func WithDirection(direction string) ActionOption { return func(o *MobileAction) { diff --git a/hrp/step.go b/hrp/step.go index ac7481f1..f10fc84f 100644 --- a/hrp/step.go +++ b/hrp/step.go @@ -31,6 +31,7 @@ var ( WithDescription = uixt.WithDescription WithDirection = uixt.WithDirection WithCustomDirection = uixt.WithCustomDirection + WithFunction = uixt.WithFunction ) var ( diff --git a/hrp/step_mobile_ui.go b/hrp/step_mobile_ui.go index 64e22f65..fa924edb 100644 --- a/hrp/step_mobile_ui.go +++ b/hrp/step_mobile_ui.go @@ -618,6 +618,13 @@ func runStepMobileUI(s *SessionRunner, step *TStep) (stepResult *StepResult, err // run actions for _, action := range actions { + if action.Function != "" { + parsedParams, err := parser.ParseString(action.Function, stepVariables) + if err != nil { + return stepResult, err + } + action.Params = parsedParams + } if action.Params, err = parser.Parse(action.Params, stepVariables); err != nil { return stepResult, errors.Wrap(err, "parse action params failed") } From 3aaa6708fe66800f1c954808d1a42d68cfdc414d Mon Sep 17 00:00:00 2001 From: "xucong.053" Date: Thu, 13 Oct 2022 14:23:06 +0800 Subject: [PATCH 2/3] update: add kuaishou ui automation case --- .../uitest/ios_kuaishou_follow_live_test.go | 60 +++++++ .../uitest/ios_kuaishou_follow_live_test.json | 154 ++++++++++++++++++ .../uitest/ios_kuaishou_follow_live_test.yaml | 84 ++++++++++ 3 files changed, 298 insertions(+) create mode 100644 examples/uitest/ios_kuaishou_follow_live_test.go create mode 100644 examples/uitest/ios_kuaishou_follow_live_test.json create mode 100644 examples/uitest/ios_kuaishou_follow_live_test.yaml diff --git a/examples/uitest/ios_kuaishou_follow_live_test.go b/examples/uitest/ios_kuaishou_follow_live_test.go new file mode 100644 index 00000000..cfbac1a0 --- /dev/null +++ b/examples/uitest/ios_kuaishou_follow_live_test.go @@ -0,0 +1,60 @@ +//go:build localtest + +package uitest + +import ( + "testing" + + "github.com/httprunner/httprunner/v4/hrp" +) + +func TestIOSKuaiShouLive(t *testing.T) { + testCase := &hrp.TestCase{ + Config: hrp.NewConfig("直播_快手_关注天窗_ios"). + WithVariables(map[string]interface{}{ + "device": "${ENV(UDID)}", + "ups": "大哥,王者", + }). + SetIOS(hrp.WithUDID("$device"), hrp.WithLogOn(true), hrp.WithWDAPort(8100), hrp.WithWDAMjpegPort(9100)), + TestSteps: []hrp.IStep{ + hrp.NewStep("启动快手"). + IOS(). + AppTerminate("com.jiangjia.gif"). + AppLaunch("com.jiangjia.gif"). + Home(). + SwipeToTapApp("快手", hrp.WithMaxRetryTimes(5)).Sleep(10). + Validate(). + AssertOCRExists("精选", "进入快手失败"), + hrp.NewStep("点击首页"). + IOS(). + TapByOCR("首页", hrp.WithIndex(-1)).Sleep(10), + hrp.NewStep("点击发现页"). + IOS(). + TapByOCR("发现", hrp.WithIndex(1)).Sleep(10), + hrp.NewStep("点击关注页"). + IOS(). + TapByOCR("关注", hrp.WithIndex(1)).Sleep(10), + hrp.NewStep("点击直播标签,进入直播间"). + IOS(). + SwipeToTapTexts([]string{}, hrp.WithFunction("${split_by_comma($ups)}"), hrp.WithCustomDirection(0.6, 0.2, 0.2, 0.2), hrp.WithIdentifier("click_live")).Sleep(60). + Validate(). + AssertOCRExists("说点什么", "进入直播间失败"), + hrp.NewStep("下滑进入下一个直播间"). + IOS(). + Swipe(0.9, 0.7, 0.9, 0.3, hrp.WithIdentifier("slide_in_live")).Sleep(60), + }, + } + + if err := testCase.Dump2JSON("ios_kuaishou_follow_live_test.json"); err != nil { + t.Fatal(err) + } + if err := testCase.Dump2YAML("ios_kuaishou_follow_live_test.yaml"); err != nil { + t.Fatal(err) + } + + runner := hrp.NewRunner(t).SetSaveTests(true) + err := runner.Run(testCase) + if err != nil { + t.Fatal(err) + } +} diff --git a/examples/uitest/ios_kuaishou_follow_live_test.json b/examples/uitest/ios_kuaishou_follow_live_test.json new file mode 100644 index 00000000..fd016081 --- /dev/null +++ b/examples/uitest/ios_kuaishou_follow_live_test.json @@ -0,0 +1,154 @@ +{ + "config": { + "name": "直播_快手_关注天窗_ios", + "variables": { + "device": "${ENV(UDID)}", + "ups": "大哥,王者" + }, + "ios": [ + { + "udid": "$device", + "port": 8100, + "mjpeg_port": 9100, + "log_on": true + } + ] + }, + "teststeps": [ + { + "name": "启动快手", + "ios": { + "actions": [ + { + "method": "app_terminate", + "params": "com.jiangjia.gif" + }, + { + "method": "app_launch", + "params": "com.jiangjia.gif" + }, + { + "method": "home" + }, + { + "method": "swipe_to_tap_app", + "params": "快手", + "max_retry_times": 5 + }, + { + "method": "sleep", + "params": 10 + } + ] + }, + "validate": [ + { + "check": "ui_ocr", + "assert": "exists", + "expect": "精选", + "msg": "进入快手失败" + } + ] + }, + { + "name": "点击首页", + "ios": { + "actions": [ + { + "method": "tap_ocr", + "params": "首页", + "index": -1 + }, + { + "method": "sleep", + "params": 10 + } + ] + } + }, + { + "name": "点击发现页", + "ios": { + "actions": [ + { + "method": "tap_ocr", + "params": "发现", + "index": 1 + }, + { + "method": "sleep", + "params": 10 + } + ] + } + }, + { + "name": "点击关注页", + "ios": { + "actions": [ + { + "method": "tap_ocr", + "params": "关注", + "index": 1 + }, + { + "method": "sleep", + "params": 10 + } + ] + } + }, + { + "name": "点击直播标签,进入直播间", + "ios": { + "actions": [ + { + "method": "swipe_to_tap_texts", + "params": [], + "identifier": "click_live", + "direction": [ + 0.6, + 0.2, + 0.2, + 0.2 + ], + "function": "${split_by_comma($ups)}" + }, + { + "method": "sleep", + "params": 60 + } + ] + }, + "validate": [ + { + "check": "ui_ocr", + "assert": "exists", + "expect": "说点什么", + "msg": "进入直播间失败" + } + ] + }, + { + "name": "下滑进入下一个直播间", + "ios": { + "actions": [ + { + "method": "swipe", + "params": [ + 0.9, + 0.7, + 0.9, + 0.3 + ], + "identifier": "slide_in_live" + }, + { + "method": "sleep", + "params": 60 + } + ] + } + } + ] +} diff --git a/examples/uitest/ios_kuaishou_follow_live_test.yaml b/examples/uitest/ios_kuaishou_follow_live_test.yaml new file mode 100644 index 00000000..c81d75b8 --- /dev/null +++ b/examples/uitest/ios_kuaishou_follow_live_test.yaml @@ -0,0 +1,84 @@ +config: + name: 直播_快手_关注天窗_ios + variables: + device: ${ENV(UDID)} + ups: 大哥,王者 + ios: + - udid: $device + port: 8100 + mjpeg_port: 9100 + log_on: true +teststeps: + - name: 启动快手 + ios: + actions: + - method: app_terminate + params: com.jiangjia.gif + - method: app_launch + params: com.jiangjia.gif + - method: home + - method: swipe_to_tap_app + params: 快手 + max_retry_times: 5 + - method: sleep + params: 10 + validate: + - check: ui_ocr + assert: exists + expect: 精选 + msg: 进入快手失败 + - name: 点击首页 + ios: + actions: + - method: tap_ocr + params: 首页 + index: -1 + - method: sleep + params: 10 + - name: 点击发现页 + ios: + actions: + - method: tap_ocr + params: 发现 + index: 1 + - method: sleep + params: 10 + - name: 点击关注页 + ios: + actions: + - method: tap_ocr + params: 关注 + index: 1 + - method: sleep + params: 10 + - name: 点击直播标签,进入直播间 + ios: + actions: + - method: swipe_to_tap_texts + params: [] + identifier: click_live + direction: + - 0.6 + - 0.2 + - 0.2 + - 0.2 + function: ${split_by_comma($ups)} + - method: sleep + params: 60 + validate: + - check: ui_ocr + assert: exists + expect: 说点什么 + msg: 进入直播间失败 + - name: 下滑进入下一个直播间 + ios: + actions: + - method: swipe + params: + - 0.9 + - 0.7 + - 0.9 + - 0.3 + identifier: slide_in_live + - method: sleep + params: 60 From 88d09f2c4268040f69dbe3737e174a15007b4f3f Mon Sep 17 00:00:00 2001 From: "xucong.053" Date: Thu, 13 Oct 2022 16:39:17 +0800 Subject: [PATCH 3/3] fix: unittest --- .../uitest/ios_kuaishou_follow_live_test.go | 4 ++-- .../uitest/ios_kuaishou_follow_live_test.json | 7 +++---- .../uitest/ios_kuaishou_follow_live_test.yaml | 5 ++--- hrp/pkg/uixt/ext.go | 21 +++++++------------ hrp/step.go | 1 - hrp/step_mobile_ui.go | 9 +------- 6 files changed, 16 insertions(+), 31 deletions(-) diff --git a/examples/uitest/ios_kuaishou_follow_live_test.go b/examples/uitest/ios_kuaishou_follow_live_test.go index cfbac1a0..e16b5be1 100644 --- a/examples/uitest/ios_kuaishou_follow_live_test.go +++ b/examples/uitest/ios_kuaishou_follow_live_test.go @@ -13,7 +13,7 @@ func TestIOSKuaiShouLive(t *testing.T) { Config: hrp.NewConfig("直播_快手_关注天窗_ios"). WithVariables(map[string]interface{}{ "device": "${ENV(UDID)}", - "ups": "大哥,王者", + "ups": "${ENV(LIVEUPLIST)}", }). SetIOS(hrp.WithUDID("$device"), hrp.WithLogOn(true), hrp.WithWDAPort(8100), hrp.WithWDAMjpegPort(9100)), TestSteps: []hrp.IStep{ @@ -36,7 +36,7 @@ func TestIOSKuaiShouLive(t *testing.T) { TapByOCR("关注", hrp.WithIndex(1)).Sleep(10), hrp.NewStep("点击直播标签,进入直播间"). IOS(). - SwipeToTapTexts([]string{}, hrp.WithFunction("${split_by_comma($ups)}"), hrp.WithCustomDirection(0.6, 0.2, 0.2, 0.2), hrp.WithIdentifier("click_live")).Sleep(60). + SwipeToTapTexts("${split_by_comma($ups)}", hrp.WithCustomDirection(0.6, 0.2, 0.2, 0.2), hrp.WithIdentifier("click_live")).Sleep(60). Validate(). AssertOCRExists("说点什么", "进入直播间失败"), hrp.NewStep("下滑进入下一个直播间"). diff --git a/examples/uitest/ios_kuaishou_follow_live_test.json b/examples/uitest/ios_kuaishou_follow_live_test.json index fd016081..3817b167 100644 --- a/examples/uitest/ios_kuaishou_follow_live_test.json +++ b/examples/uitest/ios_kuaishou_follow_live_test.json @@ -3,7 +3,7 @@ "name": "直播_快手_关注天窗_ios", "variables": { "device": "${ENV(UDID)}", - "ups": "大哥,王者" + "ups": "${ENV(LIVEUPLIST)}" }, "ios": [ { @@ -104,15 +104,14 @@ "actions": [ { "method": "swipe_to_tap_texts", - "params": [], + "params": "${split_by_comma($ups)}", "identifier": "click_live", "direction": [ 0.6, 0.2, 0.2, 0.2 - ], - "function": "${split_by_comma($ups)}" + ] }, { "method": "sleep", diff --git a/examples/uitest/ios_kuaishou_follow_live_test.yaml b/examples/uitest/ios_kuaishou_follow_live_test.yaml index c81d75b8..484f0815 100644 --- a/examples/uitest/ios_kuaishou_follow_live_test.yaml +++ b/examples/uitest/ios_kuaishou_follow_live_test.yaml @@ -2,7 +2,7 @@ config: name: 直播_快手_关注天窗_ios variables: device: ${ENV(UDID)} - ups: 大哥,王者 + ups: ${ENV(LIVEUPLIST)} ios: - udid: $device port: 8100 @@ -55,14 +55,13 @@ teststeps: ios: actions: - method: swipe_to_tap_texts - params: [] + params: ${split_by_comma($ups)} identifier: click_live direction: - 0.6 - 0.2 - 0.2 - 0.2 - function: ${split_by_comma($ups)} - method: sleep params: 60 validate: diff --git a/hrp/pkg/uixt/ext.go b/hrp/pkg/uixt/ext.go index 276b6946..e38ffc56 100644 --- a/hrp/pkg/uixt/ext.go +++ b/hrp/pkg/uixt/ext.go @@ -67,7 +67,6 @@ type MobileAction struct { Identifier string `json:"identifier,omitempty" yaml:"identifier,omitempty"` // used to identify the action in log MaxRetryTimes int `json:"max_retry_times,omitempty" yaml:"max_retry_times,omitempty"` // max retry times Direction interface{} `json:"direction,omitempty" yaml:"direction,omitempty"` // used by swipe to tap text or app - Function string `json:"function,omitempty" yaml:"function,omitempty"` // used to replace params Index int `json:"index,omitempty" yaml:"index,omitempty"` // index of the target element, should start from 1 Timeout int `json:"timeout,omitempty" yaml:"timeout,omitempty"` // TODO: wait timeout in seconds for mobile action IgnoreNotFoundError bool `json:"ignore_NotFoundError,omitempty" yaml:"ignore_NotFoundError,omitempty"` // ignore error if target element not found @@ -90,13 +89,6 @@ func WithIndex(index int) ActionOption { } } -// WithFunction replaces params -func WithFunction(function string) ActionOption { - return func(o *MobileAction) { - o.Function = function - } -} - // WithDirection inputs direction (up, down, left, right) func WithDirection(direction string) ActionOption { return func(o *MobileAction) { @@ -437,14 +429,17 @@ func (dExt *DriverExt) DoAction(action MobileAction) error { ACTION_SwipeToTapText, action.Params) case ACTION_SwipeToTapTexts: if texts, ok := action.Params.([]interface{}); ok { + var textList []string + for _, t := range texts { + textList = append(textList, t.(string)) + } + action.Params = textList + } + if texts, ok := action.Params.([]string); ok { var point PointF findText := func(d *DriverExt) error { var err error - var ts []string - for _, t := range texts { - ts = append(ts, t.(string)) - } - points, err := d.GetTextXYs(ts) + points, err := d.GetTextXYs(texts) if err != nil { return err } diff --git a/hrp/step.go b/hrp/step.go index f10fc84f..ac7481f1 100644 --- a/hrp/step.go +++ b/hrp/step.go @@ -31,7 +31,6 @@ var ( WithDescription = uixt.WithDescription WithDirection = uixt.WithDirection WithCustomDirection = uixt.WithCustomDirection - WithFunction = uixt.WithFunction ) var ( diff --git a/hrp/step_mobile_ui.go b/hrp/step_mobile_ui.go index fa924edb..8b16a9ce 100644 --- a/hrp/step_mobile_ui.go +++ b/hrp/step_mobile_ui.go @@ -263,7 +263,7 @@ func (s *StepMobile) SwipeToTapText(text string, options ...uixt.ActionOption) * return &StepMobile{step: s.step} } -func (s *StepMobile) SwipeToTapTexts(texts []string, options ...uixt.ActionOption) *StepMobile { +func (s *StepMobile) SwipeToTapTexts(texts interface{}, options ...uixt.ActionOption) *StepMobile { action := uixt.MobileAction{ Method: uixt.ACTION_SwipeToTapTexts, Params: texts, @@ -618,13 +618,6 @@ func runStepMobileUI(s *SessionRunner, step *TStep) (stepResult *StepResult, err // run actions for _, action := range actions { - if action.Function != "" { - parsedParams, err := parser.ParseString(action.Function, stepVariables) - if err != nil { - return stepResult, err - } - action.Params = parsedParams - } if action.Params, err = parser.Parse(action.Params, stepVariables); err != nil { return stepResult, errors.Wrap(err, "parse action params failed") }