fix: errors

This commit is contained in:
lilong.129
2025-02-09 10:51:03 +08:00
parent 5e45eb7836
commit 3038fb7430
47 changed files with 710 additions and 910 deletions

View File

@@ -9,13 +9,15 @@ import (
"github.com/httprunner/httprunner/v5/code"
"github.com/httprunner/httprunner/v5/internal/builtin"
"github.com/httprunner/httprunner/v5/pkg/uixt/option"
"github.com/httprunner/httprunner/v5/pkg/uixt/types"
"github.com/pkg/errors"
)
type ICVService interface {
// returns CV result including ocr texts, uploaded image url, etc
ReadFromBuffer(imageBuf *bytes.Buffer, opts ...ScreenShotOption) (*CVResult, error)
ReadFromPath(imagePath string, opts ...ScreenShotOption) (*CVResult, error)
ReadFromBuffer(imageBuf *bytes.Buffer, opts ...option.ActionOption) (*CVResult, error)
ReadFromPath(imagePath string, opts ...option.ActionOption) (*CVResult, error)
}
type CVResult struct {
@@ -75,8 +77,8 @@ type OCRText struct {
Rect image.Rectangle `json:"-"`
}
func (t OCRText) Size() Size {
return Size{
func (t OCRText) Size() types.Size {
return types.Size{
Width: t.Rect.Dx(),
Height: t.Rect.Dy(),
}
@@ -105,7 +107,7 @@ func (t OCRTexts) texts() (texts []string) {
return texts
}
func (t OCRTexts) FilterScope(scope AbsScope) (results OCRTexts) {
func (t OCRTexts) FilterScope(scope option.AbsScope) (results OCRTexts) {
for _, ocrText := range t {
rect := ocrText.Rect
@@ -127,8 +129,8 @@ func (t OCRTexts) FilterScope(scope AbsScope) (results OCRTexts) {
// FindText returns matched text with options
// Notice: filter scope should be specified with WithAbsScope
func (t OCRTexts) FindText(text string, opts ...ScreenFilterOption) (result OCRText, err error) {
options := NewScreenFilterOptions(opts...)
func (t OCRTexts) FindText(text string, opts ...option.ActionOption) (result OCRText, err error) {
options := option.NewActionOptions(opts...)
var results []OCRText
for _, ocrText := range t.FilterScope(options.AbsScope) {
@@ -172,8 +174,8 @@ func (t OCRTexts) FindText(text string, opts ...ScreenFilterOption) (result OCRT
return results[idx], nil
}
func (t OCRTexts) FindTexts(texts []string, opts ...ScreenFilterOption) (results OCRTexts, err error) {
options := NewScreenFilterOptions(opts...)
func (t OCRTexts) FindTexts(texts []string, opts ...option.ActionOption) (results OCRTexts, err error) {
options := option.NewActionOptions(opts...)
for _, text := range texts {
ocrText, err := t.FindText(text, opts...)
if err != nil {
@@ -239,7 +241,7 @@ func (box Box) Center() PointF {
type UIResults []UIResult
func (u UIResults) FilterScope(scope AbsScope) (results UIResults) {
func (u UIResults) FilterScope(scope option.AbsScope) (results UIResults) {
for _, uiResult := range u {
rect := image.Rectangle{
Min: image.Point{
@@ -267,8 +269,8 @@ func (u UIResults) FilterScope(scope AbsScope) (results UIResults) {
return
}
func (u UIResults) GetUIResult(opts ...ScreenFilterOption) (UIResult, error) {
options := NewScreenFilterOptions(opts...)
func (u UIResults) GetUIResult(opts ...option.ActionOption) (UIResult, error) {
options := option.NewActionOptions(opts...)
uiResults := u.FilterScope(options.AbsScope)
if len(uiResults) == 0 {
return UIResult{}, errors.Wrap(code.CVResultNotFoundError,
@@ -315,16 +317,7 @@ func (p PointF) IsIdentical(p2 PointF) bool {
return math.Abs(p.X-p2.X) < 1 && math.Abs(p.Y-p2.Y) < 1
}
type Size struct {
Width int `json:"width"`
Height int `json:"height"`
}
func (s Size) IsNil() bool {
return s.Width == 0 && s.Height == 0
}
type Screen struct {
StatusBarSize Size `json:"statusBarSize"`
Scale float64 `json:"scale"`
StatusBarSize types.Size `json:"statusBarSize"`
Scale float64 `json:"scale"`
}

View File

@@ -16,6 +16,7 @@ import (
"github.com/httprunner/httprunner/v5/code"
"github.com/httprunner/httprunner/v5/internal/builtin"
"github.com/httprunner/httprunner/v5/internal/json"
"github.com/httprunner/httprunner/v5/pkg/uixt/option"
)
var client = &http.Client{
@@ -46,7 +47,7 @@ func NewVEDEMImageService() (*vedemCVService, error) {
// ui - get ui position by type(s)
type vedemCVService struct{}
func (s *vedemCVService) ReadFromPath(imagePath string, opts ...ScreenShotOption) (
func (s *vedemCVService) ReadFromPath(imagePath string, opts ...option.ActionOption) (
imageResult *CVResult, err error) {
imageBuf, err := os.ReadFile(imagePath)
if err != nil {
@@ -58,9 +59,9 @@ func (s *vedemCVService) ReadFromPath(imagePath string, opts ...ScreenShotOption
return
}
func (s *vedemCVService) ReadFromBuffer(imageBuf *bytes.Buffer, opts ...ScreenShotOption) (
func (s *vedemCVService) ReadFromBuffer(imageBuf *bytes.Buffer, opts ...option.ActionOption) (
imageResult *CVResult, err error) {
actionOptions := NewScreenShotOptions(opts...)
actionOptions := option.NewActionOptions(opts...)
screenshotActions := actionOptions.List()
if len(screenshotActions) == 0 {
// skip

View File

@@ -24,7 +24,9 @@ import (
"github.com/httprunner/httprunner/v5/internal/config"
"github.com/httprunner/httprunner/v5/internal/json"
"github.com/httprunner/httprunner/v5/pkg/gadb"
"github.com/httprunner/httprunner/v5/pkg/uixt/ai"
"github.com/httprunner/httprunner/v5/pkg/uixt/option"
"github.com/httprunner/httprunner/v5/pkg/uixt/types"
)
const (
@@ -147,7 +149,7 @@ func (dev *AndroidDevice) LogEnabled() bool {
return dev.LogOn
}
func (dev *AndroidDevice) NewDriver(opts ...option.DriverOption) (driverExt *DriverExt, err error) {
func (dev *AndroidDevice) NewDriver() (driverExt IDriverExt, err error) {
var driver IDriver
if dev.UIA2 || dev.LogOn {
driver, err = NewUIA2Driver(dev)
@@ -160,18 +162,21 @@ func (dev *AndroidDevice) NewDriver(opts ...option.DriverOption) (driverExt *Dri
return nil, errors.Wrap(err, "failed to init UIA driver")
}
driverExt, err = newDriverExt(dev, driver, opts...)
if err != nil {
return nil, err
}
if dev.LogOn {
err = driverExt.Driver.StartCaptureLog("hrp_adb_log")
err = driver.StartCaptureLog("hrp_adb_log")
if err != nil {
return nil, err
}
}
driverExt, err = NewDriverExt(driver, ai.WithCVService(ai.CVServiceTypeVEDEM))
if err != nil {
return nil, errors.Wrap(err, "init android driver ext failed")
}
// setup driver
if err := driverExt.GetDriver().Setup(); err != nil {
return nil, err
}
return driverExt, nil
}
@@ -301,17 +306,17 @@ func (dev *AndroidDevice) Uninstall(packageName string) error {
return err
}
func (dev *AndroidDevice) GetCurrentWindow() (windowInfo WindowInfo, err error) {
func (dev *AndroidDevice) GetCurrentWindow() (windowInfo types.WindowInfo, err error) {
// adb shell dumpsys window | grep -E 'mCurrentFocus|mFocusedApp'
output, err := dev.RunShellCommand("dumpsys", "window", "|", "grep", "-E", "'mCurrentFocus|mFocusedApp'")
if err != nil {
return WindowInfo{}, errors.Wrap(err, "get current window failed")
return types.WindowInfo{}, errors.Wrap(err, "get current window failed")
}
// mCurrentFocus=Window{a33bc55 u0 com.miui.home/com.miui.home.launcher.Launcher}
reFocus := regexp.MustCompile(`mCurrentFocus=Window{.*? (\S+)/(\S+)}`)
matches := reFocus.FindStringSubmatch(output)
if len(matches) == 3 {
windowInfo = WindowInfo{
windowInfo = types.WindowInfo{
PackageName: matches[1],
Activity: matches[2],
}
@@ -321,7 +326,7 @@ func (dev *AndroidDevice) GetCurrentWindow() (windowInfo WindowInfo, err error)
reApp := regexp.MustCompile(`mFocusedApp=ActivityRecord{.*? (\S+)/(\S+?)\s`)
matches = reApp.FindStringSubmatch(output)
if len(matches) == 3 {
windowInfo = WindowInfo{
windowInfo = types.WindowInfo{
PackageName: matches[1],
Activity: matches[2],
}
@@ -331,24 +336,24 @@ func (dev *AndroidDevice) GetCurrentWindow() (windowInfo WindowInfo, err error)
// adb shell dumpsys activity activities | grep mResumedActivity
output, err = dev.RunShellCommand("dumpsys", "activity", "activities", "|", "grep", "mResumedActivity")
if err != nil {
return WindowInfo{}, errors.Wrap(err, "get current activity failed")
return types.WindowInfo{}, errors.Wrap(err, "get current activity failed")
}
// mResumedActivity: ActivityRecord{2db504f u0 com.miui.home/.launcher.Launcher t2}
reActivity := regexp.MustCompile(`mResumedActivity: ActivityRecord{.*? (\S+)/(\S+?)\s`)
matches = reActivity.FindStringSubmatch(output)
if len(matches) == 3 {
windowInfo = WindowInfo{
windowInfo = types.WindowInfo{
PackageName: matches[1],
Activity: matches[2],
}
return windowInfo, nil
}
return WindowInfo{}, errors.New("failed to extract current window")
return types.WindowInfo{}, errors.New("failed to extract current window")
}
func (dev *AndroidDevice) GetPackageInfo(packageName string) (AppInfo, error) {
appInfo := AppInfo{
func (dev *AndroidDevice) GetPackageInfo(packageName string) (types.AppInfo, error) {
appInfo := types.AppInfo{
Name: packageName,
}
// get package version

View File

@@ -23,8 +23,9 @@ import (
"github.com/httprunner/httprunner/v5/code"
"github.com/httprunner/httprunner/v5/internal/config"
"github.com/httprunner/httprunner/v5/internal/utf7"
"github.com/httprunner/httprunner/v5/pkg/ai"
"github.com/httprunner/httprunner/v5/pkg/uixt/ai"
"github.com/httprunner/httprunner/v5/pkg/uixt/option"
"github.com/httprunner/httprunner/v5/pkg/uixt/types"
)
func NewADBDriver(device *AndroidDevice) (*ADBDriver, error) {
@@ -86,7 +87,7 @@ func (ad *ADBDriver) DeleteSession() (err error) {
return errDriverNotImplemented
}
func (ad *ADBDriver) Status() (deviceStatus DeviceStatus, err error) {
func (ad *ADBDriver) Status() (deviceStatus types.DeviceStatus, err error) {
err = errDriverNotImplemented
return
}
@@ -95,22 +96,22 @@ func (ad *ADBDriver) GetDevice() IDevice {
return ad.AndroidDevice
}
func (ad *ADBDriver) DeviceInfo() (deviceInfo DeviceInfo, err error) {
func (ad *ADBDriver) DeviceInfo() (deviceInfo types.DeviceInfo, err error) {
err = errDriverNotImplemented
return
}
func (ad *ADBDriver) Location() (location Location, err error) {
func (ad *ADBDriver) Location() (location types.Location, err error) {
err = errDriverNotImplemented
return
}
func (ad *ADBDriver) BatteryInfo() (batteryInfo BatteryInfo, err error) {
func (ad *ADBDriver) BatteryInfo() (batteryInfo types.BatteryInfo, err error) {
err = errDriverNotImplemented
return
}
func (ad *ADBDriver) getWindowSize() (size ai.Size, err error) {
func (ad *ADBDriver) getWindowSize() (size types.Size, err error) {
// adb shell wm size
output, err := ad.runShellCommand("wm", "size")
if err != nil {
@@ -136,14 +137,14 @@ func (ad *ADBDriver) getWindowSize() (size ai.Size, err error) {
ss := strings.Split(resolution, "x")
width, _ := strconv.Atoi(ss[0])
height, _ := strconv.Atoi(ss[1])
return ai.Size{Width: width, Height: height}, nil
return types.Size{Width: width, Height: height}, nil
}
}
err = errors.New("physical window size not found by adb")
return
}
func (ad *ADBDriver) WindowSize() (size ai.Size, err error) {
func (ad *ADBDriver) WindowSize() (size types.Size, err error) {
if !ad.windowSize.IsNil() {
// use cached window size
return ad.windowSize, nil
@@ -157,11 +158,11 @@ func (ad *ADBDriver) WindowSize() (size ai.Size, err error) {
orientation, err2 := ad.Orientation()
if err2 != nil {
// Notice: do not return err if get window orientation failed
orientation = OrientationPortrait
orientation = types.OrientationPortrait
log.Warn().Err(err2).Msgf(
"get window orientation failed, use default %s", orientation)
}
if orientation != OrientationPortrait {
if orientation != types.OrientationPortrait {
size.Width, size.Height = size.Height, size.Width
}
@@ -243,7 +244,7 @@ func (ad *ADBDriver) StopCamera() (err error) {
return
}
func (ad *ADBDriver) Orientation() (orientation Orientation, err error) {
func (ad *ADBDriver) Orientation() (orientation types.Orientation, err error) {
output, err := ad.runShellCommand("dumpsys", "input", "|", "grep", "'SurfaceOrientation'")
if err != nil {
return
@@ -252,9 +253,9 @@ func (ad *ADBDriver) Orientation() (orientation Orientation, err error) {
matches := re.FindStringSubmatch(output)
if len(matches) > 1 { // 确保找到了匹配项
if matches[1] == "0" || matches[1] == "2" {
return OrientationPortrait, nil
return types.OrientationPortrait, nil
} else if matches[1] == "1" || matches[1] == "3" {
return OrientationLandscapeLeft, nil
return types.OrientationLandscapeLeft, nil
}
}
err = fmt.Errorf("not found SurfaceOrientation value")
@@ -490,12 +491,12 @@ func (ad *ADBDriver) ForceTouchFloat(x, y, pressure float64, second ...float64)
return
}
func (ad *ADBDriver) SetPasteboard(contentType PasteboardType, content string) (err error) {
func (ad *ADBDriver) SetPasteboard(contentType types.PasteboardType, content string) (err error) {
err = errDriverNotImplemented
return
}
func (ad *ADBDriver) GetPasteboard(contentType PasteboardType) (raw *bytes.Buffer, err error) {
func (ad *ADBDriver) GetPasteboard(contentType types.PasteboardType) (raw *bytes.Buffer, err error) {
err = errDriverNotImplemented
return
}
@@ -618,17 +619,17 @@ func (ad *ADBDriver) Clear(packageName string) error {
return nil
}
func (ad *ADBDriver) PressButton(devBtn DeviceButton) (err error) {
func (ad *ADBDriver) PressButton(devBtn types.DeviceButton) (err error) {
err = errDriverNotImplemented
return
}
func (ad *ADBDriver) Rotation() (rotation Rotation, err error) {
func (ad *ADBDriver) Rotation() (rotation types.Rotation, err error) {
err = errDriverNotImplemented
return
}
func (ad *ADBDriver) SetRotation(rotation Rotation) (err error) {
func (ad *ADBDriver) SetRotation(rotation types.Rotation) (err error) {
err = errDriverNotImplemented
return
}
@@ -856,7 +857,7 @@ func (ad *ADBDriver) GetDriverResults() []*DriverRequests {
return nil
}
func (ad *ADBDriver) GetForegroundApp() (app AppInfo, err error) {
func (ad *ADBDriver) GetForegroundApp() (app types.AppInfo, err error) {
packageInfo, err := ad.runShellCommand(
"CLASSPATH=/data/local/tmp/evalite", "app_process", "/",
"com.bytedance.iesqa.eval_process.PackageService", "2>/dev/null")

View File

@@ -15,6 +15,7 @@ import (
"github.com/httprunner/httprunner/v5/code"
"github.com/httprunner/httprunner/v5/internal/json"
"github.com/httprunner/httprunner/v5/pkg/uixt/option"
"github.com/httprunner/httprunner/v5/pkg/uixt/types"
)
const (
@@ -166,17 +167,17 @@ func (sad *StubAndroidDriver) close() error {
return nil
}
func (sad *StubAndroidDriver) Status() (DeviceStatus, error) {
func (sad *StubAndroidDriver) Status() (types.DeviceStatus, error) {
app, err := sad.GetForegroundApp()
if err != nil {
return DeviceStatus{}, err
return types.DeviceStatus{}, err
}
res, err := sad.sendCommand(app.PackageName, "Hello", nil)
if err != nil {
return DeviceStatus{}, err
return types.DeviceStatus{}, err
}
log.Info().Msg(fmt.Sprintf("ping stub result :%v", res))
return DeviceStatus{}, nil
return types.DeviceStatus{}, nil
}
func (sad *StubAndroidDriver) Source(srcOpt ...option.SourceOption) (source string, err error) {

View File

@@ -16,8 +16,8 @@ import (
"github.com/httprunner/httprunner/v5/code"
"github.com/httprunner/httprunner/v5/internal/utf7"
"github.com/httprunner/httprunner/v5/pkg/ai"
"github.com/httprunner/httprunner/v5/pkg/uixt/option"
"github.com/httprunner/httprunner/v5/pkg/uixt/types"
)
var errDriverNotImplemented = errors.New("driver method not implemented")
@@ -133,12 +133,12 @@ func (ud *UIA2Driver) DeleteSession() (err error) {
return err
}
func (ud *UIA2Driver) Status() (deviceStatus DeviceStatus, err error) {
func (ud *UIA2Driver) Status() (deviceStatus types.DeviceStatus, err error) {
// register(getHandler, new Status("/wd/hub/status"))
var rawResp rawResponse
// Notice: use Driver.GET instead of httpGET to avoid loop calling
if rawResp, err = ud.GET("/status"); err != nil {
return DeviceStatus{Ready: false}, err
return types.DeviceStatus{Ready: false}, err
}
reply := new(struct {
Value struct {
@@ -147,34 +147,34 @@ func (ud *UIA2Driver) Status() (deviceStatus DeviceStatus, err error) {
}
})
if err = json.Unmarshal(rawResp, reply); err != nil {
return DeviceStatus{Ready: false}, err
return types.DeviceStatus{Ready: false}, err
}
return DeviceStatus{Ready: true}, nil
return types.DeviceStatus{Ready: true}, nil
}
func (ud *UIA2Driver) DeviceInfo() (deviceInfo DeviceInfo, err error) {
func (ud *UIA2Driver) DeviceInfo() (deviceInfo types.DeviceInfo, err error) {
// register(getHandler, new GetDeviceInfo("/wd/hub/session/:sessionId/appium/device/info"))
var rawResp rawResponse
if rawResp, err = ud.httpGET("/session", ud.sessionID, "appium/device/info"); err != nil {
return DeviceInfo{}, err
return types.DeviceInfo{}, err
}
reply := new(struct{ Value struct{ DeviceInfo } })
reply := new(struct{ Value struct{ types.DeviceInfo } })
if err = json.Unmarshal(rawResp, reply); err != nil {
return DeviceInfo{}, err
return types.DeviceInfo{}, err
}
deviceInfo = reply.Value.DeviceInfo
return
}
func (ud *UIA2Driver) BatteryInfo() (batteryInfo BatteryInfo, err error) {
func (ud *UIA2Driver) BatteryInfo() (batteryInfo types.BatteryInfo, err error) {
// register(getHandler, new GetBatteryInfo("/wd/hub/session/:sessionId/appium/device/battery_info"))
var rawResp rawResponse
if rawResp, err = ud.httpGET("/session", ud.sessionID, "appium/device/battery_info"); err != nil {
return BatteryInfo{}, err
return types.BatteryInfo{}, err
}
reply := new(struct{ Value struct{ BatteryInfo } })
reply := new(struct{ Value struct{ types.BatteryInfo } })
if err = json.Unmarshal(rawResp, reply); err != nil {
return BatteryInfo{}, err
return types.BatteryInfo{}, err
}
if reply.Value.Level == -1 || reply.Value.Status == -1 {
return reply.Value.BatteryInfo, errors.New("cannot be retrieved from the system")
@@ -183,7 +183,7 @@ func (ud *UIA2Driver) BatteryInfo() (batteryInfo BatteryInfo, err error) {
return
}
func (ud *UIA2Driver) WindowSize() (size ai.Size, err error) {
func (ud *UIA2Driver) WindowSize() (size types.Size, err error) {
// register(getHandler, new GetDeviceSize("/wd/hub/session/:sessionId/window/:windowHandle/size"))
if !ud.windowSize.IsNil() {
// use cached window size
@@ -192,11 +192,11 @@ func (ud *UIA2Driver) WindowSize() (size ai.Size, err error) {
var rawResp rawResponse
if rawResp, err = ud.httpGET("/session", ud.sessionID, "window/:windowHandle/size"); err != nil {
return ai.Size{}, errors.Wrap(err, "get window size failed by UIA2 request")
return types.Size{}, errors.Wrap(err, "get window size failed by UIA2 request")
}
reply := new(struct{ Value struct{ ai.Size } })
reply := new(struct{ Value struct{ types.Size } })
if err = json.Unmarshal(rawResp, reply); err != nil {
return ai.Size{}, errors.Wrap(err, "get window size failed by UIA2 response")
return types.Size{}, errors.Wrap(err, "get window size failed by UIA2 response")
}
size = reply.Value.Size
@@ -204,9 +204,9 @@ func (ud *UIA2Driver) WindowSize() (size ai.Size, err error) {
orientation, err := ud.Orientation()
if err != nil {
log.Warn().Err(err).Msgf("window size get orientation failed, use default orientation")
orientation = OrientationPortrait
orientation = types.OrientationPortrait
}
if orientation != OrientationPortrait {
if orientation != types.OrientationPortrait {
size.Width, size.Height = size.Height, size.Width
}
@@ -244,13 +244,13 @@ func (ud *UIA2Driver) PressKeyCodes(keyCode KeyCode, metaState KeyMeta, flags ..
return
}
func (ud *UIA2Driver) Orientation() (orientation Orientation, err error) {
func (ud *UIA2Driver) Orientation() (orientation types.Orientation, err error) {
// [[FBRoute GET:@"/orientation"] respondWithTarget:self action:@selector(handleGetOrientation:)]
var rawResp rawResponse
if rawResp, err = ud.httpGET("/session", ud.sessionID, "/orientation"); err != nil {
return "", err
}
reply := new(struct{ Value Orientation })
reply := new(struct{ Value types.Orientation })
if err = json.Unmarshal(rawResp, reply); err != nil {
return "", err
}
@@ -418,7 +418,7 @@ func (ud *UIA2Driver) Swipe(fromX, fromY, toX, toY float64, opts ...option.Actio
return err
}
func (ud *UIA2Driver) SetPasteboard(contentType PasteboardType, content string) (err error) {
func (ud *UIA2Driver) SetPasteboard(contentType types.PasteboardType, content string) (err error) {
lbl := content
const defaultLabelLen = 10
@@ -436,9 +436,9 @@ func (ud *UIA2Driver) SetPasteboard(contentType PasteboardType, content string)
return
}
func (ud *UIA2Driver) GetPasteboard(contentType PasteboardType) (raw *bytes.Buffer, err error) {
func (ud *UIA2Driver) GetPasteboard(contentType types.PasteboardType) (raw *bytes.Buffer, err error) {
if len(contentType) == 0 {
contentType = PasteboardTypePlaintext
contentType = types.PasteboardTypePlaintext
}
// register(postHandler, new GetClipboard("/wd/hub/session/:sessionId/appium/device/get_clipboard"))
data := map[string]interface{}{
@@ -541,15 +541,15 @@ func (ud *UIA2Driver) Input(text string, opts ...option.ActionOption) (err error
return ud.SendKeys(text, opts...)
}
func (ud *UIA2Driver) Rotation() (rotation Rotation, err error) {
func (ud *UIA2Driver) Rotation() (rotation types.Rotation, err error) {
// register(getHandler, new GetRotation("/wd/hub/session/:sessionId/rotation"))
var rawResp rawResponse
if rawResp, err = ud.httpGET("/session", ud.sessionID, "rotation"); err != nil {
return Rotation{}, err
return types.Rotation{}, err
}
reply := new(struct{ Value Rotation })
reply := new(struct{ Value types.Rotation })
if err = json.Unmarshal(rawResp, reply); err != nil {
return Rotation{}, err
return types.Rotation{}, err
}
rotation = reply.Value

View File

@@ -10,9 +10,10 @@ import (
"github.com/httprunner/httprunner/v5/internal/builtin"
"github.com/httprunner/httprunner/v5/pkg/uixt/option"
"github.com/httprunner/httprunner/v5/pkg/uixt/types"
)
var driverExt *DriverExt
var driverExt IDriverExt
func setupAndroidAdbDriver(t *testing.T) {
device, err := NewAndroidDevice()
@@ -91,7 +92,7 @@ func TestDriver_DeviceSize(t *testing.T) {
func TestDriver_Source(t *testing.T) {
setupAndroidUIA2Driver(t)
source, err := driverExt.Driver.Source()
source, err := driverExt.GetDriver().Source()
if err != nil {
t.Fatal(err)
}
@@ -140,7 +141,7 @@ func TestDriver_DeviceInfo(t *testing.T) {
func TestDriver_Tap(t *testing.T) {
setupAndroidUIA2Driver(t)
driverExt.Driver.StartCaptureLog("")
driverExt.GetDriver().StartCaptureLog("")
err := driverExt.TapXY(0.5, 0.5,
option.WithIdentifier("test"),
option.WithPressDuration(4))
@@ -149,18 +150,18 @@ func TestDriver_Tap(t *testing.T) {
}
//time.Sleep(time.Second)
//
//err = driverExt.Driver.Tap(60.5, 125.5, WithIdentifier("test"))
//err = driverExt.GetDriver().Tap(60.5, 125.5, WithIdentifier("test"))
//if err != nil {
// t.Fatal(err)
//}
//time.Sleep(time.Second)
//result, _ := driverExt.Driver.StopCaptureLog()
//result, _ := driverExt.GetDriver().StopCaptureLog()
//t.Log(result)
}
func TestDriver_Swipe(t *testing.T) {
setupAndroidUIA2Driver(t)
err := driverExt.Driver.Swipe(400, 1000, 400, 500,
err := driverExt.GetDriver().Swipe(400, 1000, 400, 500,
option.WithPressDuration(0.5))
if err != nil {
t.Fatal(err)
@@ -192,7 +193,7 @@ func TestDriver_Drag(t *testing.T) {
func TestDriver_SendKeys(t *testing.T) {
setupAndroidUIA2Driver(t)
err := driverExt.Driver.SendKeys("辽宁省沈阳市新民市民族街36-4",
err := driverExt.GetDriver().SendKeys("辽宁省沈阳市新民市民族街36-4",
option.WithIdentifier("test"))
if err != nil {
t.Fatal(err)
@@ -222,7 +223,7 @@ func TestDriver_PressBack(t *testing.T) {
func TestDriver_SetRotation(t *testing.T) {
// err = driver.SetRotation(Rotation{Z: 0})
err := driver.SetRotation(Rotation{Z: 270})
err := driver.SetRotation(types.Rotation{Z: 270})
if err != nil {
t.Fatal(err)
}
@@ -230,10 +231,10 @@ func TestDriver_SetRotation(t *testing.T) {
func TestDriver_GetOrientation(t *testing.T) {
setupAndroidUIA2Driver(t)
_, _ = driverExt.Driver.AppTerminate("com.quark.browser")
_ = driverExt.Driver.AppLaunch("com.quark.browser")
_, _ = driverExt.GetDriver().AppTerminate("com.quark.browser")
_ = driverExt.GetDriver().AppLaunch("com.quark.browser")
time.Sleep(2 * time.Second)
_ = driverExt.Driver.Homescreen()
_ = driverExt.GetDriver().Homescreen()
}
func Test_getFreePort(t *testing.T) {
@@ -251,12 +252,12 @@ func TestDriver_AppLaunch(t *testing.T) {
t.Fatal(err)
}
err = driver.Driver.AppLaunch("com.android.settings")
err = driver.GetDriver().AppLaunch("com.android.settings")
if err != nil {
t.Fatal(err)
}
raw, err := driver.Driver.Screenshot()
raw, err := driver.GetDriver().Screenshot()
if err != nil {
t.Fatal(err)
}
@@ -268,10 +269,10 @@ func TestDriver_IsAppInForeground(t *testing.T) {
setupAndroidUIA2Driver(t)
// setupAndroidAdbDriver(t)
err := driverExt.Driver.AppLaunch("com.android.settings")
err := driverExt.GetDriver().AppLaunch("com.android.settings")
checkErr(t, err)
app, err := driverExt.Driver.GetForegroundApp()
app, err := driverExt.GetDriver().GetForegroundApp()
checkErr(t, err)
if app.PackageName != "com.android.settings" {
t.FailNow()
@@ -280,18 +281,18 @@ func TestDriver_IsAppInForeground(t *testing.T) {
t.FailNow()
}
err = driverExt.Driver.AssertForegroundApp("com.android.settings")
err = driverExt.GetDriver().AssertForegroundApp("com.android.settings")
if err != nil {
t.Fatal(err)
}
time.Sleep(2 * time.Second)
_, err = driverExt.Driver.AppTerminate("com.android.settings")
_, err = driverExt.GetDriver().AppTerminate("com.android.settings")
if err != nil {
t.Fatal(err)
}
err = driverExt.Driver.AssertForegroundApp("com.android.settings")
err = driverExt.GetDriver().AssertForegroundApp("com.android.settings")
if err == nil {
t.Fatal(err)
}
@@ -304,19 +305,19 @@ func TestDriver_KeepAlive(t *testing.T) {
t.Fatal(err)
}
err = driver.Driver.AppLaunch("com.android.settings")
err = driver.GetDriver().AppLaunch("com.android.settings")
if err != nil {
t.Fatal(err)
}
_, err = driver.Driver.Screenshot()
_, err = driver.GetDriver().Screenshot()
if err != nil {
t.Fatal(err)
}
time.Sleep(60 * time.Second)
_, err = driver.Driver.Screenshot()
_, err = driver.GetDriver().Screenshot()
if err != nil {
t.Fatal(err)
}
@@ -329,7 +330,7 @@ func TestDriver_AppTerminate(t *testing.T) {
t.Fatal(err)
}
_, err = driver.Driver.AppTerminate("tv.danmaku.bili")
_, err = driver.GetDriver().AppTerminate("tv.danmaku.bili")
if err != nil {
t.Fatal(err)
}
@@ -391,7 +392,7 @@ func TestTapTexts(t *testing.T) {
},
},
}
err := driverExt.Driver.TapByTexts(actions...)
err := driverExt.GetDriver().TapByTexts(actions...)
if err != nil {
t.Fatal(err)
}
@@ -399,7 +400,7 @@ func TestTapTexts(t *testing.T) {
func TestRecordVideo(t *testing.T) {
setupAndroidAdbDriver(t)
path, err := driverExt.Driver.(*ADBDriver).RecordScreen("", 5*time.Second)
path, err := driverExt.GetDriver().(*ADBDriver).RecordScreen("", 5*time.Second)
if err != nil {
t.Fatal(err)
}
@@ -409,7 +410,7 @@ func TestRecordVideo(t *testing.T) {
func Test_Android_Backspace(t *testing.T) {
setupAndroidAdbDriver(t)
err := driverExt.Driver.Backspace(1)
err := driverExt.GetDriver().Backspace(1)
if err != nil {
t.Fatal(err)
}

View File

@@ -22,16 +22,14 @@ func TestIOSDemo(t *testing.T) {
t.Fatal(err)
}
capabilities := option.NewCapabilities()
capabilities.WithDefaultAlertAction(option.AlertActionAccept) // or uixt.AlertActionDismiss
driverExt, err := device.NewDriver(option.WithDriverCapabilities(capabilities))
driverExt, err := device.NewDriver()
if err != nil {
t.Fatal(err)
}
// release session
defer func() {
driverExt.Driver.DeleteSession()
driverExt.GetDriver().DeleteSession()
}()
// 持续监测手机屏幕,直到出现青少年模式弹窗后,点击「我知道了」

View File

@@ -2,6 +2,7 @@ package uixt
import (
"github.com/httprunner/httprunner/v5/pkg/uixt/option"
"github.com/httprunner/httprunner/v5/pkg/uixt/types"
)
// current implemeted device: IOSDevice, AndroidDevice, HarmonyDevice
@@ -14,7 +15,7 @@ type IDevice interface {
Install(appPath string, opts ...option.InstallOption) error
Uninstall(packageName string) error
GetPackageInfo(packageName string) (AppInfo, error)
GetPackageInfo(packageName string) (types.AppInfo, error)
// TODO: remove?
LogEnabled() bool

View File

@@ -16,8 +16,9 @@ import (
"github.com/httprunner/httprunner/v5/internal/builtin"
"github.com/httprunner/httprunner/v5/internal/config"
"github.com/httprunner/httprunner/v5/internal/json"
"github.com/httprunner/httprunner/v5/pkg/ai"
"github.com/httprunner/httprunner/v5/pkg/uixt/ai"
"github.com/httprunner/httprunner/v5/pkg/uixt/option"
"github.com/httprunner/httprunner/v5/pkg/uixt/types"
)
var (
@@ -40,10 +41,10 @@ type IDriver interface {
// GetSession returns session cache, including requests, screenshots, etc.
GetSession() *Session
Status() (DeviceStatus, error)
Status() (types.DeviceStatus, error)
GetDevice() IDevice
DeviceInfo() (DeviceInfo, error)
DeviceInfo() (types.DeviceInfo, error)
// Location Returns device location data.
//
@@ -56,13 +57,13 @@ type IDriver interface {
//
// The return value could be zero even if the permission is set to 'Always'
// since the location service needs some time to update the location data.
Location() (Location, error)
BatteryInfo() (BatteryInfo, error)
Location() (types.Location, error)
BatteryInfo() (types.BatteryInfo, error)
// WindowSize Return the width and height in portrait mode.
// when getting the window size in wda/ui2/adb, if the device is in landscape mode,
// the width and height will be reversed.
WindowSize() (ai.Size, error)
WindowSize() (types.Size, error)
Screen() (ai.Screen, error)
Scale() (float64, error)
@@ -78,7 +79,7 @@ type IDriver interface {
// Either `true` if the app has been successfully terminated or `false` if it was not running
AppTerminate(packageName string) (bool, error)
// GetForegroundApp returns current foreground app package name and activity name
GetForegroundApp() (app AppInfo, err error)
GetForegroundApp() (app types.AppInfo, err error)
// AssertForegroundApp returns nil if the given package and activity are in foreground
AssertForegroundApp(packageName string, activityType ...string) error
@@ -87,10 +88,10 @@ type IDriver interface {
// StopCamera Stops the camera for recording
StopCamera() error
Orientation() (orientation Orientation, err error)
Orientation() (orientation types.Orientation, err error)
SetRotation(rotation Rotation) (err error)
Rotation() (rotation Rotation, err error)
SetRotation(rotation types.Rotation) (err error)
Rotation() (rotation types.Rotation, err error)
// Tap Sends a tap event at the coordinate.
Tap(x, y float64, opts ...option.ActionOption) error
@@ -110,10 +111,10 @@ type IDriver interface {
Swipe(fromX, fromY, toX, toY float64, opts ...option.ActionOption) error
// SetPasteboard Sets data to the general pasteboard
SetPasteboard(contentType PasteboardType, content string) error
SetPasteboard(contentType types.PasteboardType, content string) error
// GetPasteboard Gets the data contained in the general pasteboard.
// It worked when `WDA` was foreground. https://github.com/appium/WebDriverAgent/issues/330
GetPasteboard(contentType PasteboardType) (raw *bytes.Buffer, err error)
GetPasteboard(contentType types.PasteboardType) (raw *bytes.Buffer, err error)
SetIme(ime string) error
@@ -128,7 +129,7 @@ type IDriver interface {
Clear(packageName string) error
// PressButton Presses the corresponding hardware button on the device
PressButton(devBtn DeviceButton) error
PressButton(devBtn types.DeviceButton) error
// PressBack Presses the back button
PressBack(opts ...option.ActionOption) error
@@ -177,6 +178,13 @@ type IDriverExt interface {
GetScreenResult(opts ...option.ActionOption) (screenResult *ScreenResult, err error)
GetScreenTexts(opts ...option.ActionOption) (ocrTexts ai.OCRTexts, err error)
GetScreenShot(fileName string) (raw *bytes.Buffer, path string, err error)
TapByOCR(ocrText string, opts ...option.ActionOption) error
TapXY(x, y float64, opts ...option.ActionOption) error
TapAbsXY(x, y float64, opts ...option.ActionOption) error
TapOffset(param string, xOffset, yOffset float64, opts ...option.ActionOption) (err error)
TapByUIDetection(opts ...option.ActionOption) error
// swipe
SwipeRelative(fromX, fromY, toX, toY float64, opts ...option.ActionOption) error
@@ -184,15 +192,25 @@ type IDriverExt interface {
SwipeDown(opts ...option.ActionOption) error
SwipeLeft(opts ...option.ActionOption) error
SwipeRight(opts ...option.ActionOption) error
SwipeToTapApp(appName string, opts ...option.ActionOption) error
CheckPopup() (popup *PopupInfo, err error)
ClosePopupsHandler() error
DoAction(action MobileAction) (err error)
DoValidation(check, assert, expected string, message ...string) (err error)
}
func NewDriverExt(driver IDriver, opts ...ai.AIServiceOption) (IDriverExt, error) {
services := ai.NewAIService(opts...)
driverExt := &DriverExt{
Driver: driver,
ImageService: services.ImageService,
Driver: driver,
CVService: services.ICVService,
LLMService: services.ILLMService,
}
// create results directory
// TODO: move to setup
if err := builtin.EnsureFolderExists(config.ResultsPath); err != nil {
return nil, errors.Wrap(err, "create results directory failed")
}
@@ -203,25 +221,9 @@ func NewDriverExt(driver IDriver, opts ...ai.AIServiceOption) (IDriverExt, error
}
type DriverExt struct {
Driver IDriver
ImageService ai.IImageService // used to extract image data
}
func newDriverExt(device IDevice, driver IDriver, opts ...option.DriverOption) (dExt *DriverExt, err error) {
options := option.NewDriverOptions(opts...)
dExt = &DriverExt{
Driver: driver,
}
if options.WithImageService {
if dExt.ImageService, err = ai.NewVEDEMImageService(); err != nil {
return nil, err
}
}
if options.WithResultFolder {
}
return dExt, nil
Driver IDriver
CVService ai.ICVService // OCR/CV
LLMService ai.ILLMService // LLM
}
func (dExt *DriverExt) GetDriver() IDriver {

View File

@@ -13,6 +13,7 @@ import (
"github.com/httprunner/httprunner/v5/code"
"github.com/httprunner/httprunner/v5/internal/builtin"
"github.com/httprunner/httprunner/v5/pkg/uixt/option"
"github.com/httprunner/httprunner/v5/pkg/uixt/types"
)
type ActionMethod string
@@ -169,7 +170,7 @@ func (dExt *DriverExt) DoAction(action MobileAction) (err error) {
ACTION_AppLaunch, action.Params)
case ACTION_SwipeToTapApp:
if appName, ok := action.Params.(string); ok {
return dExt.swipeToTapApp(appName, action.GetOptions()...)
return dExt.SwipeToTapApp(appName, action.GetOptions()...)
}
return fmt.Errorf("invalid %s params, should be app name(string), got %v",
ACTION_SwipeToTapApp, action.Params)
@@ -201,7 +202,7 @@ func (dExt *DriverExt) DoAction(action MobileAction) (err error) {
return fmt.Errorf("app_terminate params should be bundleId(string), got %v", action.Params)
case ACTION_SetClipboard:
if text, ok := action.Params.(string); ok {
err := dExt.Driver.SetPasteboard(PasteboardTypePlaintext, text)
err := dExt.Driver.SetPasteboard(types.PasteboardTypePlaintext, text)
if err != nil {
return errors.Wrap(err, "failed to set clipboard")
}
@@ -280,7 +281,7 @@ func (dExt *DriverExt) DoAction(action MobileAction) (err error) {
return fmt.Errorf("invalid %s params: %v", ACTION_DoubleTap, action.Params)
case ACTION_Swipe:
params := action.Params
swipeAction := dExt.prepareSwipeAction(params, action.GetOptions()...)
swipeAction := prepareSwipeAction(dExt, params, action.GetOptions()...)
return swipeAction(dExt)
case ACTION_Input:
// input text on current active element
@@ -328,7 +329,7 @@ func (dExt *DriverExt) DoAction(action MobileAction) (err error) {
case ACTION_ScreenShot:
// take screenshot
log.Info().Msg("take screenshot for current screen")
_, err := dExt.GetScreenResult(action.GetOptions()...)
_, err := dExt.GetScreenResult(action.GetScreenOptions()...)
return err
case ACTION_StartCamera:
return dExt.Driver.StartCamera()

View File

@@ -5,7 +5,7 @@ import (
"github.com/rs/zerolog/log"
"github.com/httprunner/httprunner/v5/code"
"github.com/httprunner/httprunner/v5/pkg/ai"
"github.com/httprunner/httprunner/v5/pkg/uixt/ai"
"github.com/httprunner/httprunner/v5/pkg/uixt/option"
)

View File

@@ -18,14 +18,15 @@ import (
"github.com/httprunner/httprunner/v5/code"
"github.com/httprunner/httprunner/v5/internal/builtin"
"github.com/httprunner/httprunner/v5/internal/config"
"github.com/httprunner/httprunner/v5/pkg/ai"
"github.com/httprunner/httprunner/v5/pkg/uixt/ai"
"github.com/httprunner/httprunner/v5/pkg/uixt/option"
"github.com/httprunner/httprunner/v5/pkg/uixt/types"
)
type ScreenResult struct {
bufSource *bytes.Buffer // raw image buffer bytes
ImagePath string `json:"image_path"` // image file path
Resolution ai.Size `json:"resolution"`
Resolution types.Size `json:"resolution"`
UploadedURL string `json:"uploaded_url"` // uploaded image url
Texts ai.OCRTexts `json:"texts"` // dumped raw OCRTexts
Icons ai.UIResultMap `json:"icons"` // CV 识别的图标
@@ -46,26 +47,26 @@ func (s *ScreenResult) FilterTextsByScope(x1, y1, x2, y2 float64) ai.OCRTexts {
// GetScreenResult takes a screenshot, returns the image recognition result
func (dExt *DriverExt) GetScreenResult(opts ...option.ActionOption) (screenResult *ScreenResult, err error) {
actionOptions := option.NewActionOptions(opts...)
screenshotOptions := option.NewActionOptions(opts...)
var fileName string
screenshotActions := actionOptions.ScreenshotActions()
if actionOptions.ScreenShotFileName != "" {
fileName = builtin.GenNameWithTimestamp("%d_" + actionOptions.ScreenShotFileName)
} else if len(screenshotActions) != 0 {
fileName = builtin.GenNameWithTimestamp("%d_" + strings.Join(screenshotActions, "_"))
optionsList := screenshotOptions.List()
if screenshotOptions.ScreenShotFileName != "" {
fileName = builtin.GenNameWithTimestamp("%d_" + screenshotOptions.ScreenShotFileName)
} else if len(optionsList) != 0 {
fileName = builtin.GenNameWithTimestamp("%d_" + strings.Join(optionsList, "_"))
} else {
fileName = builtin.GenNameWithTimestamp("%d_screenshot")
}
var bufSource *bytes.Buffer
var imageResult *ai.ImageResult
var imageResult *ai.CVResult
var imagePath string
var windowSize ai.Size
var windowSize types.Size
var lastErr error
// get screenshot info with retry
for i := 0; i <= actionOptions.MaxRetryTimes; i++ {
for i := 0; i < 3; i++ {
bufSource, imagePath, err = dExt.GetScreenShot(fileName)
if err != nil {
lastErr = err
@@ -85,9 +86,9 @@ func (dExt *DriverExt) GetScreenResult(opts ...option.ActionOption) (screenResul
Tags: nil,
Resolution: windowSize,
}
imageResult, err = dExt.ImageService.GetImageFromBuffer(bufSource, opts...)
imageResult, err = dExt.CVService.ReadFromBuffer(bufSource, opts...)
if err != nil {
log.Error().Err(err).Msg("GetImageFromBuffer from ImageService failed")
log.Error().Err(err).Msg("ReadFromBuffer from ImageService failed")
lastErr = err
continue
}
@@ -107,7 +108,7 @@ func (dExt *DriverExt) GetScreenResult(opts ...option.ActionOption) (screenResul
screenResult.UploadedURL = imageResult.URL
screenResult.Icons = imageResult.UIResult
if actionOptions.ScreenShotWithClosePopups && imageResult.ClosePopupsResult != nil {
if screenshotOptions.ScreenShotWithClosePopups && imageResult.ClosePopupsResult != nil {
screenResult.Popup = &PopupInfo{
ClosePopupsResult: imageResult.ClosePopupsResult,
PicName: imagePath,
@@ -129,8 +130,8 @@ func (dExt *DriverExt) GetScreenResult(opts ...option.ActionOption) (screenResul
}
func (dExt *DriverExt) GetScreenTexts(opts ...option.ActionOption) (ocrTexts ai.OCRTexts, err error) {
actionOptions := option.NewActionOptions(opts...)
if actionOptions.ScreenShotFileName == "" {
options := option.NewActionOptions(opts...)
if options.ScreenShotFileName == "" {
opts = append(opts, option.WithScreenShotFileName("get_screen_texts"))
}
opts = append(opts, option.WithScreenShotOCR(true), option.WithScreenShotUpload(true))
@@ -152,8 +153,8 @@ func (dExt *DriverExt) FindUIRectInUIKit(search string, opts ...option.ActionOpt
}
func (dExt *DriverExt) FindScreenText(text string, opts ...option.ActionOption) (point ai.PointF, err error) {
actionOptions := option.NewActionOptions(opts...)
if actionOptions.ScreenShotFileName == "" {
options := option.NewActionOptions(opts...)
if options.ScreenShotFileName == "" {
opts = append(opts, option.WithScreenShotFileName(fmt.Sprintf("find_screen_text_%s", text)))
}
ocrTexts, err := dExt.GetScreenTexts(opts...)
@@ -161,7 +162,7 @@ func (dExt *DriverExt) FindScreenText(text string, opts ...option.ActionOption)
return
}
result, err := ocrTexts.FindText(text, dExt.ParseActionOptions(opts...)...)
result, err := ocrTexts.FindText(text, opts...)
if err != nil {
log.Warn().Msgf("FindText failed: %s", err.Error())
return
@@ -174,10 +175,10 @@ func (dExt *DriverExt) FindScreenText(text string, opts ...option.ActionOption)
}
func (dExt *DriverExt) FindUIResult(opts ...option.ActionOption) (point ai.PointF, err error) {
actionOptions := option.NewActionOptions(opts...)
if actionOptions.ScreenShotFileName == "" {
options := option.NewActionOptions(opts...)
if options.ScreenShotFileName == "" {
opts = append(opts, option.WithScreenShotFileName(
fmt.Sprintf("find_ui_result_%s", strings.Join(actionOptions.ScreenShotWithUITypes, "_"))))
fmt.Sprintf("find_ui_result_%s", strings.Join(options.ScreenShotWithUITypes, "_"))))
}
screenResult, err := dExt.GetScreenResult(opts...)
@@ -185,14 +186,14 @@ func (dExt *DriverExt) FindUIResult(opts ...option.ActionOption) (point ai.Point
return
}
uiResults, err := screenResult.Icons.FilterUIResults(actionOptions.ScreenShotWithUITypes)
uiResults, err := screenResult.Icons.FilterUIResults(options.ScreenShotWithUITypes)
if err != nil {
return
}
uiResult, err := uiResults.GetUIResult(dExt.ParseActionOptions(opts...)...)
uiResult, err := uiResults.GetUIResult(opts...)
point = uiResult.Center()
log.Info().Interface("text", actionOptions.ScreenShotWithUITypes).
log.Info().Interface("text", options.ScreenShotWithUITypes).
Interface("point", point).Msg("FindUIResult success")
return
}

View File

@@ -12,7 +12,7 @@ import (
"time"
"github.com/httprunner/httprunner/v5/internal/json"
"github.com/httprunner/httprunner/v5/pkg/ai"
"github.com/httprunner/httprunner/v5/pkg/uixt/types"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)
@@ -25,7 +25,7 @@ type Session struct {
// cache to avoid repeated query
scale float64
windowSize ai.Size
windowSize types.Size
// cache uia2/wda request and response
requests []*DriverRequests

View File

@@ -10,7 +10,7 @@ import (
"github.com/httprunner/httprunner/v5/code"
"github.com/httprunner/httprunner/v5/internal/builtin"
"github.com/httprunner/httprunner/v5/pkg/ai"
"github.com/httprunner/httprunner/v5/pkg/uixt/ai"
"github.com/httprunner/httprunner/v5/pkg/uixt/option"
)
@@ -86,7 +86,7 @@ func (dExt *DriverExt) LoopUntil(findAction, findCondition, foundAction Action,
fmt.Sprintf("loop %d times, match find condition failed", maxRetryTimes))
}
func (dExt *DriverExt) prepareSwipeAction(params interface{}, opts ...option.ActionOption) func(d *DriverExt) error {
func prepareSwipeAction(dExt *DriverExt, params interface{}, opts ...option.ActionOption) func(d *DriverExt) error {
actionOptions := option.NewActionOptions(opts...)
var swipeDirection interface{}
@@ -177,11 +177,11 @@ func (dExt *DriverExt) swipeToTapTexts(texts []string, opts ...option.ActionOpti
return d.TapAbsXY(point.X, point.Y, opts...)
}
findAction := dExt.prepareSwipeAction(nil, optionsWithoutIdentifier...)
findAction := prepareSwipeAction(dExt, nil, optionsWithoutIdentifier...)
return dExt.LoopUntil(findAction, findTexts, foundTextAction, optionsWithoutIdentifier...)
}
func (dExt *DriverExt) swipeToTapApp(appName string, opts ...option.ActionOption) error {
func (dExt *DriverExt) SwipeToTapApp(appName string, opts ...option.ActionOption) error {
// go to home screen
if err := dExt.Driver.Homescreen(); err != nil {
return errors.Wrap(err, "go to home screen failed")

View File

@@ -11,28 +11,30 @@ import (
func TestAndroidSwipeAction(t *testing.T) {
setupAndroidAdbDriver(t)
swipeAction := driverExt.prepareSwipeAction("up", option.WithDirection("down"))
err := swipeAction(driverExt)
dExt := driverExt.(*DriverExt)
swipeAction := prepareSwipeAction(dExt, "up", option.WithDirection("down"))
err := swipeAction(dExt)
checkErr(t, err)
swipeAction = driverExt.prepareSwipeAction("up", option.WithCustomDirection(0.5, 0.5, 0.5, 0.9))
err = swipeAction(driverExt)
swipeAction = prepareSwipeAction(dExt, "up", option.WithCustomDirection(0.5, 0.5, 0.5, 0.9))
err = swipeAction(dExt)
checkErr(t, err)
}
func TestAndroidSwipeToTapApp(t *testing.T) {
setupAndroidAdbDriver(t)
err := driverExt.swipeToTapApp("抖音")
err := driverExt.SwipeToTapApp("抖音")
checkErr(t, err)
}
func TestAndroidSwipeToTapTexts(t *testing.T) {
setupAndroidAdbDriver(t)
err := driverExt.Driver.AppLaunch("com.ss.android.ugc.aweme")
err := driverExt.GetDriver().AppLaunch("com.ss.android.ugc.aweme")
checkErr(t, err)
err = driverExt.swipeToTapTexts([]string{"点击进入直播间", "直播中"}, option.WithDirection("up"))
dExt := driverExt.(*DriverExt)
err = dExt.swipeToTapTexts([]string{"点击进入直播间", "直播中"}, option.WithDirection("up"))
checkErr(t, err)
}

View File

@@ -51,11 +51,11 @@ func (dExt *DriverExt) TapByOCR(ocrText string, opts ...option.ActionOption) err
}
func (dExt *DriverExt) TapByUIDetection(opts ...option.ActionOption) error {
actionOptions := option.NewActionOptions(opts...)
options := option.NewActionOptions(opts...)
point, err := dExt.FindUIResult(opts...)
if err != nil {
if actionOptions.IgnoreNotFoundError {
if options.IgnoreNotFoundError {
return nil
}
return err
@@ -69,11 +69,11 @@ func (dExt *DriverExt) Tap(param string, opts ...option.ActionOption) error {
}
func (dExt *DriverExt) TapOffset(param string, xOffset, yOffset float64, opts ...option.ActionOption) (err error) {
actionOptions := option.NewActionOptions(opts...)
options := option.NewActionOptions(opts...)
point, err := dExt.FindUIRectInUIKit(param, opts...)
if err != nil {
if actionOptions.IgnoreNotFoundError {
if options.IgnoreNotFoundError {
return nil
}
return err

View File

@@ -3,20 +3,14 @@ package uixt
import (
"testing"
"github.com/httprunner/httprunner/v5/pkg/ai"
"github.com/httprunner/httprunner/v5/pkg/uixt/ai"
)
func TestNewDriverExt(t *testing.T) {
device, _ := NewAndroidDevice()
var driver IDriver
var err error
if device.UIA2 || device.LogOn {
driver, err = NewUIA2Driver(device)
} else if device.STUB {
driver, err = NewStubAndroidDriver(device)
} else {
driver, err = NewADBDriver(device)
}
driver, err = NewADBDriver(device)
if err != nil {
t.Fatal(err)
}
@@ -24,6 +18,12 @@ func TestNewDriverExt(t *testing.T) {
driverExt, _ := NewDriverExt(driver,
ai.WithCVService(ai.CVServiceTypeVEDEM))
driverExt.GetDriver()
t.Log(driverExt)
texts, _ := driverExt.GetScreenTexts()
t.Log(texts)
// get original dirver
driver = driverExt.GetDriver().(*ADBDriver)
// get device
device = driver.GetDevice().(*AndroidDevice)
}

View File

@@ -1,19 +1,14 @@
package uixt
import (
"fmt"
"code.byted.org/iesqa/ghdc"
"github.com/pkg/errors"
"github.com/rs/zerolog/log"
"github.com/httprunner/httprunner/v5/code"
"github.com/httprunner/httprunner/v5/pkg/uixt/ai"
"github.com/httprunner/httprunner/v5/pkg/uixt/option"
)
var (
HdcServerHost = "localhost"
HdcServerPort = ghdc.HdcServerPort // 5037
"github.com/httprunner/httprunner/v5/pkg/uixt/types"
)
type HarmonyDevice struct {
@@ -23,65 +18,53 @@ type HarmonyDevice struct {
func NewHarmonyDevice(opts ...option.HarmonyDeviceOption) (device *HarmonyDevice, err error) {
deviceConfig := option.NewHarmonyDeviceOptions(opts...)
deviceList, err := GetHarmonyDevices(deviceConfig.ConnectKey)
// get all attached android devices
hdcClient, err := ghdc.NewClientWith(option.HdcServerHost, option.HdcServerPort)
if err != nil {
return nil, errors.Wrap(code.DeviceConnectionError, err.Error())
return nil, err
}
devices, err := hdcClient.DeviceList()
if err != nil {
return nil, err
}
if len(devices) == 0 {
return nil, errors.Wrapf(code.DeviceConnectionError,
"no attached harmony devices")
}
if deviceConfig.ConnectKey == "" && len(deviceList) > 1 {
return nil, errors.Wrap(code.DeviceConnectionError, "more than one device connected, please specify the serial")
}
dev := deviceList[0]
// filter device by serial
var harmonyDevice *ghdc.Device
if deviceConfig.ConnectKey == "" {
selectSerial := dev.Serial()
deviceConfig.ConnectKey = selectSerial
log.Warn().
Str("connectKey", deviceConfig.ConnectKey).
Msg("harmony ConnectKey is not specified, select the first one")
if len(devices) > 1 {
return nil, errors.Wrap(code.DeviceConnectionError,
"more than one device connected, please specify the serial")
}
harmonyDevice = &devices[0]
deviceConfig.ConnectKey = harmonyDevice.Serial()
log.Warn().Str("serial", deviceConfig.ConnectKey).
Msg("harmony ConnectKey is not specified, select the attached one")
} else {
for _, d := range devices {
if d.Serial() == deviceConfig.ConnectKey {
harmonyDevice = &d
break
}
}
if harmonyDevice == nil {
return nil, errors.Wrapf(code.DeviceConnectionError,
"harmony device %s not attached", harmonyDevice.Serial())
}
}
device = &HarmonyDevice{
HarmonyDeviceOptions: deviceConfig,
Device: dev,
Device: harmonyDevice,
}
log.Info().Str("connectKey", device.ConnectKey).Msg("init harmony device")
return device, nil
}
func GetHarmonyDevices(serial ...string) (devices []*ghdc.Device, err error) {
var hdcClient ghdc.Client
if hdcClient, err = ghdc.NewClientWith(HdcServerHost, HdcServerPort); err != nil {
return nil, err
}
var deviceList []ghdc.Device
if deviceList, err = hdcClient.DeviceList(); err != nil {
return nil, err
}
// filter by serial
for _, d := range deviceList {
for _, s := range serial {
if s != "" && s != d.Serial() {
continue
}
devices = append(devices, &d)
}
}
if len(devices) == 0 {
var err error
if serial == nil || (len(serial) == 1 && serial[0] == "") {
err = fmt.Errorf("no harmony device found")
} else {
err = fmt.Errorf("no harmony device found for serial %v", serial)
}
return nil, err
}
return devices, nil
}
func (dev *HarmonyDevice) Setup() error {
return nil
}
@@ -106,7 +89,26 @@ func (dev *HarmonyDevice) Uninstall(packageName string) error {
return nil
}
func (dev *HarmonyDevice) GetPackageInfo(packageName string) (AppInfo, error) {
func (dev *HarmonyDevice) GetPackageInfo(packageName string) (types.AppInfo, error) {
log.Warn().Msg("get package info not implemented for harmony device, skip")
return AppInfo{}, nil
return types.AppInfo{}, nil
}
func (dev *HarmonyDevice) NewDriver() (IDriverExt, error) {
// init harmony driver
driver, err := NewHDCDriver(dev)
if err != nil {
return nil, errors.Wrap(err, "init harmony driver failed")
}
driverExt, err := NewDriverExt(driver, ai.WithCVService(ai.CVServiceTypeVEDEM))
if err != nil {
return nil, errors.Wrap(err, "init harmony driver ext failed")
}
// setup driver
if err := driverExt.GetDriver().Setup(); err != nil {
return nil, err
}
return driverExt, nil
}

View File

@@ -10,8 +10,9 @@ import (
"code.byted.org/iesqa/ghdc"
"github.com/rs/zerolog/log"
"github.com/httprunner/httprunner/v5/pkg/ai"
"github.com/httprunner/httprunner/v5/pkg/uixt/ai"
"github.com/httprunner/httprunner/v5/pkg/uixt/option"
"github.com/httprunner/httprunner/v5/pkg/uixt/types"
)
type HDCDriver struct {
@@ -58,31 +59,31 @@ func (hd *HDCDriver) GetSession() *Session {
return hd.Session
}
func (hd *HDCDriver) Status() (DeviceStatus, error) {
return DeviceStatus{}, errDriverNotImplemented
func (hd *HDCDriver) Status() (types.DeviceStatus, error) {
return types.DeviceStatus{}, errDriverNotImplemented
}
func (hd *HDCDriver) GetDevice() IDevice {
return hd.HarmonyDevice
}
func (hd *HDCDriver) DeviceInfo() (DeviceInfo, error) {
return DeviceInfo{}, errDriverNotImplemented
func (hd *HDCDriver) DeviceInfo() (types.DeviceInfo, error) {
return types.DeviceInfo{}, errDriverNotImplemented
}
func (hd *HDCDriver) Location() (Location, error) {
return Location{}, errDriverNotImplemented
func (hd *HDCDriver) Location() (types.Location, error) {
return types.Location{}, errDriverNotImplemented
}
func (hd *HDCDriver) BatteryInfo() (BatteryInfo, error) {
return BatteryInfo{}, errDriverNotImplemented
func (hd *HDCDriver) BatteryInfo() (types.BatteryInfo, error) {
return types.BatteryInfo{}, errDriverNotImplemented
}
func (hd *HDCDriver) WindowSize() (size ai.Size, err error) {
func (hd *HDCDriver) WindowSize() (size types.Size, err error) {
display, err := hd.uiDriver.GetDisplaySize()
if err != nil {
log.Error().Err(err).Msg("failed to get window size")
return ai.Size{}, err
return types.Size{}, err
}
size.Width = display.Width
size.Height = display.Height
@@ -137,9 +138,9 @@ func (hd *HDCDriver) AppTerminate(packageName string) (bool, error) {
return true, nil
}
func (hd *HDCDriver) GetForegroundApp() (app AppInfo, err error) {
func (hd *HDCDriver) GetForegroundApp() (app types.AppInfo, err error) {
// Todo
return AppInfo{}, errDriverNotImplemented
return types.AppInfo{}, errDriverNotImplemented
}
func (hd *HDCDriver) AssertForegroundApp(packageName string, activityType ...string) error {
@@ -155,8 +156,8 @@ func (hd *HDCDriver) StopCamera() error {
return errDriverNotImplemented
}
func (hd *HDCDriver) Orientation() (orientation Orientation, err error) {
return OrientationPortrait, nil
func (hd *HDCDriver) Orientation() (orientation types.Orientation, err error) {
return types.OrientationPortrait, nil
}
func (hd *HDCDriver) Tap(x, y float64, opts ...option.ActionOption) error {
@@ -213,11 +214,11 @@ func (hd *HDCDriver) Swipe(fromX, fromY, toX, toY float64, opts ...option.Action
return hd.uiDriver.InjectGesture(ghdc.NewGesture().Start(ghdc.Point{X: int(fromX), Y: int(fromY)}).MoveTo(ghdc.Point{X: int(toX), Y: int(toY)}, duration))
}
func (hd *HDCDriver) SetPasteboard(contentType PasteboardType, content string) error {
func (hd *HDCDriver) SetPasteboard(contentType types.PasteboardType, content string) error {
return errDriverNotImplemented
}
func (hd *HDCDriver) GetPasteboard(contentType PasteboardType) (raw *bytes.Buffer, err error) {
func (hd *HDCDriver) GetPasteboard(contentType types.PasteboardType) (raw *bytes.Buffer, err error) {
return nil, errDriverNotImplemented
}
@@ -237,7 +238,7 @@ func (hd *HDCDriver) Clear(packageName string) error {
return errDriverNotImplemented
}
func (hd *HDCDriver) PressButton(devBtn DeviceButton) error {
func (hd *HDCDriver) PressButton(devBtn types.DeviceButton) error {
return errDriverNotImplemented
}
@@ -343,12 +344,12 @@ func (hd *HDCDriver) TearDown() error {
return nil
}
func (hd *HDCDriver) Rotation() (rotation Rotation, err error) {
func (hd *HDCDriver) Rotation() (rotation types.Rotation, err error) {
err = errDriverNotImplemented
return
}
func (hd *HDCDriver) SetRotation(rotation Rotation) (err error) {
func (hd *HDCDriver) SetRotation(rotation types.Rotation) (err error) {
err = errDriverNotImplemented
return
}

View File

@@ -28,7 +28,9 @@ import (
"github.com/httprunner/httprunner/v5/code"
"github.com/httprunner/httprunner/v5/internal/builtin"
"github.com/httprunner/httprunner/v5/pkg/uixt/ai"
"github.com/httprunner/httprunner/v5/pkg/uixt/option"
"github.com/httprunner/httprunner/v5/pkg/uixt/types"
)
var tunnelManager *tunnel.TunnelManager = nil
@@ -207,10 +209,10 @@ func (dev *IOSDevice) LogEnabled() bool {
return dev.LogOn
}
func (dev *IOSDevice) getAppInfo(packageName string) (appInfo AppInfo, err error) {
func (dev *IOSDevice) getAppInfo(packageName string) (appInfo types.AppInfo, err error) {
apps, err := dev.ListApps(ApplicationTypeAny)
if err != nil {
return AppInfo{}, err
return types.AppInfo{}, err
}
for _, app := range apps {
if app.CFBundleIdentifier == packageName {
@@ -222,27 +224,18 @@ func (dev *IOSDevice) getAppInfo(packageName string) (appInfo AppInfo, err error
return appInfo, err
}
}
return AppInfo{}, fmt.Errorf("not found App by bundle id: %s", packageName)
return types.AppInfo{}, fmt.Errorf("not found App by bundle id: %s", packageName)
}
func (dev *IOSDevice) NewDriver(opts ...option.DriverOption) (driverExt *DriverExt, err error) {
options := option.NewDriverOptions()
// init WDA driver
capabilities := options.Capabilities
if capabilities == nil {
capabilities = option.NewCapabilities()
capabilities.WithDefaultAlertAction(option.AlertActionAccept)
}
func (dev *IOSDevice) NewDriver() (driverExt IDriverExt, err error) {
var driver IDriver
if dev.STUB {
driver, err = dev.NewStubDriver()
driver, err = NewStubIOSDriver(dev)
if err != nil {
return nil, errors.Wrap(err, "failed to init Stub driver")
}
} else {
driver, err = dev.NewHTTPDriver(capabilities)
driver, err := NewWDADriver(dev)
if err != nil {
return nil, errors.Wrap(err, "failed to init WDA driver")
}
@@ -264,12 +257,7 @@ func (dev *IOSDevice) NewDriver(opts ...option.DriverOption) (driverExt *DriverE
}
}
driverExt, err = newDriverExt(dev, driver, opts...)
if err != nil {
return nil, err
}
settings, err := driverExt.Driver.SetAppiumSettings(map[string]interface{}{
settings, err := driver.SetAppiumSettings(map[string]interface{}{
"snapshotMaxDepth": dev.SnapshotMaxDepth,
"acceptAlertButtonSelector": dev.AcceptAlertButtonSelector,
})
@@ -279,12 +267,22 @@ func (dev *IOSDevice) NewDriver(opts ...option.DriverOption) (driverExt *DriverE
log.Info().Interface("appiumWDASettings", settings).Msg("set appium WDA settings")
if dev.LogOn {
err = driverExt.Driver.StartCaptureLog("hrp_wda_log")
err = driver.StartCaptureLog("hrp_wda_log")
if err != nil {
return nil, err
}
}
driverExt, err = NewDriverExt(driver, ai.WithCVService(ai.CVServiceTypeVEDEM))
if err != nil {
return nil, errors.Wrap(err, "init ios driver ext failed")
}
// setup driver
if err := driverExt.GetDriver().Setup(); err != nil {
return nil, err
}
return driverExt, nil
}
@@ -587,52 +585,16 @@ func (dev *IOSDevice) NewHTTPDriver(capabilities option.Capabilities) (driver ID
return wd, nil
}
const (
defaultBightInsightPort = 8000
defaultDouyinServerPort = 32921
)
func (dev *IOSDevice) NewStubDriver() (driver IDriver, err error) {
localStubPort, err := builtin.GetFreePort()
if err != nil {
return nil, errors.Wrap(code.DeviceHTTPDriverError,
fmt.Sprintf("get free port failed: %v", err))
}
if err = dev.forward(localStubPort, defaultBightInsightPort); err != nil {
return nil, errors.Wrap(code.DeviceHTTPDriverError,
fmt.Sprintf("forward tcp port failed: %v", err))
}
localServerPort, err := builtin.GetFreePort()
if err != nil {
return nil, errors.Wrap(code.DeviceHTTPDriverError,
fmt.Sprintf("get free port failed: %v", err))
}
if err = dev.forward(localServerPort, defaultDouyinServerPort); err != nil {
return nil, errors.Wrap(code.DeviceHTTPDriverError,
fmt.Sprintf("forward tcp port failed: %v", err))
}
host := "localhost"
stubDriver, err := newStubIOSDriver(
fmt.Sprintf("http://%s:%d", host, localStubPort),
fmt.Sprintf("http://%s:%d", host, localServerPort), dev)
if err != nil {
return nil, err
}
return stubDriver, nil
}
func (dev *IOSDevice) GetPackageInfo(packageName string) (AppInfo, error) {
func (dev *IOSDevice) GetPackageInfo(packageName string) (types.AppInfo, error) {
svc, err := installationproxy.New(dev.d)
if err != nil {
return AppInfo{}, errors.Wrap(code.DeviceGetInfoError, err.Error())
return types.AppInfo{}, errors.Wrap(code.DeviceGetInfoError, err.Error())
}
defer svc.Close()
apps, err := svc.BrowseAllApps()
if err != nil {
return AppInfo{}, errors.Wrap(code.DeviceGetInfoError, err.Error())
return types.AppInfo{}, errors.Wrap(code.DeviceGetInfoError, err.Error())
}
for _, app := range apps {
@@ -640,9 +602,9 @@ func (dev *IOSDevice) GetPackageInfo(packageName string) (AppInfo, error) {
continue
}
appInfo := AppInfo{
appInfo := types.AppInfo{
Name: app.CFBundleName,
AppBaseInfo: AppBaseInfo{
AppBaseInfo: types.AppBaseInfo{
BundleId: app.CFBundleIdentifier,
PackageName: app.CFBundleIdentifier,
VersionName: app.CFBundleShortVersionString,
@@ -654,6 +616,6 @@ func (dev *IOSDevice) GetPackageInfo(packageName string) (AppInfo, error) {
log.Info().Interface("appInfo", appInfo).Msg("get package info")
return appInfo, nil
}
return AppInfo{}, errors.Wrap(code.DeviceAppNotInstalled,
return types.AppInfo{}, errors.Wrap(code.DeviceAppNotInstalled,
fmt.Sprintf("%s not found", packageName))
}

View File

@@ -7,13 +7,58 @@ import (
"net/http"
"time"
"github.com/pkg/errors"
"github.com/rs/zerolog/log"
"github.com/httprunner/httprunner/v5/pkg/ai"
"github.com/httprunner/httprunner/v5/code"
"github.com/httprunner/httprunner/v5/internal/builtin"
"github.com/httprunner/httprunner/v5/pkg/uixt/ai"
"github.com/httprunner/httprunner/v5/pkg/uixt/option"
"github.com/httprunner/httprunner/v5/pkg/uixt/types"
)
type stubIOSDriver struct {
const (
defaultBightInsightPort = 8000
defaultDouyinServerPort = 32921
)
func NewStubIOSDriver(device *IOSDevice) (driver *StubIOSDriver, err error) {
localStubPort, err := builtin.GetFreePort()
if err != nil {
return nil, errors.Wrap(code.DeviceHTTPDriverError,
fmt.Sprintf("get free port failed: %v", err))
}
if err = device.forward(localStubPort, defaultBightInsightPort); err != nil {
return nil, errors.Wrap(code.DeviceHTTPDriverError,
fmt.Sprintf("forward tcp port failed: %v", err))
}
localServerPort, err := builtin.GetFreePort()
if err != nil {
return nil, errors.Wrap(code.DeviceHTTPDriverError,
fmt.Sprintf("get free port failed: %v", err))
}
if err = device.forward(localServerPort, defaultDouyinServerPort); err != nil {
return nil, errors.Wrap(code.DeviceHTTPDriverError,
fmt.Sprintf("forward tcp port failed: %v", err))
}
host := "localhost"
timeout := 10 * time.Second
driver = &StubIOSDriver{}
driver.device = device
driver.bightInsightPrefix = fmt.Sprintf("http://%s:%d", host, localStubPort)
driver.serverPrefix = fmt.Sprintf("http://%s:%d", host, localServerPort)
driver.timeout = timeout
driver.client = &http.Client{
Timeout: time.Second * 10, // 设置超时时间为 10 秒
}
return driver, nil
}
type StubIOSDriver struct {
*WDADriver
bightInsightPrefix string
@@ -22,23 +67,7 @@ type stubIOSDriver struct {
device *IOSDevice
}
func newStubIOSDriver(bightInsightAddr, serverAddr string, dev *IOSDevice, readTimeout ...time.Duration) (*stubIOSDriver, error) {
timeout := 10 * time.Second
if len(readTimeout) > 0 {
timeout = readTimeout[0]
}
driver := new(stubIOSDriver)
driver.device = dev
driver.bightInsightPrefix = bightInsightAddr
driver.serverPrefix = serverAddr
driver.timeout = timeout
driver.client = &http.Client{
Timeout: time.Second * 10, // 设置超时时间为 10 秒
}
return driver, nil
}
func (s *stubIOSDriver) setUpWda() (err error) {
func (s *StubIOSDriver) setUpWda() (err error) {
if s.WDADriver == nil {
capabilities := option.NewCapabilities()
capabilities.WithDefaultAlertAction(option.AlertActionAccept)
@@ -53,7 +82,7 @@ func (s *stubIOSDriver) setUpWda() (err error) {
}
// NewSession starts a new session and returns the DriverSession.
func (s *stubIOSDriver) NewSession(capabilities option.Capabilities) (Session, error) {
func (s *StubIOSDriver) NewSession(capabilities option.Capabilities) (Session, error) {
err := s.setUpWda()
if err != nil {
return Session{}, err
@@ -64,7 +93,7 @@ func (s *stubIOSDriver) NewSession(capabilities option.Capabilities) (Session, e
// DeleteSession Kills application associated with that session and removes session
// 1. alertsMonitor disable
// 2. testedApplicationBundleId terminate
func (s *stubIOSDriver) DeleteSession() error {
func (s *StubIOSDriver) DeleteSession() error {
err := s.setUpWda()
if err != nil {
return err
@@ -72,34 +101,34 @@ func (s *stubIOSDriver) DeleteSession() error {
return s.WDADriver.DeleteSession()
}
func (s *stubIOSDriver) Status() (DeviceStatus, error) {
func (s *StubIOSDriver) Status() (types.DeviceStatus, error) {
err := s.setUpWda()
if err != nil {
return DeviceStatus{}, err
return types.DeviceStatus{}, err
}
return s.WDADriver.Status()
}
func (s *stubIOSDriver) DeviceInfo() (DeviceInfo, error) {
func (s *StubIOSDriver) DeviceInfo() (types.DeviceInfo, error) {
err := s.setUpWda()
if err != nil {
return DeviceInfo{}, err
return types.DeviceInfo{}, err
}
return s.WDADriver.DeviceInfo()
}
func (s *stubIOSDriver) Location() (Location, error) {
func (s *StubIOSDriver) Location() (types.Location, error) {
err := s.setUpWda()
if err != nil {
return Location{}, err
return types.Location{}, err
}
return s.WDADriver.Location()
}
func (s *stubIOSDriver) BatteryInfo() (BatteryInfo, error) {
func (s *StubIOSDriver) BatteryInfo() (types.BatteryInfo, error) {
err := s.setUpWda()
if err != nil {
return BatteryInfo{}, err
return types.BatteryInfo{}, err
}
return s.WDADriver.BatteryInfo()
}
@@ -107,15 +136,15 @@ func (s *stubIOSDriver) BatteryInfo() (BatteryInfo, error) {
// WindowSize Return the width and height in portrait mode.
// when getting the window size in wda/ui2/adb, if the device is in landscape mode,
// the width and height will be reversed.
func (s *stubIOSDriver) WindowSize() (ai.Size, error) {
func (s *StubIOSDriver) WindowSize() (types.Size, error) {
err := s.setUpWda()
if err != nil {
return ai.Size{}, err
return types.Size{}, err
}
return s.WDADriver.WindowSize()
}
func (s *stubIOSDriver) Screen() (ai.Screen, error) {
func (s *StubIOSDriver) Screen() (ai.Screen, error) {
err := s.setUpWda()
if err != nil {
return ai.Screen{}, err
@@ -123,7 +152,7 @@ func (s *stubIOSDriver) Screen() (ai.Screen, error) {
return s.WDADriver.Screen()
}
func (s *stubIOSDriver) Scale() (float64, error) {
func (s *StubIOSDriver) Scale() (float64, error) {
err := s.setUpWda()
if err != nil {
return 0, err
@@ -132,7 +161,7 @@ func (s *stubIOSDriver) Scale() (float64, error) {
}
// Homescreen Forces the device under test to switch to the home screen
func (s *stubIOSDriver) Homescreen() error {
func (s *StubIOSDriver) Homescreen() error {
err := s.setUpWda()
if err != nil {
return err
@@ -140,7 +169,7 @@ func (s *stubIOSDriver) Homescreen() error {
return s.WDADriver.Homescreen()
}
func (s *stubIOSDriver) Unlock() (err error) {
func (s *StubIOSDriver) Unlock() (err error) {
err = s.setUpWda()
if err != nil {
return err
@@ -150,7 +179,7 @@ func (s *stubIOSDriver) Unlock() (err error) {
// AppLaunch Launch an application with given bundle identifier in scope of current session.
// !This method is only available since Xcode9 SDK
func (s *stubIOSDriver) AppLaunch(packageName string) error {
func (s *StubIOSDriver) AppLaunch(packageName string) error {
err := s.setUpWda()
if err != nil {
return err
@@ -160,7 +189,7 @@ func (s *stubIOSDriver) AppLaunch(packageName string) error {
// AppTerminate Terminate an application with the given package name.
// Either `true` if the app has been successfully terminated or `false` if it was not running
func (s *stubIOSDriver) AppTerminate(packageName string) (bool, error) {
func (s *StubIOSDriver) AppTerminate(packageName string) (bool, error) {
err := s.setUpWda()
if err != nil {
return false, err
@@ -169,16 +198,16 @@ func (s *stubIOSDriver) AppTerminate(packageName string) (bool, error) {
}
// GetForegroundApp returns current foreground app package name and activity name
func (s *stubIOSDriver) GetForegroundApp() (app AppInfo, err error) {
func (s *StubIOSDriver) GetForegroundApp() (app types.AppInfo, err error) {
err = s.setUpWda()
if err != nil {
return AppInfo{}, err
return types.AppInfo{}, err
}
return s.WDADriver.GetForegroundApp()
}
// StartCamera Starts a new camera for recording
func (s *stubIOSDriver) StartCamera() error {
func (s *StubIOSDriver) StartCamera() error {
err := s.setUpWda()
if err != nil {
return err
@@ -187,7 +216,7 @@ func (s *stubIOSDriver) StartCamera() error {
}
// StopCamera Stops the camera for recording
func (s *stubIOSDriver) StopCamera() error {
func (s *StubIOSDriver) StopCamera() error {
err := s.setUpWda()
if err != nil {
return err
@@ -195,16 +224,16 @@ func (s *stubIOSDriver) StopCamera() error {
return s.WDADriver.StopCamera()
}
func (s *stubIOSDriver) Orientation() (orientation Orientation, err error) {
func (s *StubIOSDriver) Orientation() (orientation types.Orientation, err error) {
err = s.setUpWda()
if err != nil {
return OrientationPortrait, err
return types.OrientationPortrait, err
}
return s.WDADriver.Orientation()
}
// Tap Sends a tap event at the coordinate.
func (s *stubIOSDriver) Tap(x, y float64, opts ...option.ActionOption) error {
func (s *StubIOSDriver) Tap(x, y float64, opts ...option.ActionOption) error {
err := s.setUpWda()
if err != nil {
return err
@@ -213,7 +242,7 @@ func (s *stubIOSDriver) Tap(x, y float64, opts ...option.ActionOption) error {
}
// DoubleTap Sends a double tap event at the coordinate.
func (s *stubIOSDriver) DoubleTap(x, y float64, opts ...option.ActionOption) error {
func (s *StubIOSDriver) DoubleTap(x, y float64, opts ...option.ActionOption) error {
err := s.setUpWda()
if err != nil {
return err
@@ -224,7 +253,7 @@ func (s *stubIOSDriver) DoubleTap(x, y float64, opts ...option.ActionOption) err
// TouchAndHold Initiates a long-press gesture at the coordinate, holding for the specified duration.
//
// second: The default value is 1
func (s *stubIOSDriver) TouchAndHold(x, y float64, opts ...option.ActionOption) error {
func (s *StubIOSDriver) TouchAndHold(x, y float64, opts ...option.ActionOption) error {
err := s.setUpWda()
if err != nil {
return err
@@ -234,7 +263,7 @@ func (s *stubIOSDriver) TouchAndHold(x, y float64, opts ...option.ActionOption)
// Drag Initiates a press-and-hold gesture at the coordinate, then drags to another coordinate.
// WithPressDurationOption option can be used to set pressForDuration (default to 1 second).
func (s *stubIOSDriver) Drag(fromX, fromY, toX, toY float64, opts ...option.ActionOption) error {
func (s *StubIOSDriver) Drag(fromX, fromY, toX, toY float64, opts ...option.ActionOption) error {
err := s.setUpWda()
if err != nil {
return err
@@ -243,7 +272,7 @@ func (s *stubIOSDriver) Drag(fromX, fromY, toX, toY float64, opts ...option.Acti
}
// SetPasteboard Sets data to the general pasteboard
func (s *stubIOSDriver) SetPasteboard(contentType PasteboardType, content string) error {
func (s *StubIOSDriver) SetPasteboard(contentType types.PasteboardType, content string) error {
err := s.setUpWda()
if err != nil {
return err
@@ -254,7 +283,7 @@ func (s *stubIOSDriver) SetPasteboard(contentType PasteboardType, content string
// GetPasteboard Gets the data contained in the general pasteboard.
//
// It worked when `WDA` was foreground. https://github.com/appium/WebDriverAgent/issues/330
func (s *stubIOSDriver) GetPasteboard(contentType PasteboardType) (raw *bytes.Buffer, err error) {
func (s *StubIOSDriver) GetPasteboard(contentType types.PasteboardType) (raw *bytes.Buffer, err error) {
err = s.setUpWda()
if err != nil {
return nil, err
@@ -262,7 +291,7 @@ func (s *stubIOSDriver) GetPasteboard(contentType PasteboardType) (raw *bytes.Bu
return s.WDADriver.GetPasteboard(contentType)
}
func (s *stubIOSDriver) SetIme(ime string) error {
func (s *StubIOSDriver) SetIme(ime string) error {
err := s.setUpWda()
if err != nil {
return err
@@ -273,7 +302,7 @@ func (s *stubIOSDriver) SetIme(ime string) error {
// SendKeys Types a string into active element. There must be element with keyboard focus,
// otherwise an error is raised.
// WithFrequency option can be used to set frequency of typing (letters per sec). The default value is 60
func (s *stubIOSDriver) SendKeys(text string, opts ...option.ActionOption) error {
func (s *StubIOSDriver) SendKeys(text string, opts ...option.ActionOption) error {
err := s.setUpWda()
if err != nil {
return err
@@ -282,7 +311,7 @@ func (s *stubIOSDriver) SendKeys(text string, opts ...option.ActionOption) error
}
// Input works like SendKeys
func (s *stubIOSDriver) Input(text string, opts ...option.ActionOption) error {
func (s *StubIOSDriver) Input(text string, opts ...option.ActionOption) error {
err := s.setUpWda()
if err != nil {
return err
@@ -290,7 +319,7 @@ func (s *stubIOSDriver) Input(text string, opts ...option.ActionOption) error {
return s.WDADriver.Input(text, opts...)
}
func (s *stubIOSDriver) Clear(packageName string) error {
func (s *StubIOSDriver) Clear(packageName string) error {
err := s.setUpWda()
if err != nil {
return err
@@ -299,7 +328,7 @@ func (s *stubIOSDriver) Clear(packageName string) error {
}
// PressButton Presses the corresponding hardware button on the device
func (s *stubIOSDriver) PressButton(devBtn DeviceButton) error {
func (s *StubIOSDriver) PressButton(devBtn types.DeviceButton) error {
err := s.setUpWda()
if err != nil {
return err
@@ -308,7 +337,7 @@ func (s *stubIOSDriver) PressButton(devBtn DeviceButton) error {
}
// PressBack Presses the back button
func (s *stubIOSDriver) PressBack(opts ...option.ActionOption) error {
func (s *StubIOSDriver) PressBack(opts ...option.ActionOption) error {
err := s.setUpWda()
if err != nil {
return err
@@ -316,7 +345,7 @@ func (s *stubIOSDriver) PressBack(opts ...option.ActionOption) error {
return s.WDADriver.PressBack(opts...)
}
func (s *stubIOSDriver) PressKeyCode(keyCode KeyCode) (err error) {
func (s *StubIOSDriver) PressKeyCode(keyCode KeyCode) (err error) {
err = s.setUpWda()
if err != nil {
return err
@@ -324,7 +353,7 @@ func (s *stubIOSDriver) PressKeyCode(keyCode KeyCode) (err error) {
return s.WDADriver.PressKeyCode(keyCode)
}
func (s *stubIOSDriver) Screenshot() (*bytes.Buffer, error) {
func (s *StubIOSDriver) Screenshot() (*bytes.Buffer, error) {
err := s.setUpWda()
if err != nil {
return nil, err
@@ -345,7 +374,7 @@ func (s *stubIOSDriver) Screenshot() (*bytes.Buffer, error) {
//return bytes.NewBuffer(imageBytes), nil
}
func (s *stubIOSDriver) TapByText(text string, opts ...option.ActionOption) error {
func (s *StubIOSDriver) TapByText(text string, opts ...option.ActionOption) error {
err := s.setUpWda()
if err != nil {
return err
@@ -353,7 +382,7 @@ func (s *stubIOSDriver) TapByText(text string, opts ...option.ActionOption) erro
return s.WDADriver.TapByText(text, opts...)
}
func (s *stubIOSDriver) TapByTexts(actions ...TapTextAction) error {
func (s *StubIOSDriver) TapByTexts(actions ...TapTextAction) error {
err := s.setUpWda()
if err != nil {
return err
@@ -362,7 +391,7 @@ func (s *stubIOSDriver) TapByTexts(actions ...TapTextAction) error {
}
// AccessibleSource Return application elements accessibility tree
func (s *stubIOSDriver) AccessibleSource() (string, error) {
func (s *StubIOSDriver) AccessibleSource() (string, error) {
err := s.setUpWda()
if err != nil {
return "", err
@@ -375,7 +404,7 @@ func (s *stubIOSDriver) AccessibleSource() (string, error) {
// Checks health of XCTest by:
// 1) Querying application for some elements,
// 2) Triggering some device events.
func (s *stubIOSDriver) HealthCheck() error {
func (s *StubIOSDriver) HealthCheck() error {
err := s.setUpWda()
if err != nil {
return err
@@ -383,7 +412,7 @@ func (s *stubIOSDriver) HealthCheck() error {
return s.WDADriver.HealthCheck()
}
func (s *stubIOSDriver) GetAppiumSettings() (map[string]interface{}, error) {
func (s *StubIOSDriver) GetAppiumSettings() (map[string]interface{}, error) {
err := s.setUpWda()
if err != nil {
return nil, err
@@ -391,7 +420,7 @@ func (s *stubIOSDriver) GetAppiumSettings() (map[string]interface{}, error) {
return s.WDADriver.GetAppiumSettings()
}
func (s *stubIOSDriver) SetAppiumSettings(settings map[string]interface{}) (map[string]interface{}, error) {
func (s *StubIOSDriver) SetAppiumSettings(settings map[string]interface{}) (map[string]interface{}, error) {
err := s.setUpWda()
if err != nil {
return nil, err
@@ -399,7 +428,7 @@ func (s *stubIOSDriver) SetAppiumSettings(settings map[string]interface{}) (map[
return s.WDADriver.SetAppiumSettings(settings)
}
func (s *stubIOSDriver) IsHealthy() (bool, error) {
func (s *StubIOSDriver) IsHealthy() (bool, error) {
err := s.setUpWda()
if err != nil {
return false, err
@@ -408,7 +437,7 @@ func (s *stubIOSDriver) IsHealthy() (bool, error) {
}
// triggers the log capture and returns the log entries
func (s *stubIOSDriver) StartCaptureLog(identifier ...string) (err error) {
func (s *StubIOSDriver) StartCaptureLog(identifier ...string) (err error) {
err = s.setUpWda()
if err != nil {
return err
@@ -416,7 +445,7 @@ func (s *stubIOSDriver) StartCaptureLog(identifier ...string) (err error) {
return s.WDADriver.StartCaptureLog(identifier...)
}
func (s *stubIOSDriver) StopCaptureLog() (result interface{}, err error) {
func (s *StubIOSDriver) StopCaptureLog() (result interface{}, err error) {
err = s.setUpWda()
if err != nil {
return nil, err
@@ -424,7 +453,7 @@ func (s *stubIOSDriver) StopCaptureLog() (result interface{}, err error) {
return s.WDADriver.StopCaptureLog()
}
func (s *stubIOSDriver) GetDriverResults() []*DriverRequests {
func (s *StubIOSDriver) GetDriverResults() []*DriverRequests {
err := s.setUpWda()
if err != nil {
return nil
@@ -432,7 +461,7 @@ func (s *stubIOSDriver) GetDriverResults() []*DriverRequests {
return s.WDADriver.GetDriverResults()
}
func (s *stubIOSDriver) Source(srcOpt ...option.SourceOption) (string, error) {
func (s *StubIOSDriver) Source(srcOpt ...option.SourceOption) (string, error) {
resp, err := s.Request(http.MethodGet, fmt.Sprintf("%s/source?format=json&onlyWeb=false", s.bightInsightPrefix), []byte{})
if err != nil {
return "", err
@@ -440,7 +469,7 @@ func (s *stubIOSDriver) Source(srcOpt ...option.SourceOption) (string, error) {
return string(resp), nil
}
func (s *stubIOSDriver) LoginNoneUI(packageName, phoneNumber string, captcha, password string) (info AppLoginInfo, err error) {
func (s *StubIOSDriver) LoginNoneUI(packageName, phoneNumber string, captcha, password string) (info AppLoginInfo, err error) {
params := map[string]interface{}{
"phone": phoneNumber,
}
@@ -478,7 +507,7 @@ func (s *stubIOSDriver) LoginNoneUI(packageName, phoneNumber string, captcha, pa
return info, nil
}
func (s *stubIOSDriver) LogoutNoneUI(packageName string) error {
func (s *StubIOSDriver) LogoutNoneUI(packageName string) error {
resp, err := s.Request(http.MethodGet, fmt.Sprintf("%s/host/loginout/", s.serverPrefix), []byte{})
if err != nil {
return err
@@ -497,12 +526,12 @@ func (s *stubIOSDriver) LogoutNoneUI(packageName string) error {
return nil
}
func (s *stubIOSDriver) TearDown() error {
func (s *StubIOSDriver) TearDown() error {
s.client.CloseIdleConnections()
return nil
}
func (s *stubIOSDriver) getLoginAppInfo(packageName string) (info AppLoginInfo, err error) {
func (s *StubIOSDriver) getLoginAppInfo(packageName string) (info AppLoginInfo, err error) {
resp, err := s.Request(http.MethodGet, fmt.Sprintf("%s/host/app/info/", s.serverPrefix), []byte{})
if err != nil {
return info, err
@@ -524,6 +553,6 @@ func (s *stubIOSDriver) getLoginAppInfo(packageName string) (info AppLoginInfo,
return info, nil
}
func (s *stubIOSDriver) GetSession() *Session {
func (s *StubIOSDriver) GetSession() *Session {
return s.Session
}

View File

@@ -11,7 +11,7 @@ import (
)
var (
iOSStubDriver IDriver
iOSStubDriver IDriverExt
iOSDevice *IOSDevice
)
@@ -22,56 +22,56 @@ func setupiOSStubDriver(t *testing.T) {
option.WithWDAMjpegPort(8800),
option.WithIOSStub(false))
checkErr(t, err)
iOSStubDriver, err = iOSDevice.NewStubDriver()
iOSStubDriver, err = iOSDevice.NewDriver()
checkErr(t, err)
}
func TestIOSLogin(t *testing.T) {
setupiOSStubDriver(t)
info, err := iOSStubDriver.LoginNoneUI("", "12342316231", "8517", "")
info, err := iOSStubDriver.GetDriver().LoginNoneUI("", "12342316231", "8517", "")
checkErr(t, err)
t.Log(info)
}
func TestIOSLogout(t *testing.T) {
setupiOSStubDriver(t)
err := iOSStubDriver.LogoutNoneUI("")
err := iOSStubDriver.GetDriver().LogoutNoneUI("")
checkErr(t, err)
}
func TestIOSIsLogin(t *testing.T) {
setupiOSStubDriver(t)
err := iOSStubDriver.LogoutNoneUI("")
err := iOSStubDriver.GetDriver().LogoutNoneUI("")
checkErr(t, err)
}
func TestIOSSource(t *testing.T) {
setupiOSStubDriver(t)
source, err := iOSStubDriver.Source()
source, err := iOSStubDriver.GetDriver().Source()
checkErr(t, err)
t.Log(source)
}
func TestIOSForeground(t *testing.T) {
setupiOSStubDriver(t)
app, err := iOSStubDriver.GetForegroundApp()
app, err := iOSStubDriver.GetDriver().GetForegroundApp()
checkErr(t, err)
t.Log(app)
}
func TestIOSSwipe(t *testing.T) {
setupiOSStubDriver(t)
iOSStubDriver.Swipe(540, 0, 540, 1000)
iOSStubDriver.GetDriver().Swipe(540, 0, 540, 1000)
}
func TestIOSSave(t *testing.T) {
setupiOSStubDriver(t)
raw, err := iOSStubDriver.Screenshot()
raw, err := iOSStubDriver.GetDriver().Screenshot()
if err != nil {
t.Fatal(err)
}
source, err := iOSStubDriver.Source()
source, err := iOSStubDriver.GetDriver().Source()
if err != nil {
t.Fatal(err)
}

View File

@@ -23,8 +23,9 @@ import (
"github.com/httprunner/httprunner/v5/code"
"github.com/httprunner/httprunner/v5/internal/builtin"
"github.com/httprunner/httprunner/v5/internal/json"
"github.com/httprunner/httprunner/v5/pkg/ai"
"github.com/httprunner/httprunner/v5/pkg/uixt/ai"
"github.com/httprunner/httprunner/v5/pkg/uixt/option"
"github.com/httprunner/httprunner/v5/pkg/uixt/types"
)
func NewWDADriver(device *IOSDevice) (*WDADriver, error) {
@@ -161,16 +162,16 @@ func (wd *WDADriver) DeleteSession() (err error) {
return
}
func (wd *WDADriver) Status() (deviceStatus DeviceStatus, err error) {
func (wd *WDADriver) Status() (deviceStatus types.DeviceStatus, err error) {
// [[FBRoute GET:@"/status"].withoutSession respondWithTarget:self action:@selector(handleGetStatus:)]
var rawResp rawResponse
// Notice: use Driver.GET instead of httpGET to avoid loop calling
if rawResp, err = wd.GET("/status"); err != nil {
return DeviceStatus{}, err
return types.DeviceStatus{}, err
}
reply := new(struct{ Value struct{ DeviceStatus } })
reply := new(struct{ Value struct{ types.DeviceStatus } })
if err = json.Unmarshal(rawResp, reply); err != nil {
return DeviceStatus{}, err
return types.DeviceStatus{}, err
}
deviceStatus = reply.Value.DeviceStatus
return
@@ -180,51 +181,51 @@ func (wd *WDADriver) GetDevice() IDevice {
return wd.IOSDevice
}
func (wd *WDADriver) DeviceInfo() (deviceInfo DeviceInfo, err error) {
func (wd *WDADriver) DeviceInfo() (deviceInfo types.DeviceInfo, err error) {
// [[FBRoute GET:@"/wda/device/info"] respondWithTarget:self action:@selector(handleGetDeviceInfo:)]
// [[FBRoute GET:@"/wda/device/info"].withoutSession
var rawResp rawResponse
if rawResp, err = wd.httpGET("/session", wd.sessionID, "/wda/device/info"); err != nil {
return DeviceInfo{}, err
return types.DeviceInfo{}, err
}
reply := new(struct{ Value struct{ DeviceInfo } })
reply := new(struct{ Value struct{ types.DeviceInfo } })
if err = json.Unmarshal(rawResp, reply); err != nil {
return DeviceInfo{}, err
return types.DeviceInfo{}, err
}
deviceInfo = reply.Value.DeviceInfo
return
}
func (wd *WDADriver) Location() (location Location, err error) {
func (wd *WDADriver) Location() (location types.Location, err error) {
// [[FBRoute GET:@"/wda/device/location"] respondWithTarget:self action:@selector(handleGetLocation:)]
// [[FBRoute GET:@"/wda/device/location"].withoutSession
var rawResp rawResponse
if rawResp, err = wd.httpGET("/session", wd.sessionID, "/wda/device/location"); err != nil {
return Location{}, err
return types.Location{}, err
}
reply := new(struct{ Value struct{ Location } })
reply := new(struct{ Value struct{ types.Location } })
if err = json.Unmarshal(rawResp, reply); err != nil {
return Location{}, err
return types.Location{}, err
}
location = reply.Value.Location
return
}
func (wd *WDADriver) BatteryInfo() (batteryInfo BatteryInfo, err error) {
func (wd *WDADriver) BatteryInfo() (batteryInfo types.BatteryInfo, err error) {
// [[FBRoute GET:@"/wda/batteryInfo"] respondWithTarget:self action:@selector(handleGetBatteryInfo:)]
var rawResp rawResponse
if rawResp, err = wd.httpGET("/session", wd.sessionID, "/wda/batteryInfo"); err != nil {
return BatteryInfo{}, err
return types.BatteryInfo{}, err
}
reply := new(struct{ Value struct{ BatteryInfo } })
reply := new(struct{ Value struct{ types.BatteryInfo } })
if err = json.Unmarshal(rawResp, reply); err != nil {
return BatteryInfo{}, err
return types.BatteryInfo{}, err
}
batteryInfo = reply.Value.BatteryInfo
return
}
func (wd *WDADriver) WindowSize() (size ai.Size, err error) {
func (wd *WDADriver) WindowSize() (size types.Size, err error) {
// [[FBRoute GET:@"/window/size"] respondWithTarget:self action:@selector(handleGetWindowSize:)]
if !wd.windowSize.IsNil() {
// use cached window size
@@ -233,16 +234,16 @@ func (wd *WDADriver) WindowSize() (size ai.Size, err error) {
var rawResp rawResponse
if rawResp, err = wd.httpGET("/session", wd.sessionID, "/window/size"); err != nil {
return ai.Size{}, errors.Wrap(err, "get window size failed by WDA request")
return types.Size{}, errors.Wrap(err, "get window size failed by WDA request")
}
reply := new(struct{ Value struct{ ai.Size } })
reply := new(struct{ Value struct{ types.Size } })
if err = json.Unmarshal(rawResp, reply); err != nil {
return ai.Size{}, errors.Wrap(err, "get window size failed by WDA response")
return types.Size{}, errors.Wrap(err, "get window size failed by WDA response")
}
size = reply.Value.Size
scale, err := wd.Scale()
if err != nil {
return ai.Size{}, errors.Wrap(err, "get window size scale failed")
return types.Size{}, errors.Wrap(err, "get window size scale failed")
}
size.Height = size.Height * int(scale)
size.Width = size.Width * int(scale)
@@ -281,28 +282,28 @@ func (wd *WDADriver) toScale(x float64) float64 {
return x / wd.scale
}
func (wd *WDADriver) ActiveAppInfo() (info AppInfo, err error) {
func (wd *WDADriver) ActiveAppInfo() (info types.AppInfo, err error) {
// [[FBRoute GET:@"/wda/activeAppInfo"] respondWithTarget:self action:@selector(handleActiveAppInfo:)]
// [[FBRoute GET:@"/wda/activeAppInfo"].withoutSession
var rawResp rawResponse
if rawResp, err = wd.httpGET("/session", wd.sessionID, "/wda/activeAppInfo"); err != nil {
return AppInfo{}, err
return types.AppInfo{}, err
}
reply := new(struct{ Value struct{ AppInfo } })
reply := new(struct{ Value struct{ types.AppInfo } })
if err = json.Unmarshal(rawResp, reply); err != nil {
return AppInfo{}, err
return types.AppInfo{}, err
}
info = reply.Value.AppInfo
return
}
func (wd *WDADriver) ActiveAppsList() (appsList []AppBaseInfo, err error) {
func (wd *WDADriver) ActiveAppsList() (appsList []types.AppBaseInfo, err error) {
// [[FBRoute GET:@"/wda/apps/list"] respondWithTarget:self action:@selector(handleGetActiveAppsList:)]
var rawResp rawResponse
if rawResp, err = wd.httpGET("/session", wd.sessionID, "/wda/apps/list"); err != nil {
return nil, err
}
reply := new(struct{ Value []AppBaseInfo })
reply := new(struct{ Value []types.AppBaseInfo })
if err = json.Unmarshal(rawResp, reply); err != nil {
return nil, err
}
@@ -310,14 +311,14 @@ func (wd *WDADriver) ActiveAppsList() (appsList []AppBaseInfo, err error) {
return
}
func (wd *WDADriver) AppState(bundleId string) (runState AppState, err error) {
func (wd *WDADriver) AppState(bundleId string) (runState types.AppState, err error) {
// [[FBRoute POST:@"/wda/apps/state"] respondWithTarget:self action:@selector(handleSessionAppState:)]
data := map[string]interface{}{"bundleId": bundleId}
var rawResp rawResponse
if rawResp, err = wd.httpPOST(data, "/session", wd.sessionID, "/wda/apps/state"); err != nil {
return 0, err
}
reply := new(struct{ Value AppState })
reply := new(struct{ Value types.AppState })
if err = json.Unmarshal(rawResp, reply); err != nil {
return 0, err
}
@@ -471,7 +472,7 @@ func (wd *WDADriver) AppDeactivate(second float64) (err error) {
return
}
func (wd *WDADriver) GetForegroundApp() (appInfo AppInfo, err error) {
func (wd *WDADriver) GetForegroundApp() (appInfo types.AppInfo, err error) {
activeAppInfo, err := wd.ActiveAppInfo()
appInfo.BundleId = activeAppInfo.BundleId
if err != nil {
@@ -611,7 +612,7 @@ func (wd *WDADriver) Swipe(fromX, fromY, toX, toY float64, opts ...option.Action
return wd.Drag(fromX, fromY, toX, toY, opts...)
}
func (wd *WDADriver) SetPasteboard(contentType PasteboardType, content string) (err error) {
func (wd *WDADriver) SetPasteboard(contentType types.PasteboardType, content string) (err error) {
// [[FBRoute POST:@"/wda/setPasteboard"] respondWithTarget:self action:@selector(handleSetPasteboard:)]
data := map[string]interface{}{
"contentType": contentType,
@@ -621,7 +622,7 @@ func (wd *WDADriver) SetPasteboard(contentType PasteboardType, content string) (
return
}
func (wd *WDADriver) GetPasteboard(contentType PasteboardType) (raw *bytes.Buffer, err error) {
func (wd *WDADriver) GetPasteboard(contentType types.PasteboardType) (raw *bytes.Buffer, err error) {
// [[FBRoute POST:@"/wda/getPasteboard"] respondWithTarget:self action:@selector(handleGetPasteboard:)]
data := map[string]interface{}{"contentType": contentType}
var rawResp rawResponse
@@ -713,7 +714,7 @@ func (wd *WDADriver) PressBack(opts ...option.ActionOption) (err error) {
return
}
func (wd *WDADriver) PressButton(devBtn DeviceButton) (err error) {
func (wd *WDADriver) PressButton(devBtn types.DeviceButton) (err error) {
// [[FBRoute POST:@"/wda/pressButton"] respondWithTarget:self action:@selector(handlePressButtonCommand:)]
data := map[string]interface{}{"name": devBtn}
_, err = wd.httpPOST(data, "/session", wd.sessionID, "/wda/pressButton")
@@ -745,13 +746,13 @@ func (wd *WDADriver) StopCamera() (err error) {
return nil
}
func (wd *WDADriver) Orientation() (orientation Orientation, err error) {
func (wd *WDADriver) Orientation() (orientation types.Orientation, err error) {
// [[FBRoute GET:@"/orientation"] respondWithTarget:self action:@selector(handleGetOrientation:)]
var rawResp rawResponse
if rawResp, err = wd.httpGET("/session", wd.sessionID, "/orientation"); err != nil {
return "", err
}
reply := new(struct{ Value Orientation })
reply := new(struct{ Value types.Orientation })
if err = json.Unmarshal(rawResp, reply); err != nil {
return "", err
}
@@ -759,28 +760,28 @@ func (wd *WDADriver) Orientation() (orientation Orientation, err error) {
return
}
func (wd *WDADriver) SetOrientation(orientation Orientation) (err error) {
func (wd *WDADriver) SetOrientation(orientation types.Orientation) (err error) {
// [[FBRoute POST:@"/orientation"] respondWithTarget:self action:@selector(handleSetOrientation:)]
data := map[string]interface{}{"orientation": orientation}
_, err = wd.httpPOST(data, "/session", wd.sessionID, "/orientation")
return
}
func (wd *WDADriver) Rotation() (rotation Rotation, err error) {
func (wd *WDADriver) Rotation() (rotation types.Rotation, err error) {
// [[FBRoute GET:@"/rotation"] respondWithTarget:self action:@selector(handleGetRotation:)]
var rawResp rawResponse
if rawResp, err = wd.httpGET("/session", wd.sessionID, "/rotation"); err != nil {
return Rotation{}, err
return types.Rotation{}, err
}
reply := new(struct{ Value Rotation })
reply := new(struct{ Value types.Rotation })
if err = json.Unmarshal(rawResp, reply); err != nil {
return Rotation{}, err
return types.Rotation{}, err
}
rotation = reply.Value
return
}
func (wd *WDADriver) SetRotation(rotation Rotation) (err error) {
func (wd *WDADriver) SetRotation(rotation types.Rotation) (err error) {
// [[FBRoute POST:@"/rotation"] respondWithTarget:self action:@selector(handleSetRotation:)]
_, err = wd.httpPOST(rotation, "/session", wd.sessionID, "/rotation")
return

View File

@@ -11,12 +11,13 @@ import (
"github.com/rs/zerolog/log"
"github.com/httprunner/httprunner/v5/pkg/uixt/option"
"github.com/httprunner/httprunner/v5/pkg/uixt/types"
)
var (
bundleId = "com.apple.Preferences"
driver IDriver
iOSDriverExt *DriverExt
iOSDriverExt IDriverExt
)
func setup(t *testing.T) {
@@ -29,11 +30,7 @@ func setup(t *testing.T) {
}
capabilities := option.NewCapabilities()
capabilities.WithDefaultAlertAction(option.AlertActionAccept)
driver, err = device.NewHTTPDriver(capabilities)
if err != nil {
t.Fatal(err)
}
iOSDriverExt, err = newDriverExt(device, driver)
iOSDriverExt, err = device.NewDriver()
if err != nil {
t.Fatal(err)
}
@@ -46,7 +43,7 @@ func TestViaUSB(t *testing.T) {
func TestInstall(t *testing.T) {
setup(t)
err := iOSDriverExt.Install("xxx.ipa",
err := iOSDriverExt.GetDriver().GetDevice().Install("xxx.ipa",
option.WithRetryTimes(5))
log.Error().Err(err)
if err != nil {
@@ -320,7 +317,7 @@ func Test_remoteWD_SetPasteboard(t *testing.T) {
setup(t)
// err := driver.SetPasteboard(PasteboardTypePlaintext, "gwda")
err := driver.SetPasteboard(PasteboardTypeUrl, "Clock-stopwatch://")
err := driver.SetPasteboard(types.PasteboardTypeUrl, "Clock-stopwatch://")
// userHomeDir, _ := os.UserHomeDir()
// bytesImg, _ := ioutil.ReadFile(userHomeDir + "/Pictures/IMG_0806.jpg")
// err := driver.SetPasteboard(PasteboardTypeImage, string(bytesImg))
@@ -335,7 +332,7 @@ func Test_remoteWD_GetPasteboard(t *testing.T) {
var buffer *bytes.Buffer
var err error
buffer, err = driver.GetPasteboard(PasteboardTypePlaintext)
buffer, err = driver.GetPasteboard(types.PasteboardTypePlaintext)
// buffer, err = driver.GetPasteboard(PasteboardTypeUrl)
if err != nil {
t.Fatal(err)
@@ -367,17 +364,17 @@ func Test_remoteWD_SendKeys(t *testing.T) {
func Test_remoteWD_PressButton(t *testing.T) {
setup(t)
err := driver.PressButton(DeviceButtonVolumeUp)
err := driver.PressButton(types.DeviceButtonVolumeUp)
if err != nil {
t.Fatal(err)
}
time.Sleep(time.Second * 1)
err = driver.PressButton(DeviceButtonVolumeDown)
err = driver.PressButton(types.DeviceButtonVolumeDown)
if err != nil {
t.Fatal(err)
}
time.Sleep(time.Second * 1)
err = driver.PressButton(DeviceButtonHome)
err = driver.PressButton(types.DeviceButtonHome)
if err != nil {
t.Fatal(err)
}

View File

@@ -6,54 +6,24 @@ import (
"github.com/httprunner/httprunner/v5/internal/builtin"
)
// (x1, y1) is the top left corner, (x2, y2) is the bottom right corner
// [x1, y1, x2, y2] in percentage of the screen
type Scope []float64
// [x1, y1, x2, y2] in absolute pixels
type AbsScope []int
func (s AbsScope) Option() ActionOption {
return WithAbsScope(s[0], s[1], s[2], s[3])
}
type ActionOptions struct {
// log
Identifier string `json:"identifier,omitempty" yaml:"identifier,omitempty"` // used to identify the action in log
// control related
MaxRetryTimes int `json:"max_retry_times,omitempty" yaml:"max_retry_times,omitempty"` // max retry times
IgnoreNotFoundError bool `json:"ignore_NotFoundError,omitempty" yaml:"ignore_NotFoundError,omitempty"` // ignore error if target element not found
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
PressDuration float64 `json:"press_duration,omitempty" yaml:"press_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
Timeout int `json:"timeout,omitempty" yaml:"timeout,omitempty"` // TODO: wait timeout in seconds for mobile action
Frequency int `json:"frequency,omitempty" yaml:"frequency,omitempty"`
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
Duration float64 `json:"duration,omitempty" yaml:"duration,omitempty"` // used to set duration of ios swipe action
PressDuration float64 `json:"press_duration,omitempty" yaml:"press_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
Timeout int `json:"timeout,omitempty" yaml:"timeout,omitempty"` // TODO: wait timeout in seconds for mobile action
Frequency int `json:"frequency,omitempty" yaml:"frequency,omitempty"`
// scope related
Scope Scope `json:"scope,omitempty" yaml:"scope,omitempty"`
AbsScope AbsScope `json:"abs_scope,omitempty" yaml:"abs_scope,omitempty"`
Regex bool `json:"regex,omitempty" yaml:"regex,omitempty"` // use regex to match text
Offset []int `json:"offset,omitempty" yaml:"offset,omitempty"` // used to tap offset of point
OffsetRandomRange []int `json:"offset_random_range,omitempty" yaml:"offset_random_range,omitempty"` // set random range [min, max] for tap/swipe points
Index int `json:"index,omitempty" yaml:"index,omitempty"` // index of the target element
MatchOne bool `json:"match_one,omitempty" yaml:"match_one,omitempty"` // match one of the targets if existed
ScreenOptions
// set custiom options such as textview, id, description
Custom map[string]interface{} `json:"custom,omitempty" yaml:"custom,omitempty"`
// screenshot related
ScreenShotWithOCR bool `json:"screenshot_with_ocr,omitempty" yaml:"screenshot_with_ocr,omitempty"`
ScreenShotWithUpload bool `json:"screenshot_with_upload,omitempty" yaml:"screenshot_with_upload,omitempty"`
ScreenShotWithLiveType bool `json:"screenshot_with_live_type,omitempty" yaml:"screenshot_with_live_type,omitempty"`
ScreenShotWithLivePopularity bool `json:"screenshot_with_live_popularity,omitempty" yaml:"screenshot_with_live_popularity,omitempty"`
ScreenShotWithUITypes []string `json:"screenshot_with_ui_types,omitempty" yaml:"screenshot_with_ui_types,omitempty"`
ScreenShotWithClosePopups bool `json:"screenshot_with_close_popups,omitempty" yaml:"screenshot_with_close_popups,omitempty"`
ScreenShotWithOCRCluster string `json:"screenshot_with_ocr_cluster,omitempty" yaml:"screenshot_with_ocr_cluster,omitempty"`
ScreenShotFileName string `json:"screenshot_file_name,omitempty" yaml:"screenshot_file_name,omitempty"`
}
func (o *ActionOptions) Options() []ActionOption {
@@ -150,57 +120,11 @@ func (o *ActionOptions) Options() []ActionOption {
}
}
// screenshot options
if o.ScreenShotWithOCR {
options = append(options, WithScreenShotOCR(true))
}
if o.ScreenShotWithUpload {
options = append(options, WithScreenShotUpload(true))
}
if o.ScreenShotWithLiveType {
options = append(options, WithScreenShotLiveType(true))
}
if o.ScreenShotWithLivePopularity {
options = append(options, WithScreenShotLivePopularity(true))
}
if len(o.ScreenShotWithUITypes) > 0 {
options = append(options, WithScreenShotUITypes(o.ScreenShotWithUITypes...))
}
if o.ScreenShotWithClosePopups {
options = append(options, WithScreenShotClosePopups(true))
}
if o.ScreenShotWithOCRCluster != "" {
options = append(options, WithScreenOCRCluster(o.ScreenShotWithOCRCluster))
}
if o.ScreenShotFileName != "" {
options = append(options, WithScreenShotFileName(o.ScreenShotFileName))
}
return options
}
func (o *ActionOptions) ScreenshotActions() []string {
actions := []string{}
if o.ScreenShotWithUpload {
actions = append(actions, "upload")
}
if o.ScreenShotWithOCR {
actions = append(actions, "ocr")
}
if o.ScreenShotWithLiveType {
actions = append(actions, "liveType")
}
if o.ScreenShotWithLivePopularity {
actions = append(actions, "livePopularity")
}
// UI detection
if len(o.ScreenShotWithUITypes) > 0 {
actions = append(actions, "ui")
}
if o.ScreenShotWithClosePopups {
actions = append(actions, "close")
}
return actions
func (o *ActionOptions) GetScreenOptions() []ActionOption {
return o.ScreenOptions.Options()
}
func (o *ActionOptions) GetRandomOffset() float64 {
@@ -283,12 +207,6 @@ func WithIdentifier(identifier string) ActionOption {
}
}
func WithIndex(index int) ActionOption {
return func(o *ActionOptions) {
o.Index = index
}
}
// set alias for compatibility
var WithWaitTime = WithInterval
@@ -330,32 +248,6 @@ func WithCustomDirection(sx, sy, ex, ey float64) ActionOption {
}
}
// WithScope inputs area of [(x1,y1), (x2,y2)]
// x1, y1, x2, y2 are all in [0, 1], which means the relative position of the screen
func WithScope(x1, y1, x2, y2 float64) ActionOption {
return func(o *ActionOptions) {
o.Scope = Scope{x1, y1, x2, y2}
}
}
// WithAbsScope inputs area of [(x1,y1), (x2,y2)]
// x1, y1, x2, y2 are all absolute position of the screen
func WithAbsScope(x1, y1, x2, y2 int) ActionOption {
return func(o *ActionOptions) {
o.AbsScope = AbsScope{x1, y1, x2, y2}
}
}
// Deprecated: use WithTapOffset instead
func WithOffset(offsetX, offsetY int) ActionOption {
return func(o *ActionOptions) {
o.Offset = []int{offsetX, offsetY}
}
}
// tap [x, y] with offset [offsetX, offsetY]
var WithTapOffset = WithOffset
// swipe [fromX, fromY, toX, toY] with offset [offsetFromX, offsetFromY, offsetToX, offsetToY]
func WithSwipeOffset(offsetFromX, offsetFromY, offsetToX, offsetToY int) ActionOption {
return func(o *ActionOptions) {
@@ -369,18 +261,6 @@ func WithOffsetRandomRange(min, max int) ActionOption {
}
}
func WithRegex(regex bool) ActionOption {
return func(o *ActionOptions) {
o.Regex = regex
}
}
func WithMatchOne(matchOne bool) ActionOption {
return func(o *ActionOptions) {
o.MatchOne = matchOne
}
}
func WithFrequency(frequency int) ActionOption {
return func(o *ActionOptions) {
o.Frequency = frequency
@@ -404,51 +284,3 @@ func WithIgnoreNotFoundError(ignoreError bool) ActionOption {
o.IgnoreNotFoundError = ignoreError
}
}
func WithScreenShotOCR(ocrOn bool) ActionOption {
return func(o *ActionOptions) {
o.ScreenShotWithOCR = ocrOn
}
}
func WithScreenShotUpload(uploadOn bool) ActionOption {
return func(o *ActionOptions) {
o.ScreenShotWithUpload = uploadOn
}
}
func WithScreenShotLiveType(liveTypeOn bool) ActionOption {
return func(o *ActionOptions) {
o.ScreenShotWithLiveType = liveTypeOn
}
}
func WithScreenShotLivePopularity(livePopularityOn bool) ActionOption {
return func(o *ActionOptions) {
o.ScreenShotWithLivePopularity = livePopularityOn
}
}
func WithScreenShotUITypes(uiTypes ...string) ActionOption {
return func(o *ActionOptions) {
o.ScreenShotWithUITypes = uiTypes
}
}
func WithScreenShotClosePopups(closeOn bool) ActionOption {
return func(o *ActionOptions) {
o.ScreenShotWithClosePopups = closeOn
}
}
func WithScreenOCRCluster(ocrCluster string) ActionOption {
return func(o *ActionOptions) {
o.ScreenShotWithOCRCluster = ocrCluster
}
}
func WithScreenShotFileName(fileName string) ActionOption {
return func(o *ActionOptions) {
o.ScreenShotFileName = fileName
}
}

View File

@@ -1,49 +0,0 @@
package option
import (
"github.com/httprunner/funplugin"
)
type DriverOptions struct {
Capabilities Capabilities
Plugin funplugin.IPlugin
WithImageService bool
WithResultFolder bool
}
func NewDriverOptions(opts ...DriverOption) *DriverOptions {
driverOptions := &DriverOptions{
WithImageService: true,
WithResultFolder: true,
}
for _, option := range opts {
option(driverOptions)
}
return driverOptions
}
type DriverOption func(*DriverOptions)
func WithDriverCapabilities(capabilities Capabilities) DriverOption {
return func(options *DriverOptions) {
options.Capabilities = capabilities
}
}
func WithDriverImageService(withImageService bool) DriverOption {
return func(options *DriverOptions) {
options.WithImageService = withImageService
}
}
func WithDriverResultFolder(withResultFolder bool) DriverOption {
return func(options *DriverOptions) {
options.WithResultFolder = withResultFolder
}
}
func WithDriverPlugin(plugin funplugin.IPlugin) DriverOption {
return func(options *DriverOptions) {
options.Plugin = plugin
}
}

View File

@@ -1,5 +1,12 @@
package option
import "code.byted.org/iesqa/ghdc"
const (
HdcServerHost = "localhost"
HdcServerPort = ghdc.HdcServerPort // 5037
)
type HarmonyDeviceOptions struct {
ConnectKey string `json:"connect_key,omitempty" yaml:"connect_key,omitempty"`
LogOn bool `json:"log_on,omitempty" yaml:"log_on,omitempty"`

View File

@@ -1,11 +1,10 @@
package ai
package option
func NewScreenShotOptions(opts ...ScreenShotOption) *ScreenShotOptions {
options := &ScreenShotOptions{}
for _, option := range opts {
option(options)
}
return options
import "github.com/httprunner/httprunner/v5/pkg/uixt/types"
type ScreenOptions struct {
ScreenShotOptions
ScreenFilterOptions
}
type ScreenShotOptions struct {
@@ -19,8 +18,8 @@ type ScreenShotOptions struct {
ScreenShotFileName string `json:"screenshot_file_name,omitempty" yaml:"screenshot_file_name,omitempty"`
}
func (o *ScreenShotOptions) Options() []ScreenShotOption {
options := make([]ScreenShotOption, 0)
func (o *ScreenShotOptions) Options() []ActionOption {
options := make([]ActionOption, 0)
if o == nil {
return options
}
@@ -78,52 +77,50 @@ func (o *ScreenShotOptions) List() []string {
return options
}
type ScreenShotOption func(o *ScreenShotOptions)
func WithScreenShotOCR(ocrOn bool) ScreenShotOption {
return func(o *ScreenShotOptions) {
func WithScreenShotOCR(ocrOn bool) ActionOption {
return func(o *ActionOptions) {
o.ScreenShotWithOCR = ocrOn
}
}
func WithScreenShotUpload(uploadOn bool) ScreenShotOption {
return func(o *ScreenShotOptions) {
func WithScreenShotUpload(uploadOn bool) ActionOption {
return func(o *ActionOptions) {
o.ScreenShotWithUpload = uploadOn
}
}
func WithScreenShotLiveType(liveTypeOn bool) ScreenShotOption {
return func(o *ScreenShotOptions) {
func WithScreenShotLiveType(liveTypeOn bool) ActionOption {
return func(o *ActionOptions) {
o.ScreenShotWithLiveType = liveTypeOn
}
}
func WithScreenShotLivePopularity(livePopularityOn bool) ScreenShotOption {
return func(o *ScreenShotOptions) {
func WithScreenShotLivePopularity(livePopularityOn bool) ActionOption {
return func(o *ActionOptions) {
o.ScreenShotWithLivePopularity = livePopularityOn
}
}
func WithScreenShotUITypes(uiTypes ...string) ScreenShotOption {
return func(o *ScreenShotOptions) {
func WithScreenShotUITypes(uiTypes ...string) ActionOption {
return func(o *ActionOptions) {
o.ScreenShotWithUITypes = uiTypes
}
}
func WithScreenShotClosePopups(closeOn bool) ScreenShotOption {
return func(o *ScreenShotOptions) {
func WithScreenShotClosePopups(closeOn bool) ActionOption {
return func(o *ActionOptions) {
o.ScreenShotWithClosePopups = closeOn
}
}
func WithScreenOCRCluster(ocrCluster string) ScreenShotOption {
return func(o *ScreenShotOptions) {
func WithScreenOCRCluster(ocrCluster string) ActionOption {
return func(o *ActionOptions) {
o.ScreenShotWithOCRCluster = ocrCluster
}
}
func WithScreenShotFileName(fileName string) ScreenShotOption {
return func(o *ScreenShotOptions) {
func WithScreenShotFileName(fileName string) ActionOption {
return func(o *ActionOptions) {
o.ScreenShotFileName = fileName
}
}
@@ -132,7 +129,7 @@ func WithScreenShotFileName(fileName string) ScreenShotOption {
// [x1, y1, x2, y2] in percentage of the screen
type Scope []float64
func (s Scope) ToAbs(windowSize Size) AbsScope {
func (s Scope) ToAbs(windowSize types.Size) AbsScope {
x1, y1, x2, y2 := s[0], s[1], s[2], s[3]
// convert relative scope to absolute scope
absX1 := int(x1 * float64(windowSize.Width))
@@ -145,12 +142,12 @@ func (s Scope) ToAbs(windowSize Size) AbsScope {
// [x1, y1, x2, y2] in absolute pixels
type AbsScope []int
func (s AbsScope) Option() ScreenFilterOption {
func (s AbsScope) Option() ActionOption {
return WithAbsScope(s[0], s[1], s[2], s[3])
}
func NewScreenFilterOptions(opts ...ScreenFilterOption) *ScreenFilterOptions {
options := &ScreenFilterOptions{}
func NewScreenFilterOptions(opts ...ActionOption) *ActionOptions {
options := &ActionOptions{}
for _, option := range opts {
option(options)
}
@@ -162,52 +159,51 @@ type ScreenFilterOptions struct {
Scope Scope `json:"scope,omitempty" yaml:"scope,omitempty"`
AbsScope AbsScope `json:"abs_scope,omitempty" yaml:"abs_scope,omitempty"`
Regex bool `json:"regex,omitempty" yaml:"regex,omitempty"` // use regex to match text
Offset []int `json:"offset,omitempty" yaml:"offset,omitempty"` // used to tap offset of point
OffsetRandomRange []int `json:"offset_random_range,omitempty" yaml:"offset_random_range,omitempty"` // set random range [min, max] for tap/swipe points
Index int `json:"index,omitempty" yaml:"index,omitempty"` // index of the target element
MatchOne bool `json:"match_one,omitempty" yaml:"match_one,omitempty"` // match one of the targets if existed
Regex bool `json:"regex,omitempty" yaml:"regex,omitempty"` // use regex to match text
Offset []int `json:"offset,omitempty" yaml:"offset,omitempty"` // used to tap offset of point
OffsetRandomRange []int `json:"offset_random_range,omitempty" yaml:"offset_random_range,omitempty"` // set random range [min, max] for tap/swipe points
Index int `json:"index,omitempty" yaml:"index,omitempty"` // index of the target element
MatchOne bool `json:"match_one,omitempty" yaml:"match_one,omitempty"`
IgnoreNotFoundError bool `json:"ignore_NotFoundError,omitempty" yaml:"ignore_NotFoundError,omitempty"` // ignore error if target element not found // match one of the targets if existed
}
type ScreenFilterOption func(o *ScreenFilterOptions)
// WithScope inputs area of [(x1,y1), (x2,y2)]
// x1, y1, x2, y2 are all in [0, 1], which means the relative position of the screen
func WithScope(x1, y1, x2, y2 float64) ScreenFilterOption {
return func(o *ScreenFilterOptions) {
func WithScope(x1, y1, x2, y2 float64) ActionOption {
return func(o *ActionOptions) {
o.Scope = Scope{x1, y1, x2, y2}
}
}
// WithAbsScope inputs area of [(x1,y1), (x2,y2)]
// x1, y1, x2, y2 are all absolute position of the screen
func WithAbsScope(x1, y1, x2, y2 int) ScreenFilterOption {
return func(o *ScreenFilterOptions) {
func WithAbsScope(x1, y1, x2, y2 int) ActionOption {
return func(o *ActionOptions) {
o.AbsScope = AbsScope{x1, y1, x2, y2}
}
}
// tap [x, y] with offset [offsetX, offsetY]
func WithTapOffset(offsetX, offsetY int) ScreenFilterOption {
return func(o *ScreenFilterOptions) {
func WithTapOffset(offsetX, offsetY int) ActionOption {
return func(o *ActionOptions) {
o.Offset = []int{offsetX, offsetY}
}
}
func WithRegex(regex bool) ScreenFilterOption {
return func(o *ScreenFilterOptions) {
func WithRegex(regex bool) ActionOption {
return func(o *ActionOptions) {
o.Regex = regex
}
}
func WithMatchOne(matchOne bool) ScreenFilterOption {
return func(o *ScreenFilterOptions) {
func WithMatchOne(matchOne bool) ActionOption {
return func(o *ActionOptions) {
o.MatchOne = matchOne
}
}
func WithIndex(index int) ScreenFilterOption {
return func(o *ScreenFilterOptions) {
func WithIndex(index int) ActionOption {
return func(o *ActionOptions) {
o.Index = index
}
}

60
pkg/uixt/types/app.go Normal file
View File

@@ -0,0 +1,60 @@
package types
type AppInfo struct {
Name string `json:"name,omitempty"`
AppBaseInfo
}
type WindowInfo struct {
PackageName string `json:"packageName,omitempty"`
Activity string `json:"activity,omitempty"`
}
type AppBaseInfo struct {
Pid int `json:"pid,omitempty"`
BundleId string `json:"bundleId,omitempty"` // ios package name
ViewController string `json:"viewController,omitempty"` // ios view controller
PackageName string `json:"packageName,omitempty"` // android package name
Activity string `json:"activity,omitempty"` // android activity
VersionName string `json:"versionName,omitempty"`
VersionCode interface{} `json:"versionCode,omitempty"` // int or string
AppName string `json:"appName,omitempty"`
AppPath string `json:"appPath,omitempty"`
AppMD5 string `json:"appMD5,omitempty"`
// AppIcon string `json:"appIcon,omitempty"`
}
type AppState int
const (
AppStateNotRunning AppState = 1 << iota
AppStateRunningBack
AppStateRunningFront
)
func (v AppState) String() string {
switch v {
case AppStateNotRunning:
return "Not Running"
case AppStateRunningBack:
return "Running (Back)"
case AppStateRunningFront:
return "Running (Front)"
default:
return "UNKNOWN"
}
}
// PasteboardType The type of the item on the pasteboard.
type PasteboardType string
const (
PasteboardTypePlaintext PasteboardType = "plaintext"
PasteboardTypeImage PasteboardType = "image"
PasteboardTypeUrl PasteboardType = "url"
)
const (
TextBackspace string = "\u0008"
TextDelete string = "\u007F"
)

View File

@@ -1,8 +1,6 @@
package uixt
package types
import (
"fmt"
)
import "fmt"
type DeviceStatus struct {
Message string `json:"message"`
@@ -152,65 +150,6 @@ func (bs BatteryStatus) String() string {
}
}
type AppInfo struct {
Name string `json:"name,omitempty"`
AppBaseInfo
}
type WindowInfo struct {
PackageName string `json:"packageName,omitempty"`
Activity string `json:"activity,omitempty"`
}
type AppBaseInfo struct {
Pid int `json:"pid,omitempty"`
BundleId string `json:"bundleId,omitempty"` // ios package name
ViewController string `json:"viewController,omitempty"` // ios view controller
PackageName string `json:"packageName,omitempty"` // android package name
Activity string `json:"activity,omitempty"` // android activity
VersionName string `json:"versionName,omitempty"`
VersionCode interface{} `json:"versionCode,omitempty"` // int or string
AppName string `json:"appName,omitempty"`
AppPath string `json:"appPath,omitempty"`
AppMD5 string `json:"appMD5,omitempty"`
// AppIcon string `json:"appIcon,omitempty"`
}
type AppState int
const (
AppStateNotRunning AppState = 1 << iota
AppStateRunningBack
AppStateRunningFront
)
func (v AppState) String() string {
switch v {
case AppStateNotRunning:
return "Not Running"
case AppStateRunningBack:
return "Running (Back)"
case AppStateRunningFront:
return "Running (Front)"
default:
return "UNKNOWN"
}
}
// PasteboardType The type of the item on the pasteboard.
type PasteboardType string
const (
PasteboardTypePlaintext PasteboardType = "plaintext"
PasteboardTypeImage PasteboardType = "image"
PasteboardTypeUrl PasteboardType = "url"
)
const (
TextBackspace string = "\u0008"
TextDelete string = "\u007F"
)
// DeviceButton A physical button on an iOS device.
type DeviceButton string
@@ -249,8 +188,6 @@ type Rotation struct {
Z int `json:"z"`
}
type Condition func(wd IDriver) (bool, error)
type Direction string
const (

10
pkg/uixt/types/ui.go Normal file
View File

@@ -0,0 +1,10 @@
package types
type Size struct {
Width int `json:"width"`
Height int `json:"height"`
}
func (s Size) IsNil() bool {
return s.Width == 0 && s.Height == 0
}