Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

append options in post data for extra WDA configurations #15

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
53 changes: 36 additions & 17 deletions driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -496,16 +496,21 @@ func (wd *remoteWD) AppAuthReset(resource ProtectedResource) (err error) {
return
}

func (wd *remoteWD) Tap(x, y int) error {
return wd.TapFloat(float64(x), float64(y))
func (wd *remoteWD) Tap(x, y int, options ...DataOption) error {
return wd.TapFloat(float64(x), float64(y), options...)
}

func (wd *remoteWD) TapFloat(x, y float64) (err error) {
func (wd *remoteWD) TapFloat(x, y float64, options ...DataOption) (err error) {
// [[FBRoute POST:@"/wda/tap/:uuid"] respondWithTarget:self action:@selector(handleTap:)]
data := map[string]interface{}{
"x": x,
"y": y,
}
// append options in post data for extra WDA configurations
// e.g. add identifier in tap event logs
for _, option := range options {
option(data)
}
_, err = wd.executePost(data, "/session", wd.sessionId, "/wda/tap/0")
return
}
Expand Down Expand Up @@ -542,32 +547,40 @@ func (wd *remoteWD) TouchAndHoldFloat(x, y float64, second ...float64) (err erro
return
}

func (wd *remoteWD) Drag(fromX, fromY, toX, toY int, pressForDuration ...float64) error {
return wd.DragFloat(float64(fromX), float64(fromY), float64(toX), float64(toY), pressForDuration...)
func (wd *remoteWD) Drag(fromX, fromY, toX, toY int, options ...DataOption) error {
return wd.DragFloat(float64(fromX), float64(fromY), float64(toX), float64(toY), options...)
}

func (wd *remoteWD) DragFloat(fromX, fromY, toX, toY float64, pressForDuration ...float64) (err error) {
func (wd *remoteWD) DragFloat(fromX, fromY, toX, toY float64, options ...DataOption) (err error) {
// [[FBRoute POST:@"/wda/dragfromtoforduration"] respondWithTarget:self action:@selector(handleDragCoordinate:)]
data := map[string]interface{}{
"fromX": fromX,
"fromY": fromY,
"toX": toX,
"toY": toY,
}
if len(pressForDuration) == 0 || pressForDuration[0] < 0 {
pressForDuration = []float64{1.0}

// append options in post data for extra WDA configurations
// e.g. use WithPressDuration to set pressForDuration
for _, option := range options {
option(data)
}

if _, ok := data["duration"]; !ok {
data["duration"] = 1.0 // default duration
}
data["duration"] = pressForDuration[0]
_, err = wd.executePost(data, "/session", wd.sessionId, "/wda/dragfromtoforduration")
return
}

func (wd *remoteWD) Swipe(fromX, fromY, toX, toY int) error {
return wd.SwipeFloat(float64(fromX), float64(fromY), float64(toX), float64(toY))
func (wd *remoteWD) Swipe(fromX, fromY, toX, toY int, options ...DataOption) error {
options = append(options, WithPressDuration(0))
return wd.SwipeFloat(float64(fromX), float64(fromY), float64(toX), float64(toY), options...)
}

func (wd *remoteWD) SwipeFloat(fromX, fromY, toX, toY float64) error {
return wd.DragFloat(fromX, fromY, toX, toY, 0)
func (wd *remoteWD) SwipeFloat(fromX, fromY, toX, toY float64, options ...DataOption) error {
options = append(options, WithPressDuration(0))
return wd.DragFloat(fromX, fromY, toX, toY, options...)
}

func (wd *remoteWD) ForceTouch(x, y int, pressure float64, second ...float64) error {
Expand Down Expand Up @@ -624,13 +637,19 @@ func (wd *remoteWD) GetPasteboard(contentType PasteboardType) (raw *bytes.Buffer
return
}

func (wd *remoteWD) SendKeys(text string, frequency ...int) (err error) {
func (wd *remoteWD) SendKeys(text string, options ...DataOption) (err error) {
// [[FBRoute POST:@"/wda/keys"] respondWithTarget:self action:@selector(handleKeys:)]
data := map[string]interface{}{"value": strings.Split(text, "")}
if len(frequency) == 0 || frequency[0] <= 0 {
frequency = []int{60}

// append options in post data for extra WDA configurations
// e.g. use WithFrequency to set frequency of typing
for _, option := range options {
option(data)
}

if _, ok := data["frequency"]; !ok {
data["frequency"] = 60 // default frequency
}
data["frequency"] = frequency[0]
_, err = wd.executePost(data, "/session", wd.sessionId, "/wda/keys")
return
}
Expand Down
4 changes: 2 additions & 2 deletions driver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ func Test_remoteWD_TouchAndHold(t *testing.T) {
func Test_remoteWD_Drag(t *testing.T) {
setup(t)

// err := driver.Drag(200, 300, 200, 500, -1)
// err := driver.Drag(200, 300, 200, 500, WithPressDuration(0.5))
err := driver.Swipe(200, 300, 200, 500)
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -511,7 +511,7 @@ func Test_remoteWD_SendKeys(t *testing.T) {
setup(t)

err := driver.SendKeys("App Store")
// err := driver.SendKeys("App Store", 3)
// err := driver.SendKeys("App Store", WithFrequency(3))
if err != nil {
t.Fatal(err)
}
Expand Down
5 changes: 4 additions & 1 deletion element.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ import (
"strings"
)

// All elements returned by search endpoints have assigned element_id.
// Given element_id you can query properties like:
// enabled, rect, size, location, text, displayed, accessible, name
type remoteWE struct {
parent *remoteWD
id string
id string // element_id
}

func (we remoteWE) Click() (err error) {
Expand Down
9 changes: 9 additions & 0 deletions element_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,9 @@ func Test_remoteWE_PickerWheelSelect(t *testing.T) {
element := setupElement(t, BySelector{ClassName: ElementType{PickerWheel: true}})

err := element.PickerWheelSelect(PickerWheelOrderNext, 3)
if err != nil {
t.Fatal(err)
}
err = element.PickerWheelSelect(PickerWheelOrderPrevious)
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -236,7 +239,13 @@ func Test_remoteWE_Rect(t *testing.T) {
element := setupElement(t, BySelector{ClassName: ElementType{Switch: true}})

rect, err := element.Rect()
if err != nil {
t.Fatal(err)
}
location, err := element.Location()
if err != nil {
t.Fatal(err)
}
size, err := element.Size()
if err != nil {
t.Fatal(err)
Expand Down
9 changes: 8 additions & 1 deletion examples/keyboard/main.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package main

import (
"github.com/electricbubble/gwda"
"log"

"github.com/electricbubble/gwda"
)

func main() {
Expand All @@ -16,6 +17,12 @@ func main() {
log.Fatalln(err)
}

// send keys with specified frequency
err = driver.SendKeys("world", gwda.WithFrequency(30))
if err != nil {
log.Fatalln(err)
}

// element, err := driver.ActiveElement()
// if err != nil {
// log.Fatalln(err)
Expand Down
33 changes: 32 additions & 1 deletion examples/touch/main.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package main

import (
"github.com/electricbubble/gwda"
"log"

"github.com/electricbubble/gwda"
)

func main() {
Expand All @@ -18,6 +19,16 @@ func main() {
log.Fatalln(err)
}

// tap action with specified identifier
option := gwda.WithCustomOption("log", map[string]interface{}{
"enable": true,
"data": "identifier-tap-A",
})
err = driver.Tap(x, y, option)
if err != nil {
log.Fatalln(err)
}

err = driver.DoubleTap(x, y)
if err != nil {
log.Fatalln(err)
Expand All @@ -35,11 +46,31 @@ func main() {
log.Fatalln(err)
}

// drag action with specified identifier
option = gwda.WithCustomOption("log", map[string]interface{}{
"enable": true,
"data": "identifier-drag-B",
})
err = driver.Drag(fromX, fromY, toX, toY, option)
if err != nil {
log.Fatalln(err)
}

err = driver.Swipe(fromX, fromY, toX, toY)
if err != nil {
log.Fatalln(err)
}

// swipe action with specified identifier
option = gwda.WithCustomOption("log", map[string]interface{}{
"enable": true,
"data": "identifier-swipe-C",
})
err = driver.Swipe(fromX, fromY, toX, toY, option)
if err != nil {
log.Fatalln(err)
}

// 需要 3D Touch 硬件支持
// err = driver.ForceTouch(x, y, 0.8)
// if err != nil {
Expand Down
52 changes: 39 additions & 13 deletions gwda.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,12 @@ func executeHTTP(method string, rawURL string, rawBody []byte, httpCli *http.Cli
}()

rawResp, err = ioutil.ReadAll(resp.Body)
debugLog(fmt.Sprintf("<-- %s %s %d %s\n%s\n", method, rawURL, resp.StatusCode, time.Since(start), rawResp))
respBody := fmt.Sprintf("<-- %s %s %d %s", method, rawURL, resp.StatusCode, time.Since(start))
if !strings.HasSuffix(rawURL, "screenshot") {
// avoid printing screenshot data
respBody += fmt.Sprintf("\n%s", rawResp)
}
debugLog(respBody)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -606,6 +611,7 @@ func elementIDFromValue(val map[string]string) string {
return ""
}

// performance ranking: class name > accessibility id > link text > predicate > class chain > xpath
type BySelector struct {
ClassName ElementType `json:"class name"`

Expand All @@ -624,7 +630,7 @@ type BySelector struct {

ClassChain string `json:"class chain"`

XPath string `json:"xpath"`
XPath string `json:"xpath"` // not recommended, it's slow because it is not supported by XCTest natively
}

func (wl BySelector) getUsingAndValue() (using, value string) {
Expand Down Expand Up @@ -879,15 +885,35 @@ const (
)

type Point struct {
X int `json:"x"`
Y int `json:"y"`
X int `json:"x"` // upper left X coordinate of selected element
Y int `json:"y"` // upper left Y coordinate of selected element
}

type Rect struct {
Point
Size
}

type DataOption func(data map[string]interface{})

func WithCustomOption(key string, value interface{}) DataOption {
return func(data map[string]interface{}) {
data[key] = value
}
}

func WithPressDuration(duraion float64) DataOption {
return func(data map[string]interface{}) {
data["duration"] = duraion
}
}

func WithFrequency(frequency int) DataOption {
return func(data map[string]interface{}) {
data["frequency"] = frequency
}
}

// WebDriver defines methods supported by WebDriver drivers.
type WebDriver interface {
// NewSession starts a new session and returns the SessionInfo.
Expand Down Expand Up @@ -970,8 +996,8 @@ type WebDriver interface {
AppAuthReset(ProtectedResource) error

// Tap Sends a tap event at the coordinate.
Tap(x, y int) error
TapFloat(x, y float64) error
Tap(x, y int, options ...DataOption) error
TapFloat(x, y float64, options ...DataOption) error

// DoubleTap Sends a double tap event at the coordinate.
DoubleTap(x, y int) error
Expand All @@ -983,13 +1009,13 @@ type WebDriver interface {
TouchAndHoldFloat(x, y float64, second ...float64) error

// Drag Initiates a press-and-hold gesture at the coordinate, then drags to another coordinate.
// pressForDuration: The default value is 1 second.
Drag(fromX, fromY, toX, toY int, pressForDuration ...float64) error
DragFloat(fromX, fromY, toX, toY float64, pressForDuration ...float64) error
// WithPressDuration option can be used to set pressForDuration (default to 1 second).
Drag(fromX, fromY, toX, toY int, options ...DataOption) error
DragFloat(fromX, fromY, toX, toY float64, options ...DataOption) error

// Swipe works like Drag, but `pressForDuration` value is 0
Swipe(fromX, fromY, toX, toY int) error
SwipeFloat(fromX, fromY, toX, toY float64) error
Swipe(fromX, fromY, toX, toY int, options ...DataOption) error
SwipeFloat(fromX, fromY, toX, toY float64, options ...DataOption) error

ForceTouch(x, y int, pressure float64, second ...float64) error
ForceTouchFloat(x, y, pressure float64, second ...float64) error
Expand All @@ -1006,8 +1032,8 @@ type WebDriver interface {

// SendKeys Types a string into active element. There must be element with keyboard focus,
// otherwise an error is raised.
// frequency: Frequency of typing (letters per sec). The default value is 60
SendKeys(text string, frequency ...int) error
// WithFrequency option can be used to set frequency of typing (letters per sec). The default value is 60
SendKeys(text string, options ...DataOption) error

// KeyboardDismiss Tries to dismiss the on-screen keyboard
KeyboardDismiss(keyNames ...string) error
Expand Down