selenium-webdriver 4.0.0-alpha.7 → 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.
package/chromium.js CHANGED
@@ -73,18 +73,20 @@
73
73
  * let driver = chrome.Driver.createSession(options, service);
74
74
  */
75
75
 
76
- 'use strict';
77
-
78
- const http = require('./http');
79
- const io = require('./io');
80
- const {Capabilities, Capability} = require('./lib/capabilities');
81
- const command = require('./lib/command');
82
- const error = require('./lib/error');
83
- const promise = require('./lib/promise');
84
- const Symbols = require('./lib/symbols');
85
- const webdriver = require('./lib/webdriver');
86
- const remote = require('./remote');
76
+ 'use strict'
87
77
 
78
+ const http = require('./http')
79
+ const io = require('./io')
80
+ const { Capabilities, Capability } = require('./lib/capabilities')
81
+ const command = require('./lib/command')
82
+ const error = require('./lib/error')
83
+ const Symbols = require('./lib/symbols')
84
+ const webdriver = require('./lib/webdriver')
85
+ const WebSocket = require('ws')
86
+ const cdp = require('./devtools/CDPConnection')
87
+ const remote = require('./remote')
88
+ const cdpTargets = ['page', 'browser']
89
+ const fs = require('fs')
88
90
 
89
91
  /**
90
92
  * Custom command names supported by Chromium WebDriver.
@@ -95,13 +97,14 @@ const Command = {
95
97
  GET_NETWORK_CONDITIONS: 'getNetworkConditions',
96
98
  SET_NETWORK_CONDITIONS: 'setNetworkConditions',
97
99
  SEND_DEVTOOLS_COMMAND: 'sendDevToolsCommand',
100
+ SEND_AND_GET_DEVTOOLS_COMMAND: 'sendAndGetDevToolsCommand',
101
+ SET_PERMISSION: 'setPermission',
98
102
  GET_CAST_SINKS: 'getCastSinks',
99
103
  SET_CAST_SINK_TO_USE: 'setCastSinkToUse',
100
104
  START_CAST_TAB_MIRRORING: 'setCastTabMirroring',
101
105
  GET_CAST_ISSUE_MESSAGE: 'getCastIssueMessage',
102
106
  STOP_CASTING: 'stopCasting',
103
- };
104
-
107
+ }
105
108
 
106
109
  /**
107
110
  * Creates a command executor with support for Chromium's custom commands.
@@ -109,58 +112,75 @@ const Command = {
109
112
  * @return {!command.Executor} The new command executor.
110
113
  */
111
114
  function createExecutor(url, vendorPrefix) {
112
- let agent = new http.Agent({ keepAlive: true });
113
- let client = url.then(url => new http.HttpClient(url, agent));
114
- let executor = new http.Executor(client);
115
- configureExecutor(executor, vendorPrefix);
116
- return executor;
115
+ let agent = new http.Agent({ keepAlive: true })
116
+ let client = url.then((url) => new http.HttpClient(url, agent))
117
+ let executor = new http.Executor(client)
118
+ configureExecutor(executor, vendorPrefix)
119
+ return executor
117
120
  }
118
121
 
119
-
120
122
  /**
121
123
  * Configures the given executor with Chromium-specific commands.
122
124
  * @param {!http.Executor} executor the executor to configure.
123
125
  */
124
126
  function configureExecutor(executor, vendorPrefix) {
125
127
  executor.defineCommand(
126
- Command.LAUNCH_APP,
127
- 'POST',
128
- '/session/:sessionId/chromium/launch_app');
128
+ Command.LAUNCH_APP,
129
+ 'POST',
130
+ '/session/:sessionId/chromium/launch_app'
131
+ )
132
+ executor.defineCommand(
133
+ Command.GET_NETWORK_CONDITIONS,
134
+ 'GET',
135
+ '/session/:sessionId/chromium/network_conditions'
136
+ )
137
+ executor.defineCommand(
138
+ Command.SET_NETWORK_CONDITIONS,
139
+ 'POST',
140
+ '/session/:sessionId/chromium/network_conditions'
141
+ )
129
142
  executor.defineCommand(
130
- Command.GET_NETWORK_CONDITIONS,
131
- 'GET',
132
- '/session/:sessionId/chromium/network_conditions');
143
+ Command.SEND_DEVTOOLS_COMMAND,
144
+ 'POST',
145
+ '/session/:sessionId/chromium/send_command'
146
+ )
133
147
  executor.defineCommand(
134
- Command.SET_NETWORK_CONDITIONS,
135
- 'POST',
136
- '/session/:sessionId/chromium/network_conditions');
148
+ Command.SEND_AND_GET_DEVTOOLS_COMMAND,
149
+ 'POST',
150
+ '/session/:sessionId/chromium/send_command_and_get_result'
151
+ )
137
152
  executor.defineCommand(
138
- Command.SEND_DEVTOOLS_COMMAND,
139
- 'POST',
140
- '/session/:sessionId/chromium/send_command');
153
+ Command.SET_PERMISSION,
154
+ 'POST',
155
+ '/session/:sessionId/permissions'
156
+ )
141
157
  executor.defineCommand(
142
- Command.GET_CAST_SINKS,
143
- 'GET',
144
- `/session/:sessionId/${vendorPrefix}/cast/get_sinks`);
158
+ Command.GET_CAST_SINKS,
159
+ 'GET',
160
+ `/session/:sessionId/${vendorPrefix}/cast/get_sinks`
161
+ )
145
162
  executor.defineCommand(
146
- Command.SET_CAST_SINK_TO_USE,
147
- 'POST',
148
- `/session/:sessionId/${vendorPrefix}/cast/set_sink_to_use`);
163
+ Command.SET_CAST_SINK_TO_USE,
164
+ 'POST',
165
+ `/session/:sessionId/${vendorPrefix}/cast/set_sink_to_use`
166
+ )
149
167
  executor.defineCommand(
150
- Command.START_CAST_TAB_MIRRORING,
151
- 'POST',
152
- `/session/:sessionId/${vendorPrefix}/cast/start_tab_mirroring`);
168
+ Command.START_CAST_TAB_MIRRORING,
169
+ 'POST',
170
+ `/session/:sessionId/${vendorPrefix}/cast/start_tab_mirroring`
171
+ )
153
172
  executor.defineCommand(
154
- Command.GET_CAST_ISSUE_MESSAGE,
155
- 'GET',
156
- `/session/:sessionId/${vendorPrefix}/cast/get_issue_message`);
173
+ Command.GET_CAST_ISSUE_MESSAGE,
174
+ 'GET',
175
+ `/session/:sessionId/${vendorPrefix}/cast/get_issue_message`
176
+ )
157
177
  executor.defineCommand(
158
- Command.STOP_CASTING,
159
- 'POST',
160
- `/session/:sessionId/${vendorPrefix}/cast/stop_casting`);
178
+ Command.STOP_CASTING,
179
+ 'POST',
180
+ `/session/:sessionId/${vendorPrefix}/cast/stop_casting`
181
+ )
161
182
  }
162
183
 
163
-
164
184
  /**
165
185
  * Creates {@link selenium-webdriver/remote.DriverService} instances that manage
166
186
  * a WebDriver server in a child process.
@@ -171,8 +191,8 @@ class ServiceBuilder extends remote.DriverService.Builder {
171
191
  * should ensure a valid path to the appropriate exe is provided.
172
192
  */
173
193
  constructor(exe) {
174
- super(exe);
175
- this.setLoopback(true); // Required
194
+ super(exe)
195
+ this.setLoopback(true) // Required
176
196
  }
177
197
 
178
198
  /**
@@ -184,7 +204,7 @@ class ServiceBuilder extends remote.DriverService.Builder {
184
204
  * @return {!ServiceBuilder} A self reference.
185
205
  */
186
206
  setAdbPort(port) {
187
- return this.addArguments('--adb-port=' + port);
207
+ return this.addArguments('--adb-port=' + port)
188
208
  }
189
209
 
190
210
  /**
@@ -194,7 +214,7 @@ class ServiceBuilder extends remote.DriverService.Builder {
194
214
  * @return {!ServiceBuilder} A self reference.
195
215
  */
196
216
  loggingTo(path) {
197
- return this.addArguments('--log-path=' + path);
217
+ return this.addArguments('--log-path=' + path)
198
218
  }
199
219
 
200
220
  /**
@@ -202,7 +222,7 @@ class ServiceBuilder extends remote.DriverService.Builder {
202
222
  * @return {!ServiceBuilder} A self reference.
203
223
  */
204
224
  enableVerboseLogging() {
205
- return this.addArguments('--verbose');
225
+ return this.addArguments('--verbose')
206
226
  }
207
227
 
208
228
  /**
@@ -212,19 +232,18 @@ class ServiceBuilder extends remote.DriverService.Builder {
212
232
  * @return {!ServiceBuilder} A self reference.
213
233
  */
214
234
  setNumHttpThreads(n) {
215
- return this.addArguments('--http-threads=' + n);
235
+ return this.addArguments('--http-threads=' + n)
216
236
  }
217
237
 
218
238
  /**
219
239
  * @override
220
240
  */
221
241
  setPath(path) {
222
- super.setPath(path);
223
- return this.addArguments('--url-base=' + path);
242
+ super.setPath(path)
243
+ return this.addArguments('--url-base=' + path)
224
244
  }
225
245
  }
226
246
 
227
-
228
247
  /**
229
248
  * Class for managing WebDriver options specific to a Chromium-based browser.
230
249
  */
@@ -234,13 +253,13 @@ class Options extends Capabilities {
234
253
  * capabilities to initialize this instance from.
235
254
  */
236
255
  constructor(other = undefined) {
237
- super(other);
256
+ super(other)
238
257
 
239
258
  /** @private {!Object} */
240
- this.options_ = this.get(this.CAPABILITY_KEY) || {};
259
+ this.options_ = this.get(this.CAPABILITY_KEY) || {}
241
260
 
242
- this.setBrowserName(this.BROWSER_NAME_VALUE);
243
- this.set(this.CAPABILITY_KEY, this.options_);
261
+ this.setBrowserName(this.BROWSER_NAME_VALUE)
262
+ this.set(this.CAPABILITY_KEY, this.options_)
244
263
  }
245
264
 
246
265
  /**
@@ -253,11 +272,11 @@ class Options extends Capabilities {
253
272
  * @return {!Options} A self reference.
254
273
  */
255
274
  addArguments(...args) {
256
- let newArgs = (this.options_.args || []).concat(...args);
275
+ let newArgs = (this.options_.args || []).concat(...args)
257
276
  if (newArgs.length) {
258
- this.options_.args = newArgs;
277
+ this.options_.args = newArgs
259
278
  }
260
- return this;
279
+ return this
261
280
  }
262
281
 
263
282
  /**
@@ -276,7 +295,7 @@ class Options extends Capabilities {
276
295
  * @return {!Options} A self reference.
277
296
  */
278
297
  headless() {
279
- return this.addArguments('headless');
298
+ return this.addArguments('headless')
280
299
  }
281
300
 
282
301
  /**
@@ -287,15 +306,15 @@ class Options extends Capabilities {
287
306
  * @throws {TypeError} if width or height is unspecified, not a number, or
288
307
  * less than or equal to 0.
289
308
  */
290
- windowSize({width, height}) {
309
+ windowSize({ width, height }) {
291
310
  function checkArg(arg) {
292
311
  if (typeof arg !== 'number' || arg <= 0) {
293
- throw TypeError('Arguments must be {width, height} with numbers > 0');
312
+ throw TypeError('Arguments must be {width, height} with numbers > 0')
294
313
  }
295
314
  }
296
- checkArg(width);
297
- checkArg(height);
298
- return this.addArguments(`window-size=${width},${height}`);
315
+ checkArg(width)
316
+ checkArg(height)
317
+ return this.addArguments(`window-size=${width},${height}`)
299
318
  }
300
319
 
301
320
  /**
@@ -306,11 +325,11 @@ class Options extends Capabilities {
306
325
  * @return {!Options} A self reference.
307
326
  */
308
327
  excludeSwitches(...args) {
309
- let switches = (this.options_.excludeSwitches || []).concat(...args);
328
+ let switches = (this.options_.excludeSwitches || []).concat(...args)
310
329
  if (switches.length) {
311
- this.options_.excludeSwitches = switches;
330
+ this.options_.excludeSwitches = switches
312
331
  }
313
- return this;
332
+ return this
314
333
  }
315
334
 
316
335
  /**
@@ -322,9 +341,9 @@ class Options extends Capabilities {
322
341
  * @return {!Options} A self reference.
323
342
  */
324
343
  addExtensions(...args) {
325
- let current = this.options_.extensions || [];
326
- this.options_.extensions = current.concat(...args);
327
- return this;
344
+ let current = this.options_.extensions || []
345
+ this.options_.extensions = current.concat(...args)
346
+ return this
328
347
  }
329
348
 
330
349
  /**
@@ -339,8 +358,8 @@ class Options extends Capabilities {
339
358
  * @return {!Options} A self reference.
340
359
  */
341
360
  setBinaryPath(path) {
342
- this.options_.binary = path;
343
- return this;
361
+ this.options_.binary = path
362
+ return this
344
363
  }
345
364
 
346
365
  /**
@@ -352,8 +371,8 @@ class Options extends Capabilities {
352
371
  * @return {!Options} A self reference.
353
372
  */
354
373
  detachDriver(detach) {
355
- this.options_.detach = detach;
356
- return this;
374
+ this.options_.detach = detach
375
+ return this
357
376
  }
358
377
 
359
378
  /**
@@ -363,8 +382,8 @@ class Options extends Capabilities {
363
382
  * @return {!Options} A self reference.
364
383
  */
365
384
  setUserPreferences(prefs) {
366
- this.options_.prefs = prefs;
367
- return this;
385
+ this.options_.prefs = prefs
386
+ return this
368
387
  }
369
388
 
370
389
  /**
@@ -392,8 +411,8 @@ class Options extends Capabilities {
392
411
  * @return {!Options} A self reference.
393
412
  */
394
413
  setPerfLoggingPrefs(prefs) {
395
- this.options_.perfLoggingPrefs = prefs;
396
- return this;
414
+ this.options_.perfLoggingPrefs = prefs
415
+ return this
397
416
  }
398
417
 
399
418
  /**
@@ -403,8 +422,8 @@ class Options extends Capabilities {
403
422
  * @return {!Options} A self reference.
404
423
  */
405
424
  setLocalState(state) {
406
- this.options_.localState = state;
407
- return this;
425
+ this.options_.localState = state
426
+ return this
408
427
  }
409
428
 
410
429
  /**
@@ -416,8 +435,8 @@ class Options extends Capabilities {
416
435
  * @return {!Options} A self reference.
417
436
  */
418
437
  androidActivity(name) {
419
- this.options_.androidActivity = name;
420
- return this;
438
+ this.options_.androidActivity = name
439
+ return this
421
440
  }
422
441
 
423
442
  /**
@@ -429,8 +448,8 @@ class Options extends Capabilities {
429
448
  * @return {!Options} A self reference.
430
449
  */
431
450
  androidDeviceSerial(serial) {
432
- this.options_.androidDeviceSerial = serial;
433
- return this;
451
+ this.options_.androidDeviceSerial = serial
452
+ return this
434
453
  }
435
454
 
436
455
  /**
@@ -441,8 +460,8 @@ class Options extends Capabilities {
441
460
  * @return {!Options} A self reference.
442
461
  */
443
462
  androidPackage(pkg) {
444
- this.options_.androidPackage = pkg;
445
- return this;
463
+ this.options_.androidPackage = pkg
464
+ return this
446
465
  }
447
466
 
448
467
  /**
@@ -454,8 +473,8 @@ class Options extends Capabilities {
454
473
  * @return {!Options} A self reference.
455
474
  */
456
475
  androidProcess(processName) {
457
- this.options_.androidProcess = processName;
458
- return this;
476
+ this.options_.androidProcess = processName
477
+ return this
459
478
  }
460
479
 
461
480
  /**
@@ -467,8 +486,8 @@ class Options extends Capabilities {
467
486
  * @return {!Options} A self reference.
468
487
  */
469
488
  androidUseRunningApp(useRunning) {
470
- this.options_.androidUseRunningApp = useRunning;
471
- return this;
489
+ this.options_.androidUseRunningApp = useRunning
490
+ return this
472
491
  }
473
492
 
474
493
  /**
@@ -478,8 +497,8 @@ class Options extends Capabilities {
478
497
  * @return {!Options} A self reference.
479
498
  */
480
499
  setBrowserLogFile(path) {
481
- this.options_.logPath = path;
482
- return this;
500
+ this.options_.logPath = path
501
+ return this
483
502
  }
484
503
 
485
504
  /**
@@ -489,8 +508,8 @@ class Options extends Capabilities {
489
508
  * @return {!Options} A self reference.
490
509
  */
491
510
  setBrowserMinidumpPath(path) {
492
- this.options_.minidumpPath = path;
493
- return this;
511
+ this.options_.minidumpPath = path
512
+ return this
494
513
  }
495
514
 
496
515
  /**
@@ -512,11 +531,11 @@ class Options extends Capabilities {
512
531
  *
513
532
  * __Example 2: Using Custom Screen Configuration__
514
533
  *
515
- * let options = new chrome.Options().setMobileEmulation({
534
+ * let options = new chrome.Options().setMobileEmulation({deviceMetrics: {
516
535
  * width: 360,
517
536
  * height: 640,
518
537
  * pixelRatio: 3.0
519
- * });
538
+ * }});
520
539
  *
521
540
  * let driver = chrome.Driver.createSession(options);
522
541
  *
@@ -530,8 +549,8 @@ class Options extends Capabilities {
530
549
  * @return {!Options} A self reference.
531
550
  */
532
551
  setMobileEmulation(config) {
533
- this.options_.mobileEmulation = config;
534
- return this;
552
+ this.options_.mobileEmulation = config
553
+ return this
535
554
  }
536
555
 
537
556
  /**
@@ -542,21 +561,22 @@ class Options extends Capabilities {
542
561
  * @suppress {checkTypes} Suppress [] access on a struct.
543
562
  */
544
563
  [Symbols.serialize]() {
545
- if (this.options_.extensions && this.options_.extensions.length) {
546
- this.options_.extensions =
547
- this.options_.extensions.map(function(extension) {
548
- if (Buffer.isBuffer(extension)) {
549
- return extension.toString('base64');
550
- }
551
- return io.read(/** @type {string} */(extension))
552
- .then(buffer => buffer.toString('base64'));
553
- });
564
+ if (this.options_.extensions && this.options_.extensions.length) {
565
+ this.options_.extensions = this.options_.extensions.map(function (
566
+ extension
567
+ ) {
568
+ if (Buffer.isBuffer(extension)) {
569
+ return extension.toString('base64')
570
+ }
571
+ return io
572
+ .read(/** @type {string} */ (extension))
573
+ .then((buffer) => buffer.toString('base64'))
574
+ })
554
575
  }
555
- return super[Symbols.serialize]();
576
+ return super[Symbols.serialize]()
556
577
  }
557
578
  }
558
579
 
559
-
560
580
  /**
561
581
  * Creates a new WebDriver client for Chromium-based browsers.
562
582
  */
@@ -573,28 +593,28 @@ class Driver extends webdriver.WebDriver {
573
593
  * @return {!Driver} A new driver instance.
574
594
  */
575
595
  static createSession(caps, opt_serviceExecutor) {
576
- let executor;
577
- let onQuit;
596
+ let executor
597
+ let onQuit
578
598
  if (opt_serviceExecutor instanceof http.Executor) {
579
- executor = opt_serviceExecutor;
580
- configureExecutor(executor, this.VENDOR_COMMAND_PREFIX);
599
+ executor = opt_serviceExecutor
600
+ configureExecutor(executor, this.VENDOR_COMMAND_PREFIX)
581
601
  } else {
582
- let service = opt_serviceExecutor || this.getDefaultService();
583
- executor = createExecutor(service.start(), this.VENDOR_COMMAND_PREFIX);
584
- onQuit = () => service.kill();
602
+ let service = opt_serviceExecutor || this.getDefaultService()
603
+ executor = createExecutor(service.start(), this.VENDOR_COMMAND_PREFIX)
604
+ onQuit = () => service.kill()
585
605
  }
586
606
 
587
607
  // W3C spec requires noProxy value to be an array of strings, but Chromium
588
608
  // expects a single host as a string.
589
- let proxy = caps.get(Capability.PROXY);
609
+ let proxy = caps.get(Capability.PROXY)
590
610
  if (proxy && Array.isArray(proxy.noProxy)) {
591
- proxy.noProxy = proxy.noProxy[0];
611
+ proxy.noProxy = proxy.noProxy[0]
592
612
  if (!proxy.noProxy) {
593
- proxy.noProxy = undefined;
613
+ proxy.noProxy = undefined
594
614
  }
595
615
  }
596
616
 
597
- return /** @type {!Driver} */(super.createSession(executor, caps, onQuit));
617
+ return /** @type {!Driver} */ (super.createSession(executor, caps, onQuit))
598
618
  }
599
619
 
600
620
  /**
@@ -612,7 +632,8 @@ class Driver extends webdriver.WebDriver {
612
632
  */
613
633
  launchApp(id) {
614
634
  return this.execute(
615
- new command.Command(Command.LAUNCH_APP).setParameter('id', id));
635
+ new command.Command(Command.LAUNCH_APP).setParameter('id', id)
636
+ )
616
637
  }
617
638
 
618
639
  /**
@@ -621,7 +642,7 @@ class Driver extends webdriver.WebDriver {
621
642
  * emulation settings are retrievied.
622
643
  */
623
644
  getNetworkConditions() {
624
- return this.execute(new command.Command(Command.GET_NETWORK_CONDITIONS));
645
+ return this.execute(new command.Command(Command.GET_NETWORK_CONDITIONS))
625
646
  }
626
647
 
627
648
  /**
@@ -642,11 +663,16 @@ class Driver extends webdriver.WebDriver {
642
663
  */
643
664
  setNetworkConditions(spec) {
644
665
  if (!spec || typeof spec !== 'object') {
645
- throw TypeError('setNetworkConditions called with non-network-conditions parameter');
666
+ throw TypeError(
667
+ 'setNetworkConditions called with non-network-conditions parameter'
668
+ )
646
669
  }
647
670
  return this.execute(
648
- new command.Command(Command.SET_NETWORK_CONDITIONS)
649
- .setParameter('network_conditions', spec));
671
+ new command.Command(Command.SET_NETWORK_CONDITIONS).setParameter(
672
+ 'network_conditions',
673
+ spec
674
+ )
675
+ )
650
676
  }
651
677
 
652
678
  /**
@@ -660,9 +686,232 @@ class Driver extends webdriver.WebDriver {
660
686
  */
661
687
  sendDevToolsCommand(cmd, params = {}) {
662
688
  return this.execute(
663
- new command.Command(Command.SEND_DEVTOOLS_COMMAND)
664
- .setParameter('cmd', cmd)
665
- .setParameter('params', params));
689
+ new command.Command(Command.SEND_DEVTOOLS_COMMAND)
690
+ .setParameter('cmd', cmd)
691
+ .setParameter('params', params)
692
+ )
693
+ }
694
+
695
+ /**
696
+ * ends an arbitrary devtools command to the browser and get the result.
697
+ *
698
+ * @param {string} cmd The name of the command to send.
699
+ * @param {Object=} params The command parameters.
700
+ * @return {!Promise<void>} A promise that will be resolved when the command
701
+ * has finished.
702
+ * @see <https://chromedevtools.github.io/devtools-protocol/>
703
+ */
704
+ sendAndGetDevToolsCommand(cmd, params = {}) {
705
+ return this.execute(
706
+ new command.Command(Command.SEND_AND_GET_DEVTOOLS_COMMAND)
707
+ .setParameter('cmd', cmd)
708
+ .setParameter('params', params)
709
+ )
710
+ }
711
+
712
+ /**
713
+ * Creates a new WebSocket connection.
714
+ * @return {!Promise<resolved>} A new CDP instance.
715
+ */
716
+ async createCDPConnection(target) {
717
+ const caps = await this.getCapabilities()
718
+ const seOptions = caps['map_'].get('se:options') || new Map()
719
+ const vendorInfo =
720
+ caps['map_'].get(this.VENDOR_COMMAND_PREFIX + ':chromeOptions') ||
721
+ new Map()
722
+ const debuggerUrl = seOptions['cdp'] || vendorInfo['debuggerAddress']
723
+ this._wsUrl = await this.getWsUrl(debuggerUrl, target)
724
+
725
+ return new Promise((resolve, reject) => {
726
+ try {
727
+ this._wsConnection = new WebSocket(this._wsUrl)
728
+ } catch (err) {
729
+ reject(err)
730
+ return
731
+ }
732
+
733
+ this._wsConnection.on('open', () => {
734
+ this._cdpConnection = new cdp.CdpConnection(this._wsConnection)
735
+ resolve(this._cdpConnection)
736
+ })
737
+
738
+ this._wsConnection.on('error', (error) => {
739
+ reject(error)
740
+ })
741
+ })
742
+ }
743
+
744
+ /**
745
+ * Retrieves 'webSocketDebuggerUrl' by sending a http request using debugger address
746
+ * @param {string} debuggerAddress
747
+ * @param {string} target
748
+ * @return {string} Returns parsed webSocketDebuggerUrl obtained from the http request
749
+ */
750
+ async getWsUrl(debuggerAddress, target) {
751
+ if (target && cdpTargets.indexOf(target.toLowerCase()) === -1) {
752
+ throw new error.InvalidArgumentError('invalid target value')
753
+ }
754
+ let path = '/json/version'
755
+
756
+ if (target === 'page') {
757
+ path = '/json'
758
+ }
759
+ let request = new http.Request('GET', path)
760
+ let client = new http.HttpClient('http://' + debuggerAddress)
761
+ let response = await client.send(request)
762
+ let url = JSON.parse(response.body)['webSocketDebuggerUrl']
763
+ if (target.toLowerCase() === 'page') {
764
+ url = JSON.parse(response.body)[0]['webSocketDebuggerUrl']
765
+ }
766
+
767
+ return url
768
+ }
769
+
770
+ /**
771
+ * Sets a listener for Fetch.authRequired event from CDP
772
+ * If event is triggered, it enter username and password
773
+ * and allows the test to move forward
774
+ * @param {string} username
775
+ * @param {string} password
776
+ * @param connection CDP Connection
777
+ */
778
+ async register(username, password, connection) {
779
+ await connection.execute("Network.setCacheDisabled", this.getRandomNumber(1, 10), {
780
+ cacheDisabled: true,
781
+ }, null);
782
+
783
+ this._wsConnection.on('message', (message) => {
784
+ const params = JSON.parse(message)
785
+
786
+ if (params.method === 'Fetch.authRequired') {
787
+ const requestParams = params['params']
788
+ connection.execute('Fetch.continueWithAuth', this.getRandomNumber(1, 10), {
789
+ requestId: requestParams['requestId'],
790
+ authChallengeResponse: {
791
+ response: 'ProvideCredentials',
792
+ username: username,
793
+ password: password,
794
+ }})
795
+ } else if (params.method === 'Fetch.requestPaused') {
796
+ const requestPausedParams = params['params']
797
+ connection.execute('Fetch.continueRequest', this.getRandomNumber(1, 10), {
798
+ requestId: requestPausedParams['requestId'],
799
+ })
800
+ }
801
+ })
802
+
803
+ await connection.execute('Fetch.enable', 1, {
804
+ handleAuthRequests: true,
805
+ }, null)
806
+ }
807
+
808
+ /**
809
+ *
810
+ * @param connection
811
+ * @param callback
812
+ * @returns {Promise<void>}
813
+ */
814
+ async onLogEvent(connection, callback) {
815
+ await connection.execute('Runtime.enable', this.getRandomNumber(1, 10), {}, null)
816
+
817
+ this._wsConnection.on('message', (message) => {
818
+ const params = JSON.parse(message)
819
+
820
+ if (params.method === 'Runtime.consoleAPICalled') {
821
+ const consoleEventParams = params['params']
822
+ let event = {
823
+ type: consoleEventParams['type'],
824
+ timestamp: new Date(consoleEventParams['timestamp']),
825
+ args: consoleEventParams['args']
826
+ }
827
+
828
+ callback(event)
829
+ }
830
+ })
831
+ }
832
+
833
+ /**
834
+ * Set a permission state to the given value.
835
+ *
836
+ * @param {string} name A name of the permission to update.
837
+ * @param {('granted'|'denied'|'prompt')} state State to set permission to.
838
+ * @returns {!Promise<Object>} A promise that will be resolved when the
839
+ * command has finished.
840
+ * @see <https://w3c.github.io/permissions/#permission-registry> for valid
841
+ * names
842
+ */
843
+ setPermission(name, state) {
844
+ return this.execute(
845
+ new command.Command(Command.SET_PERMISSION)
846
+ .setParameter('descriptor', { name })
847
+ .setParameter('state', state)
848
+ )
849
+ }
850
+
851
+ /**
852
+ *
853
+ * @param connection
854
+ * @param callback
855
+ * @returns {Promise<void>}
856
+ */
857
+ async onLogException(connection, callback) {
858
+ await connection.execute('Runtime.enable', this.getRandomNumber(1, 10), {}, null)
859
+
860
+ this._wsConnection.on('message', (message) => {
861
+ const params = JSON.parse(message)
862
+
863
+ if (params.method === 'Runtime.exceptionThrown') {
864
+ const exceptionEventParams = params['params']
865
+ let event = {
866
+ exceptionDetails: exceptionEventParams['exceptionDetails'],
867
+ timestamp: new Date(exceptionEventParams['timestamp']),
868
+ }
869
+
870
+ callback(event)
871
+ }
872
+ })
873
+ }
874
+
875
+ /**
876
+ * @param connection
877
+ * @param callback
878
+ * @returns {Promise<void>}
879
+ */
880
+ async logMutationEvents(connection, callback) {
881
+ await connection.execute('Runtime.enable', this.getRandomNumber(1, 10), {}, null)
882
+ await connection.execute('Page.enable', this.getRandomNumber(1, 10), {}, null)
883
+
884
+ await connection.execute('Runtime.addBinding', this.getRandomNumber(1, 10), {
885
+ name: '__webdriver_attribute',
886
+ }, null)
887
+
888
+ const mutationListener = fs.readFileSync('../../cdp-support/mutation-listener.js', 'utf-8').toString()
889
+
890
+ this.executeScript(mutationListener)
891
+
892
+ await connection.execute('Page.addScriptToEvaluateOnNewDocument', this.getRandomNumber(1, 10), {
893
+ source: mutationListener,
894
+ }, null)
895
+
896
+ this._wsConnection.on('message', async (message) => {
897
+ const params = JSON.parse(message)
898
+ if (params.method === 'Runtime.bindingCalled') {
899
+ let payload = JSON.parse(params['params']['payload'])
900
+ let elements = await this.findElements({css: "*[data-__webdriver_id=" + payload['target']})
901
+
902
+ if (elements.length === 0) {
903
+ return
904
+ }
905
+
906
+ let event = {
907
+ element: elements[0],
908
+ attribute_name: payload['name'],
909
+ current_value: payload['value'],
910
+ old_value: payload['oldValue']
911
+ }
912
+ callback(event)
913
+ }
914
+ })
666
915
  }
667
916
 
668
917
  /**
@@ -675,19 +924,18 @@ class Driver extends webdriver.WebDriver {
675
924
  */
676
925
  async setDownloadPath(path) {
677
926
  if (!path || typeof path !== 'string') {
678
- throw new error.InvalidArgumentError('invalid download path');
927
+ throw new error.InvalidArgumentError('invalid download path')
679
928
  }
680
- const stat = await io.stat(path);
929
+ const stat = await io.stat(path)
681
930
  if (!stat.isDirectory()) {
682
- throw new error.InvalidArgumentError('not a directory: ' + path);
931
+ throw new error.InvalidArgumentError('not a directory: ' + path)
683
932
  }
684
933
  return this.sendDevToolsCommand('Page.setDownloadBehavior', {
685
- 'behavior': 'allow',
686
- 'downloadPath': path
687
- });
934
+ behavior: 'allow',
935
+ downloadPath: path,
936
+ })
688
937
  }
689
938
 
690
-
691
939
  /**
692
940
  * Returns the list of cast sinks (Cast devices) available to the Chrome media router.
693
941
  *
@@ -696,67 +944,81 @@ class Driver extends webdriver.WebDriver {
696
944
  */
697
945
  getCastSinks() {
698
946
  return this.schedule(
699
- new command.Command(Command.GET_CAST_SINKS),
700
- 'Driver.getCastSinks()');
947
+ new command.Command(Command.GET_CAST_SINKS),
948
+ 'Driver.getCastSinks()'
949
+ )
701
950
  }
702
951
 
703
952
  /**
704
953
  * Selects a cast sink (Cast device) as the recipient of media router intents (connect or play).
705
954
  *
706
- * @param {String} Friendly name of the target device.
955
+ * @param {String} deviceName name of the target device.
707
956
  * @return {!promise.Thenable<void>} A promise that will be resolved
708
957
  * when the target device has been selected to respond further webdriver commands.
709
958
  */
710
959
  setCastSinkToUse(deviceName) {
711
960
  return this.schedule(
712
- new command.Command(Command.SET_CAST_SINK_TO_USE).setParameter('sinkName', deviceName),
713
- 'Driver.setCastSinkToUse(' + deviceName + ')');
961
+ new command.Command(Command.SET_CAST_SINK_TO_USE).setParameter(
962
+ 'sinkName',
963
+ deviceName
964
+ ),
965
+ 'Driver.setCastSinkToUse(' + deviceName + ')'
966
+ )
714
967
  }
715
968
 
716
969
  /**
717
970
  * Initiates tab mirroring for the current browser tab on the specified device.
718
971
  *
719
- * @param {String} Friendly name of the target device.
972
+ * @param {String} deviceName name of the target device.
720
973
  * @return {!promise.Thenable<void>} A promise that will be resolved
721
974
  * when the mirror command has been issued to the device.
722
975
  */
723
976
  startCastTabMirroring(deviceName) {
724
977
  return this.schedule(
725
- new command.Command(Command.START_CAST_TAB_MIRRORING).setParameter('sinkName', deviceName),
726
- 'Driver.startCastTabMirroring(' + deviceName + ')');
978
+ new command.Command(Command.START_CAST_TAB_MIRRORING).setParameter(
979
+ 'sinkName',
980
+ deviceName
981
+ ),
982
+ 'Driver.startCastTabMirroring(' + deviceName + ')'
983
+ )
727
984
  }
728
985
 
729
986
  /**
730
- * a
731
- *
732
- * @param {String} Friendly name of the target device.
987
+ * Returns an error message when there is any issue in a Cast session.
733
988
  * @return {!promise.Thenable<void>} A promise that will be resolved
734
989
  * when the mirror command has been issued to the device.
735
990
  */
736
991
  getCastIssueMessage() {
737
992
  return this.schedule(
738
- new command.Command(Command.GET_CAST_ISSUE_MESSAGE),
739
- 'Driver.getCastIssueMessage()');
993
+ new command.Command(Command.GET_CAST_ISSUE_MESSAGE),
994
+ 'Driver.getCastIssueMessage()'
995
+ )
740
996
  }
741
997
 
742
998
  /**
743
999
  * Stops casting from media router to the specified device, if connected.
744
1000
  *
745
- * @param {String} Friendly name of the target device.
1001
+ * @param {String} deviceName name of the target device.
746
1002
  * @return {!promise.Thenable<void>} A promise that will be resolved
747
1003
  * when the stop command has been issued to the device.
748
1004
  */
749
1005
  stopCasting(deviceName) {
750
1006
  return this.schedule(
751
- new command.Command(Command.STOP_CASTING).setParameter('sinkName', deviceName),
752
- 'Driver.stopCasting(' + deviceName + ')');
1007
+ new command.Command(Command.STOP_CASTING).setParameter(
1008
+ 'sinkName',
1009
+ deviceName
1010
+ ),
1011
+ 'Driver.stopCasting(' + deviceName + ')'
1012
+ )
753
1013
  }
754
- }
755
1014
 
1015
+ getRandomNumber(min, max) {
1016
+ return Math.floor(Math.random() * (max - min + 1) + min)
1017
+ }
1018
+ }
756
1019
 
757
1020
  // PUBLIC API
758
1021
 
759
-
760
- exports.Driver = Driver;
761
- exports.Options = Options;
762
- exports.ServiceBuilder = ServiceBuilder;
1022
+ exports.Driver = Driver
1023
+ exports.Options = Options
1024
+ exports.ServiceBuilder = ServiceBuilder