mirror of
https://github.com/httprunner/httprunner.git
synced 2026-05-07 08:02:42 +08:00
Merge pull request #1506 from httprunner/add-offset-to-tap
feat: support offset for tap point
This commit is contained in:
@@ -69,6 +69,7 @@ type MobileAction struct {
|
||||
WaitTime float64 `json:"wait_time,omitempty" yaml:"wait_time,omitempty"` // wait time between swipe and ocr, unit: second
|
||||
Direction interface{} `json:"direction,omitempty" yaml:"direction,omitempty"` // used by swipe to tap text or app
|
||||
Scope []float64 `json:"scope,omitempty" yaml:"scope,omitempty"` // used by ocr to get text position in the scope
|
||||
Offset []int `json:"offset,omitempty" yaml:"offset,omitempty"` // used to tap offset of point
|
||||
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
|
||||
@@ -118,6 +119,12 @@ func WithScope(x1, y1, x2, y2 float64) ActionOption {
|
||||
}
|
||||
}
|
||||
|
||||
func WithOffset(offsetX, offsetY int) ActionOption {
|
||||
return func(o *MobileAction) {
|
||||
o.Offset = []int{offsetX, offsetY}
|
||||
}
|
||||
}
|
||||
|
||||
func WithText(text string) ActionOption {
|
||||
return func(o *MobileAction) {
|
||||
o.Text = text
|
||||
@@ -396,8 +403,12 @@ func (dExt *DriverExt) DoAction(action MobileAction) error {
|
||||
if len(action.Scope) != 4 {
|
||||
action.Scope = []float64{0, 0, 1, 1}
|
||||
}
|
||||
if len(action.Offset) != 2 {
|
||||
action.Offset = []int{0, 0}
|
||||
}
|
||||
|
||||
identifierOption := WithDataIdentifier(action.Identifier)
|
||||
offsetOption := WithDataOffset(action.Offset[0], action.Offset[1])
|
||||
indexOption := WithDataIndex(action.Index)
|
||||
scopeOption := WithDataScope(dExt.getAbsScope(action.Scope[0], action.Scope[1], action.Scope[2], action.Scope[3]))
|
||||
|
||||
@@ -419,7 +430,7 @@ func (dExt *DriverExt) DoAction(action MobileAction) error {
|
||||
}
|
||||
foundTextAction := func(d *DriverExt) error {
|
||||
// tap text
|
||||
return d.TapAbsXY(point.X, point.Y, identifierOption)
|
||||
return d.TapAbsXY(point.X, point.Y, identifierOption, offsetOption)
|
||||
}
|
||||
|
||||
if action.Direction != nil {
|
||||
@@ -443,7 +454,12 @@ func (dExt *DriverExt) DoAction(action MobileAction) error {
|
||||
if len(action.Scope) != 4 {
|
||||
action.Scope = []float64{0, 0, 1, 1}
|
||||
}
|
||||
if len(action.Offset) != 2 {
|
||||
action.Offset = []int{0, 0}
|
||||
}
|
||||
|
||||
identifierOption := WithDataIdentifier(action.Identifier)
|
||||
offsetOption := WithDataOffset(action.Offset[0], action.Offset[1])
|
||||
scopeOption := WithDataScope(dExt.getAbsScope(action.Scope[0], action.Scope[1], action.Scope[2], action.Scope[3]))
|
||||
// default to retry 10 times
|
||||
if action.MaxRetryTimes == 0 {
|
||||
@@ -468,7 +484,7 @@ func (dExt *DriverExt) DoAction(action MobileAction) error {
|
||||
}
|
||||
foundTextAction := func(d *DriverExt) error {
|
||||
// tap text
|
||||
return d.TapAbsXY(point.X, point.Y, WithDataIdentifier(action.Identifier))
|
||||
return d.TapAbsXY(point.X, point.Y, identifierOption, offsetOption)
|
||||
}
|
||||
|
||||
// default to retry 10 times
|
||||
@@ -517,7 +533,10 @@ func (dExt *DriverExt) DoAction(action MobileAction) error {
|
||||
}
|
||||
x, _ := location[0].(float64)
|
||||
y, _ := location[1].(float64)
|
||||
return dExt.TapAbsXY(x, y, WithDataIdentifier(action.Identifier))
|
||||
if len(action.Offset) != 2 {
|
||||
action.Offset = []int{0, 0}
|
||||
}
|
||||
return dExt.TapAbsXY(x, y, WithDataIdentifier(action.Identifier), WithDataOffset(action.Offset[0], action.Offset[1]))
|
||||
}
|
||||
return fmt.Errorf("invalid %s params: %v", ACTION_TapAbsXY, action.Params)
|
||||
case ACTION_Tap:
|
||||
@@ -530,12 +549,16 @@ func (dExt *DriverExt) DoAction(action MobileAction) error {
|
||||
if len(action.Scope) != 4 {
|
||||
action.Scope = []float64{0, 0, 1, 1}
|
||||
}
|
||||
if len(action.Offset) != 2 {
|
||||
action.Offset = []int{0, 0}
|
||||
}
|
||||
|
||||
indexOption := WithDataIndex(action.Index)
|
||||
offsetOption := WithDataOffset(action.Offset[0], action.Offset[1])
|
||||
scopeOption := WithDataScope(dExt.getAbsScope(action.Scope[0], action.Scope[1], action.Scope[2], action.Scope[3]))
|
||||
identifierOption := WithDataIdentifier(action.Identifier)
|
||||
IgnoreNotFoundErrorOption := WithDataIgnoreNotFoundError(action.IgnoreNotFoundError)
|
||||
return dExt.TapByOCR(ocrText, identifierOption, IgnoreNotFoundErrorOption, indexOption, scopeOption)
|
||||
return dExt.TapByOCR(ocrText, identifierOption, IgnoreNotFoundErrorOption, indexOption, scopeOption, offsetOption)
|
||||
}
|
||||
return fmt.Errorf("invalid %s params: %v", ACTION_TapByOCR, action.Params)
|
||||
case ACTION_TapByCV:
|
||||
|
||||
@@ -8,6 +8,8 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/httprunner/httprunner/v4/hrp/internal/builtin"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -777,6 +779,7 @@ type Rect struct {
|
||||
type DataOptions struct {
|
||||
Data map[string]interface{} // configurations used by ios/android driver
|
||||
Scope []int // used by ocr to get text position in the scope
|
||||
Offset []int // used to tap offset of point
|
||||
Index int // index of the target element, should start from 1
|
||||
IgnoreNotFoundError bool // ignore error if target element not found
|
||||
MaxRetryTimes int // max retry times if target element not found
|
||||
@@ -821,6 +824,12 @@ func WithDataScope(x1, x2, y1, y2 int) DataOption {
|
||||
}
|
||||
}
|
||||
|
||||
func WithDataOffset(offsetX, offsetY int) DataOption {
|
||||
return func(data *DataOptions) {
|
||||
data.Offset = []int{offsetX, offsetY}
|
||||
}
|
||||
}
|
||||
|
||||
func WithDataIdentifier(identifier string) DataOption {
|
||||
if identifier == "" {
|
||||
return func(data *DataOptions) {}
|
||||
@@ -866,6 +875,17 @@ func NewData(data map[string]interface{}, options ...DataOption) *DataOptions {
|
||||
dataOptions.Scope = []int{0, 0, math.MaxInt64, math.MaxInt64} // default scope
|
||||
}
|
||||
|
||||
if len(dataOptions.Offset) == 2 {
|
||||
if x, ok := data["x"]; ok {
|
||||
xf, _ := builtin.Interface2Float64(x)
|
||||
data["x"] = xf + float64(dataOptions.Offset[0])
|
||||
}
|
||||
if y, ok := data["y"]; ok {
|
||||
yf, _ := builtin.Interface2Float64(y)
|
||||
data["y"] = yf + float64(dataOptions.Offset[1])
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := dataOptions.Data["steps"]; !ok {
|
||||
dataOptions.Data["steps"] = 12 // default steps
|
||||
}
|
||||
|
||||
@@ -129,9 +129,13 @@ func (dExt *DriverExt) swipeToTapApp(appName string, action MobileAction) error
|
||||
if len(action.Scope) != 4 {
|
||||
action.Scope = []float64{0, 0, 1, 1}
|
||||
}
|
||||
if len(action.Offset) != 2 {
|
||||
action.Offset = []int{0, -25}
|
||||
}
|
||||
|
||||
identifierOption := WithDataIdentifier(action.Identifier)
|
||||
indexOption := WithDataIndex(action.Index)
|
||||
offsetOption := WithDataOffset(action.Offset[0], action.Offset[1])
|
||||
scopeOption := WithDataScope(dExt.getAbsScope(action.Scope[0], action.Scope[1], action.Scope[2], action.Scope[3]))
|
||||
|
||||
// default to retry 5 times
|
||||
@@ -152,7 +156,7 @@ func (dExt *DriverExt) swipeToTapApp(appName string, action MobileAction) error
|
||||
}
|
||||
foundAppAction := func(d *DriverExt) error {
|
||||
// click app to launch
|
||||
return d.TapAbsXY(point.X, point.Y-25, identifierOption)
|
||||
return d.TapAbsXY(point.X, point.Y, identifierOption, offsetOption)
|
||||
}
|
||||
|
||||
// go to home screen
|
||||
|
||||
@@ -32,6 +32,7 @@ var (
|
||||
WithDirection = uixt.WithDirection
|
||||
WithCustomDirection = uixt.WithCustomDirection
|
||||
WithScope = uixt.WithScope
|
||||
WithOffset = uixt.WithOffset
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
Reference in New Issue
Block a user