Skip to content

Commit 2fb003a

Browse files
authored
Add W3C Actions (#243)
1 parent 75ca383 commit 2fb003a

File tree

4 files changed

+218
-7
lines changed

4 files changed

+218
-7
lines changed

example_test.go

+62-1
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,70 @@ func Example() {
104104
}
105105

106106
fmt.Printf("%s", strings.Replace(output, "\n\n", "\n", -1))
107-
108107
// Example Output:
109108
// Hello WebDriver!
110109
//
111110
// Program exited.
111+
112+
// The following shows an example of using the Actions API.
113+
// Please refer to the WC3 Actions spec for more detailed information.
114+
if err := wd.Get("http://play.golang.org/?simple=1"); err != nil {
115+
panic(err)
116+
}
117+
118+
// Create a point which will be used as an offset to click on the
119+
// code editor text box element on the page.
120+
offset := selenium.Point{X: 100, Y: 100}
121+
122+
// Call StorePointerActions to store a number of Pointer actions which
123+
// will be executed sequentially.
124+
// "mouse1" is used as a unique virtual device identifier for this
125+
// and future actions.
126+
// selenium.MousePointer is used to identify the type of the pointer.
127+
// The stored action chain will move the pointer and click on the code
128+
// editor text box on the page.
129+
selenium.StorePointerActions("mouse1",
130+
selenium.MousePointer,
131+
// using selenium.FromViewport as the move origin
132+
// which calculates the offset from 0,0.
133+
// the other valid option is selenium.FromPointer.
134+
selenium.PointerMoveAction(0, offset, selenium.FromViewport),
135+
selenium.PointerPauseAction(250),
136+
selenium.PointerDownAction(selenium.LeftButton),
137+
selenium.PointerPauseAction(250),
138+
selenium.PointerUpAction(selenium.LeftButton),
139+
)
140+
141+
// Call StoreKeyActions to store a number of Key actions which
142+
// will be executed sequentially.
143+
// "keyboard1" is used as a unique virtual device identifier
144+
// for this and future actions.
145+
// The stored action chain will send keyboard inputs to the browser.
146+
selenium.StoreKeyActions("keyboard1",
147+
selenium.KeyDownAction(selenium.ControlKey),
148+
selenium.KeyPauseAction(50),
149+
selenium.KeyDownAction("a"),
150+
selenium.KeyPauseAction(50),
151+
selenium.KeyUpAction("a"),
152+
selenium.KeyUpAction(selenium.ControlKey),
153+
selenium.KeyDownAction("h"),
154+
selenium.KeyDownAction("e"),
155+
selenium.KeyDownAction("l"),
156+
selenium.KeyDownAction("l"),
157+
selenium.KeyDownAction("o"),
158+
)
159+
160+
// Call PerformActions to execute stored action - based on
161+
// the order of the previous calls, PointerActions will be
162+
// executed first and then KeyActions.
163+
if err := wd.PerformActions(); err != nil {
164+
panic(err)
165+
}
166+
167+
// Call ReleaseActions to release any PointerDown or
168+
// KeyDown Actions that haven't been released through an Action.
169+
if err := wd.ReleaseActions(); err != nil {
170+
panic(err)
171+
}
172+
112173
}

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@ require (
1313
github.com/google/go-github/v27 v27.0.4
1414
github.com/mediabuyerbot/go-crx3 v1.3.1
1515
google.golang.org/api v0.7.0
16-
)
16+
)

remote.go

+102-4
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,9 @@ var remoteErrors = map[int]string{
4949
type remoteWD struct {
5050
id, urlPrefix string
5151
capabilities Capabilities
52-
53-
w3cCompatible bool
52+
w3cCompatible bool
53+
// storedActions stores KeyActions and PointerActions for later execution.
54+
storedActions Actions
5455
browser string
5556
browserVersion semver.Version
5657
}
@@ -230,6 +231,7 @@ func NewRemote(capabilities Capabilities, urlPrefix string) (WebDriver, error) {
230231
if b := capabilities["browserName"]; b != nil {
231232
wd.browser = b.(string)
232233
}
234+
233235
if _, err := wd.NewSession(); err != nil {
234236
return nil, err
235237
}
@@ -1095,8 +1097,104 @@ func (wd *remoteWD) KeyUp(keys string) error {
10951097
return wd.keyAction("keyUp", keys)
10961098
}
10971099

1098-
// TODO(minusnine): Implement PerformActions and ReleaseActions, for more
1099-
// direct access to the W3C specification.
1100+
// KeyPauseAction builds a KeyAction which pauses for the supplied duration.
1101+
func KeyPauseAction(duration time.Duration) KeyAction {
1102+
return KeyAction{
1103+
"type": "pause",
1104+
"duration": uint(duration / time.Millisecond),
1105+
}
1106+
}
1107+
1108+
// KeyUpAction builds a KeyAction press.
1109+
func KeyUpAction(key string) KeyAction {
1110+
return KeyAction{
1111+
"type": "keyUp",
1112+
"value": key,
1113+
}
1114+
}
1115+
1116+
// KeyDownAction builds a KeyAction which presses and holds
1117+
// the specified key.
1118+
func KeyDownAction(key string) KeyAction {
1119+
return KeyAction{
1120+
"type": "keyDown",
1121+
"value": key,
1122+
}
1123+
}
1124+
1125+
// PointerPause builds a PointerAction which pauses for the supplied duration.
1126+
func PointerPauseAction(duration time.Duration) PointerAction {
1127+
return PointerAction{
1128+
"type": "pause",
1129+
"duration": uint(duration / time.Millisecond),
1130+
}
1131+
}
1132+
1133+
// PointerMove builds a PointerAction which moves the pointer.
1134+
func PointerMoveAction(duration time.Duration, offset Point, origin PointerMoveOrigin) PointerAction {
1135+
return PointerAction{
1136+
"type": "pointerMove",
1137+
"duration": uint(duration / time.Millisecond),
1138+
"origin": origin,
1139+
"x": offset.X,
1140+
"y": offset.Y,
1141+
}
1142+
}
1143+
1144+
// PointerUp builds an action which releases the specified pointer key.
1145+
func PointerUpAction(button MouseButton) PointerAction {
1146+
return PointerAction{
1147+
"type": "pointerUp",
1148+
"button": button,
1149+
}
1150+
}
1151+
1152+
// PointerDown builds a PointerAction which presses
1153+
// and holds the specified pointer key.
1154+
func PointerDownAction(button MouseButton) PointerAction {
1155+
return PointerAction{
1156+
"type": "pointerDown",
1157+
"button": button,
1158+
}
1159+
}
1160+
1161+
func (wd *remoteWD) StoreKeyActions(inputID string, actions ...KeyAction) {
1162+
rawActions := []map[string]interface{}{}
1163+
for _, action := range actions {
1164+
rawActions = append(rawActions, action)
1165+
}
1166+
wd.storedActions = append(wd.storedActions, map[string]interface{}{
1167+
"type": "key",
1168+
"id": inputID,
1169+
"actions": rawActions,
1170+
})
1171+
}
1172+
1173+
func (wd *remoteWD) StorePointerActions(inputID string, pointer PointerType, actions ...PointerAction) {
1174+
rawActions := []map[string]interface{}{}
1175+
for _, action := range actions {
1176+
rawActions = append(rawActions, action)
1177+
}
1178+
wd.storedActions = append(wd.storedActions, map[string]interface{}{
1179+
"type": "pointer",
1180+
"id": inputID,
1181+
"parameters": map[string]string{"pointerType": string(pointer)},
1182+
"actions": rawActions,
1183+
})
1184+
}
1185+
1186+
func (wd *remoteWD) PerformActions() error {
1187+
err := wd.voidCommand("/session/%s/actions", map[string]interface{}{
1188+
"actions": wd.storedActions,
1189+
})
1190+
wd.storedActions = nil
1191+
return err
1192+
}
1193+
1194+
func (wd *remoteWD) ReleaseActions() error {
1195+
return voidCommand("DELETE", wd.requestURL("/session/%s/actions", wd.id), nil)
1196+
}
1197+
11001198
func (wd *remoteWD) DismissAlert() error {
11011199
return wd.voidCommand("/session/%s/alert/dismiss", nil)
11021200
}

selenium.go

+53-1
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@ const (
2222
ByCSSSelector = "css selector"
2323
)
2424

25+
type MouseButton int
26+
2527
// Mouse buttons.
2628
const (
27-
LeftButton = iota
29+
LeftButton MouseButton = iota
2830
MiddleButton
2931
RightButton
3032
)
@@ -223,6 +225,36 @@ const (
223225
SameSiteEmpty SameSite = ""
224226
)
225227

228+
// PointerType is the type of pointer used by StorePointerActions.
229+
// There are 3 different types according to the WC3 implementation.
230+
type PointerType string
231+
232+
const (
233+
MousePointer PointerType = "mouse"
234+
PenPointer = "pen"
235+
TouchPointer = "touch"
236+
)
237+
238+
// PointerMoveOrigin controls how the offset for
239+
// the pointer move action is calculated.
240+
type PointerMoveOrigin string
241+
242+
const (
243+
// FromViewport calculates the offset from the viewport at 0,0.
244+
FromViewport PointerMoveOrigin = "viewport"
245+
// FromPointer calculates the offset from the current pointer position.
246+
FromPointer = "pointer"
247+
)
248+
249+
// KeyAction represents an activity involving a keyboard key.
250+
type KeyAction map[string]interface{}
251+
252+
// PointerAction represents an activity involving a pointer.
253+
type PointerAction map[string]interface{}
254+
255+
// Actions stores KeyActions and PointerActions for later execution.
256+
type Actions []map[string]interface{}
257+
226258
// WebDriver defines methods supported by WebDriver drivers.
227259
type WebDriver interface {
228260
// Status returns various pieces of information about the server environment.
@@ -330,6 +362,26 @@ type WebDriver interface {
330362
// ButtonUp causes the left mouse button to be released.
331363
ButtonUp() error
332364

365+
// StoreKeyActions store provided actions until they are executed
366+
// by PerformActions or released by ReleaseActions.
367+
// inputID is a string used as a unique virtual device identifier for this
368+
// and future actions, the value can be set to any valid string
369+
// and used to refer to this specific device in future calls.
370+
StoreKeyActions(inputID string, actions ...KeyAction)
371+
372+
// StorePointerActions store provided actions until they are executed
373+
// by PerformActions or released by ReleaseActions.
374+
// inputID is a string used as a unique virtual device identifier for this
375+
// and future actions, the value can be set to any valid string
376+
// and used to refer to this specific device in future calls.
377+
StorePointerActions(inputID string, pointer PointerType, actions ...PointerAction)
378+
379+
// PerformActions executes actions previously stored by calls to StorePointerActions and StoreKeyActions.
380+
PerformActions() error
381+
// ReleaseActions releases keys and pointer buttons if they are pressed,
382+
// triggering any events as if they were performed by a regular action.
383+
ReleaseActions() error
384+
333385
// SendModifier sends the modifier key to the active element. The modifier
334386
// can be one of ShiftKey, ControlKey, AltKey, MetaKey.
335387
//

0 commit comments

Comments
 (0)