selenium-webdriver 4.0.0-alpha.4 → 4.0.0-alpha.8

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 (52) hide show
  1. package/.eslintrc.js +27 -0
  2. package/.prettierrc +4 -0
  3. package/CHANGES.md +22 -1
  4. package/README.md +4 -4
  5. package/chrome.js +72 -590
  6. package/chromium.js +1024 -0
  7. package/devtools/CDPConnection.js +37 -0
  8. package/devtools/generator/protocol-dts-generator.js +429 -0
  9. package/edge.js +124 -86
  10. package/firefox.js +201 -202
  11. package/http/index.js +131 -115
  12. package/http/util.js +56 -64
  13. package/ie.js +180 -104
  14. package/index.js +246 -199
  15. package/io/exec.js +34 -39
  16. package/io/index.js +141 -151
  17. package/io/zip.js +75 -65
  18. package/lib/README +5 -0
  19. package/lib/actions.js +138 -121
  20. package/lib/atoms/find-elements.js +123 -0
  21. package/lib/atoms/get-attribute.js +79 -60
  22. package/lib/atoms/is-displayed.js +72 -73
  23. package/{example/chrome_mobile_emulation.js → lib/atoms/make-atoms-module.js} +16 -23
  24. package/lib/by.js +192 -65
  25. package/lib/capabilities.js +82 -78
  26. package/lib/command.js +18 -20
  27. package/lib/error.js +134 -168
  28. package/lib/http.js +324 -230
  29. package/lib/input.js +325 -302
  30. package/lib/logging.js +127 -138
  31. package/lib/promise.js +60 -66
  32. package/lib/proxy.js +31 -41
  33. package/lib/session.js +12 -15
  34. package/lib/symbols.js +3 -4
  35. package/lib/until.js +162 -162
  36. package/lib/webdriver.js +733 -522
  37. package/net/index.js +30 -36
  38. package/net/portprober.js +31 -144
  39. package/opera.js +406 -0
  40. package/package.json +18 -11
  41. package/proxy.js +2 -2
  42. package/remote/index.js +190 -187
  43. package/safari.js +40 -49
  44. package/LICENSE +0 -202
  45. package/NOTICE +0 -2
  46. package/example/chrome_android.js +0 -42
  47. package/example/firefox_channels.js +0 -77
  48. package/example/google_search.js +0 -50
  49. package/example/google_search_test.js +0 -72
  50. package/example/headless.js +0 -55
  51. package/example/logging.js +0 -68
  52. package/testing/index.js +0 -498
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
+ let 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,151 @@ 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
+ [cmd.Name.GET_ELEMENT_TAG_NAME, get('/session/:sessionId/element/:id/name')],
238
+ [
239
+ cmd.Name.IS_ELEMENT_SELECTED,
240
+ get('/session/:sessionId/element/:id/selected'),
241
+ ],
242
+ [cmd.Name.IS_ELEMENT_ENABLED, get('/session/:sessionId/element/:id/enabled')],
243
+ [
244
+ cmd.Name.IS_ELEMENT_DISPLAYED,
245
+ get('/session/:sessionId/element/:id/displayed'),
246
+ ],
247
+ [
248
+ cmd.Name.GET_ELEMENT_LOCATION,
249
+ get('/session/:sessionId/element/:id/location'),
250
+ ],
251
+ [cmd.Name.GET_ELEMENT_SIZE, get('/session/:sessionId/element/:id/size')],
252
+ [
253
+ cmd.Name.GET_ELEMENT_ATTRIBUTE,
254
+ get('/session/:sessionId/element/:id/attribute/:name'),
255
+ ],
256
+ [
257
+ cmd.Name.GET_ELEMENT_PROPERTY,
258
+ get('/session/:sessionId/element/:id/property/:name'),
259
+ ],
260
+ [
261
+ cmd.Name.GET_ELEMENT_VALUE_OF_CSS_PROPERTY,
262
+ get('/session/:sessionId/element/:id/css/:propertyName'),
263
+ ],
264
+ [
265
+ cmd.Name.TAKE_ELEMENT_SCREENSHOT,
266
+ get('/session/:sessionId/element/:id/screenshot'),
267
+ ],
268
+ [cmd.Name.SWITCH_TO_WINDOW, post('/session/:sessionId/window')],
269
+ [
270
+ cmd.Name.MAXIMIZE_WINDOW,
271
+ post('/session/:sessionId/window/current/maximize'),
272
+ ],
273
+ [
274
+ cmd.Name.GET_WINDOW_POSITION,
275
+ get('/session/:sessionId/window/current/position'),
276
+ ],
277
+ [
278
+ cmd.Name.SET_WINDOW_POSITION,
279
+ post('/session/:sessionId/window/current/position'),
280
+ ],
281
+ [cmd.Name.GET_WINDOW_SIZE, get('/session/:sessionId/window/current/size')],
282
+ [cmd.Name.SET_WINDOW_SIZE, post('/session/:sessionId/window/current/size')],
283
+ [cmd.Name.SWITCH_TO_FRAME, post('/session/:sessionId/frame')],
284
+ [cmd.Name.SWITCH_TO_FRAME_PARENT, post('/session/:sessionId/frame/parent')],
285
+ [cmd.Name.GET_PAGE_SOURCE, get('/session/:sessionId/source')],
286
+ [cmd.Name.GET_TITLE, get('/session/:sessionId/title')],
287
+ [cmd.Name.EXECUTE_SCRIPT, post('/session/:sessionId/execute')],
288
+ [cmd.Name.EXECUTE_ASYNC_SCRIPT, post('/session/:sessionId/execute_async')],
289
+ [cmd.Name.SCREENSHOT, get('/session/:sessionId/screenshot')],
290
+ [cmd.Name.GET_TIMEOUT, get('/session/:sessionId/timeouts')],
291
+ [cmd.Name.SET_TIMEOUT, post('/session/:sessionId/timeouts')],
292
+ [cmd.Name.ACCEPT_ALERT, post('/session/:sessionId/accept_alert')],
293
+ [cmd.Name.DISMISS_ALERT, post('/session/:sessionId/dismiss_alert')],
294
+ [cmd.Name.GET_ALERT_TEXT, get('/session/:sessionId/alert_text')],
295
+ [cmd.Name.SET_ALERT_TEXT, post('/session/:sessionId/alert_text')],
296
+ [cmd.Name.GET_LOG, post('/session/:sessionId/log')],
297
+ [cmd.Name.GET_AVAILABLE_LOG_TYPES, get('/session/:sessionId/log/types')],
298
+ [cmd.Name.GET_SESSION_LOGS, post('/logs')],
299
+ [cmd.Name.UPLOAD_FILE, post('/session/:sessionId/se/file')],
300
+ [cmd.Name.LEGACY_ACTION_CLICK, post('/session/:sessionId/click')],
301
+ [
302
+ cmd.Name.LEGACY_ACTION_DOUBLE_CLICK,
303
+ post('/session/:sessionId/doubleclick'),
304
+ ],
305
+ [cmd.Name.LEGACY_ACTION_MOUSE_DOWN, post('/session/:sessionId/buttondown')],
306
+ [cmd.Name.LEGACY_ACTION_MOUSE_UP, post('/session/:sessionId/buttonup')],
307
+ [cmd.Name.LEGACY_ACTION_MOUSE_MOVE, post('/session/:sessionId/moveto')],
308
+ [cmd.Name.LEGACY_ACTION_SEND_KEYS, post('/session/:sessionId/keys')],
309
+ [cmd.Name.LEGACY_ACTION_TOUCH_DOWN, post('/session/:sessionId/touch/down')],
310
+ [cmd.Name.LEGACY_ACTION_TOUCH_UP, post('/session/:sessionId/touch/up')],
311
+ [cmd.Name.LEGACY_ACTION_TOUCH_MOVE, post('/session/:sessionId/touch/move')],
312
+ [
313
+ cmd.Name.LEGACY_ACTION_TOUCH_SCROLL,
314
+ post('/session/:sessionId/touch/scroll'),
315
+ ],
316
+ [
317
+ cmd.Name.LEGACY_ACTION_TOUCH_LONG_PRESS,
318
+ post('/session/:sessionId/touch/longclick'),
319
+ ],
320
+ [cmd.Name.LEGACY_ACTION_TOUCH_FLICK, post('/session/:sessionId/touch/flick')],
321
+ [
322
+ cmd.Name.LEGACY_ACTION_TOUCH_SINGLE_TAP,
323
+ post('/session/:sessionId/touch/click'),
324
+ ],
325
+ [
326
+ cmd.Name.LEGACY_ACTION_TOUCH_DOUBLE_TAP,
327
+ post('/session/:sessionId/touch/doubleclick'),
328
+ ],
329
+ ])
265
330
 
266
331
  /** @const {!Map<string, (CommandSpec|CommandTransformer)>} */
267
332
  const W3C_COMMAND_MAP = new Map([
@@ -305,23 +370,51 @@ const W3C_COMMAND_MAP = new Map([
305
370
  [cmd.Name.GET_ACTIVE_ELEMENT, get('/session/:sessionId/element/active')],
306
371
  [cmd.Name.FIND_ELEMENT, post('/session/:sessionId/element')],
307
372
  [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')],
373
+ [
374
+ cmd.Name.FIND_ELEMENTS_RELATIVE,
375
+ (cmd) => {
376
+ return toExecuteAtomCommand(cmd, Atom.FIND_ELEMENTS, 'args')
377
+ },
378
+ ],
379
+ [
380
+ cmd.Name.FIND_CHILD_ELEMENT,
381
+ post('/session/:sessionId/element/:id/element'),
382
+ ],
383
+ [
384
+ cmd.Name.FIND_CHILD_ELEMENTS,
385
+ post('/session/:sessionId/element/:id/elements'),
386
+ ],
310
387
  // Element interaction.
311
388
  [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')],
389
+ [
390
+ cmd.Name.GET_ELEMENT_PROPERTY,
391
+ get('/session/:sessionId/element/:id/property/:name'),
392
+ ],
393
+ [
394
+ cmd.Name.GET_ELEMENT_VALUE_OF_CSS_PROPERTY,
395
+ get('/session/:sessionId/element/:id/css/:propertyName'),
396
+ ],
313
397
  [cmd.Name.GET_ELEMENT_RECT, get('/session/:sessionId/element/:id/rect')],
314
398
  [cmd.Name.CLEAR_ELEMENT, post('/session/:sessionId/element/:id/clear')],
315
399
  [cmd.Name.CLICK_ELEMENT, post('/session/:sessionId/element/:id/click')],
316
- [cmd.Name.SEND_KEYS_TO_ELEMENT, post('/session/:sessionId/element/:id/value')],
400
+ [
401
+ cmd.Name.SEND_KEYS_TO_ELEMENT,
402
+ post('/session/:sessionId/element/:id/value'),
403
+ ],
317
404
  [cmd.Name.GET_ELEMENT_TEXT, get('/session/:sessionId/element/:id/text')],
318
405
  [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
- }],
406
+ [
407
+ cmd.Name.GET_ELEMENT_ATTRIBUTE,
408
+ (cmd) => {
409
+ return toExecuteAtomCommand(cmd, Atom.GET_ATTRIBUTE, 'id', 'name')
410
+ },
411
+ ],
412
+ [
413
+ cmd.Name.IS_ELEMENT_DISPLAYED,
414
+ (cmd) => {
415
+ return toExecuteAtomCommand(cmd, Atom.IS_DISPLAYED, 'id')
416
+ },
417
+ ],
325
418
  // Cookie management.
326
419
  [cmd.Name.GET_ALL_COOKIES, get('/session/:sessionId/cookie')],
327
420
  [cmd.Name.ADD_COOKIE, post('/session/:sessionId/cookie')],
@@ -335,9 +428,16 @@ const W3C_COMMAND_MAP = new Map([
335
428
  [cmd.Name.SET_ALERT_TEXT, post('/session/:sessionId/alert/text')],
336
429
  // Screenshots.
337
430
  [cmd.Name.SCREENSHOT, get('/session/:sessionId/screenshot')],
338
- [cmd.Name.TAKE_ELEMENT_SCREENSHOT, get('/session/:sessionId/element/:id/screenshot')],
339
- ]);
340
-
431
+ [
432
+ cmd.Name.TAKE_ELEMENT_SCREENSHOT,
433
+ get('/session/:sessionId/element/:id/screenshot'),
434
+ ],
435
+ // print page.
436
+ [cmd.Name.PRINT_PAGE, post('/session/:sessionId/print')],
437
+ // Log extensions.
438
+ [cmd.Name.GET_LOG, post('/session/:sessionId/se/log')],
439
+ [cmd.Name.GET_AVAILABLE_LOG_TYPES, get('/session/:sessionId/se/log/types')],
440
+ ])
341
441
 
342
442
  /**
343
443
  * Handles sending HTTP messages to a remote end.
@@ -345,7 +445,6 @@ const W3C_COMMAND_MAP = new Map([
345
445
  * @interface
346
446
  */
347
447
  class Client {
348
-
349
448
  /**
350
449
  * Sends a request to the server. The client will automatically follow any
351
450
  * redirects returned by the server, fulfilling the returned promise with the
@@ -355,11 +454,9 @@ class Client {
355
454
  * @return {!Promise<Response>} A promise that will be fulfilled with the
356
455
  * server's response.
357
456
  */
358
- send(httpRequest) {}
457
+ send(httpRequest) {} // eslint-disable-line
359
458
  }
360
459
 
361
-
362
-
363
460
  /**
364
461
  * @param {Map<string, CommandSpec>} customCommands
365
462
  * A map of custom command definitions.
@@ -369,46 +466,44 @@ class Client {
369
466
  * command to execute.
370
467
  */
371
468
  function buildRequest(customCommands, w3c, command) {
372
- LOG.finest(() => `Translating command: ${command.getName()}`);
373
- let spec = customCommands && customCommands.get(command.getName());
469
+ LOG.finest(() => `Translating command: ${command.getName()}`)
470
+ let spec = customCommands && customCommands.get(command.getName())
374
471
  if (spec) {
375
- return toHttpRequest(spec);
472
+ return toHttpRequest(spec)
376
473
  }
377
474
 
378
475
  if (w3c) {
379
- spec = W3C_COMMAND_MAP.get(command.getName());
476
+ spec = W3C_COMMAND_MAP.get(command.getName())
380
477
  if (typeof spec === 'function') {
381
- LOG.finest(() => `Transforming command for W3C: ${command.getName()}`);
382
- let newCommand = spec(command);
383
- return buildRequest(customCommands, w3c, newCommand);
478
+ LOG.finest(() => `Transforming command for W3C: ${command.getName()}`)
479
+ let newCommand = spec(command)
480
+ return buildRequest(customCommands, w3c, newCommand)
384
481
  } else if (spec) {
385
- return toHttpRequest(spec);
482
+ return toHttpRequest(spec)
386
483
  }
387
484
  }
388
485
 
389
- spec = COMMAND_MAP.get(command.getName());
486
+ spec = COMMAND_MAP.get(command.getName())
390
487
  if (spec) {
391
- return toHttpRequest(spec);
488
+ return toHttpRequest(spec)
392
489
  }
393
490
  throw new error.UnknownCommandError(
394
- 'Unrecognized command: ' + command.getName());
491
+ 'Unrecognized command: ' + command.getName()
492
+ )
395
493
 
396
494
  /**
397
495
  * @param {CommandSpec} resource
398
496
  * @return {!Request}
399
497
  */
400
498
  function toHttpRequest(resource) {
401
- LOG.finest(() => `Building HTTP request: ${JSON.stringify(resource)}`);
402
- let parameters = command.getParameters();
403
- let path = buildPath(resource.path, parameters);
404
- return new Request(resource.method, path, parameters);
499
+ LOG.finest(() => `Building HTTP request: ${JSON.stringify(resource)}`)
500
+ let parameters = command.getParameters()
501
+ let path = buildPath(resource.path, parameters)
502
+ return new Request(resource.method, path, parameters)
405
503
  }
406
504
  }
407
505
 
408
-
409
- const CLIENTS =
410
- /** !WeakMap<!Executor, !(Client|IThenable<!Client>)> */new WeakMap;
411
-
506
+ const CLIENTS = /** !WeakMap<!Executor, !(Client|IThenable<!Client>)> */ new WeakMap()
412
507
 
413
508
  /**
414
509
  * A command executor that communicates with the server using JSON over HTTP.
@@ -430,7 +525,7 @@ class Executor {
430
525
  * to the client.
431
526
  */
432
527
  constructor(client) {
433
- CLIENTS.set(this, client);
528
+ CLIENTS.set(this, client)
434
529
 
435
530
  /**
436
531
  * Whether this executor should use the W3C wire protocol. The executor
@@ -439,13 +534,13 @@ class Executor {
439
534
  * `true` to force the executor into W3C mode.
440
535
  * @type {boolean}
441
536
  */
442
- this.w3c = false;
537
+ this.w3c = false
443
538
 
444
539
  /** @private {Map<string, CommandSpec>} */
445
- this.customCommands_ = null;
540
+ this.customCommands_ = null
446
541
 
447
542
  /** @private {!logging.Logger} */
448
- this.log_ = logging.getLogger('webdriver.http.Executor');
543
+ this.log_ = logging.getLogger('webdriver.http.Executor')
449
544
  }
450
545
 
451
546
  /**
@@ -463,64 +558,65 @@ class Executor {
463
558
  */
464
559
  defineCommand(name, method, path) {
465
560
  if (!this.customCommands_) {
466
- this.customCommands_ = new Map;
561
+ this.customCommands_ = new Map()
467
562
  }
468
- this.customCommands_.set(name, {method, path});
563
+ this.customCommands_.set(name, { method, path })
469
564
  }
470
565
 
471
566
  /** @override */
472
567
  async execute(command) {
473
- let request = buildRequest(this.customCommands_, this.w3c, command);
474
- this.log_.finer(() => `>>> ${request.method} ${request.path}`);
568
+ let request = buildRequest(this.customCommands_, this.w3c, command)
569
+ this.log_.finer(() => `>>> ${request.method} ${request.path}`)
475
570
 
476
- let client = CLIENTS.get(this);
571
+ let client = CLIENTS.get(this)
477
572
  if (promise.isPromise(client)) {
478
- client = await client;
479
- CLIENTS.set(this, client);
573
+ client = await client
574
+ CLIENTS.set(this, client)
480
575
  }
481
576
 
482
- let response = await client.send(request);
483
- this.log_.finer(() => `>>>\n${request}\n<<<\n${response}`);
577
+ let response = await client.send(request)
578
+ this.log_.finer(() => `>>>\n${request}\n<<<\n${response}`)
484
579
 
485
- let httpResponse = /** @type {!Response} */(response);
486
- let {isW3C, value} = parseHttpResponse(command, httpResponse);
580
+ let httpResponse = /** @type {!Response} */ (response)
581
+ let { isW3C, value } = parseHttpResponse(command, httpResponse)
487
582
 
488
583
  if (command.getName() === cmd.Name.NEW_SESSION) {
489
584
  if (!value || !value.sessionId) {
490
585
  throw new error.WebDriverError(
491
- `Unable to parse new session response: ${response.body}`);
586
+ `Unable to parse new session response: ${response.body}`
587
+ )
492
588
  }
493
589
 
494
590
  // The remote end is a W3C compliant server if there is no `status`
495
591
  // field in the response.
496
592
  if (command.getName() === cmd.Name.NEW_SESSION) {
497
- this.w3c = this.w3c || isW3C;
593
+ this.w3c = this.w3c || isW3C
498
594
  }
499
595
 
500
596
  // No implementations use the `capabilities` key yet...
501
- let capabilities = value.capabilities || value.value;
597
+ let capabilities = value.capabilities || value.value
502
598
  return new Session(
503
- /** @type {{sessionId: string}} */(value).sessionId, capabilities);
599
+ /** @type {{sessionId: string}} */ (value).sessionId,
600
+ capabilities
601
+ )
504
602
  }
505
603
 
506
- return typeof value === 'undefined' ? null : value;
604
+ return typeof value === 'undefined' ? null : value
507
605
  }
508
606
  }
509
607
 
510
-
511
608
  /**
512
609
  * @param {string} str .
513
610
  * @return {?} .
514
611
  */
515
612
  function tryParse(str) {
516
613
  try {
517
- return JSON.parse(str);
614
+ return JSON.parse(str)
518
615
  } catch (ignored) {
519
616
  // Do nothing.
520
617
  }
521
618
  }
522
619
 
523
-
524
620
  /**
525
621
  * Callback used to parse {@link Response} objects from a
526
622
  * {@link HttpClient}.
@@ -536,51 +632,49 @@ function tryParse(str) {
536
632
  function parseHttpResponse(command, httpResponse) {
537
633
  if (httpResponse.status < 200) {
538
634
  // This should never happen, but throw the raw response so users report it.
539
- throw new error.WebDriverError(
540
- `Unexpected HTTP response:\n${httpResponse}`);
635
+ throw new error.WebDriverError(`Unexpected HTTP response:\n${httpResponse}`)
541
636
  }
542
637
 
543
- let parsed = tryParse(httpResponse.body);
638
+ let parsed = tryParse(httpResponse.body)
544
639
  if (parsed && typeof parsed === 'object') {
545
- let value = parsed.value;
640
+ let value = parsed.value
546
641
  let isW3C =
547
- value !== null && typeof value === 'object'
548
- && typeof parsed.status === 'undefined';
642
+ value !== null &&
643
+ typeof value === 'object' &&
644
+ typeof parsed.status === 'undefined'
549
645
 
550
646
  if (!isW3C) {
551
- error.checkLegacyResponse(parsed);
647
+ error.checkLegacyResponse(parsed)
552
648
 
553
649
  // Adjust legacy new session responses to look like W3C to simplify
554
650
  // later processing.
555
651
  if (command.getName() === cmd.Name.NEW_SESSION) {
556
- value = parsed;
652
+ value = parsed
557
653
  }
558
-
559
654
  } else if (httpResponse.status > 399) {
560
- error.throwDecodedError(value);
655
+ error.throwDecodedError(value)
561
656
  }
562
657
 
563
- return {isW3C, value};
658
+ return { isW3C, value }
564
659
  }
565
660
 
566
661
  if (parsed !== undefined) {
567
- return {isW3C: false, value: parsed};
662
+ return { isW3C: false, value: parsed }
568
663
  }
569
664
 
570
- let value = httpResponse.body.replace(/\r\n/g, '\n');
665
+ let value = httpResponse.body.replace(/\r\n/g, '\n')
571
666
 
572
667
  // 404 represents an unknown command; anything else > 399 is a generic unknown
573
668
  // error.
574
669
  if (httpResponse.status == 404) {
575
- throw new error.UnsupportedOperationError(command.getName() + ': ' + value);
670
+ throw new error.UnsupportedOperationError(command.getName() + ': ' + value)
576
671
  } else if (httpResponse.status >= 400) {
577
- throw new error.WebDriverError(value);
672
+ throw new error.WebDriverError(value)
578
673
  }
579
674
 
580
- return {isW3C: false, value: value || null};
675
+ return { isW3C: false, value: value || null }
581
676
  }
582
677
 
583
-
584
678
  /**
585
679
  * Builds a fully qualified path using the given set of command parameters. Each
586
680
  * path segment prefixed with ':' will be replaced by the value of the
@@ -591,33 +685,33 @@ function parseHttpResponse(command, httpResponse) {
591
685
  * @return {string} The modified path.
592
686
  */
593
687
  function buildPath(path, parameters) {
594
- let pathParameters = path.match(/\/:(\w+)\b/g);
688
+ let pathParameters = path.match(/\/:(\w+)\b/g)
595
689
  if (pathParameters) {
596
690
  for (let i = 0; i < pathParameters.length; ++i) {
597
- let key = pathParameters[i].substring(2); // Trim the /:
691
+ let key = pathParameters[i].substring(2) // Trim the /:
598
692
  if (key in parameters) {
599
- let value = parameters[key];
693
+ let value = parameters[key]
600
694
  if (WebElement.isId(value)) {
601
695
  // When inserting a WebElement into the URL, only use its ID value,
602
696
  // not the full JSON.
603
- value = WebElement.extractId(value);
697
+ value = WebElement.extractId(value)
604
698
  }
605
- path = path.replace(pathParameters[i], '/' + value);
606
- delete parameters[key];
699
+ path = path.replace(pathParameters[i], '/' + value)
700
+ delete parameters[key]
607
701
  } else {
608
702
  throw new error.InvalidArgumentError(
609
- 'Missing required parameter: ' + key);
703
+ 'Missing required parameter: ' + key
704
+ )
610
705
  }
611
706
  }
612
707
  }
613
- return path;
708
+ return path
614
709
  }
615
710
 
616
-
617
711
  // PUBLIC API
618
712
 
619
- exports.Executor = Executor;
620
- exports.Client = Client;
621
- exports.Request = Request;
622
- exports.Response = Response;
623
- exports.buildPath = buildPath; // Exported for testing.
713
+ exports.Executor = Executor
714
+ exports.Client = Client
715
+ exports.Request = Request
716
+ exports.Response = Response
717
+ exports.buildPath = buildPath // Exported for testing.