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

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 (53) hide show
  1. package/CHANGES.md +41 -1
  2. package/LICENSE +202 -0
  3. package/NOTICE +2 -0
  4. package/README.md +0 -0
  5. package/chrome.js +0 -0
  6. package/chromium.js +23 -202
  7. package/devtools/CDPConnection.js +16 -18
  8. package/edge.js +89 -130
  9. package/example/chrome_android.js +45 -0
  10. package/{lib/atoms/make-atoms-module.js → example/chrome_mobile_emulation.js} +26 -15
  11. package/example/firefox_channels.js +84 -0
  12. package/example/google_search.js +50 -0
  13. package/example/google_search_test.js +70 -0
  14. package/example/headless.js +63 -0
  15. package/example/logging.js +64 -0
  16. package/firefox.js +10 -9
  17. package/http/index.js +0 -0
  18. package/http/util.js +3 -3
  19. package/ie.js +0 -0
  20. package/index.js +2 -2
  21. package/io/exec.js +3 -3
  22. package/io/index.js +12 -13
  23. package/io/zip.js +5 -6
  24. package/lib/atoms/find-elements.js +78 -78
  25. package/lib/atoms/get-attribute.js +64 -68
  26. package/lib/atoms/is-displayed.js +27 -27
  27. package/lib/atoms/mutation-listener.js +55 -0
  28. package/lib/by.js +1 -1
  29. package/lib/capabilities.js +2 -3
  30. package/lib/command.js +2 -15
  31. package/lib/error.js +0 -0
  32. package/lib/http.js +17 -30
  33. package/lib/input.js +2 -286
  34. package/lib/logging.js +0 -0
  35. package/lib/promise.js +4 -16
  36. package/lib/proxy.js +0 -0
  37. package/lib/session.js +0 -0
  38. package/lib/symbols.js +0 -0
  39. package/lib/until.js +17 -15
  40. package/lib/webdriver.js +336 -16
  41. package/net/index.js +0 -0
  42. package/net/portprober.js +8 -8
  43. package/opera.js +0 -0
  44. package/package.json +13 -13
  45. package/proxy.js +0 -0
  46. package/remote/index.js +6 -7
  47. package/safari.js +0 -0
  48. package/testing/index.js +504 -0
  49. package/.eslintrc.js +0 -27
  50. package/.prettierrc +0 -4
  51. package/devtools/generator/protocol-dts-generator.js +0 -429
  52. package/lib/README +0 -5
  53. package/lib/actions.js +0 -626
@@ -0,0 +1,504 @@
1
+ // Licensed to the Software Freedom Conservancy (SFC) under one
2
+ // or more contributor license agreements. See the NOTICE file
3
+ // distributed with this work for additional information
4
+ // regarding copyright ownership. The SFC licenses this file
5
+ // to you under the Apache License, Version 2.0 (the
6
+ // "License"); you may not use this file except in compliance
7
+ // with the License. You may obtain a copy of the License at
8
+ //
9
+ // http://www.apache.org/licenses/LICENSE-2.0
10
+ //
11
+ // Unless required by applicable law or agreed to in writing,
12
+ // software distributed under the License is distributed on an
13
+ // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ // KIND, either express or implied. See the License for the
15
+ // specific language governing permissions and limitations
16
+ // under the License.
17
+
18
+ /**
19
+ * @fileoverview Provides extensions for
20
+ * [Jasmine](https://jasmine.github.io) and [Mocha](https://mochajs.org).
21
+ *
22
+ * You may conditionally suppress a test function using the exported
23
+ * "ignore" function. If the provided predicate returns true, the attached
24
+ * test case will be skipped:
25
+ *
26
+ * test.ignore(maybe()).it('is flaky', function() {
27
+ * if (Math.random() < 0.5) throw Error();
28
+ * });
29
+ *
30
+ * function maybe() { return Math.random() < 0.5; }
31
+ */
32
+
33
+ 'use strict'
34
+
35
+ const { isatty } = require('tty')
36
+ const chrome = require('../chrome')
37
+ const edge = require('../edge')
38
+ const firefox = require('../firefox')
39
+ const ie = require('../ie')
40
+ const remote = require('../remote')
41
+ const safari = require('../safari')
42
+ const opera = require('../opera')
43
+ const { Browser } = require('../lib/capabilities')
44
+ const { Builder } = require('../index')
45
+
46
+ /**
47
+ * Describes a browser targeted by a {@linkplain suite test suite}.
48
+ * @record
49
+ */
50
+ function TargetBrowser() { }
51
+
52
+ /**
53
+ * The {@linkplain Browser name} of the targeted browser.
54
+ * @type {string}
55
+ */
56
+ TargetBrowser.prototype.name
57
+
58
+ /**
59
+ * The specific version of the targeted browser, if any.
60
+ * @type {(string|undefined)}
61
+ */
62
+ TargetBrowser.prototype.version
63
+
64
+ /**
65
+ * The specific {@linkplain ../lib/capabilities.Platform platform} for the
66
+ * targeted browser, if any.
67
+ * @type {(string|undefined)}.
68
+ */
69
+ TargetBrowser.prototype.platform
70
+
71
+ /** @suppress {checkTypes} */
72
+ function color(c, s) {
73
+ return isatty(process.stdout) ? `\u001b[${c}m${s}\u001b[0m` : s
74
+ }
75
+ function green(s) {
76
+ return color(32, s)
77
+ }
78
+ function cyan(s) {
79
+ return color(36, s)
80
+ }
81
+ function info(msg) {
82
+ console.info(`${green('[INFO]')} ${msg}`)
83
+ }
84
+ function warn(msg) {
85
+ console.warn(`${cyan('[WARNING]')} ${msg}`)
86
+ }
87
+
88
+ /**
89
+ * Extracts the browsers for a test suite to target from the `SELENIUM_BROWSER`
90
+ * environment variable.
91
+ *
92
+ * @return {!Array<!TargetBrowser>} the browsers to target.
93
+ */
94
+ function getBrowsersToTestFromEnv() {
95
+ let browsers = process.env['SELENIUM_BROWSER']
96
+ if (!browsers) {
97
+ return []
98
+ }
99
+ return browsers.split(',').map((spec) => {
100
+ const parts = spec.split(/:/, 3)
101
+ let name = parts[0]
102
+ if (name === 'ie') {
103
+ name = Browser.INTERNET_EXPLORER
104
+ } else if (name === 'edge') {
105
+ name = Browser.EDGE
106
+ }
107
+ let version = parts[1]
108
+ let platform = parts[2]
109
+ return { name, version, platform }
110
+ })
111
+ }
112
+
113
+ /**
114
+ * @return {!Array<!TargetBrowser>} the browsers available for testing on this
115
+ * system.
116
+ */
117
+ function getAvailableBrowsers() {
118
+ info(`Searching for WebDriver executables installed on the current system...`)
119
+
120
+ let targets = [
121
+ [chrome.locateSynchronously, Browser.CHROME],
122
+ [edge.locateSynchronously, Browser.EDGE],
123
+ [firefox.locateSynchronously, Browser.FIREFOX],
124
+ [ie.locateSynchronously, Browser.INTERNET_EXPLORER],
125
+ [safari.locateSynchronously, Browser.SAFARI],
126
+ [opera.locateSynchronously, Browser.OPERA],
127
+ ]
128
+
129
+ let availableBrowsers = []
130
+ for (let pair of targets) {
131
+ const fn = pair[0]
132
+ const name = pair[1]
133
+ const capabilities = pair[2]
134
+ if (fn()) {
135
+ info(`... located ${name}`)
136
+ availableBrowsers.push({ name, capabilities })
137
+ }
138
+ }
139
+
140
+ if (availableBrowsers.length === 0) {
141
+ warn(`Unable to locate any WebDriver executables for testing`)
142
+ }
143
+
144
+ return availableBrowsers
145
+ }
146
+
147
+ let wasInit
148
+ let targetBrowsers
149
+ let seleniumJar
150
+ let seleniumUrl
151
+ let seleniumServer
152
+
153
+ /**
154
+ * Initializes this module by determining which browsers a
155
+ * {@linkplain ./index.suite test suite} should run against. The default
156
+ * behavior is to run tests against every browser with a WebDriver executables
157
+ * (chromedriver, firefoxdriver, etc.) are installed on the system by `PATH`.
158
+ *
159
+ * Specific browsers can be selected at runtime by setting the
160
+ * `SELENIUM_BROWSER` environment variable. This environment variable has the
161
+ * same semantics as with the WebDriver {@link ../index.Builder Builder},
162
+ * except you may use a comma-delimited list to run against multiple browsers:
163
+ *
164
+ * SELENIUM_BROWSER=chrome,firefox mocha --recursive tests/
165
+ *
166
+ * The `SELENIUM_REMOTE_URL` environment variable may be set to configure tests
167
+ * to run against an externally managed (usually remote) Selenium server. When
168
+ * set, the WebDriver builder provided by each
169
+ * {@linkplain TestEnvironment#builder TestEnvironment} will automatically be
170
+ * configured to use this server instead of starting a browser driver locally.
171
+ *
172
+ * The `SELENIUM_SERVER_JAR` environment variable may be set to the path of a
173
+ * standalone Selenium server on the local machine that should be used for
174
+ * WebDriver sessions. When set, the WebDriver builder provided by each
175
+ * {@linkplain TestEnvironment} will automatically be configured to use the
176
+ * started server instead of using a browser driver directly. It should only be
177
+ * necessary to set the `SELENIUM_SERVER_JAR` when testing locally against
178
+ * browsers not natively supported by the WebDriver
179
+ * {@link ../index.Builder Builder}.
180
+ *
181
+ * When either of the `SELENIUM_REMOTE_URL` or `SELENIUM_SERVER_JAR` environment
182
+ * variables are set, the `SELENIUM_BROWSER` variable must also be set.
183
+ *
184
+ * @param {boolean=} force whether to force this module to re-initialize and
185
+ * scan `process.env` again to determine which browsers to run tests
186
+ * against.
187
+ */
188
+ function init(force = false) {
189
+ if (wasInit && !force) {
190
+ return
191
+ }
192
+ wasInit = true
193
+
194
+ // If force re-init, kill the current server if there is one.
195
+ if (seleniumServer) {
196
+ seleniumServer.kill()
197
+ seleniumServer = null
198
+ }
199
+
200
+ seleniumJar = process.env['SELENIUM_SERVER_JAR']
201
+ seleniumUrl = process.env['SELENIUM_REMOTE_URL']
202
+ if (seleniumJar) {
203
+ info(`Using Selenium server jar: ${seleniumJar}`)
204
+ }
205
+
206
+ if (seleniumUrl) {
207
+ info(`Using Selenium remote end: ${seleniumUrl}`)
208
+ }
209
+
210
+ if (seleniumJar && seleniumUrl) {
211
+ throw Error(
212
+ 'Ambiguous test configuration: both SELENIUM_REMOTE_URL' +
213
+ ' && SELENIUM_SERVER_JAR environment variables are set'
214
+ )
215
+ }
216
+
217
+ const envBrowsers = getBrowsersToTestFromEnv()
218
+ if ((seleniumJar || seleniumUrl) && envBrowsers.length === 0) {
219
+ throw Error(
220
+ 'Ambiguous test configuration: when either the SELENIUM_REMOTE_URL or' +
221
+ ' SELENIUM_SERVER_JAR environment variable is set, the' +
222
+ ' SELENIUM_BROWSER variable must also be set.'
223
+ )
224
+ }
225
+
226
+ targetBrowsers = envBrowsers.length > 0 ? envBrowsers : getAvailableBrowsers()
227
+ info(
228
+ `Running tests against [${targetBrowsers.map((b) => b.name).join(', ')}]`
229
+ )
230
+
231
+ after(function () {
232
+ if (seleniumServer) {
233
+ return seleniumServer.kill()
234
+ }
235
+ })
236
+ }
237
+
238
+ const TARGET_MAP = /** !WeakMap<!Environment, !TargetBrowser> */ new WeakMap()
239
+ const URL_MAP = /** !WeakMap<!Environment, ?(string|remote.SeleniumServer)> */ new WeakMap()
240
+
241
+ /**
242
+ * Defines the environment a {@linkplain suite test suite} is running against.
243
+ * @final
244
+ */
245
+ class Environment {
246
+ /**
247
+ * @param {!TargetBrowser} browser the browser targetted in this environment.
248
+ * @param {?(string|remote.SeleniumServer)=} url remote URL of an existing
249
+ * Selenium server to test against.
250
+ */
251
+ constructor(browser, url = undefined) {
252
+ browser = /** @type {!TargetBrowser} */ (Object.seal(
253
+ Object.assign({}, browser)
254
+ ))
255
+
256
+ TARGET_MAP.set(this, browser)
257
+ URL_MAP.set(this, url || null)
258
+ }
259
+
260
+ /** @return {!TargetBrowser} the target browser for this test environment. */
261
+ get browser() {
262
+ return TARGET_MAP.get(this)
263
+ }
264
+
265
+ /**
266
+ * Returns a predicate function that will suppress tests in this environment
267
+ * if the {@linkplain #browser current browser} is in the list of
268
+ * `browsersToIgnore`.
269
+ *
270
+ * @param {...(string|!Browser)} browsersToIgnore the browsers that should
271
+ * be ignored.
272
+ * @return {function(): boolean} a new predicate function.
273
+ */
274
+ browsers(...browsersToIgnore) {
275
+ return () => browsersToIgnore.indexOf(this.browser.name) != -1
276
+ }
277
+
278
+ /**
279
+ * @return {!Builder} a new WebDriver builder configured to target this
280
+ * environment's {@linkplain #browser browser}.
281
+ */
282
+ builder() {
283
+ const browser = this.browser
284
+ const urlOrServer = URL_MAP.get(this)
285
+
286
+ const builder = new Builder()
287
+ builder.disableEnvironmentOverrides()
288
+
289
+ const realBuild = builder.build
290
+ builder.build = function () {
291
+
292
+ builder.forBrowser(browser.name, browser.version, browser.platform)
293
+
294
+ if (browser.capabilities) {
295
+ builder.getCapabilities().merge(browser.capabilities)
296
+ }
297
+
298
+ if (typeof urlOrServer === 'string') {
299
+ builder.usingServer(urlOrServer)
300
+ } else if (urlOrServer) {
301
+ builder.usingServer(urlOrServer.address())
302
+ }
303
+ return realBuild.call(builder)
304
+ }
305
+
306
+ return builder
307
+ }
308
+ }
309
+
310
+ /**
311
+ * Configuration options for a {@linkplain ./index.suite test suite}.
312
+ * @record
313
+ */
314
+ function SuiteOptions() { }
315
+
316
+ /**
317
+ * The browsers to run the test suite against.
318
+ * @type {!Array<!(Browser|TargetBrowser)>}
319
+ */
320
+ SuiteOptions.prototype.browsers
321
+
322
+ let inSuite = false
323
+
324
+ /**
325
+ * Defines a test suite by calling the provided function once for each of the
326
+ * target browsers. If a suite is not limited to a specific set of browsers in
327
+ * the provided {@linkplain ./index.SuiteOptions suite options}, the suite will
328
+ * be configured to run against each of the {@linkplain ./index.init runtime
329
+ * target browsers}.
330
+ *
331
+ * Sample usage:
332
+ *
333
+ * const {By, Key, until} = require('selenium-webdriver');
334
+ * const {suite} = require('selenium-webdriver/testing');
335
+ *
336
+ * suite(function(env) {
337
+ * describe('Google Search', function() {
338
+ * let driver;
339
+ *
340
+ * before(async function() {
341
+ * driver = await env.builder().build();
342
+ * });
343
+ *
344
+ * after(() => driver.quit());
345
+ *
346
+ * it('demo', async function() {
347
+ * await driver.get('http://www.google.com/ncr');
348
+ *
349
+ * let q = await driver.findElement(By.name('q'));
350
+ * await q.sendKeys('webdriver', Key.RETURN);
351
+ * await driver.wait(
352
+ * until.titleIs('webdriver - Google Search'), 1000);
353
+ * });
354
+ * });
355
+ * });
356
+ *
357
+ * By default, this example suite will run against every WebDriver-enabled
358
+ * browser on the current system. Alternatively, the `SELENIUM_BROWSER`
359
+ * environment variable may be used to run against a specific browser:
360
+ *
361
+ * SELENIUM_BROWSER=firefox mocha -t 120000 example_test.js
362
+ *
363
+ * @param {function(!Environment)} fn the function to call to build the test
364
+ * suite.
365
+ * @param {SuiteOptions=} options configuration options.
366
+ */
367
+ function suite(fn, options = undefined) {
368
+ if (inSuite) {
369
+ throw Error('Calls to suite() may not be nested')
370
+ }
371
+ try {
372
+ init()
373
+ inSuite = true
374
+
375
+ const suiteBrowsers = new Map()
376
+ if (options && options.browsers) {
377
+ for (let browser of options.browsers) {
378
+ if (typeof browser === 'string') {
379
+ suiteBrowsers.set(browser, { name: browser })
380
+ } else {
381
+ suiteBrowsers.set(browser.name, browser)
382
+ }
383
+ }
384
+ }
385
+
386
+ for (let browser of targetBrowsers) {
387
+ if (suiteBrowsers.size > 0 && !suiteBrowsers.has(browser.name)) {
388
+ continue
389
+ }
390
+
391
+ describe(`[${browser.name}]`, function () {
392
+ if (!seleniumUrl && seleniumJar && !seleniumServer) {
393
+ seleniumServer = new remote.SeleniumServer(seleniumJar)
394
+
395
+ const startTimeout = 65 * 1000
396
+ // eslint-disable-next-line no-inner-declarations
397
+ function startSelenium() {
398
+ if (typeof this.timeout === 'function') {
399
+ this.timeout(startTimeout) // For mocha.
400
+ }
401
+
402
+ info(`Starting selenium server ${seleniumJar}`)
403
+ return seleniumServer.start(60 * 1000)
404
+ }
405
+
406
+ const /** !Function */ beforeHook = global.beforeAll || global.before
407
+ beforeHook(startSelenium, startTimeout)
408
+ }
409
+
410
+ fn(new Environment(browser, seleniumUrl || seleniumServer))
411
+ })
412
+ }
413
+ } finally {
414
+ inSuite = false
415
+ }
416
+ }
417
+
418
+ /**
419
+ * Returns an object with wrappers for the standard mocha/jasmine test
420
+ * functions: `describe` and `it`, which will redirect to `xdescribe` and `xit`,
421
+ * respectively, if provided predicate function returns false.
422
+ *
423
+ * Sample usage:
424
+ *
425
+ * const {Browser} = require('selenium-webdriver');
426
+ * const {suite, ignore} = require('selenium-webdriver/testing');
427
+ *
428
+ * suite(function(env) {
429
+ *
430
+ * // Skip tests the current environment targets Chrome.
431
+ * ignore(env.browsers(Browser.CHROME)).
432
+ * describe('something', async function() {
433
+ * let driver = await env.builder().build();
434
+ * // etc.
435
+ * });
436
+ * });
437
+ *
438
+ * @param {function(): boolean} predicateFn A predicate to call to determine
439
+ * if the test should be suppressed. This function MUST be synchronous.
440
+ * @return {{describe: !Function, it: !Function}} an object with wrapped
441
+ * versions of the `describe` and `it` wtest functions.
442
+ */
443
+ function ignore(predicateFn) {
444
+ const isJasmine = global.jasmine && typeof global.jasmine === 'object'
445
+
446
+ const hooks = {
447
+ describe: getTestHook('describe'),
448
+ xdescribe: getTestHook('xdescribe'),
449
+ it: getTestHook('it'),
450
+ xit: getTestHook('xit'),
451
+ }
452
+ hooks.fdescribe = isJasmine ? getTestHook('fdescribe') : hooks.describe.only
453
+ hooks.fit = isJasmine ? getTestHook('fit') : hooks.it.only
454
+
455
+ let describe = wrap(hooks.xdescribe, hooks.describe)
456
+ let fdescribe = wrap(hooks.xdescribe, hooks.fdescribe)
457
+ //eslint-disable-next-line no-only-tests/no-only-tests
458
+ describe.only = fdescribe
459
+
460
+ let it = wrap(hooks.xit, hooks.it)
461
+ let fit = wrap(hooks.xit, hooks.fit)
462
+ //eslint-disable-next-line no-only-tests/no-only-tests
463
+ it.only = fit
464
+
465
+ return { describe, it }
466
+
467
+ function wrap(onSkip, onRun) {
468
+ return function (...args) {
469
+ if (predicateFn()) {
470
+ onSkip(...args)
471
+ } else {
472
+ onRun(...args)
473
+ }
474
+ }
475
+ }
476
+ }
477
+
478
+ /**
479
+ * @param {string} name
480
+ * @return {!Function}
481
+ * @throws {TypeError}
482
+ */
483
+ function getTestHook(name) {
484
+ let fn = global[name]
485
+ let type = typeof fn
486
+ if (type !== 'function') {
487
+ throw TypeError(
488
+ `Expected global.${name} to be a function, but is ${type}.` +
489
+ ' This can happen if you try using this module when running with' +
490
+ ' node directly instead of using jasmine or mocha'
491
+ )
492
+ }
493
+ return fn
494
+ }
495
+
496
+ // PUBLIC API
497
+
498
+ module.exports = {
499
+ Environment,
500
+ SuiteOptions,
501
+ init,
502
+ ignore,
503
+ suite,
504
+ }
package/.eslintrc.js DELETED
@@ -1,27 +0,0 @@
1
- module.exports = {
2
- env: {
3
- mocha: true,
4
- node: true,
5
- es6: true,
6
- },
7
- extends: ['eslint:recommended', 'plugin:node/recommended', 'prettier'],
8
- plugins: ['prettier', 'no-only-tests'],
9
- rules: {
10
- 'prettier/prettier': 'error',
11
- 'no-const-assign': 'error',
12
- 'no-this-before-super': 'error',
13
- 'no-undef': 'error',
14
- 'no-unreachable': 'error',
15
- 'no-unused-vars': [
16
- 'error',
17
- { varsIgnorePattern: '^_', args: 'all', argsIgnorePattern: '^_' },
18
- ],
19
- 'constructor-super': 'error',
20
- 'valid-typeof': 'error',
21
- 'no-only-tests/no-only-tests': 'error',
22
- 'node/no-unpublished-require': 'error',
23
- 'node/no-unsupported-features/es-syntax': 0,
24
- 'node/no-unsupported-features/node-builtins': 0,
25
- 'node/no-missing-import': 'error',
26
- },
27
- }
package/.prettierrc DELETED
@@ -1,4 +0,0 @@
1
- {
2
- "semi": false,
3
- "singleQuote": true
4
- }