mirror of
https://github.com/httprunner/httprunner.git
synced 2026-09-05 15:37:35 +08:00
feat: support ignoreNotFoundError, ignore error if target element not found
This commit is contained in:
@@ -17,37 +17,46 @@ func (dExt *DriverExt) TapXY(x, y float64) error {
|
|||||||
return dExt.WebDriver.TapFloat(x, y)
|
return dExt.WebDriver.TapFloat(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dExt *DriverExt) TapByOCR(ocrText string) error {
|
func (dExt *DriverExt) TapByOCR(ocrText string, ignoreNotFoundError bool) error {
|
||||||
x, y, width, height, err := dExt.FindTextByOCR(ocrText)
|
x, y, width, height, err := dExt.FindTextByOCR(ocrText)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if ignoreNotFoundError {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return dExt.WebDriver.TapFloat(x+width*0.5, y+height*0.5)
|
return dExt.WebDriver.TapFloat(x+width*0.5, y+height*0.5)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dExt *DriverExt) TapByCV(imagePath string) error {
|
func (dExt *DriverExt) TapByCV(imagePath string, ignoreNotFoundError bool) error {
|
||||||
x, y, width, height, err := dExt.FindImageRectInUIKit(imagePath)
|
x, y, width, height, err := dExt.FindImageRectInUIKit(imagePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if ignoreNotFoundError {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return dExt.WebDriver.TapFloat(x+width*0.5, y+height*0.5)
|
return dExt.WebDriver.TapFloat(x+width*0.5, y+height*0.5)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dExt *DriverExt) Tap(param string) error {
|
func (dExt *DriverExt) Tap(param string, ignoreNotFoundError bool) error {
|
||||||
return dExt.TapOffset(param, 0.5, 0.5)
|
return dExt.TapOffset(param, 0.5, 0.5, ignoreNotFoundError)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dExt *DriverExt) TapOffset(param string, xOffset, yOffset float64) (err error) {
|
func (dExt *DriverExt) TapOffset(param string, xOffset, yOffset float64, ignoreNotFoundError bool) (err error) {
|
||||||
// click on element, find by name attribute
|
// click on element, find by name attribute
|
||||||
ele, err := dExt.FindUIElement(param)
|
ele, err := dExt.FindUIElement(param)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return ele.Click()
|
return ele.Click()
|
||||||
}
|
}
|
||||||
|
|
||||||
var x, y, width, height float64
|
x, y, width, height, err := dExt.FindUIRectInUIKit(param)
|
||||||
if x, y, width, height, err = dExt.FindUIRectInUIKit(param); err != nil {
|
if err != nil {
|
||||||
|
if ignoreNotFoundError {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,6 @@ func TestDriverExt_TapWithOCR(t *testing.T) {
|
|||||||
checkErr(t, err)
|
checkErr(t, err)
|
||||||
|
|
||||||
// 需要点击文字上方的图标
|
// 需要点击文字上方的图标
|
||||||
err = driverExt.TapOffset("抖音", 0.5, -1)
|
err = driverExt.TapOffset("抖音", 0.5, -1, false)
|
||||||
checkErr(t, err)
|
checkErr(t, err)
|
||||||
}
|
}
|
||||||
|
|||||||
+17
@@ -54,6 +54,23 @@ const (
|
|||||||
type MobileAction struct {
|
type MobileAction struct {
|
||||||
Method MobileMethod `json:"method" yaml:"method"`
|
Method MobileMethod `json:"method" yaml:"method"`
|
||||||
Params interface{} `json:"params,omitempty" yaml:"params,omitempty"`
|
Params interface{} `json:"params,omitempty" yaml:"params,omitempty"`
|
||||||
|
|
||||||
|
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 WithTimeout(timeout int) ActionOption {
|
||||||
|
return func(o *MobileAction) {
|
||||||
|
o.timeout = timeout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithIgnoreNotFoundError(ignoreError bool) ActionOption {
|
||||||
|
return func(o *MobileAction) {
|
||||||
|
o.ignoreNotFoundError = ignoreError
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type StepResult struct {
|
type StepResult struct {
|
||||||
|
|||||||
+31
-15
@@ -87,29 +87,41 @@ func (s *StepIOS) TapXY(x, y float64) *StepIOS {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Tap taps on the target element
|
// Tap taps on the target element
|
||||||
func (s *StepIOS) Tap(params string) *StepIOS {
|
func (s *StepIOS) Tap(params string, options ...ActionOption) *StepIOS {
|
||||||
s.step.IOS.Actions = append(s.step.IOS.Actions, MobileAction{
|
action := MobileAction{
|
||||||
Method: uiTap,
|
Method: uiTap,
|
||||||
Params: params,
|
Params: params,
|
||||||
})
|
}
|
||||||
|
for _, option := range options {
|
||||||
|
option(&action)
|
||||||
|
}
|
||||||
|
s.step.IOS.Actions = append(s.step.IOS.Actions, action)
|
||||||
return &StepIOS{step: s.step}
|
return &StepIOS{step: s.step}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tap taps on the target element by OCR recognition
|
// Tap taps on the target element by OCR recognition
|
||||||
func (s *StepIOS) TapByOCR(ocrText string) *StepIOS {
|
func (s *StepIOS) TapByOCR(ocrText string, options ...ActionOption) *StepIOS {
|
||||||
s.step.IOS.Actions = append(s.step.IOS.Actions, MobileAction{
|
action := MobileAction{
|
||||||
Method: uiTapByOCR,
|
Method: uiTapByOCR,
|
||||||
Params: ocrText,
|
Params: ocrText,
|
||||||
})
|
}
|
||||||
|
for _, option := range options {
|
||||||
|
option(&action)
|
||||||
|
}
|
||||||
|
s.step.IOS.Actions = append(s.step.IOS.Actions, action)
|
||||||
return &StepIOS{step: s.step}
|
return &StepIOS{step: s.step}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tap taps on the target element by CV recognition
|
// Tap taps on the target element by CV recognition
|
||||||
func (s *StepIOS) TapByCV(imagePath string) *StepIOS {
|
func (s *StepIOS) TapByCV(imagePath string, options ...ActionOption) *StepIOS {
|
||||||
s.step.IOS.Actions = append(s.step.IOS.Actions, MobileAction{
|
action := MobileAction{
|
||||||
Method: uiTapByCV,
|
Method: uiTapByCV,
|
||||||
Params: imagePath,
|
Params: imagePath,
|
||||||
})
|
}
|
||||||
|
for _, option := range options {
|
||||||
|
option(&action)
|
||||||
|
}
|
||||||
|
s.step.IOS.Actions = append(s.step.IOS.Actions, action)
|
||||||
return &StepIOS{step: s.step}
|
return &StepIOS{step: s.step}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,11 +134,15 @@ func (s *StepIOS) DoubleTapXY(x, y float64) *StepIOS {
|
|||||||
return &StepIOS{step: s.step}
|
return &StepIOS{step: s.step}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StepIOS) DoubleTap(params string) *StepIOS {
|
func (s *StepIOS) DoubleTap(params string, options ...ActionOption) *StepIOS {
|
||||||
s.step.IOS.Actions = append(s.step.IOS.Actions, MobileAction{
|
action := MobileAction{
|
||||||
Method: uiDoubleTap,
|
Method: uiDoubleTap,
|
||||||
Params: params,
|
Params: params,
|
||||||
})
|
}
|
||||||
|
for _, option := range options {
|
||||||
|
option(&action)
|
||||||
|
}
|
||||||
|
s.step.IOS.Actions = append(s.step.IOS.Actions, action)
|
||||||
return &StepIOS{step: s.step}
|
return &StepIOS{step: s.step}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -529,17 +545,17 @@ func (ud *uiDriver) doAction(action MobileAction) error {
|
|||||||
return fmt.Errorf("invalid %s params: %v", uiTapXY, action.Params)
|
return fmt.Errorf("invalid %s params: %v", uiTapXY, action.Params)
|
||||||
case uiTap:
|
case uiTap:
|
||||||
if param, ok := action.Params.(string); ok {
|
if param, ok := action.Params.(string); ok {
|
||||||
return ud.Tap(param)
|
return ud.Tap(param, action.ignoreNotFoundError)
|
||||||
}
|
}
|
||||||
return fmt.Errorf("invalid %s params: %v", uiTap, action.Params)
|
return fmt.Errorf("invalid %s params: %v", uiTap, action.Params)
|
||||||
case uiTapByOCR:
|
case uiTapByOCR:
|
||||||
if ocrText, ok := action.Params.(string); ok {
|
if ocrText, ok := action.Params.(string); ok {
|
||||||
return ud.TapByOCR(ocrText)
|
return ud.TapByOCR(ocrText, action.ignoreNotFoundError)
|
||||||
}
|
}
|
||||||
return fmt.Errorf("invalid %s params: %v", uiTapByOCR, action.Params)
|
return fmt.Errorf("invalid %s params: %v", uiTapByOCR, action.Params)
|
||||||
case uiTapByCV:
|
case uiTapByCV:
|
||||||
if imagePath, ok := action.Params.(string); ok {
|
if imagePath, ok := action.Params.(string); ok {
|
||||||
return ud.TapByCV(imagePath)
|
return ud.TapByCV(imagePath, action.ignoreNotFoundError)
|
||||||
}
|
}
|
||||||
return fmt.Errorf("invalid %s params: %v", uiTapByCV, action.Params)
|
return fmt.Errorf("invalid %s params: %v", uiTapByCV, action.Params)
|
||||||
case uiDoubleTapXY:
|
case uiDoubleTapXY:
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ func TestIOSWeixinLive(t *testing.T) {
|
|||||||
NewStep("进入直播页").
|
NewStep("进入直播页").
|
||||||
IOS().
|
IOS().
|
||||||
Tap("发现").Sleep(5). // 进入「发现页」;等待 5 秒确保加载完成
|
Tap("发现").Sleep(5). // 进入「发现页」;等待 5 秒确保加载完成
|
||||||
TapXY(0.5, 0.3). // 基于坐标位置点击「直播」;TODO:通过 OCR 识别「直播」
|
TapByOCR("直播"). // 通过 OCR 识别「直播」
|
||||||
Validate().
|
Validate().
|
||||||
AssertLabelExists("直播"),
|
AssertLabelExists("直播"),
|
||||||
NewStep("向上滑动 5 次").
|
NewStep("向上滑动 5 次").
|
||||||
|
|||||||
Reference in New Issue
Block a user