selenium-webdriver 4.0.0-alpha.8 → 4.0.0-beta.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 (53) hide show
  1. package/CHANGES.md +14 -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 +7 -202
  7. package/devtools/CDPConnection.js +0 -0
  8. package/edge.js +1 -1
  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 +0 -0
  22. package/io/index.js +4 -4
  23. package/io/zip.js +0 -0
  24. package/lib/actions.js +16 -15
  25. package/lib/atoms/find-elements.js +4 -3
  26. package/lib/atoms/get-attribute.js +0 -0
  27. package/lib/atoms/is-displayed.js +0 -0
  28. package/lib/atoms/mutation-listener.js +38 -0
  29. package/lib/by.js +1 -1
  30. package/lib/capabilities.js +2 -2
  31. package/lib/command.js +2 -0
  32. package/lib/error.js +0 -0
  33. package/lib/http.js +17 -1
  34. package/lib/input.js +0 -0
  35. package/lib/logging.js +0 -0
  36. package/lib/promise.js +1 -1
  37. package/lib/proxy.js +0 -0
  38. package/lib/session.js +0 -0
  39. package/lib/symbols.js +0 -0
  40. package/lib/until.js +17 -15
  41. package/lib/webdriver.js +322 -50
  42. package/net/index.js +0 -0
  43. package/net/portprober.js +8 -8
  44. package/opera.js +0 -0
  45. package/package.json +8 -8
  46. package/proxy.js +0 -0
  47. package/remote/index.js +0 -0
  48. package/safari.js +0 -0
  49. package/testing/index.js +509 -0
  50. package/.eslintrc.js +0 -27
  51. package/.prettierrc +0 -4
  52. package/devtools/generator/protocol-dts-generator.js +0 -429
  53. package/lib/README +0 -5
package/safari.js CHANGED
File without changes
@@ -0,0 +1,509 @@
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.IE
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
+ [
124
+ () => edge.locateSynchronously('msedge'),
125
+ Browser.EDGE,
126
+ { 'ms:edgeChromium': true },
127
+ ],
128
+ [firefox.locateSynchronously, Browser.FIREFOX],
129
+ [ie.locateSynchronously, Browser.IE],
130
+ [safari.locateSynchronously, Browser.SAFARI],
131
+ [opera.locateSynchronously, Browser.OPERA],
132
+ ]
133
+
134
+ let availableBrowsers = []
135
+ for (let pair of targets) {
136
+ const fn = pair[0]
137
+ const name = pair[1]
138
+ const capabilities = pair[2]
139
+ if (fn()) {
140
+ info(`... located ${name}`)
141
+ availableBrowsers.push({ name, capabilities })
142
+ }
143
+ }
144
+
145
+ if (availableBrowsers.length === 0) {
146
+ warn(`Unable to locate any WebDriver executables for testing`)
147
+ }
148
+
149
+ return availableBrowsers
150
+ }
151
+
152
+ let wasInit
153
+ let targetBrowsers
154
+ let seleniumJar
155
+ let seleniumUrl
156
+ let seleniumServer
157
+
158
+ /**
159
+ * Initializes this module by determining which browsers a
160
+ * {@linkplain ./index.suite test suite} should run against. The default
161
+ * behavior is to run tests against every browser with a WebDriver executables
162
+ * (chromedriver, firefoxdriver, etc.) are installed on the system by `PATH`.
163
+ *
164
+ * Specific browsers can be selected at runtime by setting the
165
+ * `SELENIUM_BROWSER` environment variable. This environment variable has the
166
+ * same semantics as with the WebDriver {@link ../index.Builder Builder},
167
+ * except you may use a comma-delimited list to run against multiple browsers:
168
+ *
169
+ * SELENIUM_BROWSER=chrome,firefox mocha --recursive tests/
170
+ *
171
+ * The `SELENIUM_REMOTE_URL` environment variable may be set to configure tests
172
+ * to run against an externally managed (usually remote) Selenium server. When
173
+ * set, the WebDriver builder provided by each
174
+ * {@linkplain TestEnvironment#builder TestEnvironment} will automatically be
175
+ * configured to use this server instead of starting a browser driver locally.
176
+ *
177
+ * The `SELENIUM_SERVER_JAR` environment variable may be set to the path of a
178
+ * standalone Selenium server on the local machine that should be used for
179
+ * WebDriver sessions. When set, the WebDriver builder provided by each
180
+ * {@linkplain TestEnvironment} will automatically be configured to use the
181
+ * started server instead of using a browser driver directly. It should only be
182
+ * necessary to set the `SELENIUM_SERVER_JAR` when testing locally against
183
+ * browsers not natively supported by the WebDriver
184
+ * {@link ../index.Builder Builder}.
185
+ *
186
+ * When either of the `SELENIUM_REMOTE_URL` or `SELENIUM_SERVER_JAR` environment
187
+ * variables are set, the `SELENIUM_BROWSER` variable must also be set.
188
+ *
189
+ * @param {boolean=} force whether to force this module to re-initialize and
190
+ * scan `process.env` again to determine which browsers to run tests
191
+ * against.
192
+ */
193
+ function init(force = false) {
194
+ if (wasInit && !force) {
195
+ return
196
+ }
197
+ wasInit = true
198
+
199
+ // If force re-init, kill the current server if there is one.
200
+ if (seleniumServer) {
201
+ seleniumServer.kill()
202
+ seleniumServer = null
203
+ }
204
+
205
+ seleniumJar = process.env['SELENIUM_SERVER_JAR']
206
+ seleniumUrl = process.env['SELENIUM_REMOTE_URL']
207
+ if (seleniumJar) {
208
+ info(`Using Selenium server jar: ${seleniumJar}`)
209
+ }
210
+
211
+ if (seleniumUrl) {
212
+ info(`Using Selenium remote end: ${seleniumUrl}`)
213
+ }
214
+
215
+ if (seleniumJar && seleniumUrl) {
216
+ throw Error(
217
+ 'Ambiguous test configuration: both SELENIUM_REMOTE_URL' +
218
+ ' && SELENIUM_SERVER_JAR environment variables are set'
219
+ )
220
+ }
221
+
222
+ const envBrowsers = getBrowsersToTestFromEnv()
223
+ if ((seleniumJar || seleniumUrl) && envBrowsers.length === 0) {
224
+ throw Error(
225
+ 'Ambiguous test configuration: when either the SELENIUM_REMOTE_URL or' +
226
+ ' SELENIUM_SERVER_JAR environment variable is set, the' +
227
+ ' SELENIUM_BROWSER variable must also be set.'
228
+ )
229
+ }
230
+
231
+ targetBrowsers = envBrowsers.length > 0 ? envBrowsers : getAvailableBrowsers()
232
+ info(
233
+ `Running tests against [${targetBrowsers.map((b) => b.name).join(', ')}]`
234
+ )
235
+
236
+ after(function () {
237
+ if (seleniumServer) {
238
+ return seleniumServer.kill()
239
+ }
240
+ })
241
+ }
242
+
243
+ const TARGET_MAP = /** !WeakMap<!Environment, !TargetBrowser> */ new WeakMap()
244
+ const URL_MAP = /** !WeakMap<!Environment, ?(string|remote.SeleniumServer)> */ new WeakMap()
245
+
246
+ /**
247
+ * Defines the environment a {@linkplain suite test suite} is running against.
248
+ * @final
249
+ */
250
+ class Environment {
251
+ /**
252
+ * @param {!TargetBrowser} browser the browser targetted in this environment.
253
+ * @param {?(string|remote.SeleniumServer)=} url remote URL of an existing
254
+ * Selenium server to test against.
255
+ */
256
+ constructor(browser, url = undefined) {
257
+ browser = /** @type {!TargetBrowser} */ (Object.seal(
258
+ Object.assign({}, browser)
259
+ ))
260
+
261
+ TARGET_MAP.set(this, browser)
262
+ URL_MAP.set(this, url || null)
263
+ }
264
+
265
+ /** @return {!TargetBrowser} the target browser for this test environment. */
266
+ get browser() {
267
+ return TARGET_MAP.get(this)
268
+ }
269
+
270
+ /**
271
+ * Returns a predicate function that will suppress tests in this environment
272
+ * if the {@linkplain #browser current browser} is in the list of
273
+ * `browsersToIgnore`.
274
+ *
275
+ * @param {...(string|!Browser)} browsersToIgnore the browsers that should
276
+ * be ignored.
277
+ * @return {function(): boolean} a new predicate function.
278
+ */
279
+ browsers(...browsersToIgnore) {
280
+ return () => browsersToIgnore.indexOf(this.browser.name) != -1
281
+ }
282
+
283
+ /**
284
+ * @return {!Builder} a new WebDriver builder configured to target this
285
+ * environment's {@linkplain #browser browser}.
286
+ */
287
+ builder() {
288
+ const browser = this.browser
289
+ const urlOrServer = URL_MAP.get(this)
290
+
291
+ const builder = new Builder()
292
+ builder.disableEnvironmentOverrides()
293
+
294
+ const realBuild = builder.build
295
+ builder.build = function () {
296
+
297
+ builder.forBrowser(browser.name, browser.version, browser.platform)
298
+
299
+ if (browser.capabilities) {
300
+ builder.getCapabilities().merge(browser.capabilities)
301
+ }
302
+
303
+ if (typeof urlOrServer === 'string') {
304
+ builder.usingServer(urlOrServer)
305
+ } else if (urlOrServer) {
306
+ builder.usingServer(urlOrServer.address())
307
+ }
308
+ return realBuild.call(builder)
309
+ }
310
+
311
+ return builder
312
+ }
313
+ }
314
+
315
+ /**
316
+ * Configuration options for a {@linkplain ./index.suite test suite}.
317
+ * @record
318
+ */
319
+ function SuiteOptions() { }
320
+
321
+ /**
322
+ * The browsers to run the test suite against.
323
+ * @type {!Array<!(Browser|TargetBrowser)>}
324
+ */
325
+ SuiteOptions.prototype.browsers
326
+
327
+ let inSuite = false
328
+
329
+ /**
330
+ * Defines a test suite by calling the provided function once for each of the
331
+ * target browsers. If a suite is not limited to a specific set of browsers in
332
+ * the provided {@linkplain ./index.SuiteOptions suite options}, the suite will
333
+ * be configured to run against each of the {@linkplain ./index.init runtime
334
+ * target browsers}.
335
+ *
336
+ * Sample usage:
337
+ *
338
+ * const {By, Key, until} = require('selenium-webdriver');
339
+ * const {suite} = require('selenium-webdriver/testing');
340
+ *
341
+ * suite(function(env) {
342
+ * describe('Google Search', function() {
343
+ * let driver;
344
+ *
345
+ * before(async function() {
346
+ * driver = await env.builder().build();
347
+ * });
348
+ *
349
+ * after(() => driver.quit());
350
+ *
351
+ * it('demo', async function() {
352
+ * await driver.get('http://www.google.com/ncr');
353
+ *
354
+ * let q = await driver.findElement(By.name('q'));
355
+ * await q.sendKeys('webdriver', Key.RETURN);
356
+ * await driver.wait(
357
+ * until.titleIs('webdriver - Google Search'), 1000);
358
+ * });
359
+ * });
360
+ * });
361
+ *
362
+ * By default, this example suite will run against every WebDriver-enabled
363
+ * browser on the current system. Alternatively, the `SELENIUM_BROWSER`
364
+ * environment variable may be used to run against a specific browser:
365
+ *
366
+ * SELENIUM_BROWSER=firefox mocha -t 120000 example_test.js
367
+ *
368
+ * @param {function(!Environment)} fn the function to call to build the test
369
+ * suite.
370
+ * @param {SuiteOptions=} options configuration options.
371
+ */
372
+ function suite(fn, options = undefined) {
373
+ if (inSuite) {
374
+ throw Error('Calls to suite() may not be nested')
375
+ }
376
+ try {
377
+ init()
378
+ inSuite = true
379
+
380
+ const suiteBrowsers = new Map()
381
+ if (options && options.browsers) {
382
+ for (let browser of options.browsers) {
383
+ if (typeof browser === 'string') {
384
+ suiteBrowsers.set(browser, { name: browser })
385
+ } else {
386
+ suiteBrowsers.set(browser.name, browser)
387
+ }
388
+ }
389
+ }
390
+
391
+ for (let browser of targetBrowsers) {
392
+ if (suiteBrowsers.size > 0 && !suiteBrowsers.has(browser.name)) {
393
+ continue
394
+ }
395
+
396
+ describe(`[${browser.name}]`, function () {
397
+ if (!seleniumUrl && seleniumJar && !seleniumServer) {
398
+ seleniumServer = new remote.SeleniumServer(seleniumJar)
399
+
400
+ const startTimeout = 65 * 1000
401
+ // eslint-disable-next-line no-inner-declarations
402
+ function startSelenium() {
403
+ if (typeof this.timeout === 'function') {
404
+ this.timeout(startTimeout) // For mocha.
405
+ }
406
+
407
+ info(`Starting selenium server ${seleniumJar}`)
408
+ return seleniumServer.start(60 * 1000)
409
+ }
410
+
411
+ const /** !Function */ beforeHook = global.beforeAll || global.before
412
+ beforeHook(startSelenium, startTimeout)
413
+ }
414
+
415
+ fn(new Environment(browser, seleniumUrl || seleniumServer))
416
+ })
417
+ }
418
+ } finally {
419
+ inSuite = false
420
+ }
421
+ }
422
+
423
+ /**
424
+ * Returns an object with wrappers for the standard mocha/jasmine test
425
+ * functions: `describe` and `it`, which will redirect to `xdescribe` and `xit`,
426
+ * respectively, if provided predicate function returns false.
427
+ *
428
+ * Sample usage:
429
+ *
430
+ * const {Browser} = require('selenium-webdriver');
431
+ * const {suite, ignore} = require('selenium-webdriver/testing');
432
+ *
433
+ * suite(function(env) {
434
+ *
435
+ * // Skip tests the current environment targets Chrome.
436
+ * ignore(env.browsers(Browser.CHROME)).
437
+ * describe('something', async function() {
438
+ * let driver = await env.builder().build();
439
+ * // etc.
440
+ * });
441
+ * });
442
+ *
443
+ * @param {function(): boolean} predicateFn A predicate to call to determine
444
+ * if the test should be suppressed. This function MUST be synchronous.
445
+ * @return {{describe: !Function, it: !Function}} an object with wrapped
446
+ * versions of the `describe` and `it` wtest functions.
447
+ */
448
+ function ignore(predicateFn) {
449
+ const isJasmine = global.jasmine && typeof global.jasmine === 'object'
450
+
451
+ const hooks = {
452
+ describe: getTestHook('describe'),
453
+ xdescribe: getTestHook('xdescribe'),
454
+ it: getTestHook('it'),
455
+ xit: getTestHook('xit'),
456
+ }
457
+ hooks.fdescribe = isJasmine ? getTestHook('fdescribe') : hooks.describe.only
458
+ hooks.fit = isJasmine ? getTestHook('fit') : hooks.it.only
459
+
460
+ let describe = wrap(hooks.xdescribe, hooks.describe)
461
+ let fdescribe = wrap(hooks.xdescribe, hooks.fdescribe)
462
+ //eslint-disable-next-line no-only-tests/no-only-tests
463
+ describe.only = fdescribe
464
+
465
+ let it = wrap(hooks.xit, hooks.it)
466
+ let fit = wrap(hooks.xit, hooks.fit)
467
+ //eslint-disable-next-line no-only-tests/no-only-tests
468
+ it.only = fit
469
+
470
+ return { describe, it }
471
+
472
+ function wrap(onSkip, onRun) {
473
+ return function (...args) {
474
+ if (predicateFn()) {
475
+ onSkip(...args)
476
+ } else {
477
+ onRun(...args)
478
+ }
479
+ }
480
+ }
481
+ }
482
+
483
+ /**
484
+ * @param {string} name
485
+ * @return {!Function}
486
+ * @throws {TypeError}
487
+ */
488
+ function getTestHook(name) {
489
+ let fn = global[name]
490
+ let type = typeof fn
491
+ if (type !== 'function') {
492
+ throw TypeError(
493
+ `Expected global.${name} to be a function, but is ${type}.` +
494
+ ' This can happen if you try using this module when running with' +
495
+ ' node directly instead of using jasmine or mocha'
496
+ )
497
+ }
498
+ return fn
499
+ }
500
+
501
+ // PUBLIC API
502
+
503
+ module.exports = {
504
+ Environment,
505
+ SuiteOptions,
506
+ init,
507
+ ignore,
508
+ suite,
509
+ }
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
- }