feat: SwipeToTapApp, SwipeToTapText

This commit is contained in:
debugtalk
2022-08-31 21:21:55 +08:00
parent f13291cf95
commit c768c189e4
3 changed files with 138 additions and 2 deletions

View File

@@ -0,0 +1,45 @@
package uitest
import (
"fmt"
"testing"
"github.com/httprunner/httprunner/v4/hrp"
)
func TestIOSWeixinLive(t *testing.T) {
testCase := &hrp.TestCase{
Config: hrp.NewConfig("通过 feed 卡片进入微信直播间"),
TestSteps: []hrp.IStep{
hrp.NewStep("启动微信").
IOS().
Home().
AppTerminate("com.tencent.xin"). // 关闭已运行的微信,确保启动微信后在「微信」首页
SwipeToTapApp("微信", hrp.WithMaxRetryTimes(5)).
Validate().
AssertLabelExists("通讯录", "微信启动失败,「通讯录」不存在"),
hrp.NewStep("进入直播页").
IOS().
Tap("发现"). // 进入「发现页」
TapByOCR("视频号"). // 通过 OCR 识别「视频号」
Validate().
AssertLabelExists("视频号"),
hrp.NewStep("处理青少年弹窗").
IOS().
TapByOCR("我知道了", hrp.WithIgnoreNotFoundError(false)),
hrp.NewStep("在推荐页上划,直到出现「轻触进入直播间」").
IOS().
SwipeToTapText("轻触进入直播间", hrp.WithMaxRetryTimes(10)),
hrp.NewStep("向上滑动,等待 60s").
IOS().
SwipeUp().Sleep(60).ScreenShot(). // 上划 1 次,等待 60s截图保存
SwipeUp().Times(60).ScreenShot(), // 再上划 1 次,等待 60s截图保存
},
}
fmt.Println(testCase)
err := hrp.NewRunner(t).Run(testCase)
if err != nil {
t.Fatal(err)
}
}

View File

@@ -49,18 +49,29 @@ const (
uiSelectorImage string = "ui_image"
assertionExists string = "exists"
assertionNotExists string = "not_exists"
// custom actions
swipeToTapApp MobileMethod = "swipe_to_tap_app" // swipe left & right to find app and tap
swipeToTapText MobileMethod = "swipe_to_tap_text" // swipe up & down to find text and tap
)
type MobileAction struct {
Method MobileMethod `json:"method" yaml:"method"`
Params interface{} `json:"params,omitempty" yaml:"params,omitempty"`
maxRetryTimes int // max retry times
timeout int // TODO: wait timeout in seconds for mobile action
ignoreNotFoundError bool // ignore error if target element not found
}
type ActionOption func(o *MobileAction)
func WithMaxRetryTimes(maxRetryTimes int) ActionOption {
return func(o *MobileAction) {
o.maxRetryTimes = maxRetryTimes
}
}
func WithTimeout(timeout int) ActionOption {
return func(o *MobileAction) {
o.timeout = timeout

View File

@@ -187,6 +187,38 @@ func (s *StepIOS) SwipeRight() *StepIOS {
return &StepIOS{step: s.step}
}
func (s *StepIOS) SwipeToTapApp(appName string, options ...ActionOption) *StepIOS {
action := MobileAction{
Method: swipeToTapApp,
Params: appName,
}
for _, option := range options {
option(&action)
}
// default to retry 5 times
if action.maxRetryTimes == 0 {
action.maxRetryTimes = 5
}
s.step.IOS.Actions = append(s.step.IOS.Actions, action)
return &StepIOS{step: s.step}
}
func (s *StepIOS) SwipeToTapText(text string, options ...ActionOption) *StepIOS {
action := MobileAction{
Method: swipeToTapText,
Params: text,
}
for _, option := range options {
option(&action)
}
// default to retry 10 times
if action.maxRetryTimes == 0 {
action.maxRetryTimes = 10
}
s.step.IOS.Actions = append(s.step.IOS.Actions, action)
return &StepIOS{step: s.step}
}
func (s *StepIOS) Input(text string) *StepIOS {
s.step.IOS.Actions = append(s.step.IOS.Actions, MobileAction{
Method: uiInput,
@@ -519,12 +551,60 @@ func (ud *uiDriver) doAction(action MobileAction) error {
if bundleId, ok := action.Params.(string); ok {
return ud.AppLaunch(bundleId)
}
return fmt.Errorf("app_launch params should be bundleId(string), got %v", action.Params)
return fmt.Errorf("invalid %s params, should be bundleId(string), got %v",
appLaunch, action.Params)
case appLaunchUnattached:
if bundleId, ok := action.Params.(string); ok {
return ud.AppLaunchUnattached(bundleId)
}
return fmt.Errorf("app_launch_unattached params should be bundleId(string), got %v", action.Params)
return fmt.Errorf("invalid %s params, should be bundleId(string), got %v",
appLaunchUnattached, action.Params)
case swipeToTapApp:
if appName, ok := action.Params.(string); ok {
var x, y, width, height float64
findApp := func(d *uixt.DriverExt) error {
var err error
x, y, width, height, err = d.FindTextByOCR(appName)
return err
}
foundAppAction := func(d *uixt.DriverExt) error {
// click app to launch
return d.TapFloat(x+width*0.5, y+height*0.5-20)
}
// go to home screen
if err := ud.WebDriver.Homescreen(); err != nil {
return errors.Wrap(err, "go to home screen failed")
}
// swipe to first screen
for i := 0; i < 5; i++ {
ud.SwipeTo("right")
}
// swipe next screen until app found
return ud.SwipeUntil("left", findApp, foundAppAction, action.maxRetryTimes)
}
return fmt.Errorf("invalid %s params, should be app name(string), got %v",
swipeToTapApp, action.Params)
case swipeToTapText:
if text, ok := action.Params.(string); ok {
var x, y, width, height float64
findText := func(d *uixt.DriverExt) error {
var err error
x, y, width, height, err = d.FindTextByOCR(text)
return err
}
foundTextAction := func(d *uixt.DriverExt) error {
// tap text
return d.TapFloat(x+width*0.5, y+height*0.5)
}
// swipe until live room found
return ud.SwipeUntil("up", findText, foundTextAction, 20)
}
return fmt.Errorf("invalid %s params, should be app text(string), got %v",
swipeToTapText, action.Params)
case appTerminate:
if bundleId, ok := action.Params.(string); ok {
success, err := ud.AppTerminate(bundleId)