diff --git a/examples/globalsModule.js b/examples/globalsModule.js index 931fe6cb2e..9842ea9949 100644 --- a/examples/globalsModule.js +++ b/examples/globalsModule.js @@ -1,11 +1,11 @@ module.exports = { // this controls whether to abort the test execution when an assertion failed and skip the rest // it's being used in waitFor commands and expect assertions - abortOnAssertionFailure : true, + abortOnAssertionFailure: true, // this will overwrite the default polling interval (currently 500ms) for waitFor commands // and expect assertions that use retry - waitForConditionPollInterval : 300, + waitForConditionPollInterval: 500, // default timeout value in milliseconds for waitFor commands and implicit waitFor value for // expect assertions @@ -13,12 +13,23 @@ module.exports = { // this will cause waitFor commands on elements to throw an error if multiple // elements are found using the given locate strategy and selector - throwOnMultipleElementsReturned : false, + throwOnMultipleElementsReturned: false, - // controls the timeout time for async hooks. Expects the done() callback to be invoked within this time + // controls the timeout value for async hooks. Expects the done() callback to be invoked within this time // or an error is thrown asyncHookTimeout : 10000, + // controls the timeout value for when running async unit tests. Expects the done() callback to be invoked within this time + // or an error is thrown + unitTestsTimeout : 2000, + + // controls the timeout value for when executing the global async reporter. Expects the done() callback to be invoked within this time + // or an error is thrown + customReporterCallbackTimeout: 20000, + + // Automatically retrying failed assertions - You can tell Nightwatch to automatically retry failed assertions until a given timeout is reached, before the test runner gives up and fails the test. + retryAssertionTimeout: 1000, + 'default' : { myGlobal : function() { return 'I\'m a method'; @@ -32,34 +43,29 @@ module.exports = { } }, - before : function(cb) { + before(cb) { //console.log('GLOBAL BEFORE') cb(); }, - beforeEach : function(browser, cb) { + beforeEach(browser, cb) { //console.log('GLOBAL beforeEach') cb(); }, - after : function(cb) { + after(cb) { //console.log('GLOBAL AFTER') cb(); }, - afterEach : function(browser, cb) { + afterEach(browser, cb) { browser.perform(function() { - console.log('GLOBAL afterEach') - - + //console.log('GLOBAL afterEach') cb(); - - - }) - + }); }, - reporter : function(results, cb) { + reporter(results, cb) { cb(); } }; diff --git a/lib/index.js b/lib/index.js index 0f1c2e6f8b..f18614686b 100644 --- a/lib/index.js +++ b/lib/index.js @@ -250,8 +250,8 @@ class NightwatchClient extends EventEmitter { .setWebdriverHttpOption('username') .setWebdriverHttpOption('access_key', ['accessKey', 'access_key', 'password']); - let webdriverOpts = this.settings.webdriver || {}; - let timeoutOptions = webdriverOpts.timeout_options || {}; + const webdriverOpts = this.settings.webdriver; + const timeoutOptions = webdriverOpts.timeout_options || {}; if (webdriverOpts.port) { this.httpOpts.setPort(webdriverOpts.port); diff --git a/lib/runner/wd-instances/base-wd-server.js b/lib/runner/wd-instances/base-wd-server.js index 4600ecb5f9..d30d77ce92 100644 --- a/lib/runner/wd-instances/base-wd-server.js +++ b/lib/runner/wd-instances/base-wd-server.js @@ -256,6 +256,7 @@ class BaseWDServer { } let err = this.createError(null, code); + err.detailedErr = this.error_out || this.output; this.promiseStarted.reject(err); } } diff --git a/lib/runner/wd-instances/safaridriver.js b/lib/runner/wd-instances/safaridriver.js index a628deb25c..8845645fc6 100644 --- a/lib/runner/wd-instances/safaridriver.js +++ b/lib/runner/wd-instances/safaridriver.js @@ -8,14 +8,22 @@ class SafariDriver extends BaseWDServer { static get acceptedCLIArgs() { return [ - 'port', 'p', 'enable' + 'port', 'p', 'enable', 'legacy', 'w3c' ]; } + static get useLegacyDriver() { + return true; + } + static get serviceName() { return 'SafariDriver'; } + static get safariDriverPath() { + return '/usr/bin/safaridriver'; + } + get initialCheckProcessDelay() { return 500; } @@ -29,7 +37,7 @@ class SafariDriver extends BaseWDServer { } get serviceDownloadUrl() { - return 'https://developer.apple.com/documentation/webkit/macos_webdriver_commands_for_safari'; + return 'https://developer.apple.com/documentation/webkit/macos_webdriver_commands_for_safari_12_and_later'; } get serviceName() { @@ -37,6 +45,8 @@ class SafariDriver extends BaseWDServer { } constructor(settings) { + settings.server_path = settings.server_path || SafariDriver.safariDriverPath; + super(settings); const cliArgs = ['--port', this.settings.port]; @@ -58,6 +68,15 @@ class SafariDriver extends BaseWDServer { cliArgs.push(...argsReduced); } + const use_legacy_jsonwire = this.settings.use_legacy_jsonwire === undefined ? + SafariDriver.useLegacyDriver : this.settings.use_legacy_jsonwire; + + if (use_legacy_jsonwire) { + cliArgs.push('--legacy'); + } else { + cliArgs.push('--w3c'); + } + this.settings.cli_args = cliArgs; // safaridriver doesn't output anything to stdout, so we need to start the process check diff --git a/lib/runner/webdriver-server.js b/lib/runner/webdriver-server.js index 840d441bc3..1b7ccc9d5d 100644 --- a/lib/runner/webdriver-server.js +++ b/lib/runner/webdriver-server.js @@ -27,6 +27,10 @@ class WDServer { return __concurrencyEnabled__; } + static get instances() { + return __wd_instances__; + } + /** * @param {Object} baseConfig * @param {Object} argv @@ -128,9 +132,7 @@ class WDServer { return true; }) - .then(() => { - return this.instance.stop(); - }); + .then(() => this.instance.stop()); } } diff --git a/lib/settings/defaults.js b/lib/settings/defaults.js index b474beca28..f76eb5e891 100644 --- a/lib/settings/defaults.js +++ b/lib/settings/defaults.js @@ -99,6 +99,7 @@ module.exports = { cli_args: {}, server_path: null, log_path: '', + use_legacy_jsonwire: undefined, host: undefined, port: undefined, @@ -147,7 +148,7 @@ module.exports = { sync_test_names: true, - // Skip a tests by tag name; can be a list of comma-separated values (no space) + // Skip tests by tag name; can be a list of comma-separated values (no space) skiptags: '', // Use xpath as the default locator strategy diff --git a/lib/transport/transport.js b/lib/transport/transport.js index c72e0458ff..475c2ba900 100644 --- a/lib/transport/transport.js +++ b/lib/transport/transport.js @@ -153,11 +153,18 @@ class Transport extends EventEmitter { } createSession() { - let request = this.createProtocolAction({ + const body = {}; + if (this.settings.capabilities) { + body.capabilities = this.settings.capabilities; + } + + if (this.desiredCapabilities) { + body.desiredCapabilities = this.desiredCapabilities; + } + + const request = this.createProtocolAction({ path : '/session', - data : { - desiredCapabilities : this.desiredCapabilities - } + data : body }); request @@ -456,37 +463,70 @@ class Transport extends EventEmitter { }); } + static adaptWebdriverSettings(settings, usingSeleniumServer = false) { + const browserName = settings.desiredCapabilities.browserName.toLowerCase(); + + if (usingSeleniumServer && [BrowserName.CHROME, BrowserName.EDGE].includes(browserName)) { + settings.selenium.version2 = true; + + return; + } + + switch (browserName) { + case BrowserName.SAFARI: + if (settings.webdriver.start_process && settings.webdriver.use_legacy_jsonwire === undefined) { + const SafariDriver = require('../runner/wd-instances/safaridriver.js'); + settings.webdriver.use_legacy_jsonwire = SafariDriver.useLegacyDriver; + } + break; + + case BrowserName.FIREFOX: + settings.webdriver.use_legacy_jsonwire = false; + break; + } + + if (settings.webdriver.use_legacy_jsonwire === undefined) { + settings.webdriver.use_legacy_jsonwire = true; + } + + if (!settings.webdriver.use_legacy_jsonwire && !usingSeleniumServer) { + settings.capabilities = settings.desiredCapabilities; + } + } + static create(nightwatchInstance) { - let settings = nightwatchInstance.settings; - let browserName = settings.desiredCapabilities.browserName.toLowerCase(); - let usingSeleniumServer = settings.selenium && (settings.selenium.start_process || !settings.webdriver.start_process); - let seleniumVersion2 = usingSeleniumServer && (settings.selenium.version2 || [BrowserName.CHROME, BrowserName.EDGE].includes(browserName)); + const settings = nightwatchInstance.settings; + const usingSeleniumServer = settings.selenium && ( + settings.selenium.start_process || + !settings.webdriver.start_process && (settings.selenium_host || settings.selenium.host || settings.seleniumHost) + ); - if (seleniumVersion2) { + Transport.adaptWebdriverSettings(settings, usingSeleniumServer); + + // Legacy Selenium Server 2 + if (usingSeleniumServer && settings.selenium.version2) { const Selenium2 = require('./selenium2.js'); return new Selenium2(nightwatchInstance); } + // Selenium Server 3 if (usingSeleniumServer) { const SeleniumProtocol = require('./selenium3.js'); return new SeleniumProtocol(nightwatchInstance); } - switch (browserName) { - case BrowserName.FIREFOX: { - const WebdriverProtocol = require('./webdriver.js'); + // drivers using the legacy JSONWire protocol + if (settings.webdriver.use_legacy_jsonwire) { + const JsonWireProtocol = require('./jsonwire.js'); - return new WebdriverProtocol(nightwatchInstance); - } + return new JsonWireProtocol(nightwatchInstance); + } - default: { - const JsonWireProtocol = require('./jsonwire.js'); + const WebdriverProtocol = require('./webdriver.js'); - return new JsonWireProtocol(nightwatchInstance); - } - } + return new WebdriverProtocol(nightwatchInstance); } /** diff --git a/test/src/api/commands/testClearValue.js b/test/src/api/commands/testClearValue.js index 5e49e08445..0292f765e9 100644 --- a/test/src/api/commands/testClearValue.js +++ b/test/src/api/commands/testClearValue.js @@ -108,6 +108,10 @@ describe('clearValue', function() { MockServer.addMock({ url: '/session', postdata: JSON.stringify({ + capabilities: { + browserName: 'firefox', + acceptSslCerts: true + }, desiredCapabilities: { browserName: 'firefox', acceptSslCerts: true, diff --git a/test/src/index/testCreateTransport.js b/test/src/index/testCreateTransport.js index 3321ec9072..a1128923fb 100644 --- a/test/src/index/testCreateTransport.js +++ b/test/src/index/testCreateTransport.js @@ -1,5 +1,6 @@ const assert = require('assert'); const common = require('../../common.js'); +const NightwatchClient = common.require('index.js'); const Selenium2 = common.require('transport/selenium2.js'); const WebDriver = common.require('transport/webdriver.js'); const JsonWire = common.require('transport/jsonwire.js'); @@ -7,108 +8,133 @@ const Selenium3 = common.require('transport/selenium3.js'); describe('Transport.create()', function () { it('test create Transport for Selenium3 external with Firefox', function() { - const Transport = common.require('transport/transport.js'); - - let seleniumExternal = Transport.create({ - settings: { - selenium: { - start_process: false - }, - webdriver: {}, - desiredCapabilities: { - browserName: 'firefox' - } - } + const client = NightwatchClient.client({ + selenium: { + start_process: false, + }, + webdriver: {}, + desiredCapabilities: { + browserName: 'firefox' + }, + selenium_host: 'remote.url' }); - assert.ok(seleniumExternal instanceof Selenium3); + assert.ok(client.transport instanceof Selenium3); + assert.equal(client.settings.webdriver.host, 'remote.url'); }); - it('test create Transport for Selenium3 external with Chrome', function() { - const Transport = common.require('transport/transport.js'); + it('test create Transport for Selenium3 external with Firefox - seleniumHost property', function() { + const client = NightwatchClient.client({ + selenium: { + start_process: false, + }, + webdriver: {}, + desiredCapabilities: { + browserName: 'firefox' + }, + seleniumHost: 'remote.url' + }); - let seleniumExternal = Transport.create({ - settings: { - selenium: { - start_process: false - }, - webdriver: { + assert.ok(client.transport instanceof Selenium3); + assert.equal(client.settings.webdriver.host, 'remote.url'); + }); - }, - desiredCapabilities: { - browserName: 'chrome' - } - } + it('test create Transport for Webdriver external - host property', function() { + const client = NightwatchClient.client({ + webdriver: { + host: 'remote.url' + }, + desiredCapabilities: { + browserName: 'firefox' + }, }); - assert.ok(seleniumExternal instanceof Selenium2); + assert.ok(client.transport instanceof WebDriver); + assert.equal(client.settings.webdriver.host, 'remote.url'); }); - it('test create Transport for Selenium2 external', function() { - const Transport = common.require('transport/transport.js'); + it('test create Transport for Selenium3 external with Chrome', function() { + const client = NightwatchClient.client({ + desiredCapabilities: { + browserName: 'chrome' + }, + selenium_host: 'remote.url' + }); - let seleniumExternal = Transport.create({ - settings: { - selenium: { - start_process: false - }, - webdriver: { + assert.ok(client.transport instanceof Selenium2); + assert.equal(client.settings.webdriver.host, 'remote.url'); + }); - }, - desiredCapabilities: { - browserName: 'chrome' - } + it('test create Transport for Selenium3 managed', function() { + const client = NightwatchClient.client({ + selenium: { + start_process: true + }, + webdriver: { + start_process: false + }, + desiredCapabilities: { + browserName: 'firefox' } }); - assert.ok(seleniumExternal instanceof Selenium2); + assert.ok(client.transport instanceof Selenium3); }); - it('test create Transport for Selenium2 managed', function() { - const Transport = common.require('transport/transport.js'); - - let seleniumExternal = Transport.create({ - settings: { - selenium: { - start_process: true - }, - webdriver: { - start_process: false - }, - desiredCapabilities: { - browserName: 'firefox' - } + it('test create Transport for Selenium2 managed explicit version2 setting', function() { + const client = NightwatchClient.client({ + selenium: { + version2: true, + start_process: true + }, + webdriver: { + start_process: false + }, + desiredCapabilities: { + browserName: 'firefox' } }); - assert.ok(seleniumExternal instanceof Selenium2); + assert.ok(client.transport instanceof Selenium2); + assert.strictEqual(client.transport instanceof Selenium3, false); }); - it('test create Transport for Selenium2 managed explicit version2 setting', function() { - const Transport = common.require('transport/transport.js'); + it('test create Transport for Firefox managed', function() { + const client = NightwatchClient.client({ + webdriver: { + start_process: true + }, + desiredCapabilities: { + browserName: 'firefox' + } + }); - let seleniumExternal = Transport.create({ - settings: { - selenium: { - version2: true, - start_process: true - }, - webdriver: { - start_process: false - }, - desiredCapabilities: { - browserName: 'firefox' - } + assert.ok(client.transport instanceof WebDriver); + assert.strictEqual(client.transport instanceof Selenium2, false); + assert.strictEqual(client.transport instanceof Selenium3, false); + assert.strictEqual(client.transport instanceof JsonWire, false); + }); + + it('test create Transport for Chrome managed', function() { + const client = NightwatchClient.client({ + webdriver: { + start_process: true + }, + desiredCapabilities: { + browserName: 'chrome' } }); - assert.ok(seleniumExternal instanceof Selenium2); + assert.ok(client.transport instanceof JsonWire); + assert.strictEqual(client.transport instanceof Selenium2, false); + assert.strictEqual(client.transport instanceof Selenium3, false); + assert.strictEqual(client.transport instanceof WebDriver, false); }); - it('test create Transport for Firefox managed', function() { + it('test create Transport for Safari managed', function() { const Transport = common.require('transport/transport.js'); - let geckoDriver = Transport.create({ + let safariDriver = Transport.create({ settings: { selenium: { start_process: false @@ -117,38 +143,39 @@ describe('Transport.create()', function () { start_process: true }, desiredCapabilities: { - browserName: 'firefox' + browserName: 'safari' } } }); - assert.ok(geckoDriver instanceof WebDriver); - assert.strictEqual(geckoDriver instanceof Selenium2, false); - assert.strictEqual(geckoDriver instanceof Selenium3, false); - assert.strictEqual(geckoDriver instanceof JsonWire, false); + assert.ok(safariDriver instanceof JsonWire); + assert.strictEqual(safariDriver instanceof Selenium2, false); + assert.strictEqual(safariDriver instanceof Selenium3, false); + assert.strictEqual(safariDriver instanceof WebDriver, false); }); - it('test create Transport for Chrome managed', function() { + it('test create Transport for Safari remote', function() { const Transport = common.require('transport/transport.js'); - let chromeDriver = Transport.create({ + let safariDriver = Transport.create({ settings: { selenium: { start_process: false }, webdriver: { - start_process: true + start_process: false, + host: 'remote.url' }, desiredCapabilities: { - browserName: 'chrome' + browserName: 'safari' } } }); - assert.ok(chromeDriver instanceof JsonWire); - assert.strictEqual(chromeDriver instanceof Selenium2, false); - assert.strictEqual(chromeDriver instanceof Selenium3, false); - assert.strictEqual(chromeDriver instanceof WebDriver, false); + assert.ok(safariDriver instanceof JsonWire); + assert.strictEqual(safariDriver instanceof Selenium2, false); + assert.strictEqual(safariDriver instanceof Selenium3, false); + assert.strictEqual(safariDriver instanceof WebDriver, false); }); it('test create Transport for Chrome managed and no selenium settings', function() { @@ -171,79 +198,53 @@ describe('Transport.create()', function () { assert.strictEqual(chromeDriver instanceof WebDriver, false); }); - it('test create Transport for Selenium3 managed', function() { - const Transport = common.require('transport/transport.js'); - - let seleniumExternal = Transport.create({ - settings: { - selenium: { - start_process: true - }, - webdriver: { - start_process: false - }, - desiredCapabilities: { - browserName: 'firefox' - } - } - }); - - assert.ok(seleniumExternal instanceof Selenium2); - }); - it('test create Transport for WebDriver managed and no selenium settings', function() { - const Transport = common.require('transport/transport.js'); - - let chromeDriver = Transport.create({ - settings: { - webdriver: { - start_process: true - }, - desiredCapabilities: { - browserName: 'safari' - } + const client = NightwatchClient.client({ + webdriver: { + start_process: true + }, + desiredCapabilities: { + browserName: 'safari' } }); - assert.ok(chromeDriver instanceof JsonWire); - assert.strictEqual(chromeDriver instanceof Selenium2, false); - assert.strictEqual(chromeDriver instanceof Selenium3, false); - assert.strictEqual(chromeDriver instanceof WebDriver, false); + assert.ok(client.transport instanceof JsonWire); + assert.strictEqual(client.transport instanceof Selenium2, false); + assert.strictEqual(client.transport instanceof Selenium3, false); + assert.strictEqual(client.transport instanceof WebDriver, false); }); it('test create Transport for Selenium remote cloud service with Chrome', function() { - const Transport = common.require('transport/transport.js'); - - let seleniumExternal = Transport.create({ - settings: { - selenium: { - start_process: true - }, - desiredCapabilities: { - browserName: 'Chrome' - } - } + const client = NightwatchClient.client({ + selenium: { + start_process: false + }, + desiredCapabilities: { + browserName: 'Chrome' + }, + selenium_host: 'remote.host' }); - assert.ok(seleniumExternal instanceof Selenium2); + assert.ok(client.transport instanceof Selenium2); + assert.equal(client.settings.webdriver.host, 'remote.host'); + assert.equal(client.settings.webdriver.default_path_prefix, '/wd/hub'); }); it('test create Transport for Selenium remote cloud service with MicrosoftEdge', function() { - const Transport = common.require('transport/transport.js'); - - let seleniumExternal = Transport.create({ - settings: { - selenium: { - start_process: true - }, - desiredCapabilities: { - browserName: 'MicrosoftEdge' - } - } + const client = NightwatchClient.client({ + selenium: { + start_process: true + }, + desiredCapabilities: { + browserName: 'MicrosoftEdge' + }, + selenium_host: 'remote.host' }); - assert.ok(seleniumExternal instanceof Selenium2); - assert.strictEqual(seleniumExternal instanceof Selenium3, false); + assert.ok(client.transport instanceof Selenium2); + assert.equal(client.settings.webdriver.host, 'remote.host'); + assert.equal(client.settings.webdriver.default_path_prefix, '/wd/hub'); + assert.strictEqual(client.transport instanceof Selenium3, false); }); }); \ No newline at end of file diff --git a/test/src/index/testNightwatchIndex.js b/test/src/index/testNightwatchIndex.js index 79ca61c37d..632df1a53d 100644 --- a/test/src/index/testNightwatchIndex.js +++ b/test/src/index/testNightwatchIndex.js @@ -116,6 +116,8 @@ describe('test NightwatchIndex', function () { browserName: 'firefox', platform: 'TEST' }, + selenium_host: 'localhost', + selenium_port: 10195, silent: false, output: true, selenium: { diff --git a/test/src/runner/testRunTestcase.js b/test/src/runner/testRunTestcase.js index 293ce12a04..8681042678 100644 --- a/test/src/runner/testRunTestcase.js +++ b/test/src/runner/testRunTestcase.js @@ -56,8 +56,8 @@ describe('testRunTestcase', function() { persist_globals: true, globals: globals, output_folder: false, - output: false, - silent: true + output: true, + silent: false }; return NightwatchClient.runTests(testsPath, settings); diff --git a/test/src/runner/testRunnerSessionCreate.js b/test/src/runner/testRunnerSessionCreate.js index 171853efe6..ac078f02d3 100644 --- a/test/src/runner/testRunnerSessionCreate.js +++ b/test/src/runner/testRunnerSessionCreate.js @@ -34,6 +34,11 @@ describe('testRunnerSessionCreate', function() { url: '/session', statusCode: 500, postdata: JSON.stringify({ + capabilities: { + browserName: 'firefox', + acceptSslCerts: true, + name: 'Async/Test/Sample' + }, desiredCapabilities: { browserName: 'firefox', acceptSslCerts: true, @@ -53,6 +58,11 @@ describe('testRunnerSessionCreate', function() { url: '/session', statusCode: 500, postdata: JSON.stringify({ + capabilities: { + browserName: 'firefox', + acceptSslCerts: true, + name: 'test-Name' + }, desiredCapabilities: { browserName: 'firefox', acceptSslCerts: true,