selenium-webdriver 3.6.0 → 4.0.0-alpha.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 (97) hide show
  1. package/CHANGES.md +181 -0
  2. package/README.md +25 -27
  3. package/chrome.js +113 -127
  4. package/edge.js +42 -117
  5. package/example/chrome_android.js +8 -8
  6. package/example/chrome_mobile_emulation.js +8 -8
  7. package/example/firefox_channels.js +22 -18
  8. package/example/google_search_test.js +39 -26
  9. package/example/logging.js +39 -6
  10. package/firefox.js +769 -0
  11. package/http/index.js +41 -4
  12. package/http/util.js +11 -6
  13. package/ie.js +56 -97
  14. package/index.js +178 -114
  15. package/jasmine.json +11 -0
  16. package/lib/actions.js +68 -63
  17. package/lib/by.js +1 -1
  18. package/lib/capabilities.js +255 -192
  19. package/lib/command.js +26 -50
  20. package/lib/error.js +85 -44
  21. package/lib/http.js +133 -110
  22. package/lib/input.js +1044 -8
  23. package/lib/promise.js +222 -3323
  24. package/lib/proxy.js +134 -39
  25. package/lib/test/bootstrap_jasmine.js +28 -0
  26. package/lib/test/data/actions/click.html +24 -0
  27. package/lib/test/data/actions/drag.html +77 -0
  28. package/lib/test/data/actions/record_click.html +21 -0
  29. package/lib/test/data/chrome/download.html +2 -0
  30. package/lib/test/data/inputs.html +42 -0
  31. package/lib/test/data/selectPage.html +12 -0
  32. package/lib/test/data/simpleTest.html +5 -0
  33. package/lib/test/data/upload_invisible.html +45 -0
  34. package/lib/test/fileserver.js +23 -19
  35. package/lib/test/index.js +30 -212
  36. package/lib/test/resources.js +0 -1
  37. package/lib/webdriver.js +675 -936
  38. package/net/index.js +21 -25
  39. package/net/portprober.js +51 -68
  40. package/package.json +5 -3
  41. package/remote/index.js +5 -19
  42. package/safari.js +41 -128
  43. package/test/actions_test.js +173 -18
  44. package/test/{session_test.js → builder_test.js} +44 -37
  45. package/test/chrome/devtools_test.js +93 -0
  46. package/test/chrome/options_test.js +48 -154
  47. package/test/chrome/service_test.js +7 -7
  48. package/test/cookie_test.js +77 -63
  49. package/test/element_finding_test.js +206 -201
  50. package/test/execute_script_test.js +115 -114
  51. package/test/fingerprint_test.js +16 -15
  52. package/test/firefox_test.js +251 -0
  53. package/test/http/http_test.js +0 -1
  54. package/test/http/util_test.js +2 -2
  55. package/test/io/zip_test.js +6 -7
  56. package/test/lib/error_test.js +34 -7
  57. package/test/lib/http_test.js +8 -128
  58. package/test/lib/input_test.js +1379 -0
  59. package/test/lib/promise_test.js +473 -908
  60. package/test/lib/webdriver_test.js +296 -868
  61. package/test/logging_test.js +37 -43
  62. package/test/page_loading_test.js +71 -81
  63. package/test/proxy_test.js +64 -72
  64. package/test/rect_test.js +14 -25
  65. package/test/remote_test.js +10 -29
  66. package/test/safari_test.js +7 -71
  67. package/test/stale_element_test.js +20 -23
  68. package/test/tag_name_test.js +10 -9
  69. package/test/upload_test.js +27 -35
  70. package/test/window_test.js +72 -85
  71. package/testing/index.js +386 -314
  72. package/.npmignore +0 -2
  73. package/example/async_await_test.js +0 -69
  74. package/example/google_search_generator.js +0 -47
  75. package/example/parallel_flows.js +0 -51
  76. package/firefox/binary.js +0 -347
  77. package/firefox/extension.js +0 -224
  78. package/firefox/index.js +0 -576
  79. package/firefox/profile.js +0 -311
  80. package/lib/events.js +0 -210
  81. package/lib/test/data/firefox/jetpack-sample.xpi +0 -0
  82. package/lib/test/data/firefox/sample.xpi +0 -0
  83. package/lib/test/promise.js +0 -79
  84. package/opera.js +0 -405
  85. package/phantomjs.js +0 -282
  86. package/test/firefox/extension_test.js +0 -120
  87. package/test/firefox/firefox_test.js +0 -244
  88. package/test/firefox/profile_test.js +0 -140
  89. package/test/lib/events_test.js +0 -177
  90. package/test/lib/promise_aplus_test.js +0 -78
  91. package/test/lib/promise_error_test.js +0 -884
  92. package/test/lib/promise_flow_test.js +0 -2288
  93. package/test/lib/promise_generator_test.js +0 -310
  94. package/test/phantomjs/execute_phantomjs_test.js +0 -59
  95. package/test/testing/assert_test.js +0 -373
  96. package/test/testing/index_test.js +0 -224
  97. package/testing/assert.js +0 -378
package/lib/http.js CHANGED
@@ -29,8 +29,8 @@ const cmd = require('./command');
29
29
  const error = require('./error');
30
30
  const logging = require('./logging');
31
31
  const promise = require('./promise');
32
- const Session = require('./session').Session;
33
- const WebElement = require('./webdriver').WebElement;
32
+ const {Session} = require('./session');
33
+ const {WebElement} = require('./webdriver');
34
34
 
35
35
  const {getAttribute, isDisplayed} = /** @suppress {undefinedVars|uselessCode} */(function() {
36
36
  try {
@@ -145,7 +145,7 @@ function resource(method, path) { return {method: method, path: path}; }
145
145
  var CommandSpec;
146
146
 
147
147
 
148
- /** @typedef {function(!cmd.Command): !Promise<!cmd.Command>} */
148
+ /** @typedef {function(!cmd.Command): !cmd.Command} */
149
149
  var CommandTransformer;
150
150
 
151
151
 
@@ -155,21 +155,17 @@ class InternalTypeError extends TypeError {}
155
155
  /**
156
156
  * @param {!cmd.Command} command The initial command.
157
157
  * @param {Atom} atom The name of the atom to execute.
158
- * @return {!Promise<!cmd.Command>} The transformed command to execute.
158
+ * @return {!cmd.Command} The transformed command to execute.
159
159
  */
160
160
  function toExecuteAtomCommand(command, atom, ...params) {
161
- return new Promise((resolve, reject) => {
162
- if (typeof atom !== 'function') {
163
- reject(new InternalTypeError('atom is not a function: ' + typeof atom));
164
- return;
165
- }
161
+ if (typeof atom !== 'function') {
162
+ throw new InternalTypeError('atom is not a function: ' + typeof atom);
163
+ }
166
164
 
167
- let newCmd = new cmd.Command(cmd.Name.EXECUTE_SCRIPT)
168
- .setParameter('sessionId', command.getParameter('sessionId'))
169
- .setParameter('script', `return (${atom}).apply(null, arguments)`)
170
- .setParameter('args', params.map(param => command.getParameter(param)));
171
- resolve(newCmd);
172
- });
165
+ return new cmd.Command(cmd.Name.EXECUTE_SCRIPT)
166
+ .setParameter('sessionId', command.getParameter('sessionId'))
167
+ .setParameter('script', `return (${atom}).apply(null, arguments)`)
168
+ .setParameter('args', params.map(param => command.getParameter(param)));
173
169
  }
174
170
 
175
171
 
@@ -179,7 +175,6 @@ const COMMAND_MAP = new Map([
179
175
  [cmd.Name.GET_SERVER_STATUS, get('/status')],
180
176
  [cmd.Name.NEW_SESSION, post('/session')],
181
177
  [cmd.Name.GET_SESSIONS, get('/sessions')],
182
- [cmd.Name.DESCRIBE_SESSION, get('/session/:sessionId')],
183
178
  [cmd.Name.QUIT, del('/session/:sessionId')],
184
179
  [cmd.Name.CLOSE, del('/session/:sessionId/window')],
185
180
  [cmd.Name.GET_CURRENT_WINDOW_HANDLE, get('/session/:sessionId/window_handle')],
@@ -211,7 +206,6 @@ const COMMAND_MAP = new Map([
211
206
  [cmd.Name.GET_ELEMENT_SIZE, get('/session/:sessionId/element/:id/size')],
212
207
  [cmd.Name.GET_ELEMENT_ATTRIBUTE, get('/session/:sessionId/element/:id/attribute/:name')],
213
208
  [cmd.Name.GET_ELEMENT_VALUE_OF_CSS_PROPERTY, get('/session/:sessionId/element/:id/css/:propertyName')],
214
- [cmd.Name.ELEMENT_EQUALS, get('/session/:sessionId/element/:id/equals/:other')],
215
209
  [cmd.Name.TAKE_ELEMENT_SCREENSHOT, get('/session/:sessionId/element/:id/screenshot')],
216
210
  [cmd.Name.SWITCH_TO_WINDOW, post('/session/:sessionId/window')],
217
211
  [cmd.Name.MAXIMIZE_WINDOW, post('/session/:sessionId/window/current/maximize')],
@@ -227,57 +221,103 @@ const COMMAND_MAP = new Map([
227
221
  [cmd.Name.SCREENSHOT, get('/session/:sessionId/screenshot')],
228
222
  [cmd.Name.GET_TIMEOUT, get('/session/:sessionId/timeouts')],
229
223
  [cmd.Name.SET_TIMEOUT, post('/session/:sessionId/timeouts')],
230
- [cmd.Name.MOVE_TO, post('/session/:sessionId/moveto')],
231
- [cmd.Name.CLICK, post('/session/:sessionId/click')],
232
- [cmd.Name.DOUBLE_CLICK, post('/session/:sessionId/doubleclick')],
233
- [cmd.Name.MOUSE_DOWN, post('/session/:sessionId/buttondown')],
234
- [cmd.Name.MOUSE_UP, post('/session/:sessionId/buttonup')],
235
- [cmd.Name.MOVE_TO, post('/session/:sessionId/moveto')],
236
- [cmd.Name.SEND_KEYS_TO_ACTIVE_ELEMENT, post('/session/:sessionId/keys')],
237
- [cmd.Name.TOUCH_SINGLE_TAP, post('/session/:sessionId/touch/click')],
238
- [cmd.Name.TOUCH_DOUBLE_TAP, post('/session/:sessionId/touch/doubleclick')],
239
- [cmd.Name.TOUCH_DOWN, post('/session/:sessionId/touch/down')],
240
- [cmd.Name.TOUCH_UP, post('/session/:sessionId/touch/up')],
241
- [cmd.Name.TOUCH_MOVE, post('/session/:sessionId/touch/move')],
242
- [cmd.Name.TOUCH_SCROLL, post('/session/:sessionId/touch/scroll')],
243
- [cmd.Name.TOUCH_LONG_PRESS, post('/session/:sessionId/touch/longclick')],
244
- [cmd.Name.TOUCH_FLICK, post('/session/:sessionId/touch/flick')],
245
224
  [cmd.Name.ACCEPT_ALERT, post('/session/:sessionId/accept_alert')],
246
225
  [cmd.Name.DISMISS_ALERT, post('/session/:sessionId/dismiss_alert')],
247
226
  [cmd.Name.GET_ALERT_TEXT, get('/session/:sessionId/alert_text')],
248
227
  [cmd.Name.SET_ALERT_TEXT, post('/session/:sessionId/alert_text')],
249
- [cmd.Name.SET_ALERT_CREDENTIALS, post('/session/:sessionId/alert/credentials')],
250
228
  [cmd.Name.GET_LOG, post('/session/:sessionId/log')],
251
229
  [cmd.Name.GET_AVAILABLE_LOG_TYPES, get('/session/:sessionId/log/types')],
252
230
  [cmd.Name.GET_SESSION_LOGS, post('/logs')],
253
231
  [cmd.Name.UPLOAD_FILE, post('/session/:sessionId/file')],
232
+ [cmd.Name.LEGACY_ACTION_CLICK, post('/session/:sessionId/click')],
233
+ [cmd.Name.LEGACY_ACTION_DOUBLE_CLICK, post('/session/:sessionId/doubleclick')],
234
+ [cmd.Name.LEGACY_ACTION_MOUSE_DOWN, post('/session/:sessionId/buttondown')],
235
+ [cmd.Name.LEGACY_ACTION_MOUSE_UP, post('/session/:sessionId/buttonup')],
236
+ [cmd.Name.LEGACY_ACTION_MOUSE_MOVE, post('/session/:sessionId/moveto')],
237
+ [cmd.Name.LEGACY_ACTION_SEND_KEYS, post('/session/:sessionId/keys')],
238
+ [cmd.Name.LEGACY_ACTION_TOUCH_DOWN, post('/session/:sessionId/touch/down')],
239
+ [cmd.Name.LEGACY_ACTION_TOUCH_UP, post('/session/:sessionId/touch/up')],
240
+ [cmd.Name.LEGACY_ACTION_TOUCH_MOVE, post('/session/:sessionId/touch/move')],
241
+ [cmd.Name.LEGACY_ACTION_TOUCH_SCROLL, post('/session/:sessionId/touch/scroll')],
242
+ [cmd.Name.LEGACY_ACTION_TOUCH_LONG_PRESS, post('/session/:sessionId/touch/longclick')],
243
+ [cmd.Name.LEGACY_ACTION_TOUCH_FLICK, post('/session/:sessionId/touch/flick')],
244
+ [cmd.Name.LEGACY_ACTION_TOUCH_SINGLE_TAP, post('/session/:sessionId/touch/click')],
245
+ [cmd.Name.LEGACY_ACTION_TOUCH_DOUBLE_TAP, post('/session/:sessionId/touch/doubleclick')],
254
246
  ]);
255
247
 
256
248
 
257
249
  /** @const {!Map<string, (CommandSpec|CommandTransformer)>} */
258
250
  const W3C_COMMAND_MAP = new Map([
251
+ // Server status.
252
+ [cmd.Name.GET_SERVER_STATUS, get('/status')],
253
+ // Session management.
254
+ [cmd.Name.NEW_SESSION, post('/session')],
255
+ [cmd.Name.QUIT, del('/session/:sessionId')],
256
+ [cmd.Name.GET_TIMEOUT, get('/session/:sessionId/timeouts')],
257
+ [cmd.Name.SET_TIMEOUT, post('/session/:sessionId/timeouts')],
258
+ // Navigation.
259
+ [cmd.Name.GET_CURRENT_URL, get('/session/:sessionId/url')],
260
+ [cmd.Name.GET, post('/session/:sessionId/url')],
261
+ [cmd.Name.GO_BACK, post('/session/:sessionId/back')],
262
+ [cmd.Name.GO_FORWARD, post('/session/:sessionId/forward')],
263
+ [cmd.Name.REFRESH, post('/session/:sessionId/refresh')],
264
+ // Page inspection.
265
+ [cmd.Name.GET_PAGE_SOURCE, get('/session/:sessionId/source')],
266
+ [cmd.Name.GET_TITLE, get('/session/:sessionId/title')],
267
+ // Script execution.
268
+ [cmd.Name.EXECUTE_SCRIPT, post('/session/:sessionId/execute/sync')],
269
+ [cmd.Name.EXECUTE_ASYNC_SCRIPT, post('/session/:sessionId/execute/async')],
270
+ // Frame selection.
271
+ [cmd.Name.SWITCH_TO_FRAME, post('/session/:sessionId/frame')],
272
+ [cmd.Name.SWITCH_TO_FRAME_PARENT, post('/session/:sessionId/frame/parent')],
273
+ // Window management.
274
+ [cmd.Name.GET_CURRENT_WINDOW_HANDLE, get('/session/:sessionId/window')],
275
+ [cmd.Name.CLOSE, del('/session/:sessionId/window')],
276
+ [cmd.Name.SWITCH_TO_WINDOW, post('/session/:sessionId/window')],
277
+ [cmd.Name.GET_WINDOW_HANDLES, get('/session/:sessionId/window/handles')],
278
+ [cmd.Name.GET_WINDOW_RECT, get('/session/:sessionId/window/rect')],
279
+ [cmd.Name.SET_WINDOW_RECT, post('/session/:sessionId/window/rect')],
280
+ [cmd.Name.MAXIMIZE_WINDOW, post('/session/:sessionId/window/maximize')],
281
+ [cmd.Name.MINIMIZE_WINDOW, post('/session/:sessionId/window/minimize')],
282
+ [cmd.Name.FULLSCREEN_WINDOW, post('/session/:sessionId/window/fullscreen')],
283
+ // Actions.
284
+ [cmd.Name.ACTIONS, post('/session/:sessionId/actions')],
285
+ [cmd.Name.CLEAR_ACTIONS, del('/session/:sessionId/actions')],
286
+ // Locating elements.
259
287
  [cmd.Name.GET_ACTIVE_ELEMENT, get('/session/:sessionId/element/active')],
260
- [cmd.Name.GET_ALERT_TEXT, get('/session/:sessionId/alert/text')],
261
- [cmd.Name.SET_ALERT_TEXT, post('/session/:sessionId/alert/text')],
262
- [cmd.Name.ACCEPT_ALERT, post('/session/:sessionId/alert/accept')],
263
- [cmd.Name.DISMISS_ALERT, post('/session/:sessionId/alert/dismiss')],
288
+ [cmd.Name.FIND_ELEMENT, post('/session/:sessionId/element')],
289
+ [cmd.Name.FIND_ELEMENTS, post('/session/:sessionId/elements')],
290
+ [cmd.Name.FIND_CHILD_ELEMENT, post('/session/:sessionId/element/:id/element')],
291
+ [cmd.Name.FIND_CHILD_ELEMENTS, post('/session/:sessionId/element/:id/elements')],
292
+ // Element interaction.
293
+ [cmd.Name.GET_ELEMENT_TAG_NAME, get('/session/:sessionId/element/:id/name')],
294
+ [cmd.Name.GET_ELEMENT_VALUE_OF_CSS_PROPERTY, get('/session/:sessionId/element/:id/css/:propertyName')],
295
+ [cmd.Name.GET_ELEMENT_RECT, get('/session/:sessionId/element/:id/rect')],
296
+ [cmd.Name.CLEAR_ELEMENT, post('/session/:sessionId/element/:id/clear')],
297
+ [cmd.Name.CLICK_ELEMENT, post('/session/:sessionId/element/:id/click')],
298
+ [cmd.Name.SEND_KEYS_TO_ELEMENT, post('/session/:sessionId/element/:id/value')],
299
+ [cmd.Name.GET_ELEMENT_TEXT, get('/session/:sessionId/element/:id/text')],
300
+ [cmd.Name.IS_ELEMENT_ENABLED, get('/session/:sessionId/element/:id/enabled')],
264
301
  [cmd.Name.GET_ELEMENT_ATTRIBUTE, (cmd) => {
265
302
  return toExecuteAtomCommand(cmd, Atom.GET_ATTRIBUTE, 'id', 'name');
266
303
  }],
267
- [cmd.Name.GET_ELEMENT_LOCATION, get('/session/:sessionId/element/:id/rect')],
268
- [cmd.Name.GET_ELEMENT_SIZE, get('/session/:sessionId/element/:id/rect')],
269
304
  [cmd.Name.IS_ELEMENT_DISPLAYED, (cmd) => {
270
305
  return toExecuteAtomCommand(cmd, Atom.IS_DISPLAYED, 'id');
271
306
  }],
272
- [cmd.Name.EXECUTE_SCRIPT, post('/session/:sessionId/execute/sync')],
273
- [cmd.Name.EXECUTE_ASYNC_SCRIPT, post('/session/:sessionId/execute/async')],
274
- [cmd.Name.MAXIMIZE_WINDOW, post('/session/:sessionId/window/maximize')],
275
- [cmd.Name.GET_WINDOW_POSITION, get('/session/:sessionId/window/position')],
276
- [cmd.Name.SET_WINDOW_POSITION, post('/session/:sessionId/window/position')],
277
- [cmd.Name.GET_WINDOW_SIZE, get('/session/:sessionId/window/size')],
278
- [cmd.Name.SET_WINDOW_SIZE, post('/session/:sessionId/window/size')],
279
- [cmd.Name.GET_CURRENT_WINDOW_HANDLE, get('/session/:sessionId/window')],
280
- [cmd.Name.GET_WINDOW_HANDLES, get('/session/:sessionId/window/handles')],
307
+ // Cookie management.
308
+ [cmd.Name.GET_ALL_COOKIES, get('/session/:sessionId/cookie')],
309
+ [cmd.Name.ADD_COOKIE, post('/session/:sessionId/cookie')],
310
+ [cmd.Name.DELETE_ALL_COOKIES, del('/session/:sessionId/cookie')],
311
+ [cmd.Name.GET_COOKIE, get('/session/:sessionId/cookie/:name')],
312
+ [cmd.Name.DELETE_COOKIE, del('/session/:sessionId/cookie/:name')],
313
+ // Alert management.
314
+ [cmd.Name.ACCEPT_ALERT, post('/session/:sessionId/alert/accept')],
315
+ [cmd.Name.DISMISS_ALERT, post('/session/:sessionId/alert/dismiss')],
316
+ [cmd.Name.GET_ALERT_TEXT, get('/session/:sessionId/alert/text')],
317
+ [cmd.Name.SET_ALERT_TEXT, post('/session/:sessionId/alert/text')],
318
+ // Screenshots.
319
+ [cmd.Name.SCREENSHOT, get('/session/:sessionId/screenshot')],
320
+ [cmd.Name.TAKE_ELEMENT_SCREENSHOT, get('/session/:sessionId/element/:id/screenshot')],
281
321
  ]);
282
322
 
283
323
 
@@ -301,35 +341,13 @@ class Client {
301
341
  }
302
342
 
303
343
 
304
- const CLIENTS =
305
- /** !WeakMap<!Executor, !(Client|IThenable<!Client>)> */new WeakMap;
306
-
307
-
308
- /**
309
- * Sends a request using the given executor.
310
- * @param {!Executor} executor
311
- * @param {!Request} request
312
- * @return {!Promise<Response>}
313
- */
314
- function doSend(executor, request) {
315
- const client = CLIENTS.get(executor);
316
- if (promise.isPromise(client)) {
317
- return client.then(client => {
318
- CLIENTS.set(executor, client);
319
- return client.send(request);
320
- });
321
- } else {
322
- return client.send(request);
323
- }
324
- }
325
-
326
344
 
327
345
  /**
328
346
  * @param {Map<string, CommandSpec>} customCommands
329
347
  * A map of custom command definitions.
330
348
  * @param {boolean} w3c Whether to use W3C command mappings.
331
349
  * @param {!cmd.Command} command The command to resolve.
332
- * @return {!Promise<!Request>} A promise that will resolve with the
350
+ * @return {!Request} A promise that will resolve with the
333
351
  * command to execute.
334
352
  */
335
353
  function buildRequest(customCommands, w3c, command) {
@@ -343,8 +361,8 @@ function buildRequest(customCommands, w3c, command) {
343
361
  spec = W3C_COMMAND_MAP.get(command.getName());
344
362
  if (typeof spec === 'function') {
345
363
  LOG.finest(() => `Transforming command for W3C: ${command.getName()}`);
346
- return spec(command)
347
- .then(newCommand => buildRequest(customCommands, w3c, newCommand));
364
+ let newCommand = spec(command);
365
+ return buildRequest(customCommands, w3c, newCommand);
348
366
  } else if (spec) {
349
367
  return toHttpRequest(spec);
350
368
  }
@@ -354,23 +372,26 @@ function buildRequest(customCommands, w3c, command) {
354
372
  if (spec) {
355
373
  return toHttpRequest(spec);
356
374
  }
357
- return Promise.reject(
358
- new error.UnknownCommandError(
359
- 'Unrecognized command: ' + command.getName()));
375
+ throw new error.UnknownCommandError(
376
+ 'Unrecognized command: ' + command.getName());
360
377
 
361
378
  /**
362
379
  * @param {CommandSpec} resource
363
- * @return {!Promise<!Request>}
380
+ * @return {!Request}
364
381
  */
365
382
  function toHttpRequest(resource) {
366
383
  LOG.finest(() => `Building HTTP request: ${JSON.stringify(resource)}`);
367
384
  let parameters = command.getParameters();
368
385
  let path = buildPath(resource.path, parameters);
369
- return Promise.resolve(new Request(resource.method, path, parameters));
386
+ return new Request(resource.method, path, parameters);
370
387
  }
371
388
  }
372
389
 
373
390
 
391
+ const CLIENTS =
392
+ /** !WeakMap<!Executor, !(Client|IThenable<!Client>)> */new WeakMap;
393
+
394
+
374
395
  /**
375
396
  * A command executor that communicates with the server using JSON over HTTP.
376
397
  *
@@ -430,38 +451,41 @@ class Executor {
430
451
  }
431
452
 
432
453
  /** @override */
433
- execute(command) {
454
+ async execute(command) {
434
455
  let request = buildRequest(this.customCommands_, this.w3c, command);
435
- return request.then(request => {
436
- this.log_.finer(() => `>>> ${request.method} ${request.path}`);
437
- return doSend(this, request).then(response => {
438
- this.log_.finer(() => `>>>\n${request}\n<<<\n${response}`);
439
-
440
- let httpResponse = /** @type {!Response} */(response);
441
- let {isW3C, value} = parseHttpResponse(command, httpResponse);
442
-
443
- if (command.getName() === cmd.Name.NEW_SESSION
444
- || command.getName() === cmd.Name.DESCRIBE_SESSION) {
445
- if (!value || !value.sessionId) {
446
- throw new error.WebDriverError(
447
- `Unable to parse new session response: ${response.body}`);
448
- }
449
-
450
- // The remote end is a W3C compliant server if there is no `status`
451
- // field in the response. This is not applicable for the DESCRIBE_SESSION
452
- // command, which is not defined in the W3C spec.
453
- if (command.getName() === cmd.Name.NEW_SESSION) {
454
- this.w3c = this.w3c || isW3C;
455
- }
456
-
457
- // No implementations use the `capabilities` key yet...
458
- let capabilities = value.capabilities || value.value;
459
- return new Session(value.sessionId, capabilities);
460
- }
456
+ this.log_.finer(() => `>>> ${request.method} ${request.path}`);
457
+
458
+ let client = CLIENTS.get(this);
459
+ if (promise.isPromise(client)) {
460
+ client = await client;
461
+ CLIENTS.set(this, client);
462
+ }
463
+
464
+ let response = await client.send(request);
465
+ this.log_.finer(() => `>>>\n${request}\n<<<\n${response}`);
466
+
467
+ let httpResponse = /** @type {!Response} */(response);
468
+ let {isW3C, value} = parseHttpResponse(command, httpResponse);
469
+
470
+ if (command.getName() === cmd.Name.NEW_SESSION) {
471
+ if (!value || !value.sessionId) {
472
+ throw new error.WebDriverError(
473
+ `Unable to parse new session response: ${response.body}`);
474
+ }
475
+
476
+ // The remote end is a W3C compliant server if there is no `status`
477
+ // field in the response.
478
+ if (command.getName() === cmd.Name.NEW_SESSION) {
479
+ this.w3c = this.w3c || isW3C;
480
+ }
481
+
482
+ // No implementations use the `capabilities` key yet...
483
+ let capabilities = value.capabilities || value.value;
484
+ return new Session(
485
+ /** @type {{sessionId: string}} */(value).sessionId, capabilities);
486
+ }
461
487
 
462
- return typeof value === 'undefined' ? null : value;
463
- });
464
- });
488
+ return typeof value === 'undefined' ? null : value;
465
489
  }
466
490
  }
467
491
 
@@ -510,8 +534,7 @@ function parseHttpResponse(command, httpResponse) {
510
534
 
511
535
  // Adjust legacy new session responses to look like W3C to simplify
512
536
  // later processing.
513
- if (command.getName() === cmd.Name.NEW_SESSION
514
- || command.getName() == cmd.Name.DESCRIBE_SESSION) {
537
+ if (command.getName() === cmd.Name.NEW_SESSION) {
515
538
  value = parsed;
516
539
  }
517
540