mirror of
https://github.com/httprunner/httprunner.git
synced 2026-08-29 03:57:22 +08:00
fix: WDA tests
This commit is contained in:
@@ -1 +1 @@
|
|||||||
v5.0.0+2502171750
|
v5.0.0+2502172202
|
||||||
|
|||||||
@@ -316,8 +316,3 @@ func (p PointF) IsIdentical(p2 PointF) bool {
|
|||||||
// set the coordinate precision to 1 pixel
|
// set the coordinate precision to 1 pixel
|
||||||
return math.Abs(p.X-p2.X) < 1 && math.Abs(p.Y-p2.Y) < 1
|
return math.Abs(p.X-p2.X) < 1 && math.Abs(p.Y-p2.Y) < 1
|
||||||
}
|
}
|
||||||
|
|
||||||
type Screen struct {
|
|
||||||
StatusBarSize types.Size `json:"statusBarSize"`
|
|
||||||
Scale float64 `json:"scale"`
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -239,7 +239,7 @@ func (ud *UIA2Driver) TapAbsXY(x, y float64, opts ...option.ActionOption) error
|
|||||||
|
|
||||||
duration := 100.0
|
duration := 100.0
|
||||||
if actionOptions.PressDuration > 0 {
|
if actionOptions.PressDuration > 0 {
|
||||||
duration = actionOptions.PressDuration * 1000
|
duration = actionOptions.PressDuration * 1000 // convert to ms
|
||||||
}
|
}
|
||||||
data := map[string]interface{}{
|
data := map[string]interface{}{
|
||||||
"actions": []interface{}{
|
"actions": []interface{}{
|
||||||
@@ -256,9 +256,7 @@ func (ud *UIA2Driver) TapAbsXY(x, y float64, opts ...option.ActionOption) error
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
option.MergeOptions(data, opts...)
|
||||||
// update data options in post data for extra uiautomator configurations
|
|
||||||
actionOptions.UpdateData(data)
|
|
||||||
|
|
||||||
_, err := ud.Session.POST(data, "/session", ud.Session.ID, "actions/tap")
|
_, err := ud.Session.POST(data, "/session", ud.Session.ID, "actions/tap")
|
||||||
return err
|
return err
|
||||||
@@ -301,9 +299,7 @@ func (ud *UIA2Driver) Drag(fromX, fromY, toX, toY float64, opts ...option.Action
|
|||||||
"endX": toX,
|
"endX": toX,
|
||||||
"endY": toY,
|
"endY": toY,
|
||||||
}
|
}
|
||||||
|
option.MergeOptions(data, opts...)
|
||||||
// update data options in post data for extra uiautomator configurations
|
|
||||||
actionOptions.UpdateData(data)
|
|
||||||
|
|
||||||
// register(postHandler, new Drag("/wd/hub/session/:sessionId/touch/drag"))
|
// register(postHandler, new Drag("/wd/hub/session/:sessionId/touch/drag"))
|
||||||
_, err = ud.Session.POST(data, "/session", ud.Session.ID, "touch/drag")
|
_, err = ud.Session.POST(data, "/session", ud.Session.ID, "touch/drag")
|
||||||
@@ -328,7 +324,7 @@ func (ud *UIA2Driver) Swipe(fromX, fromY, toX, toY float64, opts ...option.Actio
|
|||||||
|
|
||||||
duration := 200.0
|
duration := 200.0
|
||||||
if actionOptions.PressDuration > 0 {
|
if actionOptions.PressDuration > 0 {
|
||||||
duration = actionOptions.PressDuration * 1000
|
duration = actionOptions.PressDuration * 1000 // ms
|
||||||
}
|
}
|
||||||
data := map[string]interface{}{
|
data := map[string]interface{}{
|
||||||
"actions": []interface{}{
|
"actions": []interface{}{
|
||||||
@@ -345,9 +341,7 @@ func (ud *UIA2Driver) Swipe(fromX, fromY, toX, toY float64, opts ...option.Actio
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
option.MergeOptions(data, opts...)
|
||||||
// update data options in post data for extra uiautomator configurations
|
|
||||||
actionOptions.UpdateData(data)
|
|
||||||
|
|
||||||
_, err = ud.Session.POST(data, "/session", ud.Session.ID, "actions/swipe")
|
_, err = ud.Session.POST(data, "/session", ud.Session.ID, "actions/swipe")
|
||||||
return err
|
return err
|
||||||
@@ -400,18 +394,16 @@ func (ud *UIA2Driver) GetPasteboard(contentType types.PasteboardType) (raw *byte
|
|||||||
func (ud *UIA2Driver) Input(text string, opts ...option.ActionOption) (err error) {
|
func (ud *UIA2Driver) Input(text string, opts ...option.ActionOption) (err error) {
|
||||||
// register(postHandler, new SendKeysToElement("/wd/hub/session/:sessionId/keys"))
|
// register(postHandler, new SendKeysToElement("/wd/hub/session/:sessionId/keys"))
|
||||||
// https://github.com/appium/appium-uiautomator2-server/blob/master/app/src/main/java/io/appium/uiautomator2/handler/SendKeysToElement.java#L76-L85
|
// https://github.com/appium/appium-uiautomator2-server/blob/master/app/src/main/java/io/appium/uiautomator2/handler/SendKeysToElement.java#L76-L85
|
||||||
actionOptions := option.NewActionOptions(opts...)
|
|
||||||
err = ud.SendUnicodeKeys(text, opts...)
|
err = ud.SendUnicodeKeys(text, opts...)
|
||||||
if err != nil {
|
if err == nil {
|
||||||
data := map[string]interface{}{
|
return nil
|
||||||
"text": text,
|
|
||||||
}
|
|
||||||
|
|
||||||
// new data options in post data for extra uiautomator configurations
|
|
||||||
actionOptions.UpdateData(data)
|
|
||||||
|
|
||||||
_, err = ud.Session.POST(data, "/session", ud.Session.ID, "/keys")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data := map[string]interface{}{
|
||||||
|
"text": text,
|
||||||
|
}
|
||||||
|
option.MergeOptions(data, opts...)
|
||||||
|
_, err = ud.Session.POST(data, "/session", ud.Session.ID, "/keys")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -446,7 +438,6 @@ func (ud *UIA2Driver) SendUnicodeKeys(text string, opts ...option.ActionOption)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ud *UIA2Driver) SendActionKey(text string, opts ...option.ActionOption) (err error) {
|
func (ud *UIA2Driver) SendActionKey(text string, opts ...option.ActionOption) (err error) {
|
||||||
actionOptions := option.NewActionOptions(opts...)
|
|
||||||
var actions []interface{}
|
var actions []interface{}
|
||||||
for i, c := range text {
|
for i, c := range text {
|
||||||
actions = append(actions, map[string]interface{}{"type": "keyDown", "value": string(c)},
|
actions = append(actions, map[string]interface{}{"type": "keyDown", "value": string(c)},
|
||||||
@@ -465,9 +456,8 @@ func (ud *UIA2Driver) SendActionKey(text string, opts ...option.ActionOption) (e
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
option.MergeOptions(data, opts...)
|
||||||
|
|
||||||
// new data options in post data for extra uiautomator configurations
|
|
||||||
actionOptions.UpdateData(data)
|
|
||||||
_, err = ud.Session.POST(data, "/session", ud.Session.ID, "/actions/keys")
|
_, err = ud.Session.POST(data, "/session", ud.Session.ID, "/actions/keys")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,10 @@ import (
|
|||||||
"github.com/httprunner/httprunner/v5/pkg/uixt/types"
|
"github.com/httprunner/httprunner/v5/pkg/uixt/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
var driverExt *XTDriver
|
var (
|
||||||
|
driver IDriver
|
||||||
|
driverExt *XTDriver
|
||||||
|
)
|
||||||
|
|
||||||
func setupAndroidAdbDriver(t *testing.T) {
|
func setupAndroidAdbDriver(t *testing.T) {
|
||||||
device, err := NewAndroidDevice()
|
device, err := NewAndroidDevice()
|
||||||
|
|||||||
@@ -176,8 +176,7 @@ func (dExt *XTDriver) DoAction(action MobileAction) (err error) {
|
|||||||
}
|
}
|
||||||
case ACTION_GetSource:
|
case ACTION_GetSource:
|
||||||
if packageName, ok := action.Params.(string); ok {
|
if packageName, ok := action.Params.(string); ok {
|
||||||
source := option.NewSourceOption().WithProcessName(packageName)
|
_, err = dExt.Source(option.WithProcessName(packageName))
|
||||||
_, err = dExt.Source(source)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "failed to set ime")
|
return errors.Wrap(err, "failed to set ime")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"image"
|
"image"
|
||||||
"image/gif"
|
"image/gif"
|
||||||
"image/jpeg"
|
"image/jpeg"
|
||||||
|
"image/png"
|
||||||
_ "image/png"
|
_ "image/png"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -214,14 +215,14 @@ func saveScreenShot(raw *bytes.Buffer, fileName string) (string, error) {
|
|||||||
|
|
||||||
// compress image and save to file
|
// compress image and save to file
|
||||||
switch format {
|
switch format {
|
||||||
case "jpeg", "png":
|
case "jpeg":
|
||||||
jpegOptions := &jpeg.Options{Quality: 95}
|
jpegOptions := &jpeg.Options{Quality: 95}
|
||||||
err = jpeg.Encode(file, img, jpegOptions)
|
err = jpeg.Encode(file, img, jpegOptions)
|
||||||
// case "png":
|
case "png":
|
||||||
// encoder := png.Encoder{
|
encoder := png.Encoder{
|
||||||
// CompressionLevel: png.BestCompression,
|
CompressionLevel: png.BestCompression,
|
||||||
// }
|
}
|
||||||
// err = encoder.Encode(file, img)
|
err = encoder.Encode(file, img)
|
||||||
case "gif":
|
case "gif":
|
||||||
gifOptions := &gif.Options{
|
gifOptions := &gif.Options{
|
||||||
NumColors: 256,
|
NumColors: 256,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package uixt
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
"math/rand/v2"
|
"math/rand/v2"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -43,8 +44,8 @@ func convertToAbsolutePoint(driver IDriver, x, y float64) (absX, absY float64, e
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
absX = float64(windowSize.Width) * x
|
absX = math.Round(float64(windowSize.Width)*x*10) / 10
|
||||||
absY = float64(windowSize.Height) * y
|
absY = math.Round(float64(windowSize.Height)*y*10) / 10
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+97
-95
@@ -9,7 +9,6 @@ import (
|
|||||||
"math"
|
"math"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -25,7 +24,6 @@ import (
|
|||||||
"github.com/httprunner/httprunner/v5/internal/builtin"
|
"github.com/httprunner/httprunner/v5/internal/builtin"
|
||||||
"github.com/httprunner/httprunner/v5/internal/config"
|
"github.com/httprunner/httprunner/v5/internal/config"
|
||||||
"github.com/httprunner/httprunner/v5/internal/json"
|
"github.com/httprunner/httprunner/v5/internal/json"
|
||||||
"github.com/httprunner/httprunner/v5/pkg/uixt/ai"
|
|
||||||
"github.com/httprunner/httprunner/v5/pkg/uixt/option"
|
"github.com/httprunner/httprunner/v5/pkg/uixt/option"
|
||||||
"github.com/httprunner/httprunner/v5/pkg/uixt/types"
|
"github.com/httprunner/httprunner/v5/pkg/uixt/types"
|
||||||
)
|
)
|
||||||
@@ -37,58 +35,22 @@ func NewWDADriver(device *IOSDevice) (*WDADriver, error) {
|
|||||||
Session: NewDriverSession(),
|
Session: NewDriverSession(),
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
|
||||||
// forward local port to device
|
|
||||||
var localPort int
|
|
||||||
localPort, err = strconv.Atoi(os.Getenv("WDA_LOCAL_PORT"))
|
|
||||||
if err != nil {
|
|
||||||
localPort, err = builtin.GetFreePort()
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(code.DeviceHTTPDriverError,
|
|
||||||
fmt.Sprintf("get free port failed: %v", err))
|
|
||||||
}
|
|
||||||
if err = device.Forward(localPort, device.Options.WDAPort); err != nil {
|
|
||||||
return nil, errors.Wrap(code.DeviceHTTPDriverError,
|
|
||||||
fmt.Sprintf("forward tcp port failed: %v", err))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.Info().Int("WDA_LOCAL_PORT", localPort).Msg("reuse WDA local port")
|
|
||||||
}
|
|
||||||
|
|
||||||
var localMjpegPort int
|
|
||||||
localMjpegPort, err = strconv.Atoi(os.Getenv("WDA_LOCAL_MJPEG_PORT"))
|
|
||||||
if err != nil {
|
|
||||||
localMjpegPort, err = builtin.GetFreePort()
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(code.DeviceHTTPDriverError,
|
|
||||||
fmt.Sprintf("get free port failed: %v", err))
|
|
||||||
}
|
|
||||||
if err = device.Forward(localMjpegPort, device.Options.WDAMjpegPort); err != nil {
|
|
||||||
return nil, errors.Wrap(code.DeviceHTTPDriverError,
|
|
||||||
fmt.Sprintf("forward tcp port failed: %v", err))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.Info().Int("WDA_LOCAL_MJPEG_PORT", localMjpegPort).
|
|
||||||
Msg("reuse WDA local mjpeg port")
|
|
||||||
}
|
|
||||||
|
|
||||||
host := "localhost"
|
host := "localhost"
|
||||||
|
localPort, err := driver.getLocalPort()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
driver.Session.SetBaseURL(fmt.Sprintf("http://%s:%d", host, localPort))
|
driver.Session.SetBaseURL(fmt.Sprintf("http://%s:%d", host, localPort))
|
||||||
|
|
||||||
|
if err = driver.initMjpegClient(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// create new session
|
// create new session
|
||||||
if err = driver.InitSession(nil); err != nil {
|
if err = driver.InitSession(nil); err != nil {
|
||||||
return nil, errors.Wrap(code.DeviceHTTPDriverError, err.Error())
|
return nil, errors.Wrap(code.DeviceHTTPDriverError, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if driver.mjpegHTTPConn, err = net.Dial(
|
|
||||||
"tcp",
|
|
||||||
fmt.Sprintf("%s:%d", host, localMjpegPort),
|
|
||||||
); err != nil {
|
|
||||||
return nil, errors.Wrap(code.DeviceHTTPDriverError, err.Error())
|
|
||||||
}
|
|
||||||
driver.mjpegClient = NewHTTPClientWithConnection(driver.mjpegHTTPConn, 30*time.Second)
|
|
||||||
driver.mjpegUrl = fmt.Sprintf("%s:%d", host, localMjpegPort)
|
|
||||||
|
|
||||||
// init WDA scale
|
// init WDA scale
|
||||||
if driver.scale, err = driver.Scale(); err != nil {
|
if driver.scale, err = driver.Scale(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -110,6 +72,61 @@ type WDADriver struct {
|
|||||||
mjpegUrl string
|
mjpegUrl string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (wd *WDADriver) getLocalPort() (int, error) {
|
||||||
|
localPort, err := strconv.Atoi(os.Getenv("WDA_LOCAL_PORT"))
|
||||||
|
if err != nil {
|
||||||
|
localPort, err = builtin.GetFreePort()
|
||||||
|
if err != nil {
|
||||||
|
return 0, errors.Wrap(code.DeviceHTTPDriverError,
|
||||||
|
fmt.Sprintf("get free port failed: %v", err))
|
||||||
|
}
|
||||||
|
// forward local port to device
|
||||||
|
if err = wd.Device.Forward(localPort, wd.Device.Options.WDAPort); err != nil {
|
||||||
|
return 0, errors.Wrap(code.DeviceHTTPDriverError,
|
||||||
|
fmt.Sprintf("forward tcp port failed: %v", err))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Info().Int("WDA_LOCAL_PORT", localPort).Msg("reuse WDA local port")
|
||||||
|
}
|
||||||
|
return localPort, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wd *WDADriver) getMjpegLocalPort() (int, error) {
|
||||||
|
localMjpegPort, err := strconv.Atoi(os.Getenv("WDA_LOCAL_MJPEG_PORT"))
|
||||||
|
if err != nil {
|
||||||
|
localMjpegPort, err = builtin.GetFreePort()
|
||||||
|
if err != nil {
|
||||||
|
return 0, errors.Wrap(code.DeviceHTTPDriverError,
|
||||||
|
fmt.Sprintf("get free port failed: %v", err))
|
||||||
|
}
|
||||||
|
if err = wd.Device.Forward(localMjpegPort, wd.Device.Options.WDAMjpegPort); err != nil {
|
||||||
|
return 0, errors.Wrap(code.DeviceHTTPDriverError,
|
||||||
|
fmt.Sprintf("forward tcp port failed: %v", err))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Info().Int("WDA_LOCAL_MJPEG_PORT", localMjpegPort).
|
||||||
|
Msg("reuse WDA local mjpeg port")
|
||||||
|
}
|
||||||
|
return localMjpegPort, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wd *WDADriver) initMjpegClient() error {
|
||||||
|
host := "localhost"
|
||||||
|
localMjpegPort, err := wd.getMjpegLocalPort()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if wd.mjpegHTTPConn, err = net.Dial(
|
||||||
|
"tcp",
|
||||||
|
fmt.Sprintf("%s:%d", host, localMjpegPort),
|
||||||
|
); err != nil {
|
||||||
|
return errors.Wrap(code.DeviceHTTPDriverError, err.Error())
|
||||||
|
}
|
||||||
|
wd.mjpegClient = NewHTTPClientWithConnection(wd.mjpegHTTPConn, 30*time.Second)
|
||||||
|
wd.mjpegUrl = fmt.Sprintf("http://%s:%d", host, localMjpegPort)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (wd *WDADriver) GetMjpegClient() *http.Client {
|
func (wd *WDADriver) GetMjpegClient() *http.Client {
|
||||||
return wd.mjpegClient
|
return wd.mjpegClient
|
||||||
}
|
}
|
||||||
@@ -145,6 +162,8 @@ func (wd *WDADriver) DeleteSession() (err error) {
|
|||||||
|
|
||||||
// [[FBRoute DELETE:@""] respondWithTarget:self action:@selector(handleDeleteSession:)]
|
// [[FBRoute DELETE:@""] respondWithTarget:self action:@selector(handleDeleteSession:)]
|
||||||
_, err = wd.Session.DELETE("/session", wd.Session.ID)
|
_, err = wd.Session.DELETE("/session", wd.Session.ID)
|
||||||
|
wd.Session.ID = ""
|
||||||
|
wd.Session.client.CloseIdleConnections()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,15 +269,20 @@ func (wd *WDADriver) Scale() (float64, error) {
|
|||||||
return screen.Scale, nil
|
return screen.Scale, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wd *WDADriver) Screen() (screen ai.Screen, err error) {
|
type Screen struct {
|
||||||
|
StatusBarSize types.Size `json:"statusBarSize"`
|
||||||
|
Scale float64 `json:"scale"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wd *WDADriver) Screen() (screen Screen, err error) {
|
||||||
// [[FBRoute GET:@"/wda/screen"] respondWithTarget:self action:@selector(handleGetScreen:)]
|
// [[FBRoute GET:@"/wda/screen"] respondWithTarget:self action:@selector(handleGetScreen:)]
|
||||||
var rawResp DriverRawResponse
|
var rawResp DriverRawResponse
|
||||||
if rawResp, err = wd.Session.GET("/session", wd.Session.ID, "/wda/screen"); err != nil {
|
if rawResp, err = wd.Session.GET("/session", wd.Session.ID, "/wda/screen"); err != nil {
|
||||||
return ai.Screen{}, err
|
return Screen{}, err
|
||||||
}
|
}
|
||||||
reply := new(struct{ Value struct{ ai.Screen } })
|
reply := new(struct{ Value struct{ Screen } })
|
||||||
if err = json.Unmarshal(rawResp, reply); err != nil {
|
if err = json.Unmarshal(rawResp, reply); err != nil {
|
||||||
return ai.Screen{}, err
|
return Screen{}, err
|
||||||
}
|
}
|
||||||
screen = reply.Value.Screen
|
screen = reply.Value.Screen
|
||||||
return
|
return
|
||||||
@@ -525,6 +549,8 @@ func (wd *WDADriver) TapAbsXY(x, y float64, opts ...option.ActionOption) error {
|
|||||||
"x": wd.toScale(x),
|
"x": wd.toScale(x),
|
||||||
"y": wd.toScale(y),
|
"y": wd.toScale(y),
|
||||||
}
|
}
|
||||||
|
option.MergeOptions(data, opts...)
|
||||||
|
|
||||||
_, err := wd.Session.POST(data, "/session", wd.Session.ID, "/wda/tap/0")
|
_, err := wd.Session.POST(data, "/session", wd.Session.ID, "/wda/tap/0")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -546,10 +572,11 @@ func (wd *WDADriver) DoubleTapXY(x, y float64, opts ...option.ActionOption) erro
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: hold not work
|
||||||
func (wd *WDADriver) TouchAndHold(x, y float64, opts ...option.ActionOption) (err error) {
|
func (wd *WDADriver) TouchAndHold(x, y float64, opts ...option.ActionOption) (err error) {
|
||||||
actionOptions := option.NewActionOptions(opts...)
|
actionOptions := option.NewActionOptions(opts...)
|
||||||
if actionOptions.Duration == 0 {
|
if actionOptions.Duration == 0 {
|
||||||
opts = append(opts, option.WithDuration(1))
|
opts = append(opts, option.WithPressDuration(1))
|
||||||
}
|
}
|
||||||
return wd.TapXY(x, y, opts...)
|
return wd.TapXY(x, y, opts...)
|
||||||
}
|
}
|
||||||
@@ -574,12 +601,7 @@ func (wd *WDADriver) Drag(fromX, fromY, toX, toY float64, opts ...option.ActionO
|
|||||||
"toX": math.Round(toX*10) / 10,
|
"toX": math.Round(toX*10) / 10,
|
||||||
"toY": math.Round(toY*10) / 10,
|
"toY": math.Round(toY*10) / 10,
|
||||||
}
|
}
|
||||||
if actionOptions.PressDuration > 0 {
|
option.MergeOptions(data, opts...)
|
||||||
data["pressDuration"] = actionOptions.PressDuration
|
|
||||||
}
|
|
||||||
|
|
||||||
// update data options in post data for extra WDA configurations
|
|
||||||
actionOptions.UpdateData(data)
|
|
||||||
// wda 43 version
|
// wda 43 version
|
||||||
_, err = wd.Session.POST(data, "/session", wd.Session.ID, "/wda/dragfromtoforduration")
|
_, err = wd.Session.POST(data, "/session", wd.Session.ID, "/wda/dragfromtoforduration")
|
||||||
// _, err = wd.Session.POST(data, "/session", wd.Session.ID, "/wda/drag")
|
// _, err = wd.Session.POST(data, "/session", wd.Session.ID, "/wda/drag")
|
||||||
@@ -619,12 +641,8 @@ func (wd *WDADriver) SetIme(ime string) error {
|
|||||||
|
|
||||||
func (wd *WDADriver) Input(text string, opts ...option.ActionOption) (err error) {
|
func (wd *WDADriver) Input(text string, opts ...option.ActionOption) (err error) {
|
||||||
// [[FBRoute POST:@"/wda/keys"] respondWithTarget:self action:@selector(handleKeys:)]
|
// [[FBRoute POST:@"/wda/keys"] respondWithTarget:self action:@selector(handleKeys:)]
|
||||||
actionOptions := option.NewActionOptions(opts...)
|
|
||||||
data := map[string]interface{}{"value": strings.Split(text, "")}
|
data := map[string]interface{}{"value": strings.Split(text, "")}
|
||||||
|
option.MergeOptions(data, opts...)
|
||||||
// new data options in post data for extra WDA configurations
|
|
||||||
actionOptions.UpdateData(data)
|
|
||||||
|
|
||||||
_, err = wd.Session.POST(data, "/session", wd.Session.ID, "/wda/keys")
|
_, err = wd.Session.POST(data, "/session", wd.Session.ID, "/wda/keys")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -633,12 +651,8 @@ func (wd *WDADriver) Backspace(count int, opts ...option.ActionOption) (err erro
|
|||||||
if count == 0 {
|
if count == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
actionOptions := option.NewActionOptions(opts...)
|
|
||||||
data := map[string]interface{}{"count": count}
|
data := map[string]interface{}{"count": count}
|
||||||
|
option.MergeOptions(data, opts...)
|
||||||
// new data options in post data for extra WDA configurations
|
|
||||||
actionOptions.UpdateData(data)
|
|
||||||
|
|
||||||
_, err = wd.Session.POST(data, "/gtf/interaction/input/backspace")
|
_, err = wd.Session.POST(data, "/gtf/interaction/input/backspace")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -720,39 +734,29 @@ func (wd *WDADriver) SetRotation(rotation types.Rotation) (err error) {
|
|||||||
func (wd *WDADriver) Source(srcOpt ...option.SourceOption) (source string, err error) {
|
func (wd *WDADriver) Source(srcOpt ...option.SourceOption) (source string, err error) {
|
||||||
// [[FBRoute GET:@"/source"] respondWithTarget:self action:@selector(handleGetSourceCommand:)]
|
// [[FBRoute GET:@"/source"] respondWithTarget:self action:@selector(handleGetSourceCommand:)]
|
||||||
// [[FBRoute GET:@"/source"].withoutSession
|
// [[FBRoute GET:@"/source"].withoutSession
|
||||||
urlStr, err := wd.Session.concatURL("/session", wd.Session.ID)
|
// urlStr, err := wd.Session.concatURL("/session", wd.Session.ID)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return "", err
|
// return "", err
|
||||||
}
|
// }
|
||||||
tmp, _ := url.Parse(urlStr)
|
options := option.NewSourceOptions(srcOpt...)
|
||||||
toJsonRaw := false
|
query := options.Query()
|
||||||
if len(srcOpt) != 0 {
|
if len(query) > 0 {
|
||||||
q := tmp.Query()
|
query = "?" + query
|
||||||
for k, val := range srcOpt[0] {
|
|
||||||
v := val.(string)
|
|
||||||
q.Set(k, v)
|
|
||||||
if k == "format" && v == "json" {
|
|
||||||
toJsonRaw = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tmp.RawQuery = q.Encode()
|
|
||||||
}
|
|
||||||
|
|
||||||
urlStr, err = wd.Session.concatURL(tmp.Path, "/source")
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
}
|
||||||
var rawResp DriverRawResponse
|
var rawResp DriverRawResponse
|
||||||
if rawResp, err = wd.Session.GET(http.MethodGet, urlStr); err != nil {
|
if rawResp, err = wd.Session.GET("/source" + query); err != nil {
|
||||||
return "", nil
|
return "", err
|
||||||
}
|
}
|
||||||
if toJsonRaw {
|
// json format
|
||||||
|
if options.Format == option.SourceFormatJSON {
|
||||||
var jr builtinJSON.RawMessage
|
var jr builtinJSON.RawMessage
|
||||||
if jr, err = rawResp.ValueConvertToJsonRawMessage(); err != nil {
|
if jr, err = rawResp.ValueConvertToJsonRawMessage(); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return string(jr), nil
|
return string(jr), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// xml/description format
|
||||||
if source, err = rawResp.ValueConvertToString(); err != nil {
|
if source, err = rawResp.ValueConvertToString(); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -850,7 +854,7 @@ func (wd *WDADriver) ScreenRecord(duration time.Duration) (videoPath string, err
|
|||||||
"-f", "mjpeg",
|
"-f", "mjpeg",
|
||||||
"-y",
|
"-y",
|
||||||
"-r", "10",
|
"-r", "10",
|
||||||
"-i", "http://"+wd.mjpegUrl,
|
"-i", wd.mjpegUrl,
|
||||||
"-c:v", "libx264",
|
"-c:v", "libx264",
|
||||||
"-vf", "pad=width=ceil(iw/2)*2:height=ceil(ih/2)*2",
|
"-vf", "pad=width=ceil(iw/2)*2:height=ceil(ih/2)*2",
|
||||||
fileName,
|
fileName,
|
||||||
@@ -936,7 +940,5 @@ func (wd *WDADriver) Setup() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (wd *WDADriver) TearDown() error {
|
func (wd *WDADriver) TearDown() error {
|
||||||
wd.mjpegClient.CloseIdleConnections()
|
return wd.DeleteSession()
|
||||||
wd.Session.client.CloseIdleConnections()
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
+97
-143
@@ -14,13 +14,7 @@ import (
|
|||||||
"github.com/httprunner/httprunner/v5/pkg/uixt/types"
|
"github.com/httprunner/httprunner/v5/pkg/uixt/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
func setupWDADriverExt(t *testing.T) *XTDriver {
|
||||||
bundleId = "com.apple.Preferences"
|
|
||||||
driver IDriver
|
|
||||||
iOSDriverExt *XTDriver
|
|
||||||
)
|
|
||||||
|
|
||||||
func setup(t *testing.T) {
|
|
||||||
device, err := NewIOSDevice(
|
device, err := NewIOSDevice(
|
||||||
option.WithWDAPort(8700),
|
option.WithWDAPort(8700),
|
||||||
option.WithWDAMjpegPort(8800),
|
option.WithWDAMjpegPort(8800),
|
||||||
@@ -28,21 +22,16 @@ func setup(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
driver, err = device.NewDriver()
|
driver, err := device.NewDriver()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
iOSDriverExt = NewXTDriver(driver, ai.WithCVService(ai.CVServiceTypeVEDEM))
|
return NewXTDriver(driver, ai.WithCVService(ai.CVServiceTypeVEDEM))
|
||||||
}
|
|
||||||
|
|
||||||
func TestViaUSB(t *testing.T) {
|
|
||||||
setup(t)
|
|
||||||
t.Log(driver.Status())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInstall(t *testing.T) {
|
func TestInstall(t *testing.T) {
|
||||||
setup(t)
|
driver := setupWDADriverExt(t)
|
||||||
err := iOSDriverExt.GetDevice().Install("xxx.ipa",
|
err := driver.GetDevice().Install("xxx.ipa",
|
||||||
option.WithRetryTimes(5))
|
option.WithRetryTimes(5))
|
||||||
log.Error().Err(err)
|
log.Error().Err(err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -84,28 +73,22 @@ func TestIOSDevice_GetPackageInfo(t *testing.T) {
|
|||||||
checkErr(t, err)
|
checkErr(t, err)
|
||||||
appInfo, err := device.GetPackageInfo("com.ss.iphone.ugc.Aweme")
|
appInfo, err := device.GetPackageInfo("com.ss.iphone.ugc.Aweme")
|
||||||
checkErr(t, err)
|
checkErr(t, err)
|
||||||
t.Log(appInfo)
|
t.Logf("%+v", appInfo)
|
||||||
}
|
|
||||||
|
|
||||||
func TestNewUSBDriver(t *testing.T) {
|
|
||||||
setup(t)
|
|
||||||
|
|
||||||
// t.Log(driver.IsWdaHealthy())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDriver_DeviceScaleRatio(t *testing.T) {
|
func TestDriver_DeviceScaleRatio(t *testing.T) {
|
||||||
setup(t)
|
driver := setupWDADriverExt(t)
|
||||||
|
|
||||||
scaleRatio, err := driver.(*WDADriver).Scale()
|
scaleRatio, err := driver.IDriver.(*WDADriver).Scale()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Log(scaleRatio)
|
t.Logf("%+v", scaleRatio)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_remoteWD_DeleteSession(t *testing.T) {
|
func Test_remoteWD_DeleteSession(t *testing.T) {
|
||||||
setup(t)
|
driver := setupWDADriverExt(t)
|
||||||
|
|
||||||
err := driver.DeleteSession()
|
err := driver.DeleteSession()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -114,26 +97,26 @@ func Test_remoteWD_DeleteSession(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Test_remoteWD_HealthCheck(t *testing.T) {
|
func Test_remoteWD_HealthCheck(t *testing.T) {
|
||||||
setup(t)
|
driver := setupWDADriverExt(t)
|
||||||
|
|
||||||
err := driver.(*WDADriver).HealthCheck()
|
err := driver.IDriver.(*WDADriver).HealthCheck()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_remoteWD_GetAppiumSettings(t *testing.T) {
|
func Test_remoteWD_GetAppiumSettings(t *testing.T) {
|
||||||
setup(t)
|
driver := setupWDADriverExt(t)
|
||||||
|
|
||||||
settings, err := driver.(*WDADriver).GetAppiumSettings()
|
settings, err := driver.IDriver.(*WDADriver).GetAppiumSettings()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Log(settings)
|
t.Logf("%+v", settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_remoteWD_SetAppiumSettings(t *testing.T) {
|
func Test_remoteWD_SetAppiumSettings(t *testing.T) {
|
||||||
setup(t)
|
driver := setupWDADriverExt(t)
|
||||||
|
|
||||||
const _acceptAlertButtonSelector = "**/XCUIElementTypeButton[`label IN {'允许','好','仅在使用应用期间','暂不'}`]"
|
const _acceptAlertButtonSelector = "**/XCUIElementTypeButton[`label IN {'允许','好','仅在使用应用期间','暂不'}`]"
|
||||||
const _dismissAlertButtonSelector = "**/XCUIElementTypeButton[`label IN {'不允许','暂不'}`]"
|
const _dismissAlertButtonSelector = "**/XCUIElementTypeButton[`label IN {'不允许','暂不'}`]"
|
||||||
@@ -142,7 +125,7 @@ func Test_remoteWD_SetAppiumSettings(t *testing.T) {
|
|||||||
value := _acceptAlertButtonSelector
|
value := _acceptAlertButtonSelector
|
||||||
|
|
||||||
// settings, err := driver.SetAppiumSettings(map[string]interface{}{"dismissAlertButtonSelector": "暂不"})
|
// settings, err := driver.SetAppiumSettings(map[string]interface{}{"dismissAlertButtonSelector": "暂不"})
|
||||||
settings, err := driver.(*WDADriver).SetAppiumSettings(map[string]interface{}{key: value})
|
settings, err := driver.IDriver.(*WDADriver).SetAppiumSettings(map[string]interface{}{key: value})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -152,39 +135,31 @@ func Test_remoteWD_SetAppiumSettings(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Test_remoteWD_IsWdaHealthy(t *testing.T) {
|
func Test_remoteWD_IsWdaHealthy(t *testing.T) {
|
||||||
setup(t)
|
driver := setupWDADriverExt(t)
|
||||||
|
|
||||||
healthy, err := driver.(*WDADriver).IsHealthy()
|
healthy, err := driver.IDriver.(*WDADriver).IsHealthy()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if healthy == false {
|
if !healthy {
|
||||||
t.Fatal("healthy =", healthy)
|
t.Fatal("assert healthy failed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// func Test_remoteWD_WdaShutdown(t *testing.T) {
|
|
||||||
// setup(t)
|
|
||||||
//
|
|
||||||
// if err := driver.WdaShutdown(); err != nil {
|
|
||||||
// t.Fatal(err)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
func Test_remoteWD_Status(t *testing.T) {
|
func Test_remoteWD_Status(t *testing.T) {
|
||||||
setup(t)
|
driver := setupWDADriverExt(t)
|
||||||
|
|
||||||
status, err := driver.Status()
|
status, err := driver.Status()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if status.Ready == false {
|
if !status.Ready {
|
||||||
t.Fatal("deviceStatus =", status)
|
t.Fatal("assert device status failed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_remoteWD_DeviceInfo(t *testing.T) {
|
func Test_remoteWD_DeviceInfo(t *testing.T) {
|
||||||
setup(t)
|
driver := setupWDADriverExt(t)
|
||||||
|
|
||||||
info, err := driver.DeviceInfo()
|
info, err := driver.DeviceInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -196,7 +171,7 @@ func Test_remoteWD_DeviceInfo(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Test_remoteWD_BatteryInfo(t *testing.T) {
|
func Test_remoteWD_BatteryInfo(t *testing.T) {
|
||||||
setup(t)
|
driver := setupWDADriverExt(t)
|
||||||
|
|
||||||
batteryInfo, err := driver.BatteryInfo()
|
batteryInfo, err := driver.BatteryInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -206,7 +181,7 @@ func Test_remoteWD_BatteryInfo(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Test_remoteWD_WindowSize(t *testing.T) {
|
func Test_remoteWD_WindowSize(t *testing.T) {
|
||||||
setup(t)
|
driver := setupWDADriverExt(t)
|
||||||
|
|
||||||
size, err := driver.WindowSize()
|
size, err := driver.WindowSize()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -216,9 +191,9 @@ func Test_remoteWD_WindowSize(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Test_remoteWD_Screen(t *testing.T) {
|
func Test_remoteWD_Screen(t *testing.T) {
|
||||||
setup(t)
|
driver := setupWDADriverExt(t)
|
||||||
|
|
||||||
screen, err := driver.(*WDADriver).Screen()
|
screen, err := driver.IDriver.(*WDADriver).Screen()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -226,7 +201,7 @@ func Test_remoteWD_Screen(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Test_remoteWD_Homescreen(t *testing.T) {
|
func Test_remoteWD_Homescreen(t *testing.T) {
|
||||||
setup(t)
|
driver := setupWDADriverExt(t)
|
||||||
|
|
||||||
err := driver.Home()
|
err := driver.Home()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -234,174 +209,154 @@ func Test_remoteWD_Homescreen(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_remoteWD_AppLaunch(t *testing.T) {
|
func Test_remoteWD_AppLaunchTerminate(t *testing.T) {
|
||||||
setup(t)
|
driver := setupWDADriverExt(t)
|
||||||
|
|
||||||
|
bundleId := "com.apple.Preferences"
|
||||||
err := driver.AppLaunch(bundleId)
|
err := driver.AppLaunch(bundleId)
|
||||||
// err := driver.AppLaunch(bundleId, NewAppLaunchOption().WithShouldWaitForQuiescence(true))
|
|
||||||
// err := driver.AppLaunch(bundleId, NewAppLaunchOption().WithArguments([]string{"-AppleLanguages", "(Russian)"}))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
time.Sleep(2 * time.Second)
|
||||||
|
|
||||||
func Test_remoteWD_AppTerminate(t *testing.T) {
|
_, err = driver.AppTerminate(bundleId)
|
||||||
setup(t)
|
|
||||||
|
|
||||||
_, err := driver.AppTerminate(bundleId)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_remoteWD_Tap(t *testing.T) {
|
func Test_remoteWD_Tap(t *testing.T) {
|
||||||
setup(t)
|
driver := setupWDADriverExt(t)
|
||||||
|
|
||||||
err := driver.TapXY(200, 300)
|
err := driver.TapXY(0.2, 0.2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_remoteWD_DoubleTap(t *testing.T) {
|
func Test_remoteWD_DoubleTap(t *testing.T) {
|
||||||
setup(t)
|
driver := setupWDADriverExt(t)
|
||||||
|
|
||||||
err := driver.DoubleTapXY(200, 300)
|
err := driver.DoubleTapXY(0.2, 0.2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_remoteWD_TouchAndHold(t *testing.T) {
|
func Test_remoteWD_TouchAndHold(t *testing.T) {
|
||||||
setup(t)
|
driver := setupWDADriverExt(t)
|
||||||
|
|
||||||
// err := driver.TouchAndHold(200, 300)
|
err := driver.TouchAndHold(0.2, 0.2)
|
||||||
err := driver.TouchAndHold(200, 300)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_remoteWD_Drag(t *testing.T) {
|
func Test_remoteWD_Drag(t *testing.T) {
|
||||||
setup(t)
|
driver := setupWDADriverExt(t)
|
||||||
|
|
||||||
// err := driver.Drag(200, 300, 200, 500, WithDataPressDuration(0.5))
|
err := driver.Drag(0.8, 0.5, 0.2, 0.5,
|
||||||
err := driver.Drag(200, 300, 200, 500,
|
option.WithDuration(0.5))
|
||||||
option.WithPressDuration(2), option.WithDuration(3))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_Relative_Drag(t *testing.T) {
|
func Test_Relative_Swipe(t *testing.T) {
|
||||||
setup(t)
|
driver := setupWDADriverExt(t)
|
||||||
|
|
||||||
// err := driver.Drag(200, 300, 200, 500, WithDataPressDuration(0.5))
|
err := driver.Swipe(0.8, 0.5, 0.2, 0.5)
|
||||||
err := iOSDriverExt.Swipe(0.5, 0.7, 0.5, 0.5)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_remoteWD_SendKeys(t *testing.T) {
|
func Test_remoteWD_SendKeys(t *testing.T) {
|
||||||
setup(t)
|
driver := setupWDADriverExt(t)
|
||||||
// driver.StartCaptureLog("hrp_wda_log")
|
driver.StartCaptureLog("hrp_wda_log")
|
||||||
err := driver.Input("test", option.WithIdentifier("test"))
|
err := driver.Input("test中文", option.WithIdentifier("test"))
|
||||||
// result, _ := driver.StopCaptureLog()
|
result, _ := driver.StopCaptureLog()
|
||||||
// err := driver.SendKeys("App Store", WithFrequency(3))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
// t.Log(result)
|
t.Log(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_remoteWD_PressButton(t *testing.T) {
|
func Test_remoteWD_PressButton(t *testing.T) {
|
||||||
setup(t)
|
driver := setupWDADriverExt(t)
|
||||||
|
|
||||||
err := driver.(*WDADriver).PressButton(types.DeviceButtonVolumeUp)
|
err := driver.IDriver.(*WDADriver).PressButton(types.DeviceButtonVolumeUp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
time.Sleep(time.Second * 1)
|
time.Sleep(time.Second * 1)
|
||||||
err = driver.(*WDADriver).PressButton(types.DeviceButtonVolumeDown)
|
err = driver.IDriver.(*WDADriver).PressButton(types.DeviceButtonVolumeDown)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
time.Sleep(time.Second * 1)
|
time.Sleep(time.Second * 1)
|
||||||
err = driver.(*WDADriver).PressButton(types.DeviceButtonHome)
|
err = driver.IDriver.(*WDADriver).PressButton(types.DeviceButtonHome)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_remoteWD_Screenshot(t *testing.T) {
|
func Test_remoteWD_Screenshot(t *testing.T) {
|
||||||
setup(t)
|
driver := setupWDADriverExt(t)
|
||||||
|
|
||||||
|
// without save file
|
||||||
screenshot, err := driver.ScreenShot()
|
screenshot, err := driver.ScreenShot()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
_ = screenshot
|
_ = screenshot
|
||||||
|
|
||||||
// img, format, err := image.Decode(screenshot)
|
// save file
|
||||||
// if err != nil {
|
screenshot, err = driver.ScreenShot(option.WithScreenShotFileName("123"))
|
||||||
// t.Fatal(err)
|
if err != nil {
|
||||||
// }
|
t.Fatal(err)
|
||||||
// userHomeDir, _ := os.UserHomeDir()
|
}
|
||||||
// file, err := os.Create(userHomeDir + "/Desktop/s1." + format)
|
_ = screenshot
|
||||||
// if err != nil {
|
|
||||||
// t.Fatal(err)
|
path, err := saveScreenShot(screenshot, "1234")
|
||||||
// }
|
if err != nil {
|
||||||
// defer func() { _ = file.Close() }()
|
t.Fatal(err)
|
||||||
// switch format {
|
}
|
||||||
// case "png":
|
t.Logf("save screenshot to %s", path)
|
||||||
// err = png.Encode(file, img)
|
|
||||||
// case "jpeg":
|
|
||||||
// err = jpeg.Encode(file, img, nil)
|
|
||||||
// }
|
|
||||||
// if err != nil {
|
|
||||||
// t.Fatal(err)
|
|
||||||
// }
|
|
||||||
// t.Log(file.Name())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_remoteWD_Source(t *testing.T) {
|
func Test_remoteWD_Source(t *testing.T) {
|
||||||
setup(t)
|
driver := setupWDADriverExt(t)
|
||||||
|
|
||||||
var source string
|
var source string
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
// source, err = driver.Source()
|
|
||||||
// if err != nil {
|
|
||||||
// t.Fatal(err)
|
|
||||||
// }
|
|
||||||
|
|
||||||
source, err = driver.Source()
|
source, err = driver.Source()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// source, err = driver.Source(NewSourceOption().WithFormatAsJson())
|
source, err = driver.Source(option.WithFormat(option.SourceFormatJSON))
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// t.Fatal(err)
|
t.Fatal(err)
|
||||||
// }
|
}
|
||||||
|
|
||||||
// source, err = driver.Source(NewSourceOption().WithFormatAsDescription())
|
source, err = driver.Source(option.WithFormat(option.SourceFormatDescription))
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// t.Fatal(err)
|
t.Fatal(err)
|
||||||
// }
|
}
|
||||||
|
|
||||||
// source, err = driver.Source(NewSourceOption().WithFormatAsXml().WithExcludedAttributes([]string{"label", "type", "index"}))
|
source, err = driver.Source(
|
||||||
// if err != nil {
|
option.WithFormat(option.SourceFormatXML),
|
||||||
// t.Fatal(err)
|
option.WithExcludedAttributes([]string{"label", "type", "index"}))
|
||||||
// }
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
_ = source
|
}
|
||||||
fmt.Println(source)
|
t.Logf("source: %s", source)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetForegroundApp(t *testing.T) {
|
func TestGetForegroundApp(t *testing.T) {
|
||||||
setup(t)
|
driver := setupWDADriverExt(t)
|
||||||
app, err := driver.ForegroundInfo()
|
app, err := driver.ForegroundInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -410,18 +365,17 @@ func TestGetForegroundApp(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Test_remoteWD_AccessibleSource(t *testing.T) {
|
func Test_remoteWD_AccessibleSource(t *testing.T) {
|
||||||
setup(t)
|
driver := setupWDADriverExt(t)
|
||||||
|
|
||||||
source, err := driver.(*WDADriver).AccessibleSource()
|
source, err := driver.IDriver.(*WDADriver).AccessibleSource()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
_ = source
|
|
||||||
fmt.Println(source)
|
fmt.Println(source)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRecord(t *testing.T) {
|
func TestRecord(t *testing.T) {
|
||||||
setup(t)
|
driver := setupWDADriverExt(t)
|
||||||
path, err := driver.ScreenRecord(5 * time.Second)
|
path, err := driver.ScreenRecord(5 * time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -429,11 +383,11 @@ func TestRecord(t *testing.T) {
|
|||||||
println(path)
|
println(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// func Test_Backspace(t *testing.T) {
|
func Test_Backspace(t *testing.T) {
|
||||||
// setup(t)
|
driver := setupWDADriverExt(t)
|
||||||
|
|
||||||
// err := driver.Backspace(3)
|
err := driver.Backspace(3)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// t.Fatal(err)
|
t.Fatal(err)
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ type ActionOptions struct {
|
|||||||
// control related
|
// control related
|
||||||
MaxRetryTimes int `json:"max_retry_times,omitempty" yaml:"max_retry_times,omitempty"` // max retry times
|
MaxRetryTimes int `json:"max_retry_times,omitempty" yaml:"max_retry_times,omitempty"` // max retry times
|
||||||
Interval float64 `json:"interval,omitempty" yaml:"interval,omitempty"` // interval between retries in seconds
|
Interval float64 `json:"interval,omitempty" yaml:"interval,omitempty"` // interval between retries in seconds
|
||||||
Duration float64 `json:"duration,omitempty" yaml:"duration,omitempty"` // used to set duration of ios swipe action
|
Duration float64 `json:"duration,omitempty" yaml:"duration,omitempty"` // used to set duration in seconds
|
||||||
PressDuration float64 `json:"press_duration,omitempty" yaml:"press_duration,omitempty"` // used to set duration of ios swipe action
|
PressDuration float64 `json:"press_duration,omitempty" yaml:"press_duration,omitempty"` // used to set press duration in seconds
|
||||||
Steps int `json:"steps,omitempty" yaml:"steps,omitempty"` // used to set steps of android swipe action
|
Steps int `json:"steps,omitempty" yaml:"steps,omitempty"` // used to set steps of action
|
||||||
Direction interface{} `json:"direction,omitempty" yaml:"direction,omitempty"` // used by swipe to tap text or app
|
Direction interface{} `json:"direction,omitempty" yaml:"direction,omitempty"` // used by swipe to tap text or app
|
||||||
Timeout int `json:"timeout,omitempty" yaml:"timeout,omitempty"` // TODO: wait timeout in seconds for mobile action
|
Timeout int `json:"timeout,omitempty" yaml:"timeout,omitempty"` // TODO: wait timeout in seconds for mobile action
|
||||||
Frequency int `json:"frequency,omitempty" yaml:"frequency,omitempty"`
|
Frequency int `json:"frequency,omitempty" yaml:"frequency,omitempty"`
|
||||||
@@ -142,7 +142,8 @@ func (o *ActionOptions) GetRandomOffset() float64 {
|
|||||||
return float64(builtin.GetRandomNumber(minOffset, maxOffset)) + rand.Float64()
|
return float64(builtin.GetRandomNumber(minOffset, maxOffset)) + rand.Float64()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ActionOptions) UpdateData(data map[string]interface{}) {
|
func MergeOptions(data map[string]interface{}, opts ...ActionOption) {
|
||||||
|
o := NewActionOptions(opts...)
|
||||||
if o.Identifier != "" {
|
if o.Identifier != "" {
|
||||||
data["log"] = map[string]interface{}{
|
data["log"] = map[string]interface{}{
|
||||||
"enable": true,
|
"enable": true,
|
||||||
@@ -164,6 +165,10 @@ func (o *ActionOptions) UpdateData(data map[string]interface{}) {
|
|||||||
data["duration"] = 0 // default duration
|
data["duration"] = 0 // default duration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if o.PressDuration > 0 {
|
||||||
|
data["pressDuration"] = o.PressDuration
|
||||||
|
}
|
||||||
|
|
||||||
if o.Frequency > 0 {
|
if o.Frequency > 0 {
|
||||||
data["frequency"] = o.Frequency
|
data["frequency"] = o.Frequency
|
||||||
}
|
}
|
||||||
|
|||||||
+54
-33
@@ -2,53 +2,74 @@ package option
|
|||||||
|
|
||||||
import "strings"
|
import "strings"
|
||||||
|
|
||||||
// SourceOption Configure the format or attribute of the Source
|
func NewSourceOptions(opts ...SourceOption) *SourceOptions {
|
||||||
type SourceOption map[string]interface{}
|
options := &SourceOptions{}
|
||||||
|
for _, option := range opts {
|
||||||
|
option(options)
|
||||||
|
}
|
||||||
|
return options
|
||||||
|
}
|
||||||
|
|
||||||
func NewSourceOption() SourceOption {
|
type SourceOptions struct {
|
||||||
return make(SourceOption)
|
Format SourceFormat `json:"format,omitempty"`
|
||||||
|
ProcessName string `json:"processName,omitempty"`
|
||||||
|
Scope string `json:"scope,omitempty"`
|
||||||
|
ExcludedAttributes string `json:"excluded_attributes,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithFormatAsJson Application elements tree in form of json string
|
func (o *SourceOptions) Query() string {
|
||||||
func (opt SourceOption) WithFormatAsJson() SourceOption {
|
query := []string{}
|
||||||
opt["format"] = "json"
|
if o.Format != "" {
|
||||||
return opt
|
query = append(query, "format="+string(o.Format))
|
||||||
|
}
|
||||||
|
if o.ProcessName != "" {
|
||||||
|
query = append(query, "processName="+o.ProcessName)
|
||||||
|
}
|
||||||
|
if o.Scope != "" {
|
||||||
|
query = append(query, "scope="+o.Scope)
|
||||||
|
}
|
||||||
|
if o.ExcludedAttributes != "" {
|
||||||
|
query = append(query, "excluded_attributes="+o.ExcludedAttributes)
|
||||||
|
}
|
||||||
|
return strings.Join(query, "&")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SourceOption func(o *SourceOptions)
|
||||||
|
|
||||||
func (opt SourceOption) WithProcessName(processName string) SourceOption {
|
type SourceFormat string
|
||||||
opt["processName"] = processName
|
|
||||||
return opt
|
const (
|
||||||
}
|
SourceFormatJSON SourceFormat = "json"
|
||||||
|
SourceFormatXML SourceFormat = "xml"
|
||||||
|
SourceFormatDescription SourceFormat = "description"
|
||||||
|
)
|
||||||
|
|
||||||
// WithFormatAsXml Application elements tree in form of xml string
|
// WithFormat specify Application elements tree format
|
||||||
func (opt SourceOption) WithFormatAsXml() SourceOption {
|
// `json` or `xml` or `description`
|
||||||
opt["format"] = "xml"
|
func WithFormat(format SourceFormat) SourceOption {
|
||||||
return opt
|
return func(o *SourceOptions) {
|
||||||
|
o.Format = format
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithFormatAsDescription Application elements tree in form of internal XCTest debugDescription string
|
func WithProcessName(name string) SourceOption {
|
||||||
func (opt SourceOption) WithFormatAsDescription() SourceOption {
|
return func(o *SourceOptions) {
|
||||||
opt["format"] = "description"
|
o.ProcessName = name
|
||||||
return opt
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithScope Allows to provide XML scope.
|
// WithSourceScope Allows to provide XML scope.
|
||||||
//
|
// only `xml` is supported.
|
||||||
// only `xml` is supported.
|
func WithSourceScope(scope string) SourceOption {
|
||||||
func (opt SourceOption) WithScope(scope string) SourceOption {
|
return func(o *SourceOptions) {
|
||||||
if vFormat, ok := opt["format"]; ok && vFormat != "xml" {
|
o.Scope = scope
|
||||||
return opt
|
|
||||||
}
|
}
|
||||||
opt["scope"] = scope
|
|
||||||
return opt
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithExcludedAttributes Excludes the given attribute names.
|
// WithExcludedAttributes Excludes the given attribute names.
|
||||||
// only `xml` is supported.
|
// only `xml` is supported.
|
||||||
func (opt SourceOption) WithExcludedAttributes(attributes []string) SourceOption {
|
func WithExcludedAttributes(attributes []string) SourceOption {
|
||||||
if vFormat, ok := opt["format"]; ok && vFormat != "xml" {
|
return func(o *SourceOptions) {
|
||||||
return opt
|
o.ExcludedAttributes = strings.Join(attributes, ",")
|
||||||
}
|
}
|
||||||
opt["excluded_attributes"] = strings.Join(attributes, ",")
|
|
||||||
return opt
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ func sourceHandler(c *gin.Context) {
|
|||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
source, err := dExt.Source(option.NewSourceOption().WithProcessName(app.PackageName))
|
source, err := dExt.Source(option.WithProcessName(app.PackageName))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Msg(fmt.Sprintf("[%s]: failed to get source %s", c.HandlerName(), app.PackageName))
|
log.Err(err).Msg(fmt.Sprintf("[%s]: failed to get source %s", c.HandlerName(), app.PackageName))
|
||||||
c.JSON(http.StatusInternalServerError,
|
c.JSON(http.StatusInternalServerError,
|
||||||
|
|||||||
Reference in New Issue
Block a user