mirror of
https://github.com/httprunner/httprunner.git
synced 2026-05-13 08:59:44 +08:00
Merge pull request #1522 from httprunner/bugfix
fix: failed to catch logcat fix: failed to find text in scope fix: failed to set duration option of swipe action change: add back action of mobile ui automation fix: failed to set steps option of android swipe action
This commit is contained in:
@@ -310,6 +310,9 @@ func ConvertPoints(data string) (eps []ExportPoint) {
|
||||
for _, line := range lines {
|
||||
if strings.Contains(line, "ext") {
|
||||
idx := strings.Index(line, "{")
|
||||
if idx == -1 {
|
||||
continue
|
||||
}
|
||||
line = line[idx:]
|
||||
p := ExportPoint{}
|
||||
err := json.Unmarshal([]byte(line), &p)
|
||||
|
||||
@@ -18,6 +18,17 @@ import (
|
||||
"github.com/httprunner/httprunner/v4/hrp/pkg/gadb"
|
||||
)
|
||||
|
||||
// See https://developer.android.com/reference/android/view/KeyEvent
|
||||
const (
|
||||
KEYCODE_BACK string = "4"
|
||||
KEYCODE_CAMERA string = "27"
|
||||
KEYCODE_ALT_LEFT string = "57"
|
||||
KEYCODE_ALT_RIGHT string = "58"
|
||||
KEYCODE_MENU string = "82"
|
||||
KEYCODE_BREAK string = "121"
|
||||
KEYCODE_ALL_APPS string = "284"
|
||||
)
|
||||
|
||||
var errDriverNotImplemented = errors.New("driver method not implemented")
|
||||
|
||||
type uiaDriver struct {
|
||||
@@ -233,9 +244,12 @@ func (ud *uiaDriver) Scale() (scale float64, err error) {
|
||||
}
|
||||
|
||||
// PressBack simulates a short press on the BACK button.
|
||||
func (ud *uiaDriver) PressBack() (err error) {
|
||||
func (ud *uiaDriver) PressBack(options ...DataOption) (err error) {
|
||||
// register(postHandler, new PressBack("/wd/hub/session/:sessionId/back"))
|
||||
_, err = ud.httpPOST(nil, "/session", ud.sessionId, "back")
|
||||
if err != nil {
|
||||
_, err = ud.adbDevice.RunShellCommand("input", "keyevent", KEYCODE_BACK)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -257,7 +271,7 @@ func (ud *uiaDriver) StartCamera() (err error) {
|
||||
return err
|
||||
}
|
||||
time.Sleep(5 * time.Second)
|
||||
if _, err = ud.adbDevice.RunShellCommand("input", "keyevent", "27"); err != nil {
|
||||
if _, err = ud.adbDevice.RunShellCommand("input", "keyevent", KEYCODE_CAMERA); err != nil {
|
||||
return err
|
||||
}
|
||||
return
|
||||
@@ -266,7 +280,7 @@ func (ud *uiaDriver) StartCamera() (err error) {
|
||||
return err
|
||||
}
|
||||
time.Sleep(5 * time.Second)
|
||||
if _, err = ud.adbDevice.RunShellCommand("input", "keyevent", "27"); err != nil {
|
||||
if _, err = ud.adbDevice.RunShellCommand("input", "keyevent", KEYCODE_CAMERA); err != nil {
|
||||
return err
|
||||
}
|
||||
return
|
||||
@@ -578,7 +592,6 @@ func (ud *uiaDriver) _swipe(startX, startY, endX, endY interface{}, options ...D
|
||||
// per step. So for a 100 steps, the swipe will take about 1/2 second to complete.
|
||||
// `steps` is the number of move steps sent to the system
|
||||
func (ud *uiaDriver) Swipe(fromX, fromY, toX, toY int, options ...DataOption) error {
|
||||
options = append(options, WithDataSteps(12))
|
||||
return ud.SwipeFloat(float64(fromX), float64(fromY), float64(toX), float64(toY), options...)
|
||||
}
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ const (
|
||||
ACTION_DoubleTap MobileMethod = "double_tap"
|
||||
ACTION_Swipe MobileMethod = "swipe"
|
||||
ACTION_Input MobileMethod = "input"
|
||||
ACTION_Back MobileMethod = "back"
|
||||
|
||||
// custom actions
|
||||
ACTION_SwipeToTapApp MobileMethod = "swipe_to_tap_app" // swipe left & right to find app and tap
|
||||
@@ -67,6 +68,8 @@ 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
|
||||
WaitTime float64 `json:"wait_time,omitempty" yaml:"wait_time,omitempty"` // wait time between swipe and ocr, unit: second
|
||||
Duration float64 `json:"duration,omitempty" yaml:"duration,omitempty"` // used to set duration of ios swipe action
|
||||
Steps int `json:"steps,omitempty" yaml:"steps,omitempty"` // used to set steps of android swipe action
|
||||
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
|
||||
@@ -98,6 +101,18 @@ func WithWaitTime(sec float64) ActionOption {
|
||||
}
|
||||
}
|
||||
|
||||
func WithDuration(duration float64) ActionOption {
|
||||
return func(o *MobileAction) {
|
||||
o.Duration = duration
|
||||
}
|
||||
}
|
||||
|
||||
func WithSteps(steps int) ActionOption {
|
||||
return func(o *MobileAction) {
|
||||
o.Steps = steps
|
||||
}
|
||||
}
|
||||
|
||||
// WithDirection inputs direction (up, down, left, right)
|
||||
func WithDirection(direction string) ActionOption {
|
||||
return func(o *MobileAction) {
|
||||
@@ -584,6 +599,11 @@ func (dExt *DriverExt) DoAction(action MobileAction) error {
|
||||
return fmt.Errorf("invalid %s params: %v", ACTION_DoubleTap, action.Params)
|
||||
case ACTION_Swipe:
|
||||
identifierOption := WithDataIdentifier(action.Identifier)
|
||||
durationOption := WithDataPressDuration(action.Duration)
|
||||
if action.Steps == 0 {
|
||||
action.Steps = 10
|
||||
}
|
||||
stepsOption := WithDataSteps(action.Steps)
|
||||
if positions, ok := action.Params.([]interface{}); ok {
|
||||
// relative fromX, fromY, toX, toY of window size: [0.5, 0.9, 0.5, 0.1]
|
||||
if len(positions) != 4 {
|
||||
@@ -593,10 +613,10 @@ func (dExt *DriverExt) DoAction(action MobileAction) error {
|
||||
fromY, _ := positions[1].(float64)
|
||||
toX, _ := positions[2].(float64)
|
||||
toY, _ := positions[3].(float64)
|
||||
return dExt.SwipeRelative(fromX, fromY, toX, toY, identifierOption)
|
||||
return dExt.SwipeRelative(fromX, fromY, toX, toY, identifierOption, durationOption, stepsOption)
|
||||
}
|
||||
if direction, ok := action.Params.(string); ok {
|
||||
return dExt.SwipeTo(direction, identifierOption)
|
||||
return dExt.SwipeTo(direction, identifierOption, durationOption, stepsOption)
|
||||
}
|
||||
return fmt.Errorf("invalid %s params: %v", ACTION_Swipe, action.Params)
|
||||
case ACTION_Input:
|
||||
@@ -618,6 +638,8 @@ func (dExt *DriverExt) DoAction(action MobileAction) error {
|
||||
options = append(options, WithDataIdentifier(action.Identifier))
|
||||
}
|
||||
return dExt.Driver.Input(param, options...)
|
||||
case ACTION_Back:
|
||||
return dExt.Driver.PressBack()
|
||||
case CtlSleep:
|
||||
if param, ok := action.Params.(json.Number); ok {
|
||||
seconds, _ := param.Float64()
|
||||
|
||||
@@ -891,7 +891,7 @@ func NewData(data map[string]interface{}, options ...DataOption) *DataOptions {
|
||||
}
|
||||
|
||||
if _, ok := dataOptions.Data["duration"]; !ok {
|
||||
dataOptions.Data["duration"] = 1.0 // default duration
|
||||
dataOptions.Data["duration"] = 0 // default duration
|
||||
}
|
||||
|
||||
if _, ok := dataOptions.Data["frequency"]; !ok {
|
||||
@@ -1046,6 +1046,9 @@ type WebDriver interface {
|
||||
// PressButton Presses the corresponding hardware button on the device
|
||||
PressButton(devBtn DeviceButton) error
|
||||
|
||||
// PressBack Presses the back button
|
||||
PressBack(options ...DataOption) error
|
||||
|
||||
// IOHIDEvent Emulated triggering of the given low-level IOHID device event.
|
||||
// duration: The event duration in float seconds (XCTest uses 0.005 for a single press event)
|
||||
IOHIDEvent(pageID EventPageID, usageID EventUsageID, duration ...float64) error
|
||||
|
||||
@@ -440,12 +440,10 @@ func (wd *wdaDriver) DragFloat(fromX, fromY, toX, toY float64, options ...DataOp
|
||||
}
|
||||
|
||||
func (wd *wdaDriver) Swipe(fromX, fromY, toX, toY int, options ...DataOption) error {
|
||||
options = append(options, WithDataPressDuration(0))
|
||||
return wd.SwipeFloat(float64(fromX), float64(fromY), float64(toX), float64(toY), options...)
|
||||
}
|
||||
|
||||
func (wd *wdaDriver) SwipeFloat(fromX, fromY, toX, toY float64, options ...DataOption) error {
|
||||
options = append(options, WithDataPressDuration(0))
|
||||
return wd.DragFloat(fromX, fromY, toX, toY, options...)
|
||||
}
|
||||
|
||||
@@ -528,6 +526,27 @@ func (wd *wdaDriver) KeyboardDismiss(keyNames ...string) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// PressBack simulates a short press on the BACK button.
|
||||
func (wd *wdaDriver) PressBack(options ...DataOption) (err error) {
|
||||
windowSize, err := wd.WindowSize()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
data := map[string]interface{}{
|
||||
"fromX": float64(windowSize.Width) * 0,
|
||||
"fromY": float64(windowSize.Height) * 0.5,
|
||||
"toX": float64(windowSize.Width) * 0.6,
|
||||
"toY": float64(windowSize.Height) * 0.5,
|
||||
}
|
||||
|
||||
// new data options in post data for extra WDA configurations
|
||||
d := NewData(data, options...)
|
||||
|
||||
_, err = wd.httpPOST(d.Data, "/session", wd.sessionId, "/wda/dragfromtoforduration")
|
||||
return
|
||||
}
|
||||
|
||||
func (wd *wdaDriver) PressButton(devBtn DeviceButton) (err error) {
|
||||
// [[FBRoute POST:@"/wda/pressButton"] respondWithTarget:self action:@selector(handlePressButtonCommand:)]
|
||||
data := map[string]interface{}{"name": devBtn}
|
||||
|
||||
@@ -179,16 +179,16 @@ func (s *veDEMOCRService) FindText(text string, imageBuf []byte, options ...Data
|
||||
}
|
||||
|
||||
rects = append(rects, rect)
|
||||
}
|
||||
|
||||
// contains text while not match exactly
|
||||
if ocrResult.Text != text {
|
||||
continue
|
||||
}
|
||||
// contains text while not match exactly
|
||||
if ocrResult.Text != text {
|
||||
continue
|
||||
}
|
||||
|
||||
// match exactly, and not specify index, return the first one
|
||||
if data.Index == 0 {
|
||||
return rect, nil
|
||||
// match exactly, and not specify index, return the first one
|
||||
if data.Index == 0 {
|
||||
return rect, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,16 +22,18 @@ const (
|
||||
var (
|
||||
WithIdentifier = uixt.WithIdentifier
|
||||
WithMaxRetryTimes = uixt.WithMaxRetryTimes
|
||||
WithWaitTime = uixt.WithWaitTime
|
||||
WithIndex = uixt.WithIndex
|
||||
WithWaitTime = uixt.WithWaitTime // only applicable to SwipeToTap* action
|
||||
WithIndex = uixt.WithIndex // index of the target element, should start from 1, only applicable to ocr actions
|
||||
WithTimeout = uixt.WithTimeout
|
||||
WithIgnoreNotFoundError = uixt.WithIgnoreNotFoundError
|
||||
WithText = uixt.WithText
|
||||
WithID = uixt.WithID
|
||||
WithDescription = uixt.WithDescription
|
||||
WithDuration = uixt.WithDuration // only applicable to ios swipe action
|
||||
WithSteps = uixt.WithSteps // only applicable to android swipe action
|
||||
WithDirection = uixt.WithDirection
|
||||
WithCustomDirection = uixt.WithCustomDirection
|
||||
WithScope = uixt.WithScope
|
||||
WithScope = uixt.WithScope // only applicable to ocr actions
|
||||
WithOffset = uixt.WithOffset
|
||||
)
|
||||
|
||||
|
||||
@@ -181,6 +181,18 @@ func (s *StepMobile) DoubleTap(params string, options ...uixt.ActionOption) *Ste
|
||||
return &StepMobile{step: s.step}
|
||||
}
|
||||
|
||||
func (s *StepMobile) Back(options ...uixt.ActionOption) *StepMobile {
|
||||
action := uixt.MobileAction{
|
||||
Method: uixt.ACTION_Back,
|
||||
Params: nil,
|
||||
}
|
||||
for _, option := range options {
|
||||
option(&action)
|
||||
}
|
||||
s.mobileStep().Actions = append(s.mobileStep().Actions, action)
|
||||
return &StepMobile{step: s.step}
|
||||
}
|
||||
|
||||
func (s *StepMobile) Swipe(sx, sy, ex, ey float64, options ...uixt.ActionOption) *StepMobile {
|
||||
action := uixt.MobileAction{
|
||||
Method: uixt.ACTION_Swipe,
|
||||
|
||||
Reference in New Issue
Block a user