Merge branch 'v5' into wings

This commit is contained in:
余泓铮
2025-02-19 15:52:41 +08:00
10 changed files with 84 additions and 79 deletions
+1 -1
View File
@@ -1 +1 @@
v5.0.0+2502182234 v5.0.0+2502191537
+7 -7
View File
@@ -298,6 +298,9 @@ func (ad *ADBDriver) TapXY(x, y float64, opts ...option.ActionOption) error {
} }
func (ad *ADBDriver) TapAbsXY(x, y float64, opts ...option.ActionOption) error { func (ad *ADBDriver) TapAbsXY(x, y float64, opts ...option.ActionOption) error {
actionOptions := option.NewActionOptions(opts...)
x, y = actionOptions.ApplyOffset(x, y)
// adb shell input tap x y // adb shell input tap x y
xStr := fmt.Sprintf("%.1f", x) xStr := fmt.Sprintf("%.1f", x)
yStr := fmt.Sprintf("%.1f", y) yStr := fmt.Sprintf("%.1f", y)
@@ -314,6 +317,9 @@ func (ad *ADBDriver) DoubleTapXY(x, y float64, opts ...option.ActionOption) erro
if x, y, err = convertToAbsolutePoint(ad, x, y); err != nil { if x, y, err = convertToAbsolutePoint(ad, x, y); err != nil {
return err return err
} }
actionOptions := option.NewActionOptions(opts...)
x, y = actionOptions.ApplyOffset(x, y)
// adb shell input tap x y // adb shell input tap x y
xStr := fmt.Sprintf("%.1f", x) xStr := fmt.Sprintf("%.1f", x)
yStr := fmt.Sprintf("%.1f", y) yStr := fmt.Sprintf("%.1f", y)
@@ -333,13 +339,7 @@ func (ad *ADBDriver) DoubleTapXY(x, y float64, opts ...option.ActionOption) erro
func (ad *ADBDriver) TouchAndHold(x, y float64, opts ...option.ActionOption) (err error) { func (ad *ADBDriver) TouchAndHold(x, y float64, opts ...option.ActionOption) (err error) {
actionOptions := option.NewActionOptions(opts...) actionOptions := option.NewActionOptions(opts...)
x, y = actionOptions.ApplyOffset(x, y)
if len(actionOptions.Offset) == 2 {
x += float64(actionOptions.Offset[0])
y += float64(actionOptions.Offset[1])
}
x += actionOptions.GetRandomOffset()
y += actionOptions.GetRandomOffset()
duration := 1000.0 duration := 1000.0
if actionOptions.Duration > 0 { if actionOptions.Duration > 0 {
duration = actionOptions.Duration * 1000 duration = actionOptions.Duration * 1000
+11 -2
View File
@@ -30,6 +30,10 @@ func NewUIA2Driver(device *AndroidDevice) (*UIA2Driver, error) {
if err := driver.Setup(); err != nil { if err := driver.Setup(); err != nil {
return nil, err return nil, err
} }
// register driver session reset handler
driver.Session.RegisterResetHandler(driver.Setup)
return driver, nil return driver, nil
} }
@@ -246,6 +250,9 @@ func (ud *UIA2Driver) DoubleTapXY(x, y float64, opts ...option.ActionOption) err
if x, y, err = convertToAbsolutePoint(ud, x, y); err != nil { if x, y, err = convertToAbsolutePoint(ud, x, y); err != nil {
return err return err
} }
actionOptions := option.NewActionOptions(opts...)
x, y = actionOptions.ApplyOffset(x, y)
data := map[string]interface{}{ data := map[string]interface{}{
"actions": []interface{}{ "actions": []interface{}{
map[string]interface{}{ map[string]interface{}{
@@ -279,6 +286,7 @@ func (ud *UIA2Driver) TapXY(x, y float64, opts ...option.ActionOption) error {
func (ud *UIA2Driver) TapAbsXY(x, y float64, opts ...option.ActionOption) error { func (ud *UIA2Driver) TapAbsXY(x, y float64, opts ...option.ActionOption) error {
// register(postHandler, new Tap("/wd/hub/session/:sessionId/appium/tap")) // register(postHandler, new Tap("/wd/hub/session/:sessionId/appium/tap"))
actionOptions := option.NewActionOptions(opts...) actionOptions := option.NewActionOptions(opts...)
x, y = actionOptions.ApplyOffset(x, y)
duration := 100.0 duration := 100.0
if actionOptions.PressDuration > 0 { if actionOptions.PressDuration > 0 {
@@ -306,8 +314,9 @@ func (ud *UIA2Driver) TapAbsXY(x, y float64, opts ...option.ActionOption) error
} }
func (ud *UIA2Driver) TouchAndHold(x, y float64, opts ...option.ActionOption) (err error) { func (ud *UIA2Driver) TouchAndHold(x, y float64, opts ...option.ActionOption) (err error) {
actionOpts := option.NewActionOptions(opts...) actionOptions := option.NewActionOptions(opts...)
duration := actionOpts.Duration x, y = actionOptions.ApplyOffset(x, y)
duration := actionOptions.Duration
if duration == 0 { if duration == 0 {
duration = 1.0 duration = 1.0
} }
+8 -5
View File
@@ -45,6 +45,14 @@ func NewStubAndroidDriver(dev *uixt.AndroidDevice) (*StubAndroidDriver, error) {
ADBDriver: adbDriver, ADBDriver: adbDriver,
} }
// setup driver
if err := driver.Setup(); err != nil {
return nil, err
}
// register driver session reset handler
driver.Session.RegisterResetHandler(driver.Setup)
return driver, nil return driver, nil
} }
@@ -268,11 +276,6 @@ func (sad *StubAndroidDriver) LogoutNoneUI(packageName string) error {
log.Err(err).Msgf("%v", res) log.Err(err).Msgf("%v", res)
return err return err
} }
fmt.Printf("%v", resp)
if err != nil {
return err
}
time.Sleep(3 * time.Second)
return nil return nil
} }
+4 -3
View File
@@ -44,6 +44,9 @@ func NewStubIOSDriver(dev *uixt.IOSDevice) (*StubIOSDriver, error) {
return nil, err return nil, err
} }
// register driver session reset handler
driver.Session.RegisterResetHandler(driver.Setup)
return driver, nil return driver, nil
} }
@@ -114,13 +117,11 @@ func (s *StubIOSDriver) Source(srcOpt ...option.SourceOption) (string, error) {
func (s *StubIOSDriver) OpenUrl(urlStr string, opts ...option.ActionOption) (err error) { func (s *StubIOSDriver) OpenUrl(urlStr string, opts ...option.ActionOption) (err error) {
targetUrl := fmt.Sprintf("/openURL?url=%s", url.QueryEscape(urlStr)) targetUrl := fmt.Sprintf("/openURL?url=%s", url.QueryEscape(urlStr))
fmt.Sprintln(targetUrl) _, err = s.Session.GET(targetUrl)
resp, err := s.Session.GET(targetUrl)
if err != nil { if err != nil {
log.Error().Err(err).Msg("get source err") log.Error().Err(err).Msg("get source err")
return nil return nil
} }
fmt.Sprintln(resp)
return nil return nil
} }
+33 -56
View File
@@ -20,7 +20,6 @@ import (
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/httprunner/httprunner/v5/internal/json" "github.com/httprunner/httprunner/v5/internal/json"
"github.com/httprunner/httprunner/v5/pkg/uixt/option"
) )
type Attachments map[string]interface{} type Attachments map[string]interface{}
@@ -61,38 +60,13 @@ type DriverSession struct {
timeout time.Duration timeout time.Duration
maxRetry int maxRetry int
// used to reset driver session when request failed
resetFn func() error
// cache driver request and response // cache driver request and response
requests []*DriverRequests requests []*DriverRequests
} }
func (s *DriverSession) Init(capabilities option.Capabilities) (err error) {
data := make(map[string]interface{})
if len(capabilities) == 0 {
data["capabilities"] = make(map[string]interface{})
} else {
data["capabilities"] = map[string]interface{}{"alwaysMatch": capabilities}
}
var rawResp DriverRawResponse
if rawResp, err = s.POST(data, "/session"); err != nil {
return err
}
reply := new(struct{ Value struct{ SessionId string } })
if err = json.Unmarshal(rawResp, reply); err != nil {
return err
}
s.ID = reply.Value.SessionId
// WDA
// sessionInfo, err := rawResp.ValueConvertToSessionInfo()
// if err != nil {
// return err
// }
// // update session ID
// wd.Session.ID = sessionInfo.ID
return nil
}
func (s *DriverSession) Reset() { func (s *DriverSession) Reset() {
s.requests = make([]*DriverRequests, 0) s.requests = make([]*DriverRequests, 0)
} }
@@ -101,6 +75,10 @@ func (s *DriverSession) SetBaseURL(baseUrl string) {
s.baseUrl = baseUrl s.baseUrl = baseUrl
} }
func (s *DriverSession) RegisterResetHandler(fn func() error) {
s.resetFn = fn
}
func (s *DriverSession) addRequestResult(driverResult *DriverRequests) { func (s *DriverSession) addRequestResult(driverResult *DriverRequests) {
s.requests = append(s.requests, driverResult) s.requests = append(s.requests, driverResult)
} }
@@ -179,7 +157,7 @@ func (s *DriverSession) GET(pathElem ...string) (rawResp DriverRawResponse, err
if err != nil { if err != nil {
return nil, err return nil, err
} }
return s.Request(http.MethodGet, urlStr, nil) return s.RequestWithRetry(http.MethodGet, urlStr, nil)
} }
func (s *DriverSession) POST(data interface{}, pathElem ...string) (rawResp DriverRawResponse, err error) { func (s *DriverSession) POST(data interface{}, pathElem ...string) (rawResp DriverRawResponse, err error) {
@@ -193,7 +171,7 @@ func (s *DriverSession) POST(data interface{}, pathElem ...string) (rawResp Driv
return nil, err return nil, err
} }
} }
return s.Request(http.MethodPost, urlStr, bsJSON) return s.RequestWithRetry(http.MethodPost, urlStr, bsJSON)
} }
func (s *DriverSession) DELETE(pathElem ...string) (rawResp DriverRawResponse, err error) { func (s *DriverSession) DELETE(pathElem ...string) (rawResp DriverRawResponse, err error) {
@@ -201,7 +179,30 @@ func (s *DriverSession) DELETE(pathElem ...string) (rawResp DriverRawResponse, e
if err != nil { if err != nil {
return nil, err return nil, err
} }
return s.Request(http.MethodDelete, urlStr, nil) return s.RequestWithRetry(http.MethodDelete, urlStr, nil)
}
func (s *DriverSession) RequestWithRetry(method string, rawURL string, rawBody []byte) (
rawResp DriverRawResponse, err error) {
for count := 1; count <= s.maxRetry; count++ {
rawResp, err = s.Request(method, rawURL, rawBody)
if err == nil {
return
}
time.Sleep(3 * time.Second)
if s.resetFn != nil {
log.Warn().Msg("reset driver session")
if err2 := s.resetFn(); err2 != nil {
log.Error().Err(err2).Msgf(
"failed to reset session, try count %v", count)
} else {
log.Info().Msgf(
"reset session success, try count %v", count)
}
}
}
return
} }
func (s *DriverSession) Request(method string, rawURL string, rawBody []byte) ( func (s *DriverSession) Request(method string, rawURL string, rawBody []byte) (
@@ -285,30 +286,6 @@ func (s *DriverSession) Request(method string, rawURL string, rawBody []byte) (
return return
} }
// TODO: FIXME
func (s *DriverSession) RequestWithRetry(method string, rawURL string, rawBody []byte) (
rawResp DriverRawResponse, err error) {
for count := 1; count <= s.maxRetry; count++ {
rawResp, err = s.Request(method, rawURL, rawBody)
if err == nil {
return
}
time.Sleep(3 * time.Second)
oldSessionID := s.ID
if err2 := s.Init(nil); err2 != nil {
log.Error().Err(err2).Msgf(
"failed to reset session, try count %v", count)
continue
}
log.Debug().Str("new session", s.ID).Str("old session", oldSessionID).Msgf(
"reset session successfully, try count %v", count)
if oldSessionID != "" {
rawURL = strings.Replace(rawURL, oldSessionID, s.ID, 1)
}
}
return
}
func (s *DriverSession) SetupPortForward(localPort int) error { func (s *DriverSession) SetupPortForward(localPort int) error {
conn, err := net.Dial("tcp", fmt.Sprintf("127.0.0.1:%d", localPort)) conn, err := net.Dial("tcp", fmt.Sprintf("127.0.0.1:%d", localPort))
if err != nil { if err != nil {
+1
View File
@@ -151,6 +151,7 @@ func (hd *HDCDriver) TapXY(x, y float64, opts ...option.ActionOption) error {
func (hd *HDCDriver) TapAbsXY(x, y float64, opts ...option.ActionOption) error { func (hd *HDCDriver) TapAbsXY(x, y float64, opts ...option.ActionOption) error {
actionOptions := option.NewActionOptions(opts...) actionOptions := option.NewActionOptions(opts...)
x, y = actionOptions.ApplyOffset(x, y)
if actionOptions.Identifier != "" { if actionOptions.Identifier != "" {
startTime := int(time.Now().UnixMilli()) startTime := int(time.Now().UnixMilli())
+8
View File
@@ -42,6 +42,9 @@ func NewWDADriver(device *IOSDevice) (*WDADriver, error) {
return nil, err return nil, err
} }
// register driver session reset handler
driver.Session.RegisterResetHandler(driver.Setup)
return driver, nil return driver, nil
} }
@@ -566,6 +569,8 @@ func (wd *WDADriver) TapXY(x, y float64, opts ...option.ActionOption) error {
func (wd *WDADriver) TapAbsXY(x, y float64, opts ...option.ActionOption) error { func (wd *WDADriver) TapAbsXY(x, y float64, opts ...option.ActionOption) error {
// [[FBRoute POST:@"/wda/tap/:uuid"] respondWithTarget:self action:@selector(handleTap:)] // [[FBRoute POST:@"/wda/tap/:uuid"] respondWithTarget:self action:@selector(handleTap:)]
actionOptions := option.NewActionOptions(opts...)
x, y = actionOptions.ApplyOffset(x, y)
data := map[string]interface{}{ data := map[string]interface{}{
"x": wd.toScale(x), "x": wd.toScale(x),
"y": wd.toScale(y), "y": wd.toScale(y),
@@ -582,6 +587,8 @@ func (wd *WDADriver) DoubleTapXY(x, y float64, opts ...option.ActionOption) erro
if x, y, err = convertToAbsolutePoint(wd, x, y); err != nil { if x, y, err = convertToAbsolutePoint(wd, x, y); err != nil {
return err return err
} }
actionOptions := option.NewActionOptions(opts...)
x, y = actionOptions.ApplyOffset(x, y)
x = wd.toScale(x) x = wd.toScale(x)
y = wd.toScale(y) y = wd.toScale(y)
@@ -596,6 +603,7 @@ func (wd *WDADriver) DoubleTapXY(x, y float64, opts ...option.ActionOption) erro
// FIXME: hold not work // FIXME: hold not work
func (wd *WDADriver) TouchAndHold(x, y float64, opts ...option.ActionOption) (err error) { func (wd *WDADriver) TouchAndHold(x, y float64, opts ...option.ActionOption) (err error) {
actionOptions := option.NewActionOptions(opts...) actionOptions := option.NewActionOptions(opts...)
x, y = actionOptions.ApplyOffset(x, y)
if actionOptions.Duration == 0 { if actionOptions.Duration == 0 {
opts = append(opts, option.WithPressDuration(1)) opts = append(opts, option.WithPressDuration(1))
} }
+11 -1
View File
@@ -131,7 +131,17 @@ func (o *ActionOptions) GetScreenOptions() []ActionOption {
return o.ScreenOptions.Options() return o.ScreenOptions.Options()
} }
func (o *ActionOptions) GetRandomOffset() float64 { func (o *ActionOptions) ApplyOffset(absX, absY float64) (float64, float64) {
if len(o.Offset) == 2 {
absX += float64(o.Offset[0])
absY += float64(o.Offset[1])
}
absX += o.GenerateRandomOffset()
absY += o.GenerateRandomOffset()
return absX, absY
}
func (o *ActionOptions) GenerateRandomOffset() float64 {
if len(o.OffsetRandomRange) != 2 { if len(o.OffsetRandomRange) != 2 {
// invalid offset random range, should be [min, max] // invalid offset random range, should be [min, max]
return 0 return 0
-4
View File
@@ -86,10 +86,6 @@ func NewIOSDeviceOptions(opts ...IOSDeviceOption) *IOSDeviceOptions {
config.DismissAlertButtonSelector = dismissAlertButtonSelector config.DismissAlertButtonSelector = dismissAlertButtonSelector
} }
// switch to iOS springboard before init WDA session
// avoid getting stuck when some super app is active such as douyin or wexin
config.ResetHomeOnStartup = true
return config return config
} }