selenium-webdriver 4.0.0-alpha.5 → 4.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/CHANGES.md +35 -1
  2. package/LICENSE +1 -1
  3. package/NOTICE +1 -1
  4. package/README.md +4 -4
  5. package/chrome.js +72 -592
  6. package/chromium.js +829 -0
  7. package/devtools/CDPConnection.js +37 -0
  8. package/edge.js +124 -86
  9. package/example/chrome_android.js +16 -13
  10. package/example/chrome_mobile_emulation.js +18 -14
  11. package/example/firefox_channels.js +35 -28
  12. package/example/google_search.js +9 -9
  13. package/example/google_search_test.js +20 -22
  14. package/example/headless.js +27 -19
  15. package/example/logging.js +34 -38
  16. package/firefox.js +200 -200
  17. package/http/index.js +131 -115
  18. package/http/util.js +56 -64
  19. package/ie.js +180 -104
  20. package/index.js +246 -199
  21. package/io/exec.js +34 -39
  22. package/io/index.js +142 -152
  23. package/io/zip.js +75 -65
  24. package/lib/actions.js +140 -122
  25. package/lib/atoms/find-elements.js +124 -0
  26. package/lib/atoms/get-attribute.js +79 -59
  27. package/lib/atoms/is-displayed.js +72 -73
  28. package/lib/atoms/mutation-listener.js +38 -0
  29. package/lib/by.js +192 -65
  30. package/lib/capabilities.js +82 -78
  31. package/lib/command.js +20 -20
  32. package/lib/error.js +134 -168
  33. package/lib/http.js +337 -230
  34. package/lib/input.js +325 -302
  35. package/lib/logging.js +127 -138
  36. package/lib/promise.js +60 -66
  37. package/lib/proxy.js +31 -41
  38. package/lib/session.js +12 -15
  39. package/lib/symbols.js +3 -4
  40. package/lib/until.js +162 -160
  41. package/lib/webdriver.js +1024 -541
  42. package/net/index.js +30 -36
  43. package/net/portprober.js +31 -144
  44. package/opera.js +406 -0
  45. package/package.json +19 -12
  46. package/proxy.js +2 -2
  47. package/remote/index.js +190 -187
  48. package/safari.js +40 -49
  49. package/testing/index.js +166 -155
package/lib/http.js CHANGED
@@ -23,21 +23,28 @@
23
23
  * the {@link Executor} to send commands to the remote end.
24
24
  */
25
25
 
26
- 'use strict';
26
+ 'use strict'
27
27
 
28
- const cmd = require('./command');
29
- const error = require('./error');
30
- const logging = require('./logging');
31
- const promise = require('./promise');
32
- const {Session} = require('./session');
33
- const {WebElement} = require('./webdriver');
28
+ const path = require('path')
29
+ const cmd = require('./command')
30
+ const error = require('./error')
31
+ const logging = require('./logging')
32
+ const promise = require('./promise')
33
+ const { Session } = require('./session')
34
+ const { WebElement } = require('./webdriver')
34
35
 
35
36
  const getAttribute = requireAtom(
36
- './atoms/get-attribute.js',
37
- '//javascript/node/selenium-webdriver/lib/atoms:get-attribute.js');
37
+ 'get-attribute.js',
38
+ '//javascript/node/selenium-webdriver/lib/atoms:get-attribute.js'
39
+ )
38
40
  const isDisplayed = requireAtom(
39
- './atoms/is-displayed.js',
40
- '//javascript/node/selenium-webdriver/lib/atoms:is-displayed.js');
41
+ 'is-displayed.js',
42
+ '//javascript/node/selenium-webdriver/lib/atoms:is-displayed.js'
43
+ )
44
+ const findElements = requireAtom(
45
+ 'find-elements.js',
46
+ '//javascript/node/selenium-webdriver/lib/atoms:find-elements.js'
47
+ )
41
48
 
42
49
  /**
43
50
  * @param {string} module
@@ -46,36 +53,36 @@ const isDisplayed = requireAtom(
46
53
  */
47
54
  function requireAtom(module, bazelTarget) {
48
55
  try {
49
- return require(module);
56
+ return require('./atoms/' + module)
50
57
  } catch (ex) {
51
58
  try {
52
- const file = bazelTarget.slice(2).replace(':', '/');
53
- return require(`../../../../bazel-genfiles/${file}`);
59
+ const file = bazelTarget.slice(2).replace(':', '/')
60
+ console.log(`../../../bazel-bin/${file}`)
61
+ return require(path.resolve(`../../../bazel-bin/${file}`))
54
62
  } catch (ex2) {
55
- console.log(ex2);
63
+ console.log(ex2)
56
64
  throw Error(
57
- `Failed to import atoms module ${module}. If running in dev mode, you`
58
- + ` need to run \`bazel build ${bazelTarget}\` from the project`
59
- + `root: ${ex}`);
65
+ `Failed to import atoms module ${module}. If running in dev mode, you` +
66
+ ` need to run \`bazel build ${bazelTarget}\` from the project` +
67
+ `root: ${ex}`
68
+ )
60
69
  }
61
70
  }
62
71
  }
63
72
 
64
-
65
73
  /**
66
74
  * Converts a headers map to a HTTP header block string.
67
75
  * @param {!Map<string, string>} headers The map to convert.
68
76
  * @return {string} The headers as a string.
69
77
  */
70
78
  function headersToString(headers) {
71
- let ret = [];
72
- headers.forEach(function(value, name) {
73
- ret.push(`${name.toLowerCase()}: ${value}`);
74
- });
75
- return ret.join('\n');
79
+ const ret = []
80
+ headers.forEach(function (value, name) {
81
+ ret.push(`${name.toLowerCase()}: ${value}`)
82
+ })
83
+ return ret.join('\n')
76
84
  }
77
85
 
78
-
79
86
  /**
80
87
  * Represents a HTTP request message. This class is a "partial" request and only
81
88
  * defines the path on the server to send a request to. It is each client's
@@ -89,25 +96,25 @@ class Request {
89
96
  * @param {Object=} opt_data This request's non-serialized JSON payload data.
90
97
  */
91
98
  constructor(method, path, opt_data) {
92
- this.method = /** string */method;
93
- this.path = /** string */path;
94
- this.data = /** Object */opt_data;
95
- this.headers = /** !Map<string, string> */new Map(
96
- [['Accept', 'application/json; charset=utf-8']]);
99
+ this.method = /** string */ method
100
+ this.path = /** string */ path
101
+ this.data = /** Object */ opt_data
102
+ this.headers = /** !Map<string, string> */ new Map([
103
+ ['Accept', 'application/json; charset=utf-8'],
104
+ ])
97
105
  }
98
106
 
99
107
  /** @override */
100
108
  toString() {
101
- let ret = `${this.method} ${this.path} HTTP/1.1\n`;
102
- ret += headersToString(this.headers) + '\n\n';
109
+ let ret = `${this.method} ${this.path} HTTP/1.1\n`
110
+ ret += headersToString(this.headers) + '\n\n'
103
111
  if (this.data) {
104
- ret += JSON.stringify(this.data);
112
+ ret += JSON.stringify(this.data)
105
113
  }
106
- return ret;
114
+ return ret
107
115
  }
108
116
  }
109
117
 
110
-
111
118
  /**
112
119
  * Represents a HTTP response message.
113
120
  * @final
@@ -120,54 +127,54 @@ class Response {
120
127
  * @param {string} body The response body.
121
128
  */
122
129
  constructor(status, headers, body) {
123
- this.status = /** number */status;
124
- this.body = /** string */body;
125
- this.headers = /** !Map<string, string>*/new Map;
130
+ this.status = /** number */ status
131
+ this.body = /** string */ body
132
+ this.headers = /** !Map<string, string>*/ new Map()
126
133
  for (let header in headers) {
127
- this.headers.set(header.toLowerCase(), headers[header]);
134
+ this.headers.set(header.toLowerCase(), headers[header])
128
135
  }
129
136
  }
130
137
 
131
138
  /** @override */
132
139
  toString() {
133
- let ret = `HTTP/1.1 ${this.status}\n${headersToString(this.headers)}\n\n`;
140
+ let ret = `HTTP/1.1 ${this.status}\n${headersToString(this.headers)}\n\n`
134
141
  if (this.body) {
135
- ret += this.body;
142
+ ret += this.body
136
143
  }
137
- return ret;
144
+ return ret
138
145
  }
139
146
  }
140
147
 
141
-
142
- const DEV_ROOT = '../../../../buck-out/gen/javascript/';
143
-
144
148
  /** @enum {!Function} */
145
149
  const Atom = {
146
150
  GET_ATTRIBUTE: getAttribute,
147
- IS_DISPLAYED: isDisplayed
148
- };
149
-
150
-
151
- const LOG = logging.getLogger('webdriver.http');
152
-
151
+ IS_DISPLAYED: isDisplayed,
152
+ FIND_ELEMENTS: findElements,
153
+ }
153
154
 
154
- function post(path) { return resource('POST', path); }
155
- function del(path) { return resource('DELETE', path); }
156
- function get(path) { return resource('GET', path); }
157
- function resource(method, path) { return {method: method, path: path}; }
155
+ const LOG = logging.getLogger('webdriver.http')
158
156
 
157
+ function post(path) {
158
+ return resource('POST', path)
159
+ }
160
+ function del(path) {
161
+ return resource('DELETE', path)
162
+ }
163
+ function get(path) {
164
+ return resource('GET', path)
165
+ }
166
+ function resource(method, path) {
167
+ return { method: method, path: path }
168
+ }
159
169
 
160
170
  /** @typedef {{method: string, path: string}} */
161
- var CommandSpec;
162
-
171
+ var CommandSpec // eslint-disable-line
163
172
 
164
173
  /** @typedef {function(!cmd.Command): !cmd.Command} */
165
- var CommandTransformer;
166
-
174
+ var CommandTransformer // eslint-disable-line
167
175
 
168
176
  class InternalTypeError extends TypeError {}
169
177
 
170
-
171
178
  /**
172
179
  * @param {!cmd.Command} command The initial command.
173
180
  * @param {Atom} atom The name of the atom to execute.
@@ -175,93 +182,159 @@ class InternalTypeError extends TypeError {}
175
182
  */
176
183
  function toExecuteAtomCommand(command, atom, ...params) {
177
184
  if (typeof atom !== 'function') {
178
- throw new InternalTypeError('atom is not a function: ' + typeof atom);
185
+ throw new InternalTypeError('atom is not a function: ' + typeof atom)
179
186
  }
180
187
 
181
188
  return new cmd.Command(cmd.Name.EXECUTE_SCRIPT)
182
- .setParameter('sessionId', command.getParameter('sessionId'))
183
- .setParameter('script', `return (${atom}).apply(null, arguments)`)
184
- .setParameter('args', params.map(param => command.getParameter(param)));
189
+ .setParameter('sessionId', command.getParameter('sessionId'))
190
+ .setParameter('script', `return (${atom}).apply(null, arguments)`)
191
+ .setParameter(
192
+ 'args',
193
+ params.map((param) => command.getParameter(param))
194
+ )
185
195
  }
186
196
 
187
-
188
-
189
197
  /** @const {!Map<string, CommandSpec>} */
190
198
  const COMMAND_MAP = new Map([
191
- [cmd.Name.GET_SERVER_STATUS, get('/status')],
192
- [cmd.Name.NEW_SESSION, post('/session')],
193
- [cmd.Name.GET_SESSIONS, get('/sessions')],
194
- [cmd.Name.QUIT, del('/session/:sessionId')],
195
- [cmd.Name.CLOSE, del('/session/:sessionId/window')],
196
- [cmd.Name.GET_CURRENT_WINDOW_HANDLE, get('/session/:sessionId/window_handle')],
197
- [cmd.Name.GET_WINDOW_HANDLES, get('/session/:sessionId/window_handles')],
198
- [cmd.Name.GET_CURRENT_URL, get('/session/:sessionId/url')],
199
- [cmd.Name.GET, post('/session/:sessionId/url')],
200
- [cmd.Name.GO_BACK, post('/session/:sessionId/back')],
201
- [cmd.Name.GO_FORWARD, post('/session/:sessionId/forward')],
202
- [cmd.Name.REFRESH, post('/session/:sessionId/refresh')],
203
- [cmd.Name.ADD_COOKIE, post('/session/:sessionId/cookie')],
204
- [cmd.Name.GET_ALL_COOKIES, get('/session/:sessionId/cookie')],
205
- [cmd.Name.DELETE_ALL_COOKIES, del('/session/:sessionId/cookie')],
206
- [cmd.Name.DELETE_COOKIE, del('/session/:sessionId/cookie/:name')],
207
- [cmd.Name.FIND_ELEMENT, post('/session/:sessionId/element')],
208
- [cmd.Name.FIND_ELEMENTS, post('/session/:sessionId/elements')],
209
- [cmd.Name.GET_ACTIVE_ELEMENT, post('/session/:sessionId/element/active')],
210
- [cmd.Name.FIND_CHILD_ELEMENT, post('/session/:sessionId/element/:id/element')],
211
- [cmd.Name.FIND_CHILD_ELEMENTS, post('/session/:sessionId/element/:id/elements')],
212
- [cmd.Name.CLEAR_ELEMENT, post('/session/:sessionId/element/:id/clear')],
213
- [cmd.Name.CLICK_ELEMENT, post('/session/:sessionId/element/:id/click')],
214
- [cmd.Name.SEND_KEYS_TO_ELEMENT, post('/session/:sessionId/element/:id/value')],
215
- [cmd.Name.SUBMIT_ELEMENT, post('/session/:sessionId/element/:id/submit')],
216
- [cmd.Name.GET_ELEMENT_TEXT, get('/session/:sessionId/element/:id/text')],
217
- [cmd.Name.GET_ELEMENT_TAG_NAME, get('/session/:sessionId/element/:id/name')],
218
- [cmd.Name.IS_ELEMENT_SELECTED, get('/session/:sessionId/element/:id/selected')],
219
- [cmd.Name.IS_ELEMENT_ENABLED, get('/session/:sessionId/element/:id/enabled')],
220
- [cmd.Name.IS_ELEMENT_DISPLAYED, get('/session/:sessionId/element/:id/displayed')],
221
- [cmd.Name.GET_ELEMENT_LOCATION, get('/session/:sessionId/element/:id/location')],
222
- [cmd.Name.GET_ELEMENT_SIZE, get('/session/:sessionId/element/:id/size')],
223
- [cmd.Name.GET_ELEMENT_ATTRIBUTE, get('/session/:sessionId/element/:id/attribute/:name')],
224
- [cmd.Name.GET_ELEMENT_VALUE_OF_CSS_PROPERTY, get('/session/:sessionId/element/:id/css/:propertyName')],
225
- [cmd.Name.TAKE_ELEMENT_SCREENSHOT, get('/session/:sessionId/element/:id/screenshot')],
226
- [cmd.Name.SWITCH_TO_WINDOW, post('/session/:sessionId/window')],
227
- [cmd.Name.MAXIMIZE_WINDOW, post('/session/:sessionId/window/current/maximize')],
228
- [cmd.Name.GET_WINDOW_POSITION, get('/session/:sessionId/window/current/position')],
229
- [cmd.Name.SET_WINDOW_POSITION, post('/session/:sessionId/window/current/position')],
230
- [cmd.Name.GET_WINDOW_SIZE, get('/session/:sessionId/window/current/size')],
231
- [cmd.Name.SET_WINDOW_SIZE, post('/session/:sessionId/window/current/size')],
232
- [cmd.Name.SWITCH_TO_FRAME, post('/session/:sessionId/frame')],
233
- [cmd.Name.SWITCH_TO_FRAME_PARENT, post('/session/:sessionId/frame/parent')],
234
- [cmd.Name.GET_PAGE_SOURCE, get('/session/:sessionId/source')],
235
- [cmd.Name.GET_TITLE, get('/session/:sessionId/title')],
236
- [cmd.Name.EXECUTE_SCRIPT, post('/session/:sessionId/execute')],
237
- [cmd.Name.EXECUTE_ASYNC_SCRIPT, post('/session/:sessionId/execute_async')],
238
- [cmd.Name.SCREENSHOT, get('/session/:sessionId/screenshot')],
239
- [cmd.Name.GET_TIMEOUT, get('/session/:sessionId/timeouts')],
240
- [cmd.Name.SET_TIMEOUT, post('/session/:sessionId/timeouts')],
241
- [cmd.Name.ACCEPT_ALERT, post('/session/:sessionId/accept_alert')],
242
- [cmd.Name.DISMISS_ALERT, post('/session/:sessionId/dismiss_alert')],
243
- [cmd.Name.GET_ALERT_TEXT, get('/session/:sessionId/alert_text')],
244
- [cmd.Name.SET_ALERT_TEXT, post('/session/:sessionId/alert_text')],
245
- [cmd.Name.GET_LOG, post('/session/:sessionId/log')],
246
- [cmd.Name.GET_AVAILABLE_LOG_TYPES, get('/session/:sessionId/log/types')],
247
- [cmd.Name.GET_SESSION_LOGS, post('/logs')],
248
- [cmd.Name.UPLOAD_FILE, post('/session/:sessionId/file')],
249
- [cmd.Name.LEGACY_ACTION_CLICK, post('/session/:sessionId/click')],
250
- [cmd.Name.LEGACY_ACTION_DOUBLE_CLICK, post('/session/:sessionId/doubleclick')],
251
- [cmd.Name.LEGACY_ACTION_MOUSE_DOWN, post('/session/:sessionId/buttondown')],
252
- [cmd.Name.LEGACY_ACTION_MOUSE_UP, post('/session/:sessionId/buttonup')],
253
- [cmd.Name.LEGACY_ACTION_MOUSE_MOVE, post('/session/:sessionId/moveto')],
254
- [cmd.Name.LEGACY_ACTION_SEND_KEYS, post('/session/:sessionId/keys')],
255
- [cmd.Name.LEGACY_ACTION_TOUCH_DOWN, post('/session/:sessionId/touch/down')],
256
- [cmd.Name.LEGACY_ACTION_TOUCH_UP, post('/session/:sessionId/touch/up')],
257
- [cmd.Name.LEGACY_ACTION_TOUCH_MOVE, post('/session/:sessionId/touch/move')],
258
- [cmd.Name.LEGACY_ACTION_TOUCH_SCROLL, post('/session/:sessionId/touch/scroll')],
259
- [cmd.Name.LEGACY_ACTION_TOUCH_LONG_PRESS, post('/session/:sessionId/touch/longclick')],
260
- [cmd.Name.LEGACY_ACTION_TOUCH_FLICK, post('/session/:sessionId/touch/flick')],
261
- [cmd.Name.LEGACY_ACTION_TOUCH_SINGLE_TAP, post('/session/:sessionId/touch/click')],
262
- [cmd.Name.LEGACY_ACTION_TOUCH_DOUBLE_TAP, post('/session/:sessionId/touch/doubleclick')],
263
- ]);
264
-
199
+ [cmd.Name.GET_SERVER_STATUS, get('/status')],
200
+ [cmd.Name.NEW_SESSION, post('/session')],
201
+ [cmd.Name.GET_SESSIONS, get('/sessions')],
202
+ [cmd.Name.QUIT, del('/session/:sessionId')],
203
+ [cmd.Name.CLOSE, del('/session/:sessionId/window')],
204
+ [
205
+ cmd.Name.GET_CURRENT_WINDOW_HANDLE,
206
+ get('/session/:sessionId/window_handle'),
207
+ ],
208
+ [cmd.Name.GET_WINDOW_HANDLES, get('/session/:sessionId/window_handles')],
209
+ [cmd.Name.GET_CURRENT_URL, get('/session/:sessionId/url')],
210
+ [cmd.Name.GET, post('/session/:sessionId/url')],
211
+ [cmd.Name.GO_BACK, post('/session/:sessionId/back')],
212
+ [cmd.Name.GO_FORWARD, post('/session/:sessionId/forward')],
213
+ [cmd.Name.REFRESH, post('/session/:sessionId/refresh')],
214
+ [cmd.Name.ADD_COOKIE, post('/session/:sessionId/cookie')],
215
+ [cmd.Name.GET_ALL_COOKIES, get('/session/:sessionId/cookie')],
216
+ [cmd.Name.DELETE_ALL_COOKIES, del('/session/:sessionId/cookie')],
217
+ [cmd.Name.DELETE_COOKIE, del('/session/:sessionId/cookie/:name')],
218
+ [cmd.Name.FIND_ELEMENT, post('/session/:sessionId/element')],
219
+ [cmd.Name.FIND_ELEMENTS, post('/session/:sessionId/elements')],
220
+ [cmd.Name.GET_ACTIVE_ELEMENT, post('/session/:sessionId/element/active')],
221
+ [
222
+ cmd.Name.FIND_CHILD_ELEMENT,
223
+ post('/session/:sessionId/element/:id/element'),
224
+ ],
225
+ [
226
+ cmd.Name.FIND_CHILD_ELEMENTS,
227
+ post('/session/:sessionId/element/:id/elements'),
228
+ ],
229
+ [cmd.Name.CLEAR_ELEMENT, post('/session/:sessionId/element/:id/clear')],
230
+ [cmd.Name.CLICK_ELEMENT, post('/session/:sessionId/element/:id/click')],
231
+ [
232
+ cmd.Name.SEND_KEYS_TO_ELEMENT,
233
+ post('/session/:sessionId/element/:id/value'),
234
+ ],
235
+ [cmd.Name.SUBMIT_ELEMENT, post('/session/:sessionId/element/:id/submit')],
236
+ [cmd.Name.GET_ELEMENT_TEXT, get('/session/:sessionId/element/:id/text')],
237
+ [
238
+ cmd.Name.GET_COMPUTED_ROLE,
239
+ get('/session/:sessionId/element/:id/computedrole'),
240
+ ],
241
+ [
242
+ cmd.Name.GET_COMPUTED_LABEL,
243
+ get('/session/:sessionId/element/:id/computedlabel'),
244
+ ],
245
+ [cmd.Name.GET_ELEMENT_TAG_NAME, get('/session/:sessionId/element/:id/name')],
246
+ [
247
+ cmd.Name.IS_ELEMENT_SELECTED,
248
+ get('/session/:sessionId/element/:id/selected'),
249
+ ],
250
+ [cmd.Name.IS_ELEMENT_ENABLED, get('/session/:sessionId/element/:id/enabled')],
251
+ [
252
+ cmd.Name.IS_ELEMENT_DISPLAYED,
253
+ get('/session/:sessionId/element/:id/displayed'),
254
+ ],
255
+ [
256
+ cmd.Name.GET_ELEMENT_LOCATION,
257
+ get('/session/:sessionId/element/:id/location'),
258
+ ],
259
+ [cmd.Name.GET_ELEMENT_SIZE, get('/session/:sessionId/element/:id/size')],
260
+ [
261
+ cmd.Name.GET_ELEMENT_ATTRIBUTE,
262
+ get('/session/:sessionId/element/:id/attribute/:name'),
263
+ ],
264
+ [
265
+ cmd.Name.GET_ELEMENT_PROPERTY,
266
+ get('/session/:sessionId/element/:id/property/:name'),
267
+ ],
268
+ [
269
+ cmd.Name.GET_ELEMENT_VALUE_OF_CSS_PROPERTY,
270
+ get('/session/:sessionId/element/:id/css/:propertyName'),
271
+ ],
272
+ [
273
+ cmd.Name.TAKE_ELEMENT_SCREENSHOT,
274
+ get('/session/:sessionId/element/:id/screenshot'),
275
+ ],
276
+ [cmd.Name.SWITCH_TO_WINDOW, post('/session/:sessionId/window')],
277
+ [
278
+ cmd.Name.MAXIMIZE_WINDOW,
279
+ post('/session/:sessionId/window/current/maximize'),
280
+ ],
281
+ [
282
+ cmd.Name.GET_WINDOW_POSITION,
283
+ get('/session/:sessionId/window/current/position'),
284
+ ],
285
+ [
286
+ cmd.Name.SET_WINDOW_POSITION,
287
+ post('/session/:sessionId/window/current/position'),
288
+ ],
289
+ [cmd.Name.GET_WINDOW_SIZE, get('/session/:sessionId/window/current/size')],
290
+ [cmd.Name.SET_WINDOW_SIZE, post('/session/:sessionId/window/current/size')],
291
+ [cmd.Name.SWITCH_TO_FRAME, post('/session/:sessionId/frame')],
292
+ [cmd.Name.SWITCH_TO_FRAME_PARENT, post('/session/:sessionId/frame/parent')],
293
+ [cmd.Name.GET_PAGE_SOURCE, get('/session/:sessionId/source')],
294
+ [cmd.Name.GET_TITLE, get('/session/:sessionId/title')],
295
+ [cmd.Name.EXECUTE_SCRIPT, post('/session/:sessionId/execute')],
296
+ [cmd.Name.EXECUTE_ASYNC_SCRIPT, post('/session/:sessionId/execute_async')],
297
+ [cmd.Name.SCREENSHOT, get('/session/:sessionId/screenshot')],
298
+ [cmd.Name.GET_TIMEOUT, get('/session/:sessionId/timeouts')],
299
+ [cmd.Name.SET_TIMEOUT, post('/session/:sessionId/timeouts')],
300
+ [cmd.Name.ACCEPT_ALERT, post('/session/:sessionId/accept_alert')],
301
+ [cmd.Name.DISMISS_ALERT, post('/session/:sessionId/dismiss_alert')],
302
+ [cmd.Name.GET_ALERT_TEXT, get('/session/:sessionId/alert_text')],
303
+ [cmd.Name.SET_ALERT_TEXT, post('/session/:sessionId/alert_text')],
304
+ [cmd.Name.GET_LOG, post('/session/:sessionId/log')],
305
+ [cmd.Name.GET_AVAILABLE_LOG_TYPES, get('/session/:sessionId/log/types')],
306
+ [cmd.Name.GET_SESSION_LOGS, post('/logs')],
307
+ [cmd.Name.UPLOAD_FILE, post('/session/:sessionId/se/file')],
308
+ [cmd.Name.LEGACY_ACTION_CLICK, post('/session/:sessionId/click')],
309
+ [
310
+ cmd.Name.LEGACY_ACTION_DOUBLE_CLICK,
311
+ post('/session/:sessionId/doubleclick'),
312
+ ],
313
+ [cmd.Name.LEGACY_ACTION_MOUSE_DOWN, post('/session/:sessionId/buttondown')],
314
+ [cmd.Name.LEGACY_ACTION_MOUSE_UP, post('/session/:sessionId/buttonup')],
315
+ [cmd.Name.LEGACY_ACTION_MOUSE_MOVE, post('/session/:sessionId/moveto')],
316
+ [cmd.Name.LEGACY_ACTION_SEND_KEYS, post('/session/:sessionId/keys')],
317
+ [cmd.Name.LEGACY_ACTION_TOUCH_DOWN, post('/session/:sessionId/touch/down')],
318
+ [cmd.Name.LEGACY_ACTION_TOUCH_UP, post('/session/:sessionId/touch/up')],
319
+ [cmd.Name.LEGACY_ACTION_TOUCH_MOVE, post('/session/:sessionId/touch/move')],
320
+ [
321
+ cmd.Name.LEGACY_ACTION_TOUCH_SCROLL,
322
+ post('/session/:sessionId/touch/scroll'),
323
+ ],
324
+ [
325
+ cmd.Name.LEGACY_ACTION_TOUCH_LONG_PRESS,
326
+ post('/session/:sessionId/touch/longclick'),
327
+ ],
328
+ [cmd.Name.LEGACY_ACTION_TOUCH_FLICK, post('/session/:sessionId/touch/flick')],
329
+ [
330
+ cmd.Name.LEGACY_ACTION_TOUCH_SINGLE_TAP,
331
+ post('/session/:sessionId/touch/click'),
332
+ ],
333
+ [
334
+ cmd.Name.LEGACY_ACTION_TOUCH_DOUBLE_TAP,
335
+ post('/session/:sessionId/touch/doubleclick'),
336
+ ],
337
+ ])
265
338
 
266
339
  /** @const {!Map<string, (CommandSpec|CommandTransformer)>} */
267
340
  const W3C_COMMAND_MAP = new Map([
@@ -305,23 +378,59 @@ const W3C_COMMAND_MAP = new Map([
305
378
  [cmd.Name.GET_ACTIVE_ELEMENT, get('/session/:sessionId/element/active')],
306
379
  [cmd.Name.FIND_ELEMENT, post('/session/:sessionId/element')],
307
380
  [cmd.Name.FIND_ELEMENTS, post('/session/:sessionId/elements')],
308
- [cmd.Name.FIND_CHILD_ELEMENT, post('/session/:sessionId/element/:id/element')],
309
- [cmd.Name.FIND_CHILD_ELEMENTS, post('/session/:sessionId/element/:id/elements')],
381
+ [
382
+ cmd.Name.FIND_ELEMENTS_RELATIVE,
383
+ (cmd) => {
384
+ return toExecuteAtomCommand(cmd, Atom.FIND_ELEMENTS, 'args')
385
+ },
386
+ ],
387
+ [
388
+ cmd.Name.FIND_CHILD_ELEMENT,
389
+ post('/session/:sessionId/element/:id/element'),
390
+ ],
391
+ [
392
+ cmd.Name.FIND_CHILD_ELEMENTS,
393
+ post('/session/:sessionId/element/:id/elements'),
394
+ ],
310
395
  // Element interaction.
311
396
  [cmd.Name.GET_ELEMENT_TAG_NAME, get('/session/:sessionId/element/:id/name')],
312
- [cmd.Name.GET_ELEMENT_VALUE_OF_CSS_PROPERTY, get('/session/:sessionId/element/:id/css/:propertyName')],
397
+ [
398
+ cmd.Name.GET_ELEMENT_PROPERTY,
399
+ get('/session/:sessionId/element/:id/property/:name'),
400
+ ],
401
+ [
402
+ cmd.Name.GET_ELEMENT_VALUE_OF_CSS_PROPERTY,
403
+ get('/session/:sessionId/element/:id/css/:propertyName'),
404
+ ],
313
405
  [cmd.Name.GET_ELEMENT_RECT, get('/session/:sessionId/element/:id/rect')],
314
406
  [cmd.Name.CLEAR_ELEMENT, post('/session/:sessionId/element/:id/clear')],
315
407
  [cmd.Name.CLICK_ELEMENT, post('/session/:sessionId/element/:id/click')],
316
- [cmd.Name.SEND_KEYS_TO_ELEMENT, post('/session/:sessionId/element/:id/value')],
408
+ [
409
+ cmd.Name.SEND_KEYS_TO_ELEMENT,
410
+ post('/session/:sessionId/element/:id/value'),
411
+ ],
317
412
  [cmd.Name.GET_ELEMENT_TEXT, get('/session/:sessionId/element/:id/text')],
413
+ [
414
+ cmd.Name.GET_COMPUTED_ROLE,
415
+ get('/session/:sessionId/element/:id/computedrole'),
416
+ ],
417
+ [
418
+ cmd.Name.GET_COMPUTED_LABEL,
419
+ get('/session/:sessionId/element/:id/computedlabel'),
420
+ ],
318
421
  [cmd.Name.IS_ELEMENT_ENABLED, get('/session/:sessionId/element/:id/enabled')],
319
- [cmd.Name.GET_ELEMENT_ATTRIBUTE, (cmd) => {
320
- return toExecuteAtomCommand(cmd, Atom.GET_ATTRIBUTE, 'id', 'name');
321
- }],
322
- [cmd.Name.IS_ELEMENT_DISPLAYED, (cmd) => {
323
- return toExecuteAtomCommand(cmd, Atom.IS_DISPLAYED, 'id');
324
- }],
422
+ [
423
+ cmd.Name.GET_ELEMENT_ATTRIBUTE,
424
+ (cmd) => {
425
+ return toExecuteAtomCommand(cmd, Atom.GET_ATTRIBUTE, 'id', 'name')
426
+ },
427
+ ],
428
+ [
429
+ cmd.Name.IS_ELEMENT_DISPLAYED,
430
+ (cmd) => {
431
+ return toExecuteAtomCommand(cmd, Atom.IS_DISPLAYED, 'id')
432
+ },
433
+ ],
325
434
  // Cookie management.
326
435
  [cmd.Name.GET_ALL_COOKIES, get('/session/:sessionId/cookie')],
327
436
  [cmd.Name.ADD_COOKIE, post('/session/:sessionId/cookie')],
@@ -335,12 +444,16 @@ const W3C_COMMAND_MAP = new Map([
335
444
  [cmd.Name.SET_ALERT_TEXT, post('/session/:sessionId/alert/text')],
336
445
  // Screenshots.
337
446
  [cmd.Name.SCREENSHOT, get('/session/:sessionId/screenshot')],
338
- [cmd.Name.TAKE_ELEMENT_SCREENSHOT, get('/session/:sessionId/element/:id/screenshot')],
447
+ [
448
+ cmd.Name.TAKE_ELEMENT_SCREENSHOT,
449
+ get('/session/:sessionId/element/:id/screenshot'),
450
+ ],
451
+ // print page.
452
+ [cmd.Name.PRINT_PAGE, post('/session/:sessionId/print')],
339
453
  // Log extensions.
340
454
  [cmd.Name.GET_LOG, post('/session/:sessionId/se/log')],
341
455
  [cmd.Name.GET_AVAILABLE_LOG_TYPES, get('/session/:sessionId/se/log/types')],
342
- ]);
343
-
456
+ ])
344
457
 
345
458
  /**
346
459
  * Handles sending HTTP messages to a remote end.
@@ -348,7 +461,6 @@ const W3C_COMMAND_MAP = new Map([
348
461
  * @interface
349
462
  */
350
463
  class Client {
351
-
352
464
  /**
353
465
  * Sends a request to the server. The client will automatically follow any
354
466
  * redirects returned by the server, fulfilling the returned promise with the
@@ -358,11 +470,9 @@ class Client {
358
470
  * @return {!Promise<Response>} A promise that will be fulfilled with the
359
471
  * server's response.
360
472
  */
361
- send(httpRequest) {}
473
+ send(httpRequest) {} // eslint-disable-line
362
474
  }
363
475
 
364
-
365
-
366
476
  /**
367
477
  * @param {Map<string, CommandSpec>} customCommands
368
478
  * A map of custom command definitions.
@@ -372,46 +482,44 @@ class Client {
372
482
  * command to execute.
373
483
  */
374
484
  function buildRequest(customCommands, w3c, command) {
375
- LOG.finest(() => `Translating command: ${command.getName()}`);
376
- let spec = customCommands && customCommands.get(command.getName());
485
+ LOG.finest(() => `Translating command: ${command.getName()}`)
486
+ let spec = customCommands && customCommands.get(command.getName())
377
487
  if (spec) {
378
- return toHttpRequest(spec);
488
+ return toHttpRequest(spec)
379
489
  }
380
490
 
381
491
  if (w3c) {
382
- spec = W3C_COMMAND_MAP.get(command.getName());
492
+ spec = W3C_COMMAND_MAP.get(command.getName())
383
493
  if (typeof spec === 'function') {
384
- LOG.finest(() => `Transforming command for W3C: ${command.getName()}`);
385
- let newCommand = spec(command);
386
- return buildRequest(customCommands, w3c, newCommand);
494
+ LOG.finest(() => `Transforming command for W3C: ${command.getName()}`)
495
+ let newCommand = spec(command)
496
+ return buildRequest(customCommands, w3c, newCommand)
387
497
  } else if (spec) {
388
- return toHttpRequest(spec);
498
+ return toHttpRequest(spec)
389
499
  }
390
500
  }
391
501
 
392
- spec = COMMAND_MAP.get(command.getName());
502
+ spec = COMMAND_MAP.get(command.getName())
393
503
  if (spec) {
394
- return toHttpRequest(spec);
504
+ return toHttpRequest(spec)
395
505
  }
396
506
  throw new error.UnknownCommandError(
397
- 'Unrecognized command: ' + command.getName());
507
+ 'Unrecognized command: ' + command.getName()
508
+ )
398
509
 
399
510
  /**
400
511
  * @param {CommandSpec} resource
401
512
  * @return {!Request}
402
513
  */
403
514
  function toHttpRequest(resource) {
404
- LOG.finest(() => `Building HTTP request: ${JSON.stringify(resource)}`);
405
- let parameters = command.getParameters();
406
- let path = buildPath(resource.path, parameters);
407
- return new Request(resource.method, path, parameters);
515
+ LOG.finest(() => `Building HTTP request: ${JSON.stringify(resource)}`)
516
+ let parameters = command.getParameters()
517
+ let path = buildPath(resource.path, parameters)
518
+ return new Request(resource.method, path, parameters)
408
519
  }
409
520
  }
410
521
 
411
-
412
- const CLIENTS =
413
- /** !WeakMap<!Executor, !(Client|IThenable<!Client>)> */new WeakMap;
414
-
522
+ const CLIENTS = /** !WeakMap<!Executor, !(Client|IThenable<!Client>)> */ new WeakMap()
415
523
 
416
524
  /**
417
525
  * A command executor that communicates with the server using JSON over HTTP.
@@ -433,7 +541,7 @@ class Executor {
433
541
  * to the client.
434
542
  */
435
543
  constructor(client) {
436
- CLIENTS.set(this, client);
544
+ CLIENTS.set(this, client)
437
545
 
438
546
  /**
439
547
  * Whether this executor should use the W3C wire protocol. The executor
@@ -442,13 +550,13 @@ class Executor {
442
550
  * `true` to force the executor into W3C mode.
443
551
  * @type {boolean}
444
552
  */
445
- this.w3c = false;
553
+ this.w3c = false
446
554
 
447
555
  /** @private {Map<string, CommandSpec>} */
448
- this.customCommands_ = null;
556
+ this.customCommands_ = null
449
557
 
450
558
  /** @private {!logging.Logger} */
451
- this.log_ = logging.getLogger('webdriver.http.Executor');
559
+ this.log_ = logging.getLogger('webdriver.http.Executor')
452
560
  }
453
561
 
454
562
  /**
@@ -466,64 +574,65 @@ class Executor {
466
574
  */
467
575
  defineCommand(name, method, path) {
468
576
  if (!this.customCommands_) {
469
- this.customCommands_ = new Map;
577
+ this.customCommands_ = new Map()
470
578
  }
471
- this.customCommands_.set(name, {method, path});
579
+ this.customCommands_.set(name, { method, path })
472
580
  }
473
581
 
474
582
  /** @override */
475
583
  async execute(command) {
476
- let request = buildRequest(this.customCommands_, this.w3c, command);
477
- this.log_.finer(() => `>>> ${request.method} ${request.path}`);
584
+ let request = buildRequest(this.customCommands_, this.w3c, command)
585
+ this.log_.finer(() => `>>> ${request.method} ${request.path}`)
478
586
 
479
- let client = CLIENTS.get(this);
587
+ let client = CLIENTS.get(this)
480
588
  if (promise.isPromise(client)) {
481
- client = await client;
482
- CLIENTS.set(this, client);
589
+ client = await client
590
+ CLIENTS.set(this, client)
483
591
  }
484
592
 
485
- let response = await client.send(request);
486
- this.log_.finer(() => `>>>\n${request}\n<<<\n${response}`);
593
+ let response = await client.send(request)
594
+ this.log_.finer(() => `>>>\n${request}\n<<<\n${response}`)
487
595
 
488
- let httpResponse = /** @type {!Response} */(response);
489
- let {isW3C, value} = parseHttpResponse(command, httpResponse);
596
+ let httpResponse = /** @type {!Response} */ (response)
597
+ let { isW3C, value } = parseHttpResponse(command, httpResponse)
490
598
 
491
599
  if (command.getName() === cmd.Name.NEW_SESSION) {
492
600
  if (!value || !value.sessionId) {
493
601
  throw new error.WebDriverError(
494
- `Unable to parse new session response: ${response.body}`);
602
+ `Unable to parse new session response: ${response.body}`
603
+ )
495
604
  }
496
605
 
497
606
  // The remote end is a W3C compliant server if there is no `status`
498
607
  // field in the response.
499
608
  if (command.getName() === cmd.Name.NEW_SESSION) {
500
- this.w3c = this.w3c || isW3C;
609
+ this.w3c = this.w3c || isW3C
501
610
  }
502
611
 
503
612
  // No implementations use the `capabilities` key yet...
504
- let capabilities = value.capabilities || value.value;
613
+ let capabilities = value.capabilities || value.value
505
614
  return new Session(
506
- /** @type {{sessionId: string}} */(value).sessionId, capabilities);
615
+ /** @type {{sessionId: string}} */ (value).sessionId,
616
+ capabilities
617
+ )
507
618
  }
508
619
 
509
- return typeof value === 'undefined' ? null : value;
620
+ return typeof value === 'undefined' ? null : value
510
621
  }
511
622
  }
512
623
 
513
-
514
624
  /**
515
625
  * @param {string} str .
516
626
  * @return {?} .
517
627
  */
518
628
  function tryParse(str) {
519
629
  try {
520
- return JSON.parse(str);
630
+ return JSON.parse(str)
521
631
  } catch (ignored) {
522
632
  // Do nothing.
523
633
  }
524
634
  }
525
635
 
526
-
527
636
  /**
528
637
  * Callback used to parse {@link Response} objects from a
529
638
  * {@link HttpClient}.
@@ -539,51 +648,49 @@ function tryParse(str) {
539
648
  function parseHttpResponse(command, httpResponse) {
540
649
  if (httpResponse.status < 200) {
541
650
  // This should never happen, but throw the raw response so users report it.
542
- throw new error.WebDriverError(
543
- `Unexpected HTTP response:\n${httpResponse}`);
651
+ throw new error.WebDriverError(`Unexpected HTTP response:\n${httpResponse}`)
544
652
  }
545
653
 
546
- let parsed = tryParse(httpResponse.body);
654
+ let parsed = tryParse(httpResponse.body)
547
655
  if (parsed && typeof parsed === 'object') {
548
- let value = parsed.value;
656
+ let value = parsed.value
549
657
  let isW3C =
550
- value !== null && typeof value === 'object'
551
- && typeof parsed.status === 'undefined';
658
+ value !== null &&
659
+ typeof value === 'object' &&
660
+ typeof parsed.status === 'undefined'
552
661
 
553
662
  if (!isW3C) {
554
- error.checkLegacyResponse(parsed);
663
+ error.checkLegacyResponse(parsed)
555
664
 
556
665
  // Adjust legacy new session responses to look like W3C to simplify
557
666
  // later processing.
558
667
  if (command.getName() === cmd.Name.NEW_SESSION) {
559
- value = parsed;
668
+ value = parsed
560
669
  }
561
-
562
670
  } else if (httpResponse.status > 399) {
563
- error.throwDecodedError(value);
671
+ error.throwDecodedError(value)
564
672
  }
565
673
 
566
- return {isW3C, value};
674
+ return { isW3C, value }
567
675
  }
568
676
 
569
677
  if (parsed !== undefined) {
570
- return {isW3C: false, value: parsed};
678
+ return { isW3C: false, value: parsed }
571
679
  }
572
680
 
573
- let value = httpResponse.body.replace(/\r\n/g, '\n');
681
+ let value = httpResponse.body.replace(/\r\n/g, '\n')
574
682
 
575
683
  // 404 represents an unknown command; anything else > 399 is a generic unknown
576
684
  // error.
577
685
  if (httpResponse.status == 404) {
578
- throw new error.UnsupportedOperationError(command.getName() + ': ' + value);
686
+ throw new error.UnsupportedOperationError(command.getName() + ': ' + value)
579
687
  } else if (httpResponse.status >= 400) {
580
- throw new error.WebDriverError(value);
688
+ throw new error.WebDriverError(value)
581
689
  }
582
690
 
583
- return {isW3C: false, value: value || null};
691
+ return { isW3C: false, value: value || null }
584
692
  }
585
693
 
586
-
587
694
  /**
588
695
  * Builds a fully qualified path using the given set of command parameters. Each
589
696
  * path segment prefixed with ':' will be replaced by the value of the
@@ -594,33 +701,33 @@ function parseHttpResponse(command, httpResponse) {
594
701
  * @return {string} The modified path.
595
702
  */
596
703
  function buildPath(path, parameters) {
597
- let pathParameters = path.match(/\/:(\w+)\b/g);
704
+ let pathParameters = path.match(/\/:(\w+)\b/g)
598
705
  if (pathParameters) {
599
706
  for (let i = 0; i < pathParameters.length; ++i) {
600
- let key = pathParameters[i].substring(2); // Trim the /:
707
+ let key = pathParameters[i].substring(2) // Trim the /:
601
708
  if (key in parameters) {
602
- let value = parameters[key];
709
+ let value = parameters[key]
603
710
  if (WebElement.isId(value)) {
604
711
  // When inserting a WebElement into the URL, only use its ID value,
605
712
  // not the full JSON.
606
- value = WebElement.extractId(value);
713
+ value = WebElement.extractId(value)
607
714
  }
608
- path = path.replace(pathParameters[i], '/' + value);
609
- delete parameters[key];
715
+ path = path.replace(pathParameters[i], '/' + value)
716
+ delete parameters[key]
610
717
  } else {
611
718
  throw new error.InvalidArgumentError(
612
- 'Missing required parameter: ' + key);
719
+ 'Missing required parameter: ' + key
720
+ )
613
721
  }
614
722
  }
615
723
  }
616
- return path;
724
+ return path
617
725
  }
618
726
 
619
-
620
727
  // PUBLIC API
621
728
 
622
- exports.Executor = Executor;
623
- exports.Client = Client;
624
- exports.Request = Request;
625
- exports.Response = Response;
626
- exports.buildPath = buildPath; // Exported for testing.
729
+ exports.Executor = Executor
730
+ exports.Client = Client
731
+ exports.Request = Request
732
+ exports.Response = Response
733
+ exports.buildPath = buildPath // Exported for testing.