selenium-webdriver 4.0.0-beta.3 → 4.0.0

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/lib/webdriver.js CHANGED
@@ -29,26 +29,28 @@ const input = require('./input')
29
29
  const logging = require('./logging')
30
30
  const promise = require('./promise')
31
31
  const Symbols = require('./symbols')
32
- const cdpTargets = ['page', 'browser']
33
32
  const cdp = require('../devtools/CDPConnection')
34
33
  const WebSocket = require('ws')
35
34
  const http = require('../http/index')
36
35
  const fs = require('fs')
37
36
  const { Capabilities } = require('./capabilities')
38
37
  const path = require('path')
38
+ const { NoSuchElementError } = require('./error')
39
+ const cdpTargets = ['page', 'browser']
39
40
 
40
41
  // Capability names that are defined in the W3C spec.
41
42
  const W3C_CAPABILITY_NAMES = new Set([
42
43
  'acceptInsecureCerts',
43
44
  'browserName',
44
45
  'browserVersion',
45
- 'platformName',
46
46
  'pageLoadStrategy',
47
+ 'platformName',
47
48
  'proxy',
48
49
  'setWindowRect',
49
- 'timeouts',
50
50
  'strictFileInteractability',
51
+ 'timeouts',
51
52
  'unhandledPromptBehavior',
53
+ 'webSocketUrl'
52
54
  ])
53
55
 
54
56
  /**
@@ -649,7 +651,6 @@ function filterNonW3CCaps(capabilities) {
649
651
  * @implements {IWebDriver}
650
652
  */
651
653
  class WebDriver {
652
-
653
654
  /**
654
655
  * @param {!(./session.Session|IThenable<!./session.Session>)} session Either
655
656
  * a known session or a promise that will be resolved to a session.
@@ -972,16 +973,46 @@ class WebDriver {
972
973
  /** @override */
973
974
  findElement(locator) {
974
975
  let id
975
- locator = by.checkedLocator(locator)
976
+ let cmd = null
977
+
978
+ if (locator instanceof RelativeBy) {
979
+ cmd = new command.Command(
980
+ command.Name.FIND_ELEMENTS_RELATIVE
981
+ ).setParameter('args', locator.marshall())
982
+ } else {
983
+ locator = by.checkedLocator(locator)
984
+ }
985
+
976
986
  if (typeof locator === 'function') {
977
987
  id = this.findElementInternal_(locator, this)
978
- } else {
979
- let cmd = new command.Command(command.Name.FIND_ELEMENT)
988
+ return new WebElementPromise(this, id)
989
+ } else if (cmd === null) {
990
+ cmd = new command.Command(command.Name.FIND_ELEMENT)
980
991
  .setParameter('using', locator.using)
981
992
  .setParameter('value', locator.value)
982
- id = this.execute(cmd)
983
993
  }
984
- return new WebElementPromise(this, id)
994
+
995
+ id = this.execute(cmd)
996
+ if (locator instanceof RelativeBy) {
997
+ return this.normalize_(id)
998
+ } else {
999
+ return new WebElementPromise(this, id)
1000
+ }
1001
+ }
1002
+
1003
+ /**
1004
+ * @param {!Function} webElementPromise The webElement in unresolved state
1005
+ * @return {!Promise<!WebElement>} First single WebElement from array of resolved promises
1006
+ */
1007
+ async normalize_(webElementPromise) {
1008
+ let result = await webElementPromise
1009
+ if (result.length === 0) {
1010
+ throw new NoSuchElementError(
1011
+ 'Cannot locate an element with provided parameters'
1012
+ )
1013
+ } else {
1014
+ return result[0]
1015
+ }
985
1016
  }
986
1017
 
987
1018
  /**
@@ -1166,10 +1197,9 @@ class WebDriver {
1166
1197
  caps['map_'].get(this.VENDOR_COMMAND_PREFIX + ':chromeOptions') ||
1167
1198
  caps['map_'].get(this.VENDOR_CAPABILITY_PREFIX + ':edgeOptions') ||
1168
1199
  caps['map_'].get('moz:debuggerAddress') ||
1169
- new Map();
1200
+ new Map()
1170
1201
  const debuggerUrl = seCdp || vendorInfo['debuggerAddress'] || vendorInfo
1171
- this._wsUrl = await this.getWsUrl(debuggerUrl, target)
1172
-
1202
+ this._wsUrl = await this.getWsUrl(debuggerUrl, target, caps)
1173
1203
  return new Promise((resolve, reject) => {
1174
1204
  try {
1175
1205
  this._wsConnection = new WebSocket(this._wsUrl)
@@ -1192,30 +1222,38 @@ class WebDriver {
1192
1222
  /**
1193
1223
  * Retrieves 'webSocketDebuggerUrl' by sending a http request using debugger address
1194
1224
  * @param {string} debuggerAddress
1195
- * @param {string} target
1225
+ * @param target
1226
+ * @param caps
1196
1227
  * @return {string} Returns parsed webSocketDebuggerUrl obtained from the http request
1197
1228
  */
1198
- async getWsUrl(debuggerAddress, target) {
1229
+ async getWsUrl(debuggerAddress, target, caps) {
1199
1230
  if (target && cdpTargets.indexOf(target.toLowerCase()) === -1) {
1200
1231
  throw new error.InvalidArgumentError('invalid target value')
1201
1232
  }
1233
+
1234
+ if (debuggerAddress.match(/\/se\/cdp/)) {
1235
+ return debuggerAddress;
1236
+ }
1237
+
1202
1238
  let path
1203
- if (target === 'page') {
1239
+ if (target === 'page' && caps['map_'].get('browserName')!=='firefox' ){
1204
1240
  path = '/json'
1205
- } else {
1241
+ } else if(target === 'page' && caps['map_'].get('browserName')==='firefox'){
1242
+ path = '/json/list'
1243
+ }
1244
+ else {
1206
1245
  path = '/json/version'
1207
1246
  }
1247
+
1208
1248
  let request = new http.Request('GET', path)
1209
1249
  let client = new http.HttpClient('http://' + debuggerAddress)
1210
1250
  let response = await client.send(request)
1211
- let url
1251
+
1212
1252
  if (target.toLowerCase() === 'page') {
1213
- url = JSON.parse(response.body)[0]['webSocketDebuggerUrl']
1253
+ return JSON.parse(response.body)[0]['webSocketDebuggerUrl']
1214
1254
  } else {
1215
- url = JSON.parse(response.body)['webSocketDebuggerUrl']
1255
+ return JSON.parse(response.body)['webSocketDebuggerUrl']
1216
1256
  }
1217
-
1218
- return url
1219
1257
  }
1220
1258
 
1221
1259
  /**
@@ -1227,14 +1265,6 @@ class WebDriver {
1227
1265
  * @param connection CDP Connection
1228
1266
  */
1229
1267
  async register(username, password, connection) {
1230
- await connection.execute(
1231
- 'Network.setCacheDisabled',
1232
- this.getRandomNumber(1, 10),
1233
- {
1234
- cacheDisabled: true,
1235
- },
1236
- null
1237
- )
1238
1268
 
1239
1269
  this._wsConnection.on('message', (message) => {
1240
1270
  const params = JSON.parse(message)
@@ -1273,8 +1303,69 @@ class WebDriver {
1273
1303
  },
1274
1304
  null
1275
1305
  )
1306
+ await connection.execute(
1307
+ 'Network.setCacheDisabled',
1308
+ this.getRandomNumber(1, 10),
1309
+ {
1310
+ cacheDisabled: true,
1311
+ },
1312
+ null
1313
+ )
1276
1314
  }
1277
1315
 
1316
+ /**
1317
+ * Handle Network interception requests
1318
+ * @param connection WebSocket connection to the browser
1319
+ * @param httpResponse Object representing what we are intercepting
1320
+ * as well as what should be returned.
1321
+ * @param callback callback called when we intercept requests.
1322
+ */
1323
+ async onIntercept(connection, httpResponse, callback) {
1324
+
1325
+ this._wsConnection.on('message', (message) => {
1326
+ const params = JSON.parse(message)
1327
+ if (params.method === 'Fetch.requestPaused') {
1328
+ const requestPausedParams = params['params']
1329
+ if (requestPausedParams.request.url == httpResponse.urlToIntercept) {
1330
+ connection.execute(
1331
+ 'Fetch.continueRequest',
1332
+ this.getRandomNumber(1, 10),
1333
+ {
1334
+ requestId: requestPausedParams['requestId'],
1335
+ url: httpResponse.urlToIntercept,
1336
+ method: httpResponse.method,
1337
+ headers: httpResponse.headers,
1338
+ postData: httpResponse.body
1339
+ }
1340
+ )
1341
+ callback()
1342
+ } else {
1343
+ connection.execute(
1344
+ 'Fetch.continueRequest',
1345
+ this.getRandomNumber(1, 10),
1346
+ {
1347
+ requestId: requestPausedParams['requestId'],
1348
+ }
1349
+ )
1350
+ }
1351
+ }
1352
+ })
1353
+
1354
+ await connection.execute(
1355
+ 'Fetch.enable',
1356
+ 1,
1357
+ {},
1358
+ null
1359
+ )
1360
+ await connection.execute(
1361
+ 'Network.setCacheDisabled',
1362
+ this.getRandomNumber(1, 10),
1363
+ {
1364
+ cacheDisabled: true,
1365
+ },
1366
+ null
1367
+ )
1368
+ }
1278
1369
  /**
1279
1370
  *
1280
1371
  * @param connection
@@ -1282,12 +1373,7 @@ class WebDriver {
1282
1373
  * @returns {Promise<void>}
1283
1374
  */
1284
1375
  async onLogEvent(connection, callback) {
1285
- await connection.execute(
1286
- 'Runtime.enable',
1287
- this.getRandomNumber(1, 10),
1288
- {},
1289
- null
1290
- )
1376
+
1291
1377
 
1292
1378
  this._wsConnection.on('message', (message) => {
1293
1379
  const params = JSON.parse(message)
@@ -1303,6 +1389,12 @@ class WebDriver {
1303
1389
  callback(event)
1304
1390
  }
1305
1391
  })
1392
+ await connection.execute(
1393
+ 'Runtime.enable',
1394
+ this.getRandomNumber(1, 10),
1395
+ {},
1396
+ null
1397
+ )
1306
1398
  }
1307
1399
 
1308
1400
  /**
@@ -1374,7 +1466,10 @@ class WebDriver {
1374
1466
  .toString()
1375
1467
  } catch {
1376
1468
  mutationListener = fs
1377
- .readFileSync(path.resolve(__dirname, './atoms/mutation-listener.js'), 'utf-8')
1469
+ .readFileSync(
1470
+ path.resolve(__dirname, './atoms/mutation-listener.js'),
1471
+ 'utf-8'
1472
+ )
1378
1473
  .toString()
1379
1474
  }
1380
1475
 
@@ -2692,18 +2787,12 @@ class WebElement {
2692
2787
  * Take a screenshot of the visible region encompassed by this element's
2693
2788
  * bounding rectangle.
2694
2789
  *
2695
- * @param {boolean=} scroll Optional argument that indicates whether the
2696
- * element should be scrolled into view before taking a screenshot.
2697
- * Defaults to false.
2698
2790
  * @return {!Promise<string>} A promise that will be
2699
2791
  * resolved to the screenshot as a base-64 encoded PNG.
2700
2792
  */
2701
- takeScreenshot(scroll = false) {
2793
+ takeScreenshot() {
2702
2794
  return this.execute_(
2703
- new command.Command(command.Name.TAKE_ELEMENT_SCREENSHOT).setParameter(
2704
- 'scroll',
2705
- scroll
2706
- )
2795
+ new command.Command(command.Name.TAKE_ELEMENT_SCREENSHOT)
2707
2796
  )
2708
2797
  }
2709
2798
  }
package/opera.js CHANGED
@@ -383,9 +383,9 @@ class Driver extends webdriver.WebDriver {
383
383
  caps = options.toCapabilities(caps)
384
384
  }
385
385
 
386
- return /** @type {!Driver} */ (super.createSession(executor, caps, () =>
387
- service.kill()
388
- ))
386
+ return /** @type {!Driver} */ (
387
+ super.createSession(executor, caps, () => service.kill())
388
+ )
389
389
  }
390
390
 
391
391
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "selenium-webdriver",
3
- "version": "4.0.0-beta.3",
3
+ "version": "4.0.0",
4
4
  "description": "The official WebDriver JavaScript bindings from the Selenium project",
5
5
  "license": "Apache-2.0",
6
6
  "keywords": [
@@ -23,24 +23,24 @@
23
23
  "node": ">= 10.15.0"
24
24
  },
25
25
  "dependencies": {
26
- "jszip": "^3.5.0",
27
- "rimraf": "^2.7.1",
26
+ "jszip": "^3.6.0",
27
+ "rimraf": "^3.0.2",
28
28
  "tmp": "^0.2.1",
29
- "ws": "^7.3.1"
29
+ "ws": ">=7.4.6"
30
30
  },
31
31
  "devDependencies": {
32
- "eslint": "^7.15.0",
33
- "eslint-config-prettier": "^7.0.0",
34
- "eslint-plugin-no-only-tests": "^2.4.0",
32
+ "eslint": "^7.26.0",
33
+ "eslint-config-prettier": "^8.3.0",
34
+ "eslint-plugin-no-only-tests": "^2.6.0",
35
35
  "eslint-plugin-node": "^11.1.0",
36
- "eslint-plugin-prettier": "^3.2.0",
36
+ "eslint-plugin-prettier": "^3.4.0",
37
37
  "express": "^4.17.1",
38
- "jasmine": "^3.6.1",
38
+ "jasmine": "^3.8.0",
39
39
  "mocha": "^8.1.0",
40
40
  "multer": "^1.4.2",
41
- "prettier": "^2.2.1",
41
+ "prettier": "^2.3.0",
42
42
  "serve-index": "^1.9.1",
43
- "sinon": "^7.5.0"
43
+ "sinon": "^10.0.0"
44
44
  },
45
45
  "scripts": {
46
46
  "lint": "eslint --ignore-pattern node_modules --ignore-pattern generator --ext js lib/http.js \"**/*.js\"",
package/remote/index.js CHANGED
@@ -448,7 +448,7 @@ DriverService.Builder = class {
448
448
 
449
449
  /**
450
450
  * Manages the life and death of the
451
- * <a href="http://selenium-release.storage.googleapis.com/index.html">
451
+ * <a href="https://www.selenium.dev/downloads/">
452
452
  * standalone Selenium server</a>.
453
453
  */
454
454
  class SeleniumServer extends DriverService {
@@ -562,7 +562,7 @@ SeleniumServer.Options = class {
562
562
  /**
563
563
  * A {@link webdriver.FileDetector} that may be used when running
564
564
  * against a remote
565
- * [Selenium server](http://selenium-release.storage.googleapis.com/index.html).
565
+ * [Selenium server](https://www.selenium.dev/downloads/).
566
566
  *
567
567
  * When a file path on the local machine running this script is entered with
568
568
  * {@link webdriver.WebElement#sendKeys WebElement#sendKeys}, this file detector
package/safari.js CHANGED
@@ -154,9 +154,9 @@ class Driver extends webdriver.WebDriver {
154
154
  service.start().then((url) => new http.HttpClient(url))
155
155
  )
156
156
 
157
- return /** @type {!Driver} */ (super.createSession(executor, caps, () =>
158
- service.kill()
159
- ))
157
+ return /** @type {!Driver} */ (
158
+ super.createSession(executor, caps, () => service.kill())
159
+ )
160
160
  }
161
161
  }
162
162
 
package/testing/index.js CHANGED
@@ -40,7 +40,7 @@ const ie = require('../ie')
40
40
  const remote = require('../remote')
41
41
  const safari = require('../safari')
42
42
  const opera = require('../opera')
43
- const { Browser } = require('../lib/capabilities')
43
+ const { Browser, Capabilities } = require('../lib/capabilities')
44
44
  const { Builder } = require('../index')
45
45
 
46
46
  /**
@@ -236,7 +236,8 @@ function init(force = false) {
236
236
  }
237
237
 
238
238
  const TARGET_MAP = /** !WeakMap<!Environment, !TargetBrowser> */ new WeakMap()
239
- const URL_MAP = /** !WeakMap<!Environment, ?(string|remote.SeleniumServer)> */ new WeakMap()
239
+ const URL_MAP =
240
+ /** !WeakMap<!Environment, ?(string|remote.SeleniumServer)> */ new WeakMap()
240
241
 
241
242
  /**
242
243
  * Defines the environment a {@linkplain suite test suite} is running against.
@@ -249,9 +250,9 @@ class Environment {
249
250
  * Selenium server to test against.
250
251
  */
251
252
  constructor(browser, url = undefined) {
252
- browser = /** @type {!TargetBrowser} */ (Object.seal(
253
- Object.assign({}, browser)
254
- ))
253
+ browser = /** @type {!TargetBrowser} */ (
254
+ Object.seal(Object.assign({}, browser))
255
+ )
255
256
 
256
257
  TARGET_MAP.set(this, browser)
257
258
  URL_MAP.set(this, url || null)
@@ -289,7 +290,7 @@ class Environment {
289
290
  const realBuild = builder.build
290
291
  builder.build = function () {
291
292
 
292
- builder.forBrowser(browser.name, browser.version, browser.platform)
293
+ builder.withCapabilities(Capabilities[browser.name].apply(Capabilities))
293
294
 
294
295
  if (browser.capabilities) {
295
296
  builder.getCapabilities().merge(browser.capabilities)