2015-04-04 09:53:59 -07:00
|
|
|
// Licensed to the Software Freedom Conservancy (SFC) under one
|
|
|
|
|
// or more contributor license agreements. See the NOTICE file
|
|
|
|
|
// distributed with this work for additional information
|
|
|
|
|
// regarding copyright ownership. The SFC licenses this file
|
|
|
|
|
// to you under the Apache License, Version 2.0 (the
|
|
|
|
|
// "License"); you may not use this file except in compliance
|
|
|
|
|
// with the License. You may obtain a copy of the License at
|
2014-11-12 19:33:37 +00:00
|
|
|
//
|
2015-04-04 09:53:59 -07:00
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
2014-11-12 19:33:37 +00:00
|
|
|
//
|
2015-04-04 09:53:59 -07:00
|
|
|
// Unless required by applicable law or agreed to in writing,
|
|
|
|
|
// software distributed under the License is distributed on an
|
|
|
|
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
|
|
|
// KIND, either express or implied. See the License for the
|
|
|
|
|
// specific language governing permissions and limitations
|
|
|
|
|
// under the License.
|
2013-03-05 21:03:26 -08:00
|
|
|
|
|
|
|
|
/**
|
2017-10-02 19:32:10 -04:00
|
|
|
* @fileoverview Provides extensions for
|
2017-10-22 13:51:44 -07:00
|
|
|
* [Jasmine](https://jasmine.github.io) and [Mocha](https://mochajs.org).
|
2013-03-05 21:03:26 -08:00
|
|
|
*
|
2015-02-15 20:16:33 -08:00
|
|
|
* You may conditionally suppress a test function using the exported
|
2013-03-05 21:03:26 -08:00
|
|
|
* "ignore" function. If the provided predicate returns true, the attached
|
|
|
|
|
* test case will be skipped:
|
|
|
|
|
*
|
2015-02-15 20:16:33 -08:00
|
|
|
* test.ignore(maybe()).it('is flaky', function() {
|
|
|
|
|
* if (Math.random() < 0.5) throw Error();
|
|
|
|
|
* });
|
|
|
|
|
*
|
|
|
|
|
* function maybe() { return Math.random() < 0.5; }
|
2013-03-05 21:03:26 -08:00
|
|
|
*/
|
|
|
|
|
|
2020-08-03 17:56:31 +03:00
|
|
|
'use strict'
|
|
|
|
|
|
2024-06-27 18:33:36 +01:00
|
|
|
const fs = require('node:fs')
|
|
|
|
|
const path = require('node:path')
|
2024-04-16 01:50:58 +05:30
|
|
|
const { isatty } = require('node:tty')
|
2020-08-03 17:56:31 +03:00
|
|
|
const chrome = require('../chrome')
|
|
|
|
|
const edge = require('../edge')
|
|
|
|
|
const firefox = require('../firefox')
|
|
|
|
|
const ie = require('../ie')
|
|
|
|
|
const remote = require('../remote')
|
|
|
|
|
const safari = require('../safari')
|
2022-06-02 23:41:17 +05:30
|
|
|
const { Browser } = require('../lib/capabilities')
|
2020-08-03 17:56:31 +03:00
|
|
|
const { Builder } = require('../index')
|
2024-04-22 13:24:18 +02:00
|
|
|
const { getBinaryPaths } = require('../common/driverFinder')
|
2017-10-22 13:51:44 -07:00
|
|
|
|
2024-08-10 15:55:20 +05:30
|
|
|
let runfiles
|
|
|
|
|
try {
|
|
|
|
|
// Attempt to require @bazel/runfiles
|
|
|
|
|
runfiles = require('@bazel/runfiles').runfiles
|
|
|
|
|
} catch {
|
|
|
|
|
// Fall through
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-22 13:51:44 -07:00
|
|
|
/**
|
2020-04-21 22:23:57 +05:30
|
|
|
* Describes a browser targeted by a {@linkplain suite test suite}.
|
2017-10-22 13:51:44 -07:00
|
|
|
* @record
|
|
|
|
|
*/
|
2022-06-02 23:41:17 +05:30
|
|
|
function TargetBrowser() {}
|
2017-10-22 13:51:44 -07:00
|
|
|
|
|
|
|
|
/**
|
2020-04-21 22:23:57 +05:30
|
|
|
* The {@linkplain Browser name} of the targeted browser.
|
2017-10-22 13:51:44 -07:00
|
|
|
* @type {string}
|
|
|
|
|
*/
|
2020-08-03 17:56:31 +03:00
|
|
|
TargetBrowser.prototype.name
|
2017-10-22 13:51:44 -07:00
|
|
|
|
|
|
|
|
/**
|
2020-04-21 22:23:57 +05:30
|
|
|
* The specific version of the targeted browser, if any.
|
2017-10-22 13:51:44 -07:00
|
|
|
* @type {(string|undefined)}
|
|
|
|
|
*/
|
2020-08-03 17:56:31 +03:00
|
|
|
TargetBrowser.prototype.version
|
2017-10-22 13:51:44 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The specific {@linkplain ../lib/capabilities.Platform platform} for the
|
2020-04-21 22:23:57 +05:30
|
|
|
* targeted browser, if any.
|
2017-10-22 13:51:44 -07:00
|
|
|
* @type {(string|undefined)}.
|
|
|
|
|
*/
|
2020-08-03 17:56:31 +03:00
|
|
|
TargetBrowser.prototype.platform
|
2017-10-22 13:51:44 -07:00
|
|
|
|
|
|
|
|
/** @suppress {checkTypes} */
|
|
|
|
|
function color(c, s) {
|
2020-08-03 17:56:31 +03:00
|
|
|
return isatty(process.stdout) ? `\u001b[${c}m${s}\u001b[0m` : s
|
|
|
|
|
}
|
2024-03-08 12:13:00 +00:00
|
|
|
|
2020-08-03 17:56:31 +03:00
|
|
|
function green(s) {
|
|
|
|
|
return color(32, s)
|
|
|
|
|
}
|
2024-03-08 12:13:00 +00:00
|
|
|
|
2020-08-03 17:56:31 +03:00
|
|
|
function cyan(s) {
|
|
|
|
|
return color(36, s)
|
|
|
|
|
}
|
2024-03-08 12:13:00 +00:00
|
|
|
|
2020-08-03 17:56:31 +03:00
|
|
|
function info(msg) {
|
|
|
|
|
console.info(`${green('[INFO]')} ${msg}`)
|
|
|
|
|
}
|
2024-03-08 12:13:00 +00:00
|
|
|
|
2020-08-03 17:56:31 +03:00
|
|
|
function warn(msg) {
|
|
|
|
|
console.warn(`${cyan('[WARNING]')} ${msg}`)
|
2017-10-22 13:51:44 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Extracts the browsers for a test suite to target from the `SELENIUM_BROWSER`
|
|
|
|
|
* environment variable.
|
|
|
|
|
*
|
2022-08-11 22:38:36 +02:00
|
|
|
* @return {{name: string, version: string, platform: string}}[] the browsers to target.
|
2017-10-22 13:51:44 -07:00
|
|
|
*/
|
|
|
|
|
function getBrowsersToTestFromEnv() {
|
2020-08-03 17:56:31 +03:00
|
|
|
let browsers = process.env['SELENIUM_BROWSER']
|
2017-10-22 13:51:44 -07:00
|
|
|
if (!browsers) {
|
2020-08-03 17:56:31 +03:00
|
|
|
return []
|
2017-10-22 13:51:44 -07:00
|
|
|
}
|
2020-08-03 17:56:31 +03:00
|
|
|
return browsers.split(',').map((spec) => {
|
|
|
|
|
const parts = spec.split(/:/, 3)
|
|
|
|
|
let name = parts[0]
|
2017-10-22 13:51:44 -07:00
|
|
|
if (name === 'ie') {
|
2021-02-16 11:13:25 +05:30
|
|
|
name = Browser.INTERNET_EXPLORER
|
2017-10-22 13:51:44 -07:00
|
|
|
} else if (name === 'edge') {
|
2020-08-03 17:56:31 +03:00
|
|
|
name = Browser.EDGE
|
2017-10-22 13:51:44 -07:00
|
|
|
}
|
2020-08-03 17:56:31 +03:00
|
|
|
let version = parts[1]
|
|
|
|
|
let platform = parts[2]
|
|
|
|
|
return { name, version, platform }
|
|
|
|
|
})
|
2017-10-22 13:51:44 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return {!Array<!TargetBrowser>} the browsers available for testing on this
|
|
|
|
|
* system.
|
|
|
|
|
*/
|
|
|
|
|
function getAvailableBrowsers() {
|
2020-08-03 17:56:31 +03:00
|
|
|
info(`Searching for WebDriver executables installed on the current system...`)
|
2017-10-22 13:51:44 -07:00
|
|
|
|
|
|
|
|
let targets = [
|
2024-04-22 13:24:18 +02:00
|
|
|
[getBinaryPaths(new chrome.Options()), Browser.CHROME],
|
|
|
|
|
[getBinaryPaths(new edge.Options()), Browser.EDGE],
|
|
|
|
|
[getBinaryPaths(new firefox.Options()), Browser.FIREFOX],
|
2020-08-03 17:56:31 +03:00
|
|
|
]
|
2023-08-12 23:50:25 +02:00
|
|
|
if (process.platform === 'win32') {
|
2024-04-22 13:24:18 +02:00
|
|
|
targets.push([getBinaryPaths(new ie.Options()), Browser.INTERNET_EXPLORER])
|
2023-08-12 23:50:25 +02:00
|
|
|
}
|
|
|
|
|
if (process.platform === 'darwin') {
|
2024-04-22 13:24:18 +02:00
|
|
|
targets.push([getBinaryPaths(new safari.Options()), Browser.SAFARI])
|
2023-08-12 23:50:25 +02:00
|
|
|
}
|
2017-10-22 13:51:44 -07:00
|
|
|
|
2020-08-03 17:56:31 +03:00
|
|
|
let availableBrowsers = []
|
2017-10-22 13:51:44 -07:00
|
|
|
for (let pair of targets) {
|
2023-08-11 23:41:36 +02:00
|
|
|
const driverPath = pair[0].driverPath
|
|
|
|
|
const browserPath = pair[0].browserPath
|
2020-08-03 17:56:31 +03:00
|
|
|
const name = pair[1]
|
|
|
|
|
const capabilities = pair[2]
|
2023-08-11 23:41:36 +02:00
|
|
|
if (driverPath.length > 0 && browserPath && browserPath.length > 0) {
|
2020-08-03 17:56:31 +03:00
|
|
|
info(`... located ${name}`)
|
|
|
|
|
availableBrowsers.push({ name, capabilities })
|
2017-10-22 13:51:44 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (availableBrowsers.length === 0) {
|
2020-08-03 17:56:31 +03:00
|
|
|
warn(`Unable to locate any WebDriver executables for testing`)
|
2017-10-22 13:51:44 -07:00
|
|
|
}
|
|
|
|
|
|
2020-08-03 17:56:31 +03:00
|
|
|
return availableBrowsers
|
2017-10-22 13:51:44 -07:00
|
|
|
}
|
|
|
|
|
|
2020-08-03 17:56:31 +03:00
|
|
|
let wasInit
|
|
|
|
|
let targetBrowsers
|
|
|
|
|
let seleniumJar
|
|
|
|
|
let seleniumUrl
|
|
|
|
|
let seleniumServer
|
2017-10-22 13:51:44 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Initializes this module by determining which browsers a
|
|
|
|
|
* {@linkplain ./index.suite test suite} should run against. The default
|
|
|
|
|
* behavior is to run tests against every browser with a WebDriver executables
|
|
|
|
|
* (chromedriver, firefoxdriver, etc.) are installed on the system by `PATH`.
|
|
|
|
|
*
|
|
|
|
|
* Specific browsers can be selected at runtime by setting the
|
|
|
|
|
* `SELENIUM_BROWSER` environment variable. This environment variable has the
|
|
|
|
|
* same semantics as with the WebDriver {@link ../index.Builder Builder},
|
|
|
|
|
* except you may use a comma-delimited list to run against multiple browsers:
|
|
|
|
|
*
|
|
|
|
|
* SELENIUM_BROWSER=chrome,firefox mocha --recursive tests/
|
|
|
|
|
*
|
|
|
|
|
* The `SELENIUM_REMOTE_URL` environment variable may be set to configure tests
|
2020-04-21 22:23:57 +05:30
|
|
|
* to run against an externally managed (usually remote) Selenium server. When
|
2017-10-22 13:51:44 -07:00
|
|
|
* set, the WebDriver builder provided by each
|
|
|
|
|
* {@linkplain TestEnvironment#builder TestEnvironment} will automatically be
|
2020-04-21 22:23:57 +05:30
|
|
|
* configured to use this server instead of starting a browser driver locally.
|
2017-10-22 13:51:44 -07:00
|
|
|
*
|
|
|
|
|
* The `SELENIUM_SERVER_JAR` environment variable may be set to the path of a
|
|
|
|
|
* standalone Selenium server on the local machine that should be used for
|
|
|
|
|
* WebDriver sessions. When set, the WebDriver builder provided by each
|
|
|
|
|
* {@linkplain TestEnvironment} will automatically be configured to use the
|
|
|
|
|
* started server instead of using a browser driver directly. It should only be
|
|
|
|
|
* necessary to set the `SELENIUM_SERVER_JAR` when testing locally against
|
|
|
|
|
* browsers not natively supported by the WebDriver
|
|
|
|
|
* {@link ../index.Builder Builder}.
|
|
|
|
|
*
|
|
|
|
|
* When either of the `SELENIUM_REMOTE_URL` or `SELENIUM_SERVER_JAR` environment
|
|
|
|
|
* variables are set, the `SELENIUM_BROWSER` variable must also be set.
|
|
|
|
|
*
|
|
|
|
|
* @param {boolean=} force whether to force this module to re-initialize and
|
|
|
|
|
* scan `process.env` again to determine which browsers to run tests
|
|
|
|
|
* against.
|
|
|
|
|
*/
|
|
|
|
|
function init(force = false) {
|
|
|
|
|
if (wasInit && !force) {
|
2020-08-03 17:56:31 +03:00
|
|
|
return
|
2017-10-22 13:51:44 -07:00
|
|
|
}
|
2020-08-03 17:56:31 +03:00
|
|
|
wasInit = true
|
2017-10-22 13:51:44 -07:00
|
|
|
|
|
|
|
|
// If force re-init, kill the current server if there is one.
|
|
|
|
|
if (seleniumServer) {
|
2020-08-03 17:56:31 +03:00
|
|
|
seleniumServer.kill()
|
|
|
|
|
seleniumServer = null
|
2017-10-22 13:51:44 -07:00
|
|
|
}
|
|
|
|
|
|
2020-08-03 17:56:31 +03:00
|
|
|
seleniumJar = process.env['SELENIUM_SERVER_JAR']
|
|
|
|
|
seleniumUrl = process.env['SELENIUM_REMOTE_URL']
|
2017-10-22 13:51:44 -07:00
|
|
|
if (seleniumJar) {
|
2020-08-03 17:56:31 +03:00
|
|
|
info(`Using Selenium server jar: ${seleniumJar}`)
|
2017-10-22 13:51:44 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (seleniumUrl) {
|
2020-08-03 17:56:31 +03:00
|
|
|
info(`Using Selenium remote end: ${seleniumUrl}`)
|
2017-10-22 13:51:44 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (seleniumJar && seleniumUrl) {
|
|
|
|
|
throw Error(
|
2020-08-03 17:56:31 +03:00
|
|
|
'Ambiguous test configuration: both SELENIUM_REMOTE_URL' +
|
2024-02-07 16:07:24 +00:00
|
|
|
' && SELENIUM_SERVER_JAR environment variables are set',
|
2020-08-03 17:56:31 +03:00
|
|
|
)
|
2017-10-22 13:51:44 -07:00
|
|
|
}
|
|
|
|
|
|
2020-08-03 17:56:31 +03:00
|
|
|
const envBrowsers = getBrowsersToTestFromEnv()
|
2017-10-22 13:51:44 -07:00
|
|
|
if ((seleniumJar || seleniumUrl) && envBrowsers.length === 0) {
|
|
|
|
|
throw Error(
|
2020-08-03 17:56:31 +03:00
|
|
|
'Ambiguous test configuration: when either the SELENIUM_REMOTE_URL or' +
|
2022-06-02 23:41:17 +05:30
|
|
|
' SELENIUM_SERVER_JAR environment variable is set, the' +
|
2024-02-07 16:07:24 +00:00
|
|
|
' SELENIUM_BROWSER variable must also be set.',
|
2020-08-03 17:56:31 +03:00
|
|
|
)
|
2017-10-22 13:51:44 -07:00
|
|
|
}
|
|
|
|
|
|
2020-08-03 17:56:31 +03:00
|
|
|
targetBrowsers = envBrowsers.length > 0 ? envBrowsers : getAvailableBrowsers()
|
2024-02-07 16:07:24 +00:00
|
|
|
info(`Running tests against [${targetBrowsers.map((b) => b.name).join(', ')}]`)
|
2017-10-22 13:51:44 -07:00
|
|
|
|
2020-08-03 17:56:31 +03:00
|
|
|
after(function () {
|
2017-10-22 13:51:44 -07:00
|
|
|
if (seleniumServer) {
|
2020-08-03 17:56:31 +03:00
|
|
|
return seleniumServer.kill()
|
2017-10-22 13:51:44 -07:00
|
|
|
}
|
2020-08-03 17:56:31 +03:00
|
|
|
})
|
2017-10-22 13:51:44 -07:00
|
|
|
}
|
|
|
|
|
|
2020-08-03 17:56:31 +03:00
|
|
|
const TARGET_MAP = /** !WeakMap<!Environment, !TargetBrowser> */ new WeakMap()
|
2024-02-07 16:07:24 +00:00
|
|
|
const URL_MAP = /** !WeakMap<!Environment, ?(string|remote.SeleniumServer)> */ new WeakMap()
|
2013-03-05 21:03:26 -08:00
|
|
|
|
|
|
|
|
/**
|
2017-10-22 13:51:44 -07:00
|
|
|
* Defines the environment a {@linkplain suite test suite} is running against.
|
|
|
|
|
* @final
|
|
|
|
|
*/
|
|
|
|
|
class Environment {
|
|
|
|
|
/**
|
2025-07-08 17:23:29 +09:00
|
|
|
* @param {!TargetBrowser} browser the browser targeted in this environment.
|
2017-10-22 13:51:44 -07:00
|
|
|
* @param {?(string|remote.SeleniumServer)=} url remote URL of an existing
|
|
|
|
|
* Selenium server to test against.
|
|
|
|
|
*/
|
|
|
|
|
constructor(browser, url = undefined) {
|
2024-02-07 16:07:24 +00:00
|
|
|
browser = /** @type {!TargetBrowser} */ (Object.seal(Object.assign({}, browser)))
|
2017-10-22 13:51:44 -07:00
|
|
|
|
2020-08-03 17:56:31 +03:00
|
|
|
TARGET_MAP.set(this, browser)
|
|
|
|
|
URL_MAP.set(this, url || null)
|
2017-10-22 13:51:44 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @return {!TargetBrowser} the target browser for this test environment. */
|
|
|
|
|
get browser() {
|
2020-08-03 17:56:31 +03:00
|
|
|
return TARGET_MAP.get(this)
|
2017-10-22 13:51:44 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns a predicate function that will suppress tests in this environment
|
|
|
|
|
* if the {@linkplain #browser current browser} is in the list of
|
|
|
|
|
* `browsersToIgnore`.
|
|
|
|
|
*
|
|
|
|
|
* @param {...(string|!Browser)} browsersToIgnore the browsers that should
|
|
|
|
|
* be ignored.
|
|
|
|
|
* @return {function(): boolean} a new predicate function.
|
|
|
|
|
*/
|
|
|
|
|
browsers(...browsersToIgnore) {
|
2022-01-09 19:39:27 +05:30
|
|
|
return () => browsersToIgnore.indexOf(this.browser.name) !== -1
|
2017-10-22 13:51:44 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return {!Builder} a new WebDriver builder configured to target this
|
|
|
|
|
* environment's {@linkplain #browser browser}.
|
|
|
|
|
*/
|
|
|
|
|
builder() {
|
2020-08-03 17:56:31 +03:00
|
|
|
const browser = this.browser
|
|
|
|
|
const urlOrServer = URL_MAP.get(this)
|
2017-10-22 13:51:44 -07:00
|
|
|
|
2020-08-03 17:56:31 +03:00
|
|
|
const builder = new Builder()
|
2024-06-27 18:33:36 +01:00
|
|
|
|
|
|
|
|
// Sniff the environment variables for paths to use for the common browsers
|
|
|
|
|
// Chrome
|
|
|
|
|
if ('SE_CHROMEDRIVER' in process.env) {
|
|
|
|
|
const found = locate(process.env.SE_CHROMEDRIVER)
|
|
|
|
|
const service = new chrome.ServiceBuilder(found)
|
|
|
|
|
builder.setChromeService(service)
|
|
|
|
|
}
|
|
|
|
|
if ('SE_CHROME' in process.env) {
|
|
|
|
|
const binary = locate(process.env.SE_CHROME)
|
|
|
|
|
const options = new chrome.Options()
|
|
|
|
|
options.setChromeBinaryPath(binary)
|
|
|
|
|
options.setAcceptInsecureCerts(true)
|
|
|
|
|
options.addArguments('disable-infobars', 'disable-breakpad', 'disable-dev-shm-usage', 'no-sandbox')
|
|
|
|
|
builder.setChromeOptions(options)
|
|
|
|
|
}
|
|
|
|
|
// Edge
|
|
|
|
|
// Firefox
|
|
|
|
|
if ('SE_GECKODRIVER' in process.env) {
|
|
|
|
|
const found = locate(process.env.SE_GECKODRIVER)
|
|
|
|
|
const service = new firefox.ServiceBuilder(found)
|
|
|
|
|
builder.setFirefoxService(service)
|
|
|
|
|
}
|
|
|
|
|
if ('SE_FIREFOX' in process.env) {
|
|
|
|
|
const binary = locate(process.env.SE_FIREFOX)
|
|
|
|
|
const options = new firefox.Options()
|
|
|
|
|
options.enableBidi()
|
|
|
|
|
options.setBinary(binary)
|
|
|
|
|
builder.setFirefoxOptions(options)
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-03 17:56:31 +03:00
|
|
|
builder.disableEnvironmentOverrides()
|
2017-10-22 13:51:44 -07:00
|
|
|
|
2020-08-03 17:56:31 +03:00
|
|
|
const realBuild = builder.build
|
|
|
|
|
builder.build = function () {
|
2022-06-02 23:41:17 +05:30
|
|
|
builder.forBrowser(browser.name, browser.version, browser.platform)
|
2022-01-09 20:37:03 +05:30
|
|
|
|
2020-03-04 16:38:33 +02:00
|
|
|
if (browser.capabilities) {
|
2022-06-02 23:41:17 +05:30
|
|
|
builder.getCapabilities().merge(browser.capabilities)
|
2022-01-09 20:37:03 +05:30
|
|
|
}
|
|
|
|
|
|
2022-01-21 11:25:17 +00:00
|
|
|
if (browser.name === 'firefox') {
|
2022-06-02 23:41:17 +05:30
|
|
|
builder.setCapability('moz:debuggerAddress', true)
|
2020-03-04 16:38:33 +02:00
|
|
|
}
|
|
|
|
|
|
2024-04-10 15:56:40 +05:30
|
|
|
// Enable BiDi for supporting browsers.
|
|
|
|
|
if (browser.name === Browser.FIREFOX || browser.name === Browser.CHROME || browser.name === Browser.EDGE) {
|
|
|
|
|
builder.setCapability('webSocketUrl', true)
|
2024-08-27 11:32:27 +05:30
|
|
|
builder.setCapability('unhandledPromptBehavior', 'ignore')
|
2024-04-10 15:56:40 +05:30
|
|
|
}
|
|
|
|
|
|
2017-10-22 13:51:44 -07:00
|
|
|
if (typeof urlOrServer === 'string') {
|
2020-08-03 17:56:31 +03:00
|
|
|
builder.usingServer(urlOrServer)
|
2017-10-22 13:51:44 -07:00
|
|
|
} else if (urlOrServer) {
|
2020-08-03 17:56:31 +03:00
|
|
|
builder.usingServer(urlOrServer.address())
|
2017-10-22 13:51:44 -07:00
|
|
|
}
|
2020-08-03 17:56:31 +03:00
|
|
|
return realBuild.call(builder)
|
|
|
|
|
}
|
2017-10-22 13:51:44 -07:00
|
|
|
|
2020-08-03 17:56:31 +03:00
|
|
|
return builder
|
2017-10-22 13:51:44 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Configuration options for a {@linkplain ./index.suite test suite}.
|
|
|
|
|
* @record
|
|
|
|
|
*/
|
2022-06-02 23:41:17 +05:30
|
|
|
function SuiteOptions() {}
|
2017-10-22 13:51:44 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The browsers to run the test suite against.
|
|
|
|
|
* @type {!Array<!(Browser|TargetBrowser)>}
|
|
|
|
|
*/
|
2020-08-03 17:56:31 +03:00
|
|
|
SuiteOptions.prototype.browsers
|
2017-10-22 13:51:44 -07:00
|
|
|
|
2020-08-03 17:56:31 +03:00
|
|
|
let inSuite = false
|
2017-10-22 13:51:44 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Defines a test suite by calling the provided function once for each of the
|
|
|
|
|
* target browsers. If a suite is not limited to a specific set of browsers in
|
|
|
|
|
* the provided {@linkplain ./index.SuiteOptions suite options}, the suite will
|
|
|
|
|
* be configured to run against each of the {@linkplain ./index.init runtime
|
|
|
|
|
* target browsers}.
|
|
|
|
|
*
|
|
|
|
|
* Sample usage:
|
|
|
|
|
*
|
|
|
|
|
* const {By, Key, until} = require('selenium-webdriver');
|
|
|
|
|
* const {suite} = require('selenium-webdriver/testing');
|
|
|
|
|
*
|
|
|
|
|
* suite(function(env) {
|
|
|
|
|
* describe('Google Search', function() {
|
|
|
|
|
* let driver;
|
|
|
|
|
*
|
|
|
|
|
* before(async function() {
|
|
|
|
|
* driver = await env.builder().build();
|
|
|
|
|
* });
|
|
|
|
|
*
|
|
|
|
|
* after(() => driver.quit());
|
|
|
|
|
*
|
|
|
|
|
* it('demo', async function() {
|
|
|
|
|
* await driver.get('http://www.google.com/ncr');
|
|
|
|
|
*
|
|
|
|
|
* let q = await driver.findElement(By.name('q'));
|
|
|
|
|
* await q.sendKeys('webdriver', Key.RETURN);
|
|
|
|
|
* await driver.wait(
|
|
|
|
|
* until.titleIs('webdriver - Google Search'), 1000);
|
|
|
|
|
* });
|
|
|
|
|
* });
|
|
|
|
|
* });
|
|
|
|
|
*
|
|
|
|
|
* By default, this example suite will run against every WebDriver-enabled
|
|
|
|
|
* browser on the current system. Alternatively, the `SELENIUM_BROWSER`
|
|
|
|
|
* environment variable may be used to run against a specific browser:
|
|
|
|
|
*
|
|
|
|
|
* SELENIUM_BROWSER=firefox mocha -t 120000 example_test.js
|
|
|
|
|
*
|
|
|
|
|
* @param {function(!Environment)} fn the function to call to build the test
|
|
|
|
|
* suite.
|
|
|
|
|
* @param {SuiteOptions=} options configuration options.
|
|
|
|
|
*/
|
|
|
|
|
function suite(fn, options = undefined) {
|
|
|
|
|
if (inSuite) {
|
2020-08-03 17:56:31 +03:00
|
|
|
throw Error('Calls to suite() may not be nested')
|
2017-10-22 13:51:44 -07:00
|
|
|
}
|
|
|
|
|
try {
|
2020-08-03 17:56:31 +03:00
|
|
|
init()
|
|
|
|
|
inSuite = true
|
2017-10-22 13:51:44 -07:00
|
|
|
|
2020-08-03 17:56:31 +03:00
|
|
|
const suiteBrowsers = new Map()
|
2017-10-22 13:51:44 -07:00
|
|
|
if (options && options.browsers) {
|
|
|
|
|
for (let browser of options.browsers) {
|
|
|
|
|
if (typeof browser === 'string') {
|
2020-08-03 17:56:31 +03:00
|
|
|
suiteBrowsers.set(browser, { name: browser })
|
2017-10-22 13:51:44 -07:00
|
|
|
} else {
|
2020-08-03 17:56:31 +03:00
|
|
|
suiteBrowsers.set(browser.name, browser)
|
2017-10-22 13:51:44 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (let browser of targetBrowsers) {
|
|
|
|
|
if (suiteBrowsers.size > 0 && !suiteBrowsers.has(browser.name)) {
|
2020-08-03 17:56:31 +03:00
|
|
|
continue
|
2017-10-22 13:51:44 -07:00
|
|
|
}
|
|
|
|
|
|
2020-08-03 17:56:31 +03:00
|
|
|
describe(`[${browser.name}]`, function () {
|
2017-10-22 13:51:44 -07:00
|
|
|
if (!seleniumUrl && seleniumJar && !seleniumServer) {
|
2020-08-03 17:56:31 +03:00
|
|
|
seleniumServer = new remote.SeleniumServer(seleniumJar)
|
2017-10-22 13:51:44 -07:00
|
|
|
|
2020-08-03 17:56:31 +03:00
|
|
|
const startTimeout = 65 * 1000
|
2024-03-08 12:13:00 +00:00
|
|
|
|
2017-10-22 13:51:44 -07:00
|
|
|
function startSelenium() {
|
|
|
|
|
if (typeof this.timeout === 'function') {
|
2020-08-03 17:56:31 +03:00
|
|
|
this.timeout(startTimeout) // For mocha.
|
2017-10-22 13:51:44 -07:00
|
|
|
}
|
|
|
|
|
|
2020-08-03 17:56:31 +03:00
|
|
|
info(`Starting selenium server ${seleniumJar}`)
|
|
|
|
|
return seleniumServer.start(60 * 1000)
|
2017-10-22 13:51:44 -07:00
|
|
|
}
|
|
|
|
|
|
2020-08-03 17:56:31 +03:00
|
|
|
const /** !Function */ beforeHook = global.beforeAll || global.before
|
|
|
|
|
beforeHook(startSelenium, startTimeout)
|
2017-10-22 13:51:44 -07:00
|
|
|
}
|
|
|
|
|
|
2020-08-03 17:56:31 +03:00
|
|
|
fn(new Environment(browser, seleniumUrl || seleniumServer))
|
|
|
|
|
})
|
2017-10-22 13:51:44 -07:00
|
|
|
}
|
|
|
|
|
} finally {
|
2020-08-03 17:56:31 +03:00
|
|
|
inSuite = false
|
2017-10-22 13:51:44 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns an object with wrappers for the standard mocha/jasmine test
|
|
|
|
|
* functions: `describe` and `it`, which will redirect to `xdescribe` and `xit`,
|
|
|
|
|
* respectively, if provided predicate function returns false.
|
|
|
|
|
*
|
|
|
|
|
* Sample usage:
|
|
|
|
|
*
|
|
|
|
|
* const {Browser} = require('selenium-webdriver');
|
|
|
|
|
* const {suite, ignore} = require('selenium-webdriver/testing');
|
|
|
|
|
*
|
|
|
|
|
* suite(function(env) {
|
|
|
|
|
*
|
|
|
|
|
* // Skip tests the current environment targets Chrome.
|
|
|
|
|
* ignore(env.browsers(Browser.CHROME)).
|
|
|
|
|
* describe('something', async function() {
|
|
|
|
|
* let driver = await env.builder().build();
|
|
|
|
|
* // etc.
|
|
|
|
|
* });
|
|
|
|
|
* });
|
|
|
|
|
*
|
2013-03-05 21:03:26 -08:00
|
|
|
* @param {function(): boolean} predicateFn A predicate to call to determine
|
|
|
|
|
* if the test should be suppressed. This function MUST be synchronous.
|
2017-10-22 13:51:44 -07:00
|
|
|
* @return {{describe: !Function, it: !Function}} an object with wrapped
|
2022-06-02 23:41:17 +05:30
|
|
|
* versions of the `describe` and `it` test functions.
|
2013-03-05 21:03:26 -08:00
|
|
|
*/
|
|
|
|
|
function ignore(predicateFn) {
|
2020-08-03 17:56:31 +03:00
|
|
|
const isJasmine = global.jasmine && typeof global.jasmine === 'object'
|
2017-10-22 13:51:44 -07:00
|
|
|
|
|
|
|
|
const hooks = {
|
|
|
|
|
describe: getTestHook('describe'),
|
|
|
|
|
xdescribe: getTestHook('xdescribe'),
|
|
|
|
|
it: getTestHook('it'),
|
2020-08-03 17:56:31 +03:00
|
|
|
xit: getTestHook('xit'),
|
|
|
|
|
}
|
|
|
|
|
hooks.fdescribe = isJasmine ? getTestHook('fdescribe') : hooks.describe.only
|
|
|
|
|
hooks.fit = isJasmine ? getTestHook('fit') : hooks.it.only
|
2017-10-22 13:51:44 -07:00
|
|
|
|
2020-08-03 17:56:31 +03:00
|
|
|
let describe = wrap(hooks.xdescribe, hooks.describe)
|
|
|
|
|
let fdescribe = wrap(hooks.xdescribe, hooks.fdescribe)
|
|
|
|
|
//eslint-disable-next-line no-only-tests/no-only-tests
|
|
|
|
|
describe.only = fdescribe
|
2013-03-05 21:03:26 -08:00
|
|
|
|
2020-08-03 17:56:31 +03:00
|
|
|
let it = wrap(hooks.xit, hooks.it)
|
|
|
|
|
let fit = wrap(hooks.xit, hooks.fit)
|
|
|
|
|
//eslint-disable-next-line no-only-tests/no-only-tests
|
|
|
|
|
it.only = fit
|
2013-07-04 19:46:17 -07:00
|
|
|
|
2020-08-03 17:56:31 +03:00
|
|
|
return { describe, it }
|
2013-03-05 21:03:26 -08:00
|
|
|
|
2013-07-04 19:46:17 -07:00
|
|
|
function wrap(onSkip, onRun) {
|
2020-08-03 17:56:31 +03:00
|
|
|
return function (...args) {
|
2013-07-04 19:46:17 -07:00
|
|
|
if (predicateFn()) {
|
2020-08-03 17:56:31 +03:00
|
|
|
onSkip(...args)
|
2013-07-04 19:46:17 -07:00
|
|
|
} else {
|
2020-08-03 17:56:31 +03:00
|
|
|
onRun(...args)
|
2013-07-04 19:46:17 -07:00
|
|
|
}
|
2020-08-03 17:56:31 +03:00
|
|
|
}
|
2013-07-04 19:46:17 -07:00
|
|
|
}
|
2013-06-22 10:40:38 -07:00
|
|
|
}
|
2013-03-05 21:03:26 -08:00
|
|
|
|
2016-09-23 11:04:25 -07:00
|
|
|
/**
|
|
|
|
|
* @param {string} name
|
|
|
|
|
* @return {!Function}
|
|
|
|
|
* @throws {TypeError}
|
|
|
|
|
*/
|
2017-10-22 13:51:44 -07:00
|
|
|
function getTestHook(name) {
|
2020-08-03 17:56:31 +03:00
|
|
|
let fn = global[name]
|
|
|
|
|
let type = typeof fn
|
2016-09-23 11:04:25 -07:00
|
|
|
if (type !== 'function') {
|
|
|
|
|
throw TypeError(
|
2020-08-03 17:56:31 +03:00
|
|
|
`Expected global.${name} to be a function, but is ${type}.` +
|
2022-06-02 23:41:17 +05:30
|
|
|
' This can happen if you try using this module when running with' +
|
2024-02-07 16:07:24 +00:00
|
|
|
' node directly instead of using jasmine or mocha',
|
2020-08-03 17:56:31 +03:00
|
|
|
)
|
2016-09-23 11:04:25 -07:00
|
|
|
}
|
2020-08-03 17:56:31 +03:00
|
|
|
return fn
|
2016-09-23 11:04:25 -07:00
|
|
|
}
|
|
|
|
|
|
2024-06-27 18:33:36 +01:00
|
|
|
function locate(fileLike) {
|
|
|
|
|
if (fs.existsSync(fileLike)) {
|
|
|
|
|
return fileLike
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-10 15:55:20 +05:30
|
|
|
if (!runfiles) {
|
|
|
|
|
throw new Error('Unable to find ' + fileLike)
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-27 18:33:36 +01:00
|
|
|
try {
|
|
|
|
|
return runfiles.resolve(fileLike)
|
|
|
|
|
} catch {
|
|
|
|
|
// Fall through
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Is the item in the workspace?
|
|
|
|
|
try {
|
|
|
|
|
return runfiles.resolveWorkspaceRelative(fileLike)
|
|
|
|
|
} catch {
|
|
|
|
|
// Fall through
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Find the repo mapping file
|
|
|
|
|
let repoMappingFile
|
|
|
|
|
try {
|
|
|
|
|
repoMappingFile = runfiles.resolve('_repo_mapping')
|
|
|
|
|
} catch {
|
|
|
|
|
throw new Error('Unable to locate (no repo mapping file): ' + fileLike)
|
|
|
|
|
}
|
|
|
|
|
const lines = fs.readFileSync(repoMappingFile, { encoding: 'utf8' }).split('\n')
|
|
|
|
|
|
|
|
|
|
// Build a map of "repo we declared we need" to "path"
|
|
|
|
|
const mapping = {}
|
|
|
|
|
for (const line of lines) {
|
|
|
|
|
if (line.startsWith(',')) {
|
|
|
|
|
const parts = line.split(',', 3)
|
|
|
|
|
mapping[parts[1]] = parts[2]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get the first segment of the path
|
|
|
|
|
const pathSegments = fileLike.split('/')
|
|
|
|
|
if (!pathSegments.length) {
|
|
|
|
|
throw new Error('Unable to locate ' + fileLike)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pathSegments[0] = mapping[pathSegments[0]] ? mapping[pathSegments[0]] : '_main'
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
return runfiles.resolve(path.join(...pathSegments))
|
|
|
|
|
} catch {
|
|
|
|
|
// Fall through
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
throw new Error('Unable to find ' + fileLike)
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-05 21:03:26 -08:00
|
|
|
// PUBLIC API
|
|
|
|
|
|
2017-10-02 19:32:10 -04:00
|
|
|
module.exports = {
|
2017-10-22 13:51:44 -07:00
|
|
|
Environment,
|
|
|
|
|
SuiteOptions,
|
|
|
|
|
init,
|
2017-10-02 19:32:10 -04:00
|
|
|
ignore,
|
2020-08-03 17:56:31 +03:00
|
|
|
suite,
|
|
|
|
|
}
|