From 943dcfa7516fa3304d318c172dc9baf0b4ee6d61 Mon Sep 17 00:00:00 2001 From: Thomas Hermsdorff Date: Tue, 18 Jul 2023 12:24:07 +0200 Subject: [PATCH 01/38] fix(cucumber-runner): allow esm imports (#3805) (#3806) * fix(cucumber-runner): allow esm imports (#3805) * fix(cucumber-runner): add cli-arg 'enable-esm' * test(cucumber-runner): add tests for enable esm options/cli arg --- lib/runner/test-runners/cucumber.js | 13 ++++-- .../cucumber-integration/testCliArgs.js | 45 ++++++++++++++++++- 2 files changed, 53 insertions(+), 5 deletions(-) diff --git a/lib/runner/test-runners/cucumber.js b/lib/runner/test-runners/cucumber.js index a3904fbc24..cf4f79dbe1 100644 --- a/lib/runner/test-runners/cucumber.js +++ b/lib/runner/test-runners/cucumber.js @@ -107,14 +107,21 @@ class CucumberSuite extends TestSuite { } createInitialRequires() { + const {options} = this.settings.test_runner; + const isESMEnable = options.enable_esm || this.argv['enable-esm']; + const importTypeArgument = isESMEnable ? '--import' : '--require'; const initialRequires = [ - '--require', CucumberSuite.cucumberSetupFile + importTypeArgument, CucumberSuite.cucumberSetupFile ]; - initialRequires.push(...this.buildArgvValue(['require', 'require-module'])); + if (isESMEnable){ + initialRequires.push(...this.buildArgvValue(['import'])); + } else { + initialRequires.push(...this.buildArgvValue(['require', 'require-module'])); + } return this.allModulePaths.reduce((prev, spec) => { - prev.push('--require', spec); + prev.push(importTypeArgument, spec); return prev; }, initialRequires); diff --git a/test/src/runner/cucumber-integration/testCliArgs.js b/test/src/runner/cucumber-integration/testCliArgs.js index 3a5f78a101..c87ca2e4db 100644 --- a/test/src/runner/cucumber-integration/testCliArgs.js +++ b/test/src/runner/cucumber-integration/testCliArgs.js @@ -70,6 +70,7 @@ describe('Cucumber cli arguments', function(){ assert.ok(cliArgs.includes('--no-strict')); assert.ok(cliArgs.includes('--parallel')); assert.strictEqual(cliArgs[cliArgs.indexOf('--parallel')+1], 3); + assert.ok(cliArgs.includes('--require')); }); it('Cucumber cli arg --dry-run', function(){ @@ -90,7 +91,7 @@ describe('Cucumber cli arguments', function(){ assert.ok(cliArgs.includes('--dry-run')); }); - it('Cucumbr additional option --retries', function(){ + it('Cucumber additional option --retries', function(){ const runner = new CucumberRunner({ test_runner: { type: 'cucumber', @@ -108,7 +109,7 @@ describe('Cucumber cli arguments', function(){ assert.ok(cliArgs.includes('--retry')); }); - it('Cucumbr additional options --retry and --format', function(){ + it('Cucumber additional options --retry and --format', function(){ const runner = new CucumberRunner({ test_runner: { type: 'cucumber', @@ -129,4 +130,44 @@ describe('Cucumber cli arguments', function(){ assert.strictEqual(cliArgs[cliArgs.indexOf('--retry')+1], 3); assert.strictEqual(cliArgs[cliArgs.indexOf('--format')+1], '@cucumber/pretty-formatter'); }); + + it('Cucumber cli arg --enable-esm', function(){ + const runner = new CucumberRunner({ + test_runner: { + type: 'cucumber', + options: {} + } + }, { + 'enable-esm': true + }, {}); + + runner.createTestSuite({ + modules: [path.join(__dirname, '../../../cucumber-integration-tests/sample_cucumber_tests/integration/testSample.js')], + modulePath: [path.join(__dirname, '../../../cucumber-integration-tests/sample_cucumber_tests/integration/testSample.js')] + }); + + assert.ok(cliArgs.includes('--import')); + assert.ok(!cliArgs.includes('--require')); + }); + + it('Cucumber options enable esm support', function(){ + const runner = new CucumberRunner({ + test_runner: { + type: 'cucumber', + options: { + enable_esm: true + } + } + }, {}, {}); + + const testModulePath = path.join(__dirname, '../../../cucumber-integration-tests/sample_cucumber_tests/integration/testSample.js'); + + runner.createTestSuite({ + modules: [testModulePath], + modulePath: [testModulePath] + }); + + assert.ok(cliArgs.includes('--import')); + assert.ok(!cliArgs.includes('--require')); + }); }); From 0088762e1de30c45fadcc35aab96836ae6cecaa5 Mon Sep 17 00:00:00 2001 From: Priyansh Garg <39924567+garg3133@users.noreply.github.com> Date: Wed, 19 Jul 2023 00:15:27 +0530 Subject: [PATCH 02/38] Fix sync tests getting skipped in parallel mode. (#3791) --- lib/reporter/index.js | 5 +- lib/runner/concurrency/worker-task.js | 8 +++ lib/testsuite/index.js | 20 ++++---- .../testUsingES6AsyncCustomCommands.js | 11 +++++ test/extra/commands/other/otherCommand.js | 6 +-- .../extra/parallelism-customCommandsSync.json | 20 ++++++++ .../custom-commands/testCustomCommandSync.js | 49 +++++++++++++++++++ 7 files changed, 104 insertions(+), 15 deletions(-) create mode 100644 test/apidemos/custom-commands-parallel/testUsingES6AsyncCustomCommands.js create mode 100644 test/extra/parallelism-customCommandsSync.json create mode 100644 test/src/apidemos/custom-commands/testCustomCommandSync.js diff --git a/lib/reporter/index.js b/lib/reporter/index.js index 5ae14d97b9..3411961e63 100644 --- a/lib/reporter/index.js +++ b/lib/reporter/index.js @@ -195,10 +195,11 @@ class Reporter extends SimplifiedReporter { result.status === -1 ); - // Use only necessary values + // Use only necessary values if (result) { const {status, message, showDiff, name, abortOnFailure, stack, beautifiedStack} = result; - commandResult ={ + + commandResult = { status, message, showDiff, diff --git a/lib/runner/concurrency/worker-task.js b/lib/runner/concurrency/worker-task.js index 427a99c641..9041b91b84 100644 --- a/lib/runner/concurrency/worker-task.js +++ b/lib/runner/concurrency/worker-task.js @@ -2,6 +2,7 @@ const boxen = require('boxen'); const {MessageChannel} = require('worker_threads'); const {Logger, symbols} = require('../../utils'); const EventEmitter = require('events'); +const {SafeJSON, isString} = require('../../utils'); let prevIndex = 0; @@ -72,6 +73,13 @@ class WorkerTask extends EventEmitter { const {port1, port2} = new MessageChannel(); port2.onmessage = ({data: result}) => { + if (isString(result)) { + try { + result = JSON.parse(result); + // eslint-disable-next-line no-empty + } catch (e) {} + } + switch (result.type) { case 'testsuite_finished': result.itemKey = this.label, diff --git a/lib/testsuite/index.js b/lib/testsuite/index.js index 20d119d4b2..e8e7c85a65 100644 --- a/lib/testsuite/index.js +++ b/lib/testsuite/index.js @@ -58,13 +58,13 @@ class TestSuite { } get skipTestcasesOnFail() { - let localDefinedValue = this.context.getSkipTestcasesOnFail(); + const localDefinedValue = this.context.getSkipTestcasesOnFail(); if (localDefinedValue !== undefined) { return localDefinedValue; } - let settingsValueUndefined = this.settings.skip_testcases_on_fail === undefined; + const settingsValueUndefined = this.settings.skip_testcases_on_fail === undefined; if (settingsValueUndefined && this.context.unitTestingMode) { // false by default when running unit tests return false; @@ -75,7 +75,7 @@ class TestSuite { } get endSessionOnFail() { - let definedValue = this.context.getEndSessionOnFail(); + const definedValue = this.context.getEndSessionOnFail(); return definedValue === undefined ? this.settings.end_session_on_fail : definedValue; } @@ -399,10 +399,10 @@ class TestSuite { return this; } - let capabilities = data.capabilities || {}; - let browserName = (capabilities.browserName && capabilities.browserName.toUpperCase()) || ''; - let browserVersion = capabilities.version || capabilities.browserVersion || ''; - let platformVersion = capabilities.platform || capabilities.platformVersion || ''; + const capabilities = data.capabilities || {}; + const browserName = (capabilities.browserName && capabilities.browserName.toUpperCase()) || ''; + const browserVersion = capabilities.version || capabilities.browserVersion || ''; + const platformVersion = capabilities.platform || capabilities.platformVersion || ''; if (!this.context.unitTestingMode) { this.settings.report_prefix = this.__reportPrefix = `${browserName}_${browserVersion}_${platformVersion}_`.replace(/ /g, '_'); @@ -637,7 +637,7 @@ class TestSuite { return this.retrySuite(); } - let failures = errorOrFailures || failedResult || !this.reporter.allTestsPassed; + const failures = errorOrFailures || failedResult || !this.reporter.allTestsPassed; return this.stopSession(failures); }); @@ -668,11 +668,11 @@ class TestSuite { httpOutput: Logger.collectOutput() })); } else if (process.port && typeof process.port.postMessage === 'function') { - process.port.postMessage({ + process.port.postMessage(SafeJSON.stringify({ type: 'testsuite_finished', results: this.reporter.exportResults(), httpOutput: Logger.collectOutput() - }); + })); } } diff --git a/test/apidemos/custom-commands-parallel/testUsingES6AsyncCustomCommands.js b/test/apidemos/custom-commands-parallel/testUsingES6AsyncCustomCommands.js new file mode 100644 index 0000000000..3b60eefe69 --- /dev/null +++ b/test/apidemos/custom-commands-parallel/testUsingES6AsyncCustomCommands.js @@ -0,0 +1,11 @@ +describe('Test Using Sync Custom Command returning NightwatchAPI', function() { + before(browser => { + browser.url('http://localhost'); + }); + + it('sampleTest', browser => { + browser + .otherCommand() + .end(); + }); +}); diff --git a/test/extra/commands/other/otherCommand.js b/test/extra/commands/other/otherCommand.js index 1de68f562d..b49cef30e4 100644 --- a/test/extra/commands/other/otherCommand.js +++ b/test/extra/commands/other/otherCommand.js @@ -1,5 +1,5 @@ -module.exports = { - command: function() { - return this; +module.exports = class OtherCommand { + command() { + return this.api.pause(10); } }; diff --git a/test/extra/parallelism-customCommandsSync.json b/test/extra/parallelism-customCommandsSync.json new file mode 100644 index 0000000000..a80ae994a8 --- /dev/null +++ b/test/extra/parallelism-customCommandsSync.json @@ -0,0 +1,20 @@ +{ + "src_folders" : ["./test/apidemos/custom-commands-parallel"], + "test_workers": true, + "custom_commands_path": ["./test/extra/commands/other"], + "persist_globals": true, + "output_folder" : false, + "output" : false, + "silent": false, + "selenium" : { + "start_process" : false, + "port": 10195 + }, + "test_settings": { + "default" : { + "desiredCapabilities" : { + "browserName" : "firefox" + } + } + } +} diff --git a/test/src/apidemos/custom-commands/testCustomCommandSync.js b/test/src/apidemos/custom-commands/testCustomCommandSync.js new file mode 100644 index 0000000000..2b2208ff06 --- /dev/null +++ b/test/src/apidemos/custom-commands/testCustomCommandSync.js @@ -0,0 +1,49 @@ +const path = require('path'); +const assert = require('assert'); +const MockServer = require('../../../lib/mockserver.js'); +const Mocks = require('../../../lib/command-mocks.js'); +const common = require('../../../common.js'); +const {settings} = common; +const NightwatchClient = common.require('index.js'); + +describe('sync custom commands', function() { + beforeEach(function(done) { + this.server = MockServer.init(); + this.server.on('listening', () => { + done(); + }); + }); + + afterEach(function(done) { + this.server.close(function() { + done(); + }); + }); + + it('test sync custom command returning NightwatchAPI as result', function() { + const testsPath = path.join(__dirname, '../../../apidemos/custom-commands-parallel'); + Mocks.createNewW3CSession({ + testName: 'Test Sync Custom Commands returning NightwatchAPI' + }); + + const globals = { + waitForConditionPollInterval: 50, + waitForConditionTimeout: 120, + retryAssertionTimeout: 1000, + + reporter(results) { + assert.strictEqual(Object.keys(results.modules).length, 1); + if (results.lastError) { + throw results.lastError; + } + } + }; + + return NightwatchClient.runTests({ + env: 'default', + config: 'test/extra/parallelism-customCommandsSync.json' + }, Object.assign({}, { + globals + })); + }); +}); From f7999e807cd1130d115a4f1a8c13e85467508881 Mon Sep 17 00:00:00 2001 From: Priyansh <88396544+itsspriyansh@users.noreply.github.com> Date: Wed, 19 Jul 2023 15:18:37 +0530 Subject: [PATCH 03/38] npm un -D coveralls (#3816) --- package-lock.json | 637 ---------------------------------------------- package.json | 1 - 2 files changed, 638 deletions(-) diff --git a/package-lock.json b/package-lock.json index d537ba94be..7dfa461638 100644 --- a/package-lock.json +++ b/package-lock.json @@ -56,7 +56,6 @@ "@swc/core": "^1.3.67", "@types/node": "^18.11.7", "copyfiles": "^2.4.1", - "coveralls": "^3.1.1", "eslint": "^8.9.0", "husky": "^8.0.0", "is-ci": "^3.0.1", @@ -1747,15 +1746,6 @@ "node": ">=0.10.0" } }, - "node_modules/asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dev": true, - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, "node_modules/assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", @@ -1823,21 +1813,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", - "dev": true - }, "node_modules/axe-core": { "version": "4.7.2", "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.2.tgz", @@ -1870,15 +1845,6 @@ } ] }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "dev": true, - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -2116,12 +2082,6 @@ "upper-case-first": "^2.0.2" } }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "dev": true - }, "node_modules/chai-nightwatch": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/chai-nightwatch/-/chai-nightwatch-0.5.3.tgz", @@ -2536,25 +2496,6 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" }, - "node_modules/coveralls": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.1.1.tgz", - "integrity": "sha512-+dxnG2NHncSD1NrqbSM3dn/lE57O6Qf/koe9+I7c+wzkqRmEvcp0kgJdxKInzYzkICKkFMZsX3Vct3++tsF9ww==", - "dev": true, - "dependencies": { - "js-yaml": "^3.13.1", - "lcov-parse": "^1.0.0", - "log-driver": "^1.2.7", - "minimist": "^1.2.5", - "request": "^2.88.2" - }, - "bin": { - "coveralls": "bin/coveralls.js" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/crc-32": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", @@ -2618,18 +2559,6 @@ "node": ">=14" } }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/data-urls": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz", @@ -2898,16 +2827,6 @@ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "dev": true, - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, "node_modules/ejs": { "version": "3.1.8", "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.8.tgz", @@ -3319,12 +3238,6 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, "node_modules/extsprintf": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz", @@ -3549,29 +3462,6 @@ "node": ">=8.0.0" } }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, "node_modules/fromentries": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", @@ -3712,15 +3602,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - } - }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -3834,29 +3715,6 @@ "node": ">=4.x" } }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "deprecated": "this library is no longer supported", - "dev": true, - "dependencies": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/hard-rejection": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", @@ -4040,21 +3898,6 @@ "node": ">= 6" } }, - "node_modules/http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - }, - "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" - } - }, "node_modules/https-proxy-agent": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", @@ -4634,12 +4477,6 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, - "node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", - "dev": true - }, "node_modules/istanbul-lib-coverage": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", @@ -4816,12 +4653,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "dev": true - }, "node_modules/jsdom": { "version": "21.1.2", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-21.1.2.tgz", @@ -4919,12 +4750,6 @@ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true - }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -4966,44 +4791,6 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "dev": true, - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/jsprim/node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", - "dev": true, - "engines": [ - "node >=0.6.0" - ] - }, - "node_modules/jsprim/node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, "node_modules/jszip": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", @@ -5088,15 +4875,6 @@ "safe-buffer": "~5.1.0" } }, - "node_modules/lcov-parse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-1.0.0.tgz", - "integrity": "sha512-aprLII/vPzuQvYZnDRU78Fns9I2Ag3gi4Ipga/hxnVMCZC8DnR2nI7XBqrPoywGfxqIx/DgarGvDJZAD3YBTgQ==", - "dev": true, - "bin": { - "lcov-parse": "bin/cli.js" - } - }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -5560,15 +5338,6 @@ "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==" }, - "node_modules/log-driver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz", - "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==", - "dev": true, - "engines": { - "node": ">=0.8.6" - } - }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -6678,15 +6447,6 @@ "node": ">=6" } }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -7041,12 +6801,6 @@ "node": "*" } }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "dev": true - }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -7259,15 +7013,6 @@ "node": ">=6" } }, - "node_modules/qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, "node_modules/querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", @@ -7627,48 +7372,6 @@ "node": ">=0.10" } }, - "node_modules/request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", - "dev": true, - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/request/node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "dev": true, - "bin": { - "uuid": "bin/uuid" - } - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -8345,31 +8048,6 @@ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, - "node_modules/sshpk": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", - "dev": true, - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/stackframe": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", @@ -8696,19 +8374,6 @@ "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==", "dev": true }, - "node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/tr46": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", @@ -8808,24 +8473,6 @@ "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", "dev": true }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -10718,15 +10365,6 @@ "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", "dev": true }, - "asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dev": true, - "requires": { - "safer-buffer": "~2.1.0" - } - }, "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", @@ -10778,18 +10416,6 @@ "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", - "dev": true - }, - "aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", - "dev": true - }, "axe-core": { "version": "4.7.2", "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.2.tgz", @@ -10805,15 +10431,6 @@ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "dev": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -10973,12 +10590,6 @@ "upper-case-first": "^2.0.2" } }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "dev": true - }, "chai-nightwatch": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/chai-nightwatch/-/chai-nightwatch-0.5.3.tgz", @@ -11283,19 +10894,6 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" }, - "coveralls": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.1.1.tgz", - "integrity": "sha512-+dxnG2NHncSD1NrqbSM3dn/lE57O6Qf/koe9+I7c+wzkqRmEvcp0kgJdxKInzYzkICKkFMZsX3Vct3++tsF9ww==", - "dev": true, - "requires": { - "js-yaml": "^3.13.1", - "lcov-parse": "^1.0.0", - "log-driver": "^1.2.7", - "minimist": "^1.2.5", - "request": "^2.88.2" - } - }, "crc-32": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", @@ -11341,15 +10939,6 @@ "rrweb-cssom": "^0.6.0" } }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, "data-urls": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz", @@ -11548,16 +11137,6 @@ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "dev": true, - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, "ejs": { "version": "3.1.8", "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.8.tgz", @@ -11866,12 +11445,6 @@ "strip-final-newline": "^2.0.0" } }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, "extsprintf": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz", @@ -12044,23 +11617,6 @@ "signal-exit": "^3.0.2" } }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", - "dev": true - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, "fromentries": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", @@ -12153,15 +11709,6 @@ "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, "glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -12241,22 +11788,6 @@ "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==" }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", - "dev": true - }, - "har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "dev": true, - "requires": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - } - }, "hard-rejection": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", @@ -12390,17 +11921,6 @@ "debug": "4" } }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, "https-proxy-agent": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", @@ -12782,12 +12302,6 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", - "dev": true - }, "istanbul-lib-coverage": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", @@ -12927,12 +12441,6 @@ "esprima": "^4.0.0" } }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "dev": true - }, "jsdom": { "version": "21.1.2", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-21.1.2.tgz", @@ -13006,12 +12514,6 @@ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, - "json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true - }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -13045,37 +12547,6 @@ "universalify": "^2.0.0" } }, - "jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - }, - "dependencies": { - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", - "dev": true - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - } - } - }, "jszip": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", @@ -13158,12 +12629,6 @@ } } }, - "lcov-parse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-1.0.0.tgz", - "integrity": "sha512-aprLII/vPzuQvYZnDRU78Fns9I2Ag3gi4Ipga/hxnVMCZC8DnR2nI7XBqrPoywGfxqIx/DgarGvDJZAD3YBTgQ==", - "dev": true - }, "levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -13530,12 +12995,6 @@ "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==" }, - "log-driver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz", - "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==", - "dev": true - }, "log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -14433,12 +13892,6 @@ } } }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true - }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -14686,12 +14139,6 @@ "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==" }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "dev": true - }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -14852,12 +14299,6 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==" }, - "qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", - "dev": true - }, "querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", @@ -15136,42 +14577,6 @@ "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", "dev": true }, - "request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "dev": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "dev": true - } - } - }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -15670,23 +15075,6 @@ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, - "sshpk": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", - "dev": true, - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, "stackframe": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", @@ -15942,16 +15330,6 @@ "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==", "dev": true }, - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - }, "tr46": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", @@ -16016,21 +15394,6 @@ "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", "dev": true }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true - }, "type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/package.json b/package.json index af948c51de..c7bcf81870 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,6 @@ "@swc/core": "^1.3.67", "@types/node": "^18.11.7", "copyfiles": "^2.4.1", - "coveralls": "^3.1.1", "eslint": "^8.9.0", "husky": "^8.0.0", "is-ci": "^3.0.1", From 54e1e3e40b3721e3951c51ff4eb36ee725731bfa Mon Sep 17 00:00:00 2001 From: Binayak Ghosh Date: Wed, 19 Jul 2023 15:29:45 +0530 Subject: [PATCH 04/38] Feature/disable process listener for programattic api (#3800) * disable programattic api for process listners * refactor and add tests --- lib/index.js | 4 +- lib/runner/cli/cli.js | 9 +++- test/src/index/testProgrammaticApis.js | 70 ++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 3 deletions(-) diff --git a/lib/index.js b/lib/index.js index 27d78e7349..7bc09bbf68 100644 --- a/lib/index.js +++ b/lib/index.js @@ -43,6 +43,7 @@ module.exports.createClient = function({ debug = false, enable_global_apis = false, config = './nightwatch.json', + disable_process_listener = false, test_settings } = {}) { if (browserName && !env) { @@ -73,7 +74,8 @@ module.exports.createClient = function({ timeout, devtools, debug, - parallel + parallel, + disable_process_listener }); const settings = arguments[0] || {}; diff --git a/lib/runner/cli/cli.js b/lib/runner/cli/cli.js index 0048f4f279..bc42fffc46 100644 --- a/lib/runner/cli/cli.js +++ b/lib/runner/cli/cli.js @@ -109,7 +109,10 @@ class CliRunner { this.globals = null; this.testEnv = null; this.testEnvArray = []; - this.processListener = new ProcessListener(); + + if (!argv.disable_process_listener) { + this.processListener = new ProcessListener(); + } } initTestSettings(userSettings = {}, baseSettings = null, argv = null, testEnv = '', asyncLoading) { @@ -452,7 +455,9 @@ class CliRunner { globalsInstance: this.globals }); - this.processListener.setTestRunner(this.testRunner); + if (this.processListener) { + this.processListener.setTestRunner(this.testRunner); + } return this; } diff --git a/test/src/index/testProgrammaticApis.js b/test/src/index/testProgrammaticApis.js index 27b2307e38..f281e54be9 100644 --- a/test/src/index/testProgrammaticApis.js +++ b/test/src/index/testProgrammaticApis.js @@ -570,4 +570,74 @@ describe('test programmatic apis', function () { CliRunner.createDefaultConfig = createDefaultConfig; CliRunner.prototype.loadConfig = loadConfig; }); + + it('test if process listener get disabled', async function() { + let processListenerCalled = false; + mockery.enable({useCleanCache: true, warnOnUnregistered: false}); + mockery.registerMock('../process-listener.js', class { + constructor() { + processListenerCalled = true; + } + + setTestRunner() {} + }); + + const CliRunner = common.require('runner/cli/cli.js'); + const Nightwatch = common.require('index.js'); + + const createDefaultConfig = CliRunner.createDefaultConfig; + const loadConfig = CliRunner.prototype.loadConfig; + const defaultConfig = { + test_settings: { + default: { + launchUrl: 'http://localhost' + } + }, + selenium: { + port: 10195, + start_process: false + }, + selenium_host: 'localhost' + }; + + CliRunner.createDefaultConfig = function(destFileName) { + return defaultConfig; + }; + + CliRunner.prototype.loadConfig = function () { + return defaultConfig; + }; + + const clientWithoutListner = Nightwatch.createClient({ + timeout: 500, + useAsync: false, + output: false, + silent: false, + headless: true, + output_folder: 'output', + globals: { + testGlobal: 'one' + }, + disable_process_listener: true + }); + + assert.ok(!processListenerCalled); + + const client = Nightwatch.createClient({ + timeout: 500, + useAsync: false, + output: false, + silent: false, + headless: true, + output_folder: 'output', + globals: { + testGlobal: 'one' + } + }); + + assert.ok(processListenerCalled); + + CliRunner.createDefaultConfig = createDefaultConfig; + CliRunner.prototype.loadConfig = loadConfig; + }); }); From 3cf114ff8267313d7f4404eb0fc34d120981675b Mon Sep 17 00:00:00 2001 From: Yash Pratap Singh <102533457+yashPratp983@users.noreply.github.com> Date: Wed, 19 Jul 2023 16:58:14 +0530 Subject: [PATCH 05/38] Move network-related commands to .network namespace. (#3797) --- .../captureRequests.js} | 13 +- .../mockResponse.js} | 13 +- .../setConditions.js} | 28 ++- .../client/testCaptureNetworkRequests.js | 67 ++++++ .../client/testMockNetworkResponse.js | 80 +++++++ .../client/testSetNetworkConditions.js | 70 +++++- types/index.d.ts | 196 ++++++++------- types/tests/chromiumClientCommands.test-d.ts | 226 ++++++++++++++++++ 8 files changed, 582 insertions(+), 111 deletions(-) rename lib/api/client-commands/{captureNetworkRequests.js => network/captureRequests.js} (84%) rename lib/api/client-commands/{mockNetworkResponse.js => network/mockResponse.js} (84%) rename lib/api/client-commands/{setNetworkConditions.js => network/setConditions.js} (61%) diff --git a/lib/api/client-commands/captureNetworkRequests.js b/lib/api/client-commands/network/captureRequests.js similarity index 84% rename from lib/api/client-commands/captureNetworkRequests.js rename to lib/api/client-commands/network/captureRequests.js index d71794cdb2..658aab01f2 100644 --- a/lib/api/client-commands/captureNetworkRequests.js +++ b/lib/api/client-commands/network/captureRequests.js @@ -1,5 +1,5 @@ -const ClientCommand = require('./_base-command.js'); -const {Logger} = require('../../utils'); +const ClientCommand = require('../_base-command.js'); +const {Logger} = require('../../../utils'); /** * Capture outgoing network calls from the browser. @@ -9,7 +9,7 @@ const {Logger} = require('../../utils'); * it('captures and logs network requests as they occur', function(this: ExtendDescribeThis<{requestCount: number}>) { * this.requestCount = 1; * browser - * .captureNetworkRequests((requestParams) => { + * .network.captureRequests((requestParams) => { * console.log('Request Number:', this.requestCount!++); * console.log('Request URL:', requestParams.request.url); * console.log('Request method:', requestParams.request.method); @@ -19,8 +19,9 @@ const {Logger} = require('../../utils'); * }); * }); * - * @method captureNetworkRequests + * @method network.captureRequests * @syntax .captureNetworkRequests(onRequestCallback) + * @syntax .network.captureRequests(onRequestCallback) * @param {function} onRequestCallback Callback function called whenever a new outgoing network request is made. * @api protocol.cdp * @since 2.2.0 @@ -28,6 +29,10 @@ const {Logger} = require('../../utils'); */ class CaptureNetworkCalls extends ClientCommand { + static get namespacedAliases() { + return 'captureNetworkRequests'; + } + performAction(callback) { if (!this.api.isChrome() && !this.api.isEdge()) { diff --git a/lib/api/client-commands/mockNetworkResponse.js b/lib/api/client-commands/network/mockResponse.js similarity index 84% rename from lib/api/client-commands/mockNetworkResponse.js rename to lib/api/client-commands/network/mockResponse.js index e564b46a7e..e38bcbd54b 100644 --- a/lib/api/client-commands/mockNetworkResponse.js +++ b/lib/api/client-commands/network/mockResponse.js @@ -1,5 +1,5 @@ -const ClientCommand = require('./_base-command.js'); -const {Logger} = require('../../utils'); +const ClientCommand = require('../_base-command.js'); +const {Logger} = require('../../../utils'); /** * Intercept the request made on a particular URL and mock the response. @@ -8,7 +8,7 @@ const {Logger} = require('../../utils'); * describe('mock network response', function() { * it('intercepts the request made to Google search and mocks its response', function() { * browser - * .mockNetworkResponse('https://www.google.com/', { + * .network.mockResponse('https://www.google.com/', { * status: 200, * headers: { * 'Content-Type': 'UTF-8' @@ -20,8 +20,9 @@ const {Logger} = require('../../utils'); * }); * }); * - * @method mockNetworkResponse + * @method network.mockResponse * @syntax .mockNetworkResponse(urlToIntercept, {status, headers, body}, [callback]) + * @syntax .network.mockResponse(urlToIntercept, {status, headers, body}, [callback]) * @param {string} urlToIntercept URL to intercept and mock the response from. * @param {object} response Response to return. Defaults: `{status: 200, headers: {}, body: ''}`. * @param {function} [callback] Callback function to be called when the command finishes. @@ -31,6 +32,10 @@ const {Logger} = require('../../utils'); */ class MockNetworkResponse extends ClientCommand { + static get namespacedAliases() { + return 'mockNetworkResponse'; + } + performAction(callback) { if (!this.api.isChrome() && !this.api.isEdge()) { diff --git a/lib/api/client-commands/setNetworkConditions.js b/lib/api/client-commands/network/setConditions.js similarity index 61% rename from lib/api/client-commands/setNetworkConditions.js rename to lib/api/client-commands/network/setConditions.js index 6a932c70c7..7d642f4b6e 100644 --- a/lib/api/client-commands/setNetworkConditions.js +++ b/lib/api/client-commands/network/setConditions.js @@ -1,28 +1,36 @@ -const ClientCommand = require('./_base-command.js'); -const {Logger} = require('../../utils'); +const ClientCommand = require('../_base-command.js'); +const {Logger} = require('../../../utils'); /** * * Command to set Chrome network emulation settings. * * @example - * this.demoTest = function (browser) { - * browser.setNetworkConditions({ + * describe('set network conditions', function() { + * it('sets the network conditions',function() { + * browser + * .network.setConditions({ * offline: false, - * latency: 50000, - * download_throughput: 450 * 1024, - * upload_throughput: 150 * 1024 + * latency: 3000, + * download_throughput: 500 * 1024, + * upload_throughput: 500 * 1024 * }); - * }; + * }); + * }); * - * - * @method setNetworkConditions + * @method network.setConditions * @syntax .setNetworkConditions(spec, [callback]) + * @syntax .network.setConditions(spec, [callback]) * @param {object} spec * @param {function} [callback] Optional callback function to be called when the command finishes. * @api protocol.sessions */ class SetNetworkConditions extends ClientCommand { + + static get namespacedAliases() { + return 'setNetworkConditions'; + } + performAction(callback) { if (!this.api.isChrome() && !this.api.isEdge()) { const error = new Error('SetNetworkConditions is not supported while using this driver'); diff --git a/test/src/api/commands/client/testCaptureNetworkRequests.js b/test/src/api/commands/client/testCaptureNetworkRequests.js index 90920f1f63..fea08563b2 100644 --- a/test/src/api/commands/client/testCaptureNetworkRequests.js +++ b/test/src/api/commands/client/testCaptureNetworkRequests.js @@ -85,6 +85,73 @@ describe('.captureNetworkRequests()', function () { }); }); + it('browser.network.captureRequests()', function (done) { + + MockServer.addMock({ + url: '/session', + response: { + value: { + sessionId: '13521-10219-202', + capabilities: { + browserName: 'chrome', + browserVersion: '92.0' + } + } + }, + method: 'POST', + statusCode: 201 + }, true); + + Nightwatch.initW3CClient({ + desiredCapabilities: { + browserName: 'chrome', + 'goog:chromeOptions': {} + }, + output: process.env.VERBOSE === '1', + silent: false + }).then(client => { + const expected = {}; + + const cdpNetworkEvent = JSON.stringify({ + method: 'Network.requestWillBeSent', + params: { + request: { + url: 'https://www.google.com', + method: 'GET', + headers: [] + } + } + }); + + cdp.resetConnection(); + client.transport.driver.createCDPConnection = function() { + return Promise.resolve({ + _wsConnection: { + on: (event, callback) => { + expected['wsEvent'] = event; + callback(cdpNetworkEvent); + } + }, + execute: function(command, params) { + expected['cdpCommand'] = command; + expected['cdpParams'] = params; + } + }); + }; + + const userCallback = (requestParams) => { + expected['requestParams'] = requestParams; + }; + client.api.network.captureRequests(userCallback, function () { + assert.deepEqual(expected.cdpCommand, 'Network.enable'); + assert.deepEqual(expected.cdpParams, {}); + assert.strictEqual(expected.wsEvent, 'message'); + assert.deepEqual(expected.requestParams, JSON.parse(cdpNetworkEvent).params); + }); + client.start(done); + }); + }); + it('throws error without callback', function (done) { MockServer.addMock({ diff --git a/test/src/api/commands/client/testMockNetworkResponse.js b/test/src/api/commands/client/testMockNetworkResponse.js index 3d9f812edb..c5cf2b8c97 100644 --- a/test/src/api/commands/client/testMockNetworkResponse.js +++ b/test/src/api/commands/client/testMockNetworkResponse.js @@ -98,6 +98,86 @@ describe('.mockNetworkResponse()', function () { }); }); + it('browser.network.mockResponse(urlToIntercept, {status, headers, body}) with url match', function (done) { + MockServer.addMock({ + url: '/session', + response: { + value: { + sessionId: '13521-10219-202', + capabilities: { + browserName: 'chrome', + browserVersion: '92.0' + } + } + }, + method: 'POST', + statusCode: 201 + }, true); + + Nightwatch.initW3CClient({ + desiredCapabilities: { + browserName: 'chrome', + 'goog:chromeOptions': {} + }, + output: process.env.VERBOSE === '1', + silent: false + }).then(client => { + const expected = { + cdpCommands: [] + }; + + // Parameters of actual request made by browser + const cdpFetchRequestPauseEvent = JSON.stringify({ + method: 'Fetch.requestPaused', + params: { + requestId: '123', + request: { + url: 'https://www.google.com/' + } + } + }); + + cdp.resetConnection(); + client.transport.driver.createCDPConnection = function() { + return Promise.resolve({ + _wsConnection: { + on: (event, callback) => { + expected['wsEvent'] = event; + callback(cdpFetchRequestPauseEvent); + } + }, + execute: function(command, params) { + expected.cdpCommands.push(command); + if (command === 'Fetch.fulfillRequest') { + expected['requestId'] = params.requestId; + expected['responseCode'] = params.responseCode; + expected['responseHeaders'] = params.responseHeaders; + expected['responseBody'] = params.body; + } + } + }); + }; + + const response = { + status: 200, + headers: {'Content-Type': 'UTF-8'}, + body: 'Hey there!' + }; + client.api.network.mockResponse('https://www.google.com/', response, function () { + // Assert final response with response passed + assert.strictEqual(expected.responseCode, response.status); + assert.deepEqual(expected.responseHeaders, [{name: 'Content-Type', value: 'UTF-8'}]); + assert.strictEqual(expected.responseBody, Buffer.from(response.body, 'utf-8').toString('base64')); + + assert.strictEqual(expected.requestId, JSON.parse(cdpFetchRequestPauseEvent).params.requestId); + assert.strictEqual(expected.wsEvent, 'message'); + assert.deepEqual(expected.cdpCommands, ['Fetch.fulfillRequest', 'Fetch.enable', 'Network.setCacheDisabled']); + }); + + client.start(done); + }); + }); + it('browser.mockNetworkResponse(urlToIntercept, {status, headers, body}) with multiple mocks', function (done) { MockServer.addMock({ url: '/session', diff --git a/test/src/api/commands/client/testSetNetworkConditions.js b/test/src/api/commands/client/testSetNetworkConditions.js index 9087db3531..e05b6f1708 100644 --- a/test/src/api/commands/client/testSetNetworkConditions.js +++ b/test/src/api/commands/client/testSetNetworkConditions.js @@ -5,7 +5,11 @@ const Nightwatch = require('../../../../lib/nightwatch.js'); describe('.setNetworkConditions()', function () { beforeEach(function (done) { - CommandGlobals.beforeEach.call(this, done); + this.server = MockServer.init(); + + this.server.on('listening', () => { + done(); + }); }); afterEach(function (done) { @@ -59,6 +63,70 @@ describe('.setNetworkConditions()', function () { }); }); + + it('browser.network.setConditions()', function (done) { + MockServer.addMock( + { + url: '/session', + response: { + value: { + sessionId: '13521-10219-202', + capabilities: { + browserName: 'chrome', + browserVersion: '92.0' + } + } + }, + method: 'POST', + statusCode: 201 + }, + true + ); + + Nightwatch.initW3CClient({ + desiredCapabilities: { + browserName: 'chrome', + 'goog:chromeOptions': {} + }, + output: process.env.VERBOSE === '1', + silent: false + }).then((client) => { + const expected = {}; + client.transport.driver.setNetworkConditions = function (spec) { + expected['download_throughput'] = spec.download_throughput; + expected['latency'] = spec.latency; + expected['offline'] = spec.offline; + expected['upload_throughput'] = spec.upload_throughput; + + return Promise.resolve(); + }; + + client.api.network.setConditions({ + offline: false, + latency: 50000, + download_throughput: 450 * 1024, + upload_throughput: 150 * 1024 + }, + function (result) { + expected['callback_result'] = result.value; + }); + + client.start(function (err) { + try { + assert.strictEqual(err, undefined); + assert.strictEqual(expected.callback_result, null); + assert.strictEqual(expected.download_throughput, 460800); + assert.strictEqual(expected.latency, 50000); + assert.strictEqual(expected.offline, false); + assert.strictEqual(expected.upload_throughput, 153600); + done(); + } catch (e){ + done(e); + } + }); + }); + }); + it('browser.setNetworkConditions - driver not supported', function (done) { Nightwatch.initW3CClient({ desiredCapabilities: { diff --git a/types/index.d.ts b/types/index.d.ts index 3c8286b92b..42b7d9a7a6 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -516,6 +516,7 @@ export interface NamespacedApi { document: DocumentNsCommands; window: WindowNsCommands; firefox: FirefoxNsCommands; + network: NetworkNsCommands; assert: Assert; verify: Assert; @@ -1383,70 +1384,6 @@ export interface ChromiumClientCommands { ) => void ): Awaitable; - /** - * Capture outgoing network calls from the browser. - * - * @example - * describe('capture network requests', function() { - * it('captures and logs network requests as they occur', function(this: ExtendDescribeThis<{requestCount: number}>) { - * this.requestCount = 1; - * browser - * .captureNetworkRequests((requestParams) => { - * console.log('Request Number:', this.requestCount!++); - * console.log('Request URL:', requestParams.request.url); - * console.log('Request method:', requestParams.request.method); - * console.log('Request headers:', requestParams.request.headers); - * }) - * .navigateTo('https://www.google.com'); - * }); - * }); - * - * @see https://nightwatchjs.org/guide/network-requests/capture-network-calls.html - */ - captureNetworkRequests( - onRequestCallback: ( - requestParams: Protocol.Network.RequestWillBeSentEvent - ) => void, - callback?: ( - this: NightwatchAPI, - result: NightwatchCallbackResult - ) => void - ): Awaitable; - - /** - * Intercept the request made on a particular URL and mock the response. - * - * @example - * describe('mock network response', function() { - * it('intercepts the request made to Google search and mocks its response', function() { - * browser - * .mockNetworkResponse('https://www.google.com/', { - * status: 200, - * headers: { - * 'Content-Type': 'UTF-8' - * }, - * body: 'Hello there!' - * }) - * .navigateTo('https://www.google.com/') - * .pause(2000); - * }); - * }); - * - * @see https://nightwatchjs.org/guide/network-requests/mock-network-response.html - */ - mockNetworkResponse( - urlToIntercept: string, - response?: { - status?: Protocol.Fetch.FulfillRequestRequest['responseCode']; - headers?: { [name: string]: string }; - body?: Protocol.Fetch.FulfillRequestRequest['body']; - }, - callback?: ( - this: NightwatchAPI, - result: NightwatchCallbackResult - ) => void - ): Awaitable; - /** * Override device mode/dimensions. * @@ -1576,6 +1513,12 @@ export interface ChromiumClientCommands { ) => void ): Awaitable; + captureNetworkRequests: NetworkNsCommands['captureRequests']; + + mockNetworkResponse: NetworkNsCommands['mockResponse']; + + setNetworkConditions: NetworkNsCommands['setConditions']; + /** * Listen to the `console` events (ex. `console.log` event) and * register callback to process the same. @@ -5214,6 +5157,103 @@ export interface FirefoxNsCommands { uninstallAddon(addonId: string | PromiseLike): Awaitable, null>; } +export interface NetworkNsCommands { + /** + * Capture outgoing network calls from the browser. + * + * @example + * describe('capture network requests', function() { + * it('captures and logs network requests as they occur', function(this: ExtendDescribeThis<{requestCount: number}>) { + * this.requestCount = 1; + * browser + * .network.captureRequests((requestParams) => { + * console.log('Request Number:', this.requestCount!++); + * console.log('Request URL:', requestParams.request.url); + * console.log('Request method:', requestParams.request.method); + * console.log('Request headers:', requestParams.request.headers); + * }) + * .navigateTo('https://www.google.com'); + * }); + * }); + * + * @see https://nightwatchjs.org/guide/network-requests/capture-network-calls.html + */ + captureRequests( + onRequestCallback: ( + requestParams: Protocol.Network.RequestWillBeSentEvent + ) => void, + callback?: ( + this: NightwatchAPI, + result: NightwatchCallbackResult + ) => void + ): Awaitable, null>; + + /** + * Intercept the request made on a particular URL and mock the response. + * + * @example + * describe('mock network response', function() { + * it('intercepts the request made to Google search and mocks its response', function() { + * browser + * .network.mockResponse('https://www.google.com/', { + * status: 200, + * headers: { + * 'Content-Type': 'UTF-8' + * }, + * body: 'Hello there!' + * }) + * .navigateTo('https://www.google.com/') + * .pause(2000); + * }); + * }); + * + * @see https://nightwatchjs.org/guide/network-requests/mock-network-response.html + */ + mockResponse( + urlToIntercept: string, + response?: { + status?: Protocol.Fetch.FulfillRequestRequest['responseCode']; + headers?: { [name: string]: string }; + body?: Protocol.Fetch.FulfillRequestRequest['body']; + }, + callback?: ( + this: NightwatchAPI, + result: NightwatchCallbackResult + ) => void + ): Awaitable, null>; + + /** + * Command to set Chrome network emulation settings. + * + * @example + * describe('set network conditions', function() { + * it('sets the network conditions',function() { + * browser + * .network.setConditions({ + * offline: false, + * latency: 3000, + * download_throughput: 500 * 1024, + * upload_throughput: 500 * 1024 + * }); + * }); + * }); + * + * @see https://nightwatchjs.org/api/setNetworkConditions.html + */ + setConditions( + spec: { + offline: boolean; + latency: number; + download_throughput: number; + upload_throughput: number; + }, + callback?: ( + this: NightwatchAPI, + result: NightwatchCallbackResult + ) => void + ): Awaitable, null>; +} + export interface AlertsNsCommands { /** * Accepts the currently displayed alert dialog. Usually, this is equivalent to clicking on the 'OK' button in the dialog. @@ -6040,34 +6080,6 @@ export interface WebDriverProtocolSessions { result: NightwatchCallbackResult ) => void ): Awaitable; - - /** - * Command to set Chrome network emulation settings. - * - * @example - * this.demoTest = function() { - * browser.setNetworkConditions({ - * offline: false, - * latency: 50000, - * download_throughput: 450 * 1024, - * upload_throughput: 150 * 1024 - * }); - * }; - * - * @see https://nightwatchjs.org/api/setNetworkConditions.html - */ - setNetworkConditions( - spec: { - offline: boolean; - latency: number; - download_throughput: number; - upload_throughput: number; - }, - callback?: ( - this: NightwatchAPI, - result: NightwatchCallbackResult - ) => void - ): Awaitable; } export interface WebDriverProtocolNavigation { diff --git a/types/tests/chromiumClientCommands.test-d.ts b/types/tests/chromiumClientCommands.test-d.ts index 6feb7641bc..a0ec87531f 100644 --- a/types/tests/chromiumClientCommands.test-d.ts +++ b/types/tests/chromiumClientCommands.test-d.ts @@ -97,6 +97,41 @@ describe('capture network requests', function () { expectType(result); }); + + it('captures and logs network requests as they occur', function (this: ExtendDescribeThis<{ requestCount: number }>) { + this.requestCount = 1; + browser + .network.captureRequests((requestParams) => { + console.log('Request Number:', this.requestCount!++); + console.log('Request URL:', requestParams.request.url); + console.log('Request method:', requestParams.request.method); + console.log('Request headers:', requestParams.request.headers); + }) + .navigateTo('https://www.google.com'); + }); + + it('tests different ways of using captureRequests', () => { + // with all parameters + browser.network.captureRequests( + (requestParams) => { + console.log('Request URL:', requestParams.request.url); + console.log('Request method:', requestParams.request.method); + console.log('Request headers:', requestParams.request.headers); + }, + function (result) { + expectType(this); + // without any parameter + expectError(this.network.captureRequests()) + console.log(result.value); + } + ); + }); + + it('tests captureRequests with async', async () => { + const result = await browser.network.captureRequests(() => {}); + + expectType(result); + }); }); // @@ -152,6 +187,197 @@ describe('mock network response', function () { expectType(result); }); + + it('intercepts the request made to Google search and mocks its response', function () { + browser + .network.mockResponse('https://www.google.com/', { + status: 200, + headers: { + 'Content-Type': 'UTF-8', + }, + body: 'Hello there!', + }) + .navigateTo('https://www.google.com/') + .pause(2000); + }); + + it('tests different ways of using mockNetworkResponse', () => { + // with all parameters + browser.network.mockResponse( + 'https://www.google.com/', + { + status: 200, + headers: { + 'Content-Type': 'UTF-8', + }, + body: 'Hello there!', + }, + function (result) { + expectType(this); + // without any parameter (invalid) + expectError(this.network.mockResponse()) + console.log(result.value); + } + ); + + // with no response + browser.network.mockResponse('https://www.google.com/'); + + // with empty response + browser.network.mockResponse('https://www.google.com/', {}); + + // with just one parameter + browser.network.mockResponse('https://www.google.com/', { + body: 'Hello there!', + }); + }); + + it('tests mockResponse with async', async () => { + const result = await browser.network.mockResponse('https://www.google.com/'); + + expectType(result); + }); +}); + +// +//.setNetworkConditions +// +describe('set network conditions', function () { + it('sets the network conditions', function () { + browser + .setNetworkConditions({ + offline: false, + latency: 3000, // Additional latency (ms). + download_throughput: 500 * 1024, // Maximal aggregated download throughput. + upload_throughput: 500 * 1024, // Maximal aggregated upload throughput. + }) + .navigateTo('https://www.google.com') + .pause(2000) + }); + + it('tests different ways of using setNetworkConditions', () => { + // with all parameters + browser.setNetworkConditions( + { + offline: false, + latency: 3000, // Additional latency (ms). + download_throughput: 500 * 1024, // Maximal aggregated download throughput. + upload_throughput: 500 * 1024, // Maximal aggregated upload throughput. + }, + function (result) { + expectType(this); + // without any parameter (resets the network conditions) + // without any parameter (invalid) + expectError(this.setNetworkConditions()) + // missing 'offline' parameter + expectError(this.setNetworkConditions({ + latency: 3000, + download_throughput: 500 * 1024, + upload_throughput: 500 * 1024, + })); + // missing 'latency' parameter + expectError(this.setNetworkConditions({ + offline: false, + download_throughput: 500 * 1024, + upload_throughput: 500 * 1024, + })); + // missing 'download_throughput' parameter + expectError(this.setNetworkConditions({ + offline: false, + latency: 3000, + upload_throughput: 500 * 1024, + })); + // missing 'upload_throughput' parameter + expectError(this.setNetworkConditions({ + offline: false, + latency: 3000, + download_throughput: 500 * 1024, + })); + + console.log(result.value); + } + ); + + }); + + it('tests setNetworkConditions with async', async () => { + const result = await browser.setNetworkConditions({ + offline: false, + latency: 3000, // Additional latency (ms). + download_throughput: 500 * 1024, // Maximal aggregated download throughput. + upload_throughput: 500 * 1024, // Maximal aggregated upload throughput. + }); + + expectType(result); + }); + + it('sets the network conditions', function () { + browser + .network.setConditions({ + offline: false, + latency: 3000, // Additional latency (ms). + download_throughput: 500 * 1024, // Maximal aggregated download throughput. + upload_throughput: 500 * 1024, // Maximal aggregated upload throughput. + }) + .navigateTo('https://www.google.com') + .pause(2000) + }); + + it('tests different ways of using setNetworkConditions', () => { + // with all parameters + browser.network.setConditions( + { + offline: false, + latency: 3000, // Additional latency (ms). + download_throughput: 500 * 1024, // Maximal aggregated download throughput. + upload_throughput: 500 * 1024, // Maximal aggregated upload throughput. + }, + function (result) { + expectType(this); + // without any parameter (resets the network conditions) + // without any parameter (invalid) + expectError(this.network.setConditions()) + // missing 'offline' parameter + expectError(this.network.setConditions({ + latency: 3000, + download_throughput: 500 * 1024, + upload_throughput: 500 * 1024, + })); + // missing 'latency' parameter + expectError(this.network.setConditions({ + offline: false, + download_throughput: 500 * 1024, + upload_throughput: 500 * 1024, + })); + // missing 'download_throughput' parameter + expectError(this.network.setConditions({ + offline: false, + latency: 3000, + upload_throughput: 500 * 1024, + })); + // missing 'upload_throughput' parameter + expectError(this.network.setConditions({ + offline: false, + latency: 3000, + download_throughput: 500 * 1024, + })); + + console.log(result.value); + } + ); + + }); + + it('tests setConditions with async', async () => { + const result = await browser.network.setConditions({ + offline: false, + latency: 3000, // Additional latency (ms). + download_throughput: 500 * 1024, // Maximal aggregated download throughput. + upload_throughput: 500 * 1024, // Maximal aggregated upload throughput. + }); + + expectType(result); + }); }); // From 51f2d2d15e2cabf4cff524cc272b106eabb0e5d7 Mon Sep 17 00:00:00 2001 From: Binayak Ghosh Date: Mon, 24 Jul 2023 14:16:30 +0530 Subject: [PATCH 06/38] Add missing documentation (#3826) * add missing documentation * add method names --- lib/api/protocol/forward.js | 1 + lib/api/protocol/frame.js | 1 + lib/api/protocol/frameParent.js | 1 + lib/api/protocol/refresh.js | 1 + lib/api/protocol/screenshot.js | 1 + lib/api/protocol/session.js | 1 + lib/api/protocol/sessions.js | 1 + lib/api/protocol/status.js | 1 + lib/api/protocol/submit.js | 1 + lib/api/protocol/timeouts.js | 1 + lib/api/protocol/timeoutsAsyncScript.js | 1 + lib/api/protocol/timeoutsImplicitWait.js | 1 + lib/api/protocol/url.js | 1 + lib/api/protocol/waitUntil.js | 1 + lib/api/web-element/commands/setValue.js | 29 ++++++++++++++++++++++++ 15 files changed, 43 insertions(+) diff --git a/lib/api/protocol/forward.js b/lib/api/protocol/forward.js index ca22bf4859..facb4c8462 100644 --- a/lib/api/protocol/forward.js +++ b/lib/api/protocol/forward.js @@ -3,6 +3,7 @@ const ProtocolAction = require('./_base-action.js'); /** * Navigate forward in the browser history, if possible (the equivalent of hitting the browser forward button). * + * @method forward * @link /#back * @param {function} [callback] Optional callback function to be called when the command finishes. * @api protocol.navigation diff --git a/lib/api/protocol/frame.js b/lib/api/protocol/frame.js index 85ae2f915d..8c9d78d9b5 100644 --- a/lib/api/protocol/frame.js +++ b/lib/api/protocol/frame.js @@ -21,6 +21,7 @@ const ProtocolAction = require('./_base-action.js'); * }); * } * + * @method frame * @link /#switch-to-frame * @param {string|number|null} [frameId] Identifier for the frame to change focus to. * @param {function} [callback] Optional callback function to be called when the command finishes. diff --git a/lib/api/protocol/frameParent.js b/lib/api/protocol/frameParent.js index a95b9be6f9..ddf85cf3a2 100644 --- a/lib/api/protocol/frameParent.js +++ b/lib/api/protocol/frameParent.js @@ -10,6 +10,7 @@ const ProtocolAction = require('./_base-action.js'); * }); * } * + * @method frameParent * @link /#switch-to-parent-frame * @param {function} [callback] Optional callback function to be called when the command finishes. * @since v0.4.8 diff --git a/lib/api/protocol/refresh.js b/lib/api/protocol/refresh.js index e5a599d0de..e0ff600cb7 100644 --- a/lib/api/protocol/refresh.js +++ b/lib/api/protocol/refresh.js @@ -3,6 +3,7 @@ const ProtocolAction = require('./_base-action.js'); /** * Refresh the current page. * + * @method refresh * @link /#refresh * @param {function} [callback] Optional callback function to be called when the command finishes. * @api protocol.navigation diff --git a/lib/api/protocol/screenshot.js b/lib/api/protocol/screenshot.js index 697e9840f8..6be05ae812 100644 --- a/lib/api/protocol/screenshot.js +++ b/lib/api/protocol/screenshot.js @@ -3,6 +3,7 @@ const ProtocolAction = require('./_base-action.js'); /** * Take a screenshot of the current page. * + * @method screenshot * @link /#take-screenshot * @param {boolean} log_screenshot_data Whether or not the screenshot data should appear in the logs when running with --verbose * @param {function} callback Callback function which is called with the result value. diff --git a/lib/api/protocol/session.js b/lib/api/protocol/session.js index 5f32100b0c..eeac7afdfe 100644 --- a/lib/api/protocol/session.js +++ b/lib/api/protocol/session.js @@ -19,6 +19,7 @@ const ProtocolAction = require('./_base-action.js'); * } * * + * @method session * @link /#new-session * @editline L141 * @syntax .session([action], [sessionId], [callback]) diff --git a/lib/api/protocol/sessions.js b/lib/api/protocol/sessions.js index 83b1bb629b..b548eda4f4 100644 --- a/lib/api/protocol/sessions.js +++ b/lib/api/protocol/sessions.js @@ -10,6 +10,7 @@ const ProtocolAction = require('./_base-action.js'); * }); * } * + * @method sessions * @editline L166 * @section sessions * @syntax .sessions(callback) diff --git a/lib/api/protocol/status.js b/lib/api/protocol/status.js index 58d952b6e9..8d75e9b314 100644 --- a/lib/api/protocol/status.js +++ b/lib/api/protocol/status.js @@ -3,6 +3,7 @@ const ProtocolAction = require('./_base-action.js'); /** * Query the server's current status. * + * @method status * @link /#status * @syntax .status([callback]) * @param {function} callback Callback function which is called with the result value. diff --git a/lib/api/protocol/submit.js b/lib/api/protocol/submit.js index ab2ff0be58..69c8d9706b 100644 --- a/lib/api/protocol/submit.js +++ b/lib/api/protocol/submit.js @@ -3,6 +3,7 @@ const ProtocolAction = require('./_base-action.js'); /** * Submit a FORM element. The submit command may also be applied to any element that is a descendant of a FORM element. * + * @method submit * @param {string} webElementId The [Web Element ID](https://www.w3.org/TR/webdriver1/#dfn-web-elements) of the element to route the command to. * @param {function} [callback] Optional callback function to be called when the command finishes. * @api protocol.elementinternal diff --git a/lib/api/protocol/timeouts.js b/lib/api/protocol/timeouts.js index 4af7b999af..caabdfb453 100644 --- a/lib/api/protocol/timeouts.js +++ b/lib/api/protocol/timeouts.js @@ -17,6 +17,7 @@ const ProtocolAction = require('./_base-action.js'); * }); * } * + * @method timeouts * @link /#set-timeout * @editline L188Í * @syntax .timeouts([callback]) diff --git a/lib/api/protocol/timeoutsAsyncScript.js b/lib/api/protocol/timeoutsAsyncScript.js index 7fbe73d460..a79d00055c 100644 --- a/lib/api/protocol/timeoutsAsyncScript.js +++ b/lib/api/protocol/timeoutsAsyncScript.js @@ -10,6 +10,7 @@ const ProtocolAction = require('./_base-action.js'); * }); * } * + * @method timeoutsAsyncScript * @syntax .timeoutsAsyncScript(ms, [callback]) * @jsonwire * @param {number} ms The amount of time, in milliseconds, that time-limited commands are permitted to run. diff --git a/lib/api/protocol/timeoutsImplicitWait.js b/lib/api/protocol/timeoutsImplicitWait.js index af37b02c97..bd6e015898 100644 --- a/lib/api/protocol/timeoutsImplicitWait.js +++ b/lib/api/protocol/timeoutsImplicitWait.js @@ -10,6 +10,7 @@ const ProtocolAction = require('./_base-action.js'); * }); * } * + * @method timeoutsImplicitWait * @jsonwire * @syntax .timeoutsImplicitWait(ms, [callback]) * @param {number} ms The amount of time, in milliseconds, that time-limited commands are permitted to run. diff --git a/lib/api/protocol/url.js b/lib/api/protocol/url.js index bcee9b7e48..88dbe1baa3 100644 --- a/lib/api/protocol/url.js +++ b/lib/api/protocol/url.js @@ -22,6 +22,7 @@ const ora = require('ora'); * } * } * + * @method url * @link /#navigate-to * @syntax .url([url], [callback]) * @syntax .url(callback) diff --git a/lib/api/protocol/waitUntil.js b/lib/api/protocol/waitUntil.js index 3af89b24a4..97f84bd972 100644 --- a/lib/api/protocol/waitUntil.js +++ b/lib/api/protocol/waitUntil.js @@ -21,6 +21,7 @@ const ProtocolAction = require('./_base-action.js'); * }); * } * + * @method waitUntil * @link https://www.selenium.dev/selenium/docs/api/javascript/module/selenium-webdriver/index_exports_WebDriver.html#wait * @selenium_webdriver * @syntax .waitUntil(conditionFn, [callback]) diff --git a/lib/api/web-element/commands/setValue.js b/lib/api/web-element/commands/setValue.js index d27c86ae3a..44cd424991 100644 --- a/lib/api/web-element/commands/setValue.js +++ b/lib/api/web-element/commands/setValue.js @@ -1,3 +1,32 @@ +/** + * Sends some text to an element. Can be used to set the value of a form element or to send a sequence of key strokes to an element. Any UTF-8 character may be specified. + * + *
From Nightwatch v2, setValue also clears the existing value of the element by calling the clearValue() beforehand.
+ * + * An object map with available keys and their respective UTF-8 characters, as defined on [W3C WebDriver draft spec](https://www.w3.org/TR/webdriver/#character-types), is loaded onto the main Nightwatch instance as `browser.Keys`. + * + * For more info on working with DOM elements in Nightwatch, refer to the Finding & interacting with DOM Elements guide page. + * @example + * // send some simple text to an input + * this.demoTest = function (browser) { + * const result = await browser.element('input[type=text]').setValue('nightwatch'); + * }; + * + * // send some text to an input and hit enter. + * this.demoTest = function (browser) { + * const result = await browser.element('input[type=text]').setValue(['nightwatch', browser.Keys.ENTER]); + * }; + * + * + * @link /session/:sessionId/element/:id/value + * @method setValue + * @memberof ScopedWebElement + * @instance + * @syntax browser.element(selector).setValue(inputValue) + * @param {string|array} inputValue The text to send to the element or key strokes. + * @param {function} [callback] Optional callback function to be called when the command finishes. + * @link https://www.w3.org/TR/webdriver#element-send-keys + */ module.exports.command = function(...args) { const keys = args.reduce((prev, key) => { const keyList = Array.isArray(key) ? key : [key]; From cf4d9f04900d51fe0f7c53bf477dbaf7368a3894 Mon Sep 17 00:00:00 2001 From: Priyansh <88396544+itsspriyansh@users.noreply.github.com> Date: Wed, 26 Jul 2023 14:16:38 +0530 Subject: [PATCH 07/38] updated semver to v7.5.2 (#3829) --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7dfa461638..0d4860c26c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42,7 +42,7 @@ "ora": "5.4.1", "piscina": "^3.2.0", "selenium-webdriver": "~4.10.0", - "semver": "7.3.5", + "semver": "7.5.2", "stacktrace-parser": "0.1.10", "strip-ansi": "6.0.1", "untildify": "^4.0.0", @@ -7567,9 +7567,9 @@ } }, "node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.2.tgz", + "integrity": "sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -14721,9 +14721,9 @@ } }, "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.2.tgz", + "integrity": "sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ==", "requires": { "lru-cache": "^6.0.0" } diff --git a/package.json b/package.json index c7bcf81870..6bf7c4dbe1 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "ora": "5.4.1", "piscina": "^3.2.0", "selenium-webdriver": "~4.10.0", - "semver": "7.3.5", + "semver": "7.5.2", "stacktrace-parser": "0.1.10", "strip-ansi": "6.0.1", "untildify": "^4.0.0", From d8a3d7308b94c8848e0c4baf9616219ffe475192 Mon Sep 17 00:00:00 2001 From: Yash Pratap Singh <102533457+yashPratp983@users.noreply.github.com> Date: Wed, 26 Jul 2023 14:17:12 +0530 Subject: [PATCH 08/38] Updated Error Message for Browser Compatibility Information. (#3809) --- lib/api/client-commands/network/setConditions.js | 2 +- lib/api/client-commands/registerBasicAuth.js | 2 +- test/src/api/commands/client/testRegisterBasicAuth.js | 2 +- test/src/api/commands/client/testSetNetworkConditions.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/api/client-commands/network/setConditions.js b/lib/api/client-commands/network/setConditions.js index 7d642f4b6e..a3f8f34b70 100644 --- a/lib/api/client-commands/network/setConditions.js +++ b/lib/api/client-commands/network/setConditions.js @@ -33,7 +33,7 @@ class SetNetworkConditions extends ClientCommand { performAction(callback) { if (!this.api.isChrome() && !this.api.isEdge()) { - const error = new Error('SetNetworkConditions is not supported while using this driver'); + const error = new Error('The command .setNetworkConditions() is only supported in Chromium based drivers'); Logger.error(error); return callback(error); diff --git a/lib/api/client-commands/registerBasicAuth.js b/lib/api/client-commands/registerBasicAuth.js index 1b15fadb54..715a123534 100644 --- a/lib/api/client-commands/registerBasicAuth.js +++ b/lib/api/client-commands/registerBasicAuth.js @@ -28,7 +28,7 @@ class RegisterBasicAuth extends ClientCommand { performAction(callback) { if (!this.api.isChrome() && !this.api.isEdge()) { - const error = new Error('RegisterBasicAuth is not supported while using this driver'); + const error = new Error('The command .registerBasicAuth() is only supported in Chromium based drivers'); Logger.error(error); return callback(error); diff --git a/test/src/api/commands/client/testRegisterBasicAuth.js b/test/src/api/commands/client/testRegisterBasicAuth.js index 7f4c758e7a..d5ed4e253f 100644 --- a/test/src/api/commands/client/testRegisterBasicAuth.js +++ b/test/src/api/commands/client/testRegisterBasicAuth.js @@ -65,7 +65,7 @@ describe('.registerBasicAuth()', function () { }).then(client => { client.api.registerBasicAuth('admin', 'admin', function(result){ assert.strictEqual(result.status, -1); - assert.strictEqual(result.error, 'RegisterBasicAuth is not supported while using this driver'); + assert.strictEqual(result.error, 'The command .registerBasicAuth() is only supported in Chromium based drivers'); }); client.start(done); diff --git a/test/src/api/commands/client/testSetNetworkConditions.js b/test/src/api/commands/client/testSetNetworkConditions.js index e05b6f1708..3e5e102a0b 100644 --- a/test/src/api/commands/client/testSetNetworkConditions.js +++ b/test/src/api/commands/client/testSetNetworkConditions.js @@ -141,7 +141,7 @@ describe('.setNetworkConditions()', function () { }, function (result) { assert.strictEqual(result.status, -1); - assert.strictEqual(result.error, 'SetNetworkConditions is not supported while using this driver'); + assert.strictEqual(result.error, 'The command .setNetworkConditions() is only supported in Chromium based drivers'); } ); client.start(done); From d3de801978277b0fe319f10d0c1761258318dbe9 Mon Sep 17 00:00:00 2001 From: Binayak Ghosh Date: Wed, 26 Jul 2023 21:15:19 +0530 Subject: [PATCH 09/38] programatic-api: add methods to call global hooks, add a cleanup method (#3822) --- lib/core/queue.js | 16 ++- lib/index.js | 16 +++ lib/utils/logger/index.js | 17 ++- test/src/index/testProgrammaticApis.js | 157 ++++++++++++++++++++++++- 4 files changed, 201 insertions(+), 5 deletions(-) diff --git a/lib/core/queue.js b/lib/core/queue.js index d16386353f..34a973eca6 100644 --- a/lib/core/queue.js +++ b/lib/core/queue.js @@ -34,6 +34,10 @@ class CommandQueue extends EventEmitter { const {compatMode} = this; const parentContext = this.currentNode.context; + if (!this.deferred) { + this.deferred = Utils.createPromise(); + } + const node = new Node({ name: commandName, parent: this.currentNode, @@ -133,12 +137,22 @@ class CommandQueue extends EventEmitter { } } + waitForCompletion() { + if (this.deferred) { + return this.deferred.promise; + } + + return Promise.resolve(); + } + run() { if (this.tree.started) { return this; } - this.deferred = Utils.createPromise(); + if (!this.deferred) { + this.deferred = Utils.createPromise(); + } this.scheduleTraverse(); return this.deferred.promise; diff --git a/lib/index.js b/lib/index.js index 7bc09bbf68..f8503c500f 100644 --- a/lib/index.js +++ b/lib/index.js @@ -131,6 +131,14 @@ module.exports.createClient = function({ return client.mergeCapabilities(value); }, + runGlobalBeforeHook() { + return cliRunner.globals.runGlobalHook('before'); + }, + + runGlobalAfterHook() { + return cliRunner.globals.runGlobalHook('after'); + }, + launchBrowser() { const {argv} = cliRunner; @@ -141,6 +149,14 @@ module.exports.createClient = function({ .then(_ => { return client.api; }); + }, + + async cleanup() { + await client.queue.waitForCompletion(); + client.queue.empty(); + client.queue.reset(); + client.queue.removeAllListeners(); + Logger.reset(); } }; diff --git a/lib/utils/logger/index.js b/lib/utils/logger/index.js index 1941a6247d..965c5af04e 100644 --- a/lib/utils/logger/index.js +++ b/lib/utils/logger/index.js @@ -36,7 +36,7 @@ function timestamp(d = new Date(), format) { return d.toISOString(); } - let time = [ + const time = [ pad(d.getHours()), pad(d.getMinutes()), pad(d.getSeconds()) @@ -76,8 +76,8 @@ function logMessage(type, message, args, alwaysShow) { let messageStr = ''; let logMethod = 'log'; let prefix; - let d = new Date(); - let timeIso = d.toISOString(); + const d = new Date(); + const timeIso = d.toISOString(); let timestamp = logTimestamp(d); switch (type) { @@ -482,3 +482,14 @@ module.exports.collectTestSectionOutput = function() { return testSectionOutput; }; + +module.exports.reset = function() { + const instance = Logger.getInstance(); + + if (!instance) { + return; + } + + instance.testSectionOutput = []; + instance.output = []; +}; diff --git a/test/src/index/testProgrammaticApis.js b/test/src/index/testProgrammaticApis.js index f281e54be9..7f64bca9c3 100644 --- a/test/src/index/testProgrammaticApis.js +++ b/test/src/index/testProgrammaticApis.js @@ -2,6 +2,7 @@ const assert = require('assert'); const mockery = require('mockery'); const MockServer = require('../../lib/command-mocks.js'); const common = require('../../common.js'); +const {Logger} = common.require('utils'); describe('test programmatic apis', function () { // [ '-vv', '--port=62625' ] @@ -75,7 +76,8 @@ describe('test programmatic apis', function () { assert.ok(!!global.browser); assert.ok(!!global.browser.page); - assert.deepStrictEqual(Object.keys(client), ['updateCapabilities', 'launchBrowser']); + assert.deepStrictEqual(Object.keys(client), ['updateCapabilities', 'runGlobalBeforeHook', + 'runGlobalAfterHook', 'launchBrowser', 'cleanup']); assert.strictEqual(typeof client.launchBrowser, 'function'); assert.strictEqual(typeof client.settings, 'object'); @@ -640,4 +642,157 @@ describe('test programmatic apis', function () { CliRunner.createDefaultConfig = createDefaultConfig; CliRunner.prototype.loadConfig = loadConfig; }); + + it('test runGlobalBeforeHook() programmatic API', async function() { + const CliRunner = common.require('runner/cli/cli.js'); + const Nightwatch = common.require('index.js'); + MockServer.createFirefoxSession({}); + + let globalBeforeCalled = false; + + const defaultConfig = { + test_settings: { + default: { + launchUrl: 'http://localhost' + } + }, + selenium: { + port: 10195, + start_process: false + }, + selenium_host: 'localhost', + + globals: { + before() { + globalBeforeCalled = true; + } + } + }; + + const createDefaultConfig = CliRunner.createDefaultConfig; + const loadConfig = CliRunner.prototype.loadConfig; + + CliRunner.createDefaultConfig = function(destFileName) { + return defaultConfig; + }; + + CliRunner.prototype.loadConfig = function () { + return defaultConfig; + }; + + const client = Nightwatch.createClient({ + headless: true, + silent: false, + output: false, + enable_global_apis: true + }); + + await client.runGlobalBeforeHook(); + + assert.ok(globalBeforeCalled); + + CliRunner.createDefaultConfig = createDefaultConfig; + CliRunner.prototype.loadConfig = loadConfig; + }); + + it('test runGlobalAfterHook() programmatic API', async function() { + const CliRunner = common.require('runner/cli/cli.js'); + const Nightwatch = common.require('index.js'); + MockServer.createFirefoxSession({}); + + let globalAfterCalled = false; + + const defaultConfig = { + test_settings: { + default: { + launchUrl: 'http://localhost' + } + }, + selenium: { + port: 10195, + start_process: false + }, + selenium_host: 'localhost', + + globals: { + after() { + globalAfterCalled = true; + } + } + }; + + const createDefaultConfig = CliRunner.createDefaultConfig; + const loadConfig = CliRunner.prototype.loadConfig; + + CliRunner.createDefaultConfig = function(destFileName) { + return defaultConfig; + }; + + CliRunner.prototype.loadConfig = function () { + return defaultConfig; + }; + + const client = Nightwatch.createClient({ + headless: true, + silent: false, + output: false, + enable_global_apis: true + }); + + await client.runGlobalAfterHook(); + + assert.ok(globalAfterCalled); + + CliRunner.createDefaultConfig = createDefaultConfig; + CliRunner.prototype.loadConfig = loadConfig; + }); + + it('test cleanup() programmatic API', async function() { + const CliRunner = common.require('runner/cli/cli.js'); + const Nightwatch = common.require('index.js'); + MockServer.createFirefoxSession({}); + + const defaultConfig = { + test_settings: { + default: { + launchUrl: 'http://localhost' + } + }, + selenium: { + port: 10195, + start_process: false + }, + selenium_host: 'localhost' + }; + + const createDefaultConfig = CliRunner.createDefaultConfig; + const loadConfig = CliRunner.prototype.loadConfig; + + CliRunner.createDefaultConfig = function(destFileName) { + return defaultConfig; + }; + + CliRunner.prototype.loadConfig = function () { + return defaultConfig; + }; + + const client = Nightwatch.createClient({ + headless: true, + silent: false, + output: false, + enable_global_apis: true + }); + + const session = await client.launchBrowser(); + + await client.cleanup(); + + const httpOutput = Logger.collectOutput(); + const httpSectionOutput = Logger.collectTestSectionOutput(); + + assert.equal(httpOutput.length, 0); + assert.equal(httpSectionOutput.length, 0); + CliRunner.createDefaultConfig = createDefaultConfig; + CliRunner.prototype.loadConfig = loadConfig; + }); }); From fcb9dd8cd9b1eead4599ac5fce7f10552ad45492 Mon Sep 17 00:00:00 2001 From: Ravi Sawlani Date: Wed, 26 Jul 2023 21:16:32 +0530 Subject: [PATCH 10/38] add error handling for worker threads (#3828) --- lib/runner/concurrency/index.js | 17 ++++++-- lib/runner/concurrency/worker-task.js | 6 +++ test/src/runner/cli/testCliRunnerParallel.js | 46 ++++++++++++++++++++ 3 files changed, 66 insertions(+), 3 deletions(-) diff --git a/lib/runner/concurrency/index.js b/lib/runner/concurrency/index.js index 1eb6890eb4..5cb894fe2d 100644 --- a/lib/runner/concurrency/index.js +++ b/lib/runner/concurrency/index.js @@ -185,7 +185,7 @@ class Concurrency extends EventEmitter { if (this.isSafariEnvPresent) { extraArgs.push('--serial'); } - let childProcess = this.createChildProcess(environment, args, extraArgs, index); + const childProcess = this.createChildProcess(environment, args, extraArgs, index); return this.runChildProcess(childProcess, environment + ' environment', availColors, 'envs'); })); @@ -216,8 +216,14 @@ class Concurrency extends EventEmitter { }); }); - return Promise.all(workerPool.tasks); + return new Promise((resolve, reject) => { + Promise.allSettled(workerPool.tasks) + .then(values => { + values.some(({status}) => status === 'rejected') ? reject() : resolve(); + }); + }); } + /** * * @param {Array} modules @@ -296,7 +302,12 @@ class Concurrency extends EventEmitter { }); - return Promise.all(workerPool.tasks); + return new Promise((resolve, reject) => { + Promise.allSettled(workerPool.tasks) + .then(values => { + values.some(({status}) => status === 'rejected') ? reject() : resolve(); + }); + }); } diff --git a/lib/runner/concurrency/worker-task.js b/lib/runner/concurrency/worker-task.js index 9041b91b84..f752b3946b 100644 --- a/lib/runner/concurrency/worker-task.js +++ b/lib/runner/concurrency/worker-task.js @@ -94,6 +94,7 @@ class WorkerTask extends EventEmitter { port2.unref(); return this.piscina.run({argv: this.argv, port1}, {transferList: [port1]}) + .catch(err => err) .then(failures => { if (this.settings.disable_output_boxes){ // eslint-disable-next-line no-console @@ -102,6 +103,11 @@ class WorkerTask extends EventEmitter { // eslint-disable-next-line no-console console.log(boxen(this.task_output.join('\n'), {title: `────────────────── ${failures ? symbols.fail : symbols.ok} ${this.task_label}`, padding: 1, borderColor: 'cyan'})); } + + //throw error to mark exit-code of the process + if (failures) { + throw new Error(); + } }); } } diff --git a/test/src/runner/cli/testCliRunnerParallel.js b/test/src/runner/cli/testCliRunnerParallel.js index e767cbc50d..31e45a4252 100644 --- a/test/src/runner/cli/testCliRunnerParallel.js +++ b/test/src/runner/cli/testCliRunnerParallel.js @@ -3,6 +3,7 @@ const path = require('path'); const mockery = require('mockery'); const common = require('../../../common.js'); const NightwatchClient = common.require('index.js'); +const {settings} = common; describe('Test CLI Runner in Parallel', function () { const ChildProcess = common.require('runner/concurrency/child-process.js'); @@ -105,6 +106,51 @@ describe('Test CLI Runner in Parallel', function () { }); }); + it('run error test file with concurrency - worker threads', function() { + let numberOfTasks = 0; + class RunnerBaseMock extends RunnerBase { + static readTestSource(settings, argv) { + assert.strictEqual(settings.testWorkersEnabled, true); + + return [ + 'test_file_1.js', + 'test_file_2.js' + ]; + } + } + + class WorkerProcessMock extends WorkerProcess { + addTask({colors}) { + + this.__tasks.push(new Promise((resolve, reject) => { + setTimeout(()=>{ + numberOfTasks++; + reject(new Error('Nigtwatch custom error')); + }, 10*(numberOfTasks+1)); + })); + + return Promise.resolve(0); + } + } + mockery.registerMock('./worker-process.js', WorkerProcessMock); + mockery.registerMock('../runner.js', RunnerBaseMock); + + return NightwatchClient.runTests({ + env: 'default', + config: path.join(__dirname, '../../../extra/withgeckodriver-concurrent.json') + }, settings({ + globals: { + reporter() { + assert.strictEqual(numberOfTasks, 2); + } + }, + use_child_process: false, + silent: false, + output: false, + output_folder: false + })); + }); + it('start single test run with geckodriver and test workers enabled', function () { const testPath = path.join(__dirname, '../../../sampletests/async/test/sample.js'); const runner = NightwatchClient.CliRunner({ From 2e0b867b444db6d3c43c7eabd537e6878095833d Mon Sep 17 00:00:00 2001 From: Priyansh <88396544+itsspriyansh@users.noreply.github.com> Date: Wed, 26 Jul 2023 21:19:27 +0530 Subject: [PATCH 11/38] handle error for src folders while using tags (#3824) --- lib/runner/folder-walk.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/runner/folder-walk.js b/lib/runner/folder-walk.js index aec2f3115f..a829ed10dd 100644 --- a/lib/runner/folder-walk.js +++ b/lib/runner/folder-walk.js @@ -68,12 +68,12 @@ class Walker { err.showTrace = false; if (Array.isArray(this.settings.src_folders) && this.settings.src_folders.length > 0) { - let srcFolders = this.settings.src_folders.map(item => `"${item}"`).join(', '); + const srcFolders = this.settings.src_folders.map(item => `"${item}"`).join(', '); err.message += `; src_folders: ${srcFolders}`; } if (this.argv.group) { - let groups = this.argv.group.map(item => `"${item}"`).join(', '); + const groups = this.argv.group.map(item => `"${item}"`).join(', '); err.message += `; group(s): ${groups}`; } @@ -118,7 +118,7 @@ class Walker { matched = false; } - let filename = filePath.split(path.sep).slice(-1)[0]; + const filename = filePath.split(path.sep).slice(-1)[0]; if (this.settings.filename_filter) { matched = matched && minimatch(filename, this.settings.filename_filter); @@ -129,6 +129,10 @@ class Walker { } async applyTagFilter(list) { + if (!Array.isArray(list)) { + return; + } + if (!this.tags.anyTagsDefined() || this.usingCucumber) { return list; } @@ -147,7 +151,7 @@ class Walker { } promiseFn(resolve, reject) { - let sourcePath = this.modulePathsCopy.shift(); + const sourcePath = this.modulePathsCopy.shift(); let fullPath = path.resolve(sourcePath); Utils.checkPath(fullPath) From adf29445f44aebebeef62c775a4977b124148e79 Mon Sep 17 00:00:00 2001 From: Vinod Reddy <105217169+vinodreddy-bs@users.noreply.github.com> Date: Wed, 26 Jul 2023 22:23:20 +0530 Subject: [PATCH 12/38] Fix - Issue #3625 - Changed to recursive merge on caps (#3831) --- lib/api/protocol/url.js | 2 +- lib/core/client.js | 3 +- test/src/index/testProgrammaticApis.js | 63 ++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 2 deletions(-) diff --git a/lib/api/protocol/url.js b/lib/api/protocol/url.js index 88dbe1baa3..875914c969 100644 --- a/lib/api/protocol/url.js +++ b/lib/api/protocol/url.js @@ -37,7 +37,7 @@ module.exports = class Action extends ProtocolAction { command(url, callback = function(r) {return r}) { if (typeof url == 'string') { - let startTime = new Date(); + const startTime = new Date(); let spinner; if (this.settings.output) { spinner = ora({ diff --git a/lib/core/client.js b/lib/core/client.js index 3be3fd1271..1928496df7 100644 --- a/lib/core/client.js +++ b/lib/core/client.js @@ -1,6 +1,7 @@ const EventEmitter = require('events'); const {Key, Capabilities, Browser} = require('selenium-webdriver'); +const lodashMerge = require('lodash/merge.js'); const HttpOptions = require('../http/options.js'); const HttpRequest = require('../http/request.js'); const Utils = require('../utils'); @@ -591,7 +592,7 @@ class NightwatchClient extends EventEmitter { return; } - Object.assign(this.initialCapabilities, props); + lodashMerge(this.initialCapabilities, props); this.setSessionOptions(); } diff --git a/test/src/index/testProgrammaticApis.js b/test/src/index/testProgrammaticApis.js index 7f64bca9c3..aa993b65ae 100644 --- a/test/src/index/testProgrammaticApis.js +++ b/test/src/index/testProgrammaticApis.js @@ -795,4 +795,67 @@ describe('test programmatic apis', function () { CliRunner.createDefaultConfig = createDefaultConfig; CliRunner.prototype.loadConfig = loadConfig; }); + + it('should test updateCapabilities() programmatic API with multiple nested caps', async function() { + const CliRunner = common.require('runner/cli/cli.js'); + const Nightwatch = common.require('index.js'); + MockServer.createFirefoxSession({}); + + const defaultConfig = { + test_settings: { + default: { + launchUrl: 'http://localhost' + } + }, + selenium: { + port: 10195, + start_process: false + }, + selenium_host: 'localhost' + }; + + const createDefaultConfig = CliRunner.createDefaultConfig; + const loadConfig = CliRunner.prototype.loadConfig; + + CliRunner.createDefaultConfig = function(destFileName) { + return defaultConfig; + }; + + CliRunner.prototype.loadConfig = function () { + return defaultConfig; + }; + + const client = Nightwatch.createClient({ + headless: true, + silent: false, + output: false, + enable_global_apis: true + }); + + client.updateCapabilities({ + 'testName': 'newCaps', + 'options': { + 'testCapabilitiesOne': 'capabilityOne' + } + }); + + client.updateCapabilities({ + 'testName': 'updatedCaps', + 'options': { + 'testCapabilitiesTwo': 'capabilityTwo' + } + }); + + const session = await client.launchBrowser(); + assert.deepStrictEqual(session.desiredCapabilities, { + browserName: 'firefox', + testName: 'updatedCaps', + options: { + testCapabilitiesOne: 'capabilityOne', + testCapabilitiesTwo: 'capabilityTwo' + } + }); + CliRunner.createDefaultConfig = createDefaultConfig; + CliRunner.prototype.loadConfig = loadConfig; + }); }); From e1bed6afe4855800ba2921abb6bde6c8fe576fc4 Mon Sep 17 00:00:00 2001 From: AutomatedTester Date: Wed, 26 Jul 2023 21:39:47 +0100 Subject: [PATCH 13/38] 3.1.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0d4860c26c..7d8009a6cc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "nightwatch", - "version": "3.0.1", + "version": "3.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "nightwatch", - "version": "3.0.1", + "version": "3.1.0", "license": "MIT", "dependencies": { "@nightwatch/chai": "5.0.2", diff --git a/package.json b/package.json index 6bf7c4dbe1..b815abbd89 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nightwatch", "description": "Easy to use Node.js based end-to-end testing solution for web applications using the W3C WebDriver API.", - "version": "3.0.1", + "version": "3.1.0", "author": "Andrei Rusu", "homepage": "https://nightwatchjs.org", "main": "./dist/index.js", From 222c60357068e75b8508f4d1f43669fbcef70ea1 Mon Sep 17 00:00:00 2001 From: Ravi Sawlani Date: Thu, 27 Jul 2023 20:33:31 +0530 Subject: [PATCH 14/38] update lodash.merge dependency in client (#3836) --- lib/core/client.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/client.js b/lib/core/client.js index 1928496df7..e7e2dda824 100644 --- a/lib/core/client.js +++ b/lib/core/client.js @@ -1,7 +1,7 @@ const EventEmitter = require('events'); const {Key, Capabilities, Browser} = require('selenium-webdriver'); -const lodashMerge = require('lodash/merge.js'); +const lodashMerge = require('lodash.merge'); const HttpOptions = require('../http/options.js'); const HttpRequest = require('../http/request.js'); const Utils = require('../utils'); From 96e1b3462b28e89a2cda299fa67be1d864033dea Mon Sep 17 00:00:00 2001 From: Priyansh Garg <39924567+garg3133@users.noreply.github.com> Date: Fri, 28 Jul 2023 21:00:05 +0530 Subject: [PATCH 15/38] Fix for failing TS tests after upgrading to v3. (#3845) --- lib/utils/index.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/utils/index.js b/lib/utils/index.js index 2d1613ee32..5384994693 100644 --- a/lib/utils/index.js +++ b/lib/utils/index.js @@ -590,6 +590,7 @@ class Utils { try { require('ts-node').register({ esm: false, + transpileOnly: true, project: projectTsFile }); } catch (err) { @@ -693,8 +694,6 @@ class Utils { } } - - lodashMerge(Utils, { PrimitiveTypes, BrowserName, From 05ee135b251515919c62ad9155cfad7fb3536306 Mon Sep 17 00:00:00 2001 From: Binayak Ghosh Date: Mon, 31 Jul 2023 15:38:44 +0530 Subject: [PATCH 16/38] update waitUntil documentation; fix a bug in waitUntil (#3839) --- lib/api/web-element/waitUntil.js | 51 ++++++++++++++++++++- test/apidemos/web-elements/waitUntilTest.js | 4 ++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/lib/api/web-element/waitUntil.js b/lib/api/web-element/waitUntil.js index 6b1f151013..257e772eef 100644 --- a/lib/api/web-element/waitUntil.js +++ b/lib/api/web-element/waitUntil.js @@ -12,6 +12,55 @@ const mapToSeleniumFunction = { 'disabled': until.elementIsDisabled }; +/** + * Waits a given time in milliseconds (default 5000ms) for an element to be present in a specified state in the page before performing any other commands or assertions. + * If the element fails to be present in the specified state within the given time, the test fails. You can change this by setting `abortOnFailure` to `false`. + * + * You can change the polling interval by defining a `waitForConditionPollInterval` property (in milliseconds) in as a global property in your `nightwatch.conf.js` or in your external globals file. + * Similarly, the default timeout can be specified as a global `waitForConditionTimeout` property (in milliseconds). + * + * @example + * describe('demo Test', function() { + * it ('wait for container', async function(browser){ + * // with default implicit timeout of 5000ms (can be overwritten in settings under 'globals.waitForConditionTimeout') + * await browser.element.find('#index-container').waitUntil('visible'); + * + * // with explicit timeout (in milliseconds) + * await browser.element.find('#index-container').waitUntil('visible', {timeout: 1000}); + * + * // continue if failed + * await browser.element.find('#index-container').waitUntil('visible', {timeout: 1000, abortOnFailure: false}); + * + * // with negative assertion + * await browser.element.find('#index-container').waitUntil('not.visible'); + * + * // with xpath as the locate strategy + * await browser.element.find(by.xpath('//*[@id="index-container"]')).waitUntil('visible', {message: 'The index container is found.'}); + * + * // with custom message + * await browser.element.find('#index-container').waitUntil('visible', {message: 'The index container is found.'}); + * }); + * + * + * it('page object demo Test', async function (browser) { + * const nightwatchPage = browser.page.nightwatch(); + * + * nightwatchPage + * .navigate() + * .assert.titleContains('Nightwatch.js'); + * + * await nightwatchPage.element.find('@featuresList').waitUntil('visible'); + * }); + * }); + * + * @method waitUntil + * @syntax .waitUntil(action, {timeout, retryInterval, message, abortOnFailure}); + * @param {string} action The locator strategy to use. See [W3C Webdriver - locator strategies](https://www.w3.org/TR/webdriver/#locator-strategies) + * @param {number} [timeout] The total number of milliseconds to wait before failing. Can also be set using 'globals.waitForConditionTimeout' under settings. + * @param {number} [retryInterval] The number of milliseconds to wait between retries. You can use this only if you also specify the time parameter. Can also be set using 'globals.waitForConditionPollInterval' under settings. + * @param {string} [message] Optional message to be shown in the output. The message supports two placeholders: %s for current selector and %d for the time (e.g. Element %s was not in the page for %d ms). + * @param {boolean} [abortOnFailure=abortOnAssertionFailure] By the default if the element is not found the test will fail. Set this to false if you wish for the test to continue even if the assertion fails. To set this globally you can define a property `abortOnAssertionFailure` in your globals. + */ class WaitUntil { constructor(scopedElement, {action, timeout, retryInterval, message, nightwatchInstance, selector, abortOnFailure}) { this.scopedElement = scopedElement; @@ -31,7 +80,7 @@ class WaitUntil { throw new Error(`Invalid action ${this.action} for element.waitUntil command. Possible actions: ${Object.keys(mapToSeleniumFunction).toString()}`); } - return actions.wait(this.conditionFn(webElement), this.timeout, this.retryInterval, this.message, ()=>{}) + return actions.wait(this.conditionFn(webElement), this.timeout, this.message, this.retryInterval, ()=>{}) .then(result => { const elapsedTime = new Date().getTime() - node.startTime; if (result.error) { diff --git a/test/apidemos/web-elements/waitUntilTest.js b/test/apidemos/web-elements/waitUntilTest.js index c56d45200e..c85c13220b 100644 --- a/test/apidemos/web-elements/waitUntilTest.js +++ b/test/apidemos/web-elements/waitUntilTest.js @@ -10,5 +10,9 @@ describe('demo tests using waitUntil element APIs', function() { it('wait until element is enabled', function({element}) { element('#weblogin').waitUntil('enabled'); }); + + it('wait until with custom message', function({element}) { + element('#weblogin').waitUntil('enabled', {message: 'elemento %s no era presente en %d ms'}); + }); }); From 74e2e2cd5ce450015b81cec22c28645dbc39da2c Mon Sep 17 00:00:00 2001 From: Ravi Sawlani Date: Thu, 3 Aug 2023 14:45:44 +0530 Subject: [PATCH 17/38] 3.1.2 (#3854) --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7d8009a6cc..a15104ee05 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "nightwatch", - "version": "3.1.0", + "version": "3.1.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "nightwatch", - "version": "3.1.0", + "version": "3.1.2", "license": "MIT", "dependencies": { "@nightwatch/chai": "5.0.2", diff --git a/package.json b/package.json index b815abbd89..f6fe03bb5d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nightwatch", "description": "Easy to use Node.js based end-to-end testing solution for web applications using the W3C WebDriver API.", - "version": "3.1.0", + "version": "3.1.2", "author": "Andrei Rusu", "homepage": "https://nightwatchjs.org", "main": "./dist/index.js", From 904b97f360ca747d341e4cfd0e3019cdf7da7373 Mon Sep 17 00:00:00 2001 From: Yash Pratap Singh <102533457+yashPratp983@users.noreply.github.com> Date: Wed, 9 Aug 2023 15:10:26 +0530 Subject: [PATCH 18/38] Fixed build script and dev script for running tests on windows. (#3866) * fixed build script for running test on windows * used cross-env npm package in dev script to enable running of example tests on windows * made cross-env dev dependency * used cross-env npm package in dev script to enable running of example tests --- package-lock.json | 28 ++++++++++++++++++++++++++++ package.json | 5 +++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index a15104ee05..7974b894a2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -56,6 +56,7 @@ "@swc/core": "^1.3.67", "@types/node": "^18.11.7", "copyfiles": "^2.4.1", + "cross-env": "^7.0.3", "eslint": "^8.9.0", "husky": "^8.0.0", "is-ci": "^3.0.1", @@ -2525,6 +2526,24 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -10914,6 +10933,15 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, + "cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.1" + } + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", diff --git a/package.json b/package.json index f6fe03bb5d..0cce13b1d6 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ "@swc/core": "^1.3.67", "@types/node": "^18.11.7", "copyfiles": "^2.4.1", + "cross-env": "^7.0.3", "eslint": "^8.9.0", "husky": "^8.0.0", "is-ci": "^3.0.1", @@ -100,10 +101,10 @@ }, "man": "", "scripts": { - "build": "rm -rf dist && tsc", + "build": "rimraf dist && tsc", "postbuild": "copyfiles -u 1 lib/**/*.ejs dist", "prepublishOnly": "npm run build", - "dev": "NIGHTWATCH_TS_NODE_DEV=true npx ts-node --swc ./bin/nightwatch", + "dev": "cross-env NIGHTWATCH_TS_NODE_DEV=true npx ts-node --swc ./bin/nightwatch", "eslint": "eslint index.js lib bin api examples cucumber-js test --quiet", "mocha": "npm run build && mocha", "mocha-coverage": "nyc --reporter=html mocha test/src/ --recursive", From c89e346bfd52994d1b33d3d0536ce2525bfe0f90 Mon Sep 17 00:00:00 2001 From: Priyansh Garg <39924567+garg3133@users.noreply.github.com> Date: Wed, 9 Aug 2023 15:10:50 +0530 Subject: [PATCH 19/38] Fix flaky disable_typescript flag test. (#3865) --- test/src/runner/testRunnerMixedFiles.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/test/src/runner/testRunnerMixedFiles.js b/test/src/runner/testRunnerMixedFiles.js index 40913bca6e..7406a57610 100644 --- a/test/src/runner/testRunnerMixedFiles.js +++ b/test/src/runner/testRunnerMixedFiles.js @@ -10,7 +10,10 @@ describe('testRunnerMixedFiles', function() { let tsNode; before(function(done) { - tsNode = require('ts-node').register(); + tsNode = require('ts-node').register({ + project: path.resolve('tsconfig.json'), + swc: true + }); this.server = MockServer.init(); this.server.on('listening', () => { @@ -35,8 +38,8 @@ describe('testRunnerMixedFiles', function() { this.timeout(5000); it('testRunWithoutDisablingTypescriptExplicitly', function() { - let testsPath = path.join(__dirname, '../../sampletests/mixed-files'); - let globals = { + const testsPath = path.join(__dirname, '../../sampletests/mixed-files'); + const globals = { reporter({lastError, errmessages, modules}) { if (lastError) { throw lastError; @@ -45,7 +48,7 @@ describe('testRunnerMixedFiles', function() { if (errmessages.length) { throw new Error(errmessages[0]); } - + assert.ok('sampleJs' in modules); assert.ok('sampleTs' in modules); assert.strictEqual(modules['sampleJs'].modulePath, path.join(__dirname, '../../sampletests/mixed-files/sampleJs.js')); @@ -62,8 +65,8 @@ describe('testRunnerMixedFiles', function() { }); it('testRunWithoutDisablingTypescriptImplicitly', function() { - let testsPath = path.join(__dirname, '../../sampletests/mixed-files'); - let globals = { + const testsPath = path.join(__dirname, '../../sampletests/mixed-files'); + const globals = { reporter({lastError, errmessages, modules}) { if (lastError) { throw lastError; @@ -87,8 +90,8 @@ describe('testRunnerMixedFiles', function() { }); it('testRunSimpleDisablingTypescript', function() { - let testsPath = path.join(__dirname, '../../sampletests/mixed-files'); - let globals = { + const testsPath = path.join(__dirname, '../../sampletests/mixed-files'); + const globals = { reporter({lastError, errmessages, modules}) { if (lastError) { throw lastError; From e33361cf159a07ff858220e94bd2c7b7f99d32be Mon Sep 17 00:00:00 2001 From: Denys Lins Date: Wed, 9 Aug 2023 08:41:29 -0300 Subject: [PATCH 20/38] Fix: .registerBasicAuth() not working in Edge browser #3848 (#3857) --------- Co-authored-by: Priyansh Garg <39924567+garg3133@users.noreply.github.com> --- lib/core/client.js | 10 ++++++++-- test/src/index/transport/testEdgeOptions.js | 12 ++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/lib/core/client.js b/lib/core/client.js index e7e2dda824..e98e4fbc2b 100644 --- a/lib/core/client.js +++ b/lib/core/client.js @@ -68,7 +68,13 @@ class NightwatchAPI { const browserNames = [this.browserName, lowerCaseBrowserName]; if (alternateName) { - return [browser, alternateName].some(name => browserNames.includes(name)); + alternateName = Array.isArray(alternateName) + ? alternateName + : [alternateName]; + + return [browser, ...alternateName].some(name => + browserNames.includes(name) + ); } return browserNames.includes(browser); @@ -107,7 +113,7 @@ class NightwatchAPI { } isEdge() { - return this.__isBrowserName(Browser.EDGE, 'edge'); + return this.__isBrowserName(Browser.EDGE, ['edge', 'msedge']); } isInternetExplorer() { diff --git a/test/src/index/transport/testEdgeOptions.js b/test/src/index/transport/testEdgeOptions.js index f566bb1c79..d442579698 100644 --- a/test/src/index/transport/testEdgeOptions.js +++ b/test/src/index/transport/testEdgeOptions.js @@ -130,5 +130,17 @@ describe('Test edge option', function(){ }); }); + it('msedge as browserName', function () { + const client = Nightwatch.createClient({ + desiredCapabilities: { + browserName: 'msedge' + } + }); + const options = client.transport.createSessionOptions(); + + assert.strictEqual(options instanceof EdgeOptions, true); + assert.strictEqual(client.api.isEdge(), true); + assert.strictEqual(client.api.browserName, 'msedge'); + }); }); From 46e6e12b0d415799c6bd5325cd41847215c25563 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=B3bert=20Kiss?= Date: Wed, 9 Aug 2023 17:29:11 +0200 Subject: [PATCH 21/38] fix: es6 module import (#3858) --- test/src/utils/__data__/meaning-of-life.js | 1 + test/src/utils/__data__/meaning-of-life.mjs | 1 + test/src/utils/testRequireModule.js | 21 +++++++++++++++++++++ tsconfig.json | 2 +- 4 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 test/src/utils/__data__/meaning-of-life.js create mode 100644 test/src/utils/__data__/meaning-of-life.mjs create mode 100644 test/src/utils/testRequireModule.js diff --git a/test/src/utils/__data__/meaning-of-life.js b/test/src/utils/__data__/meaning-of-life.js new file mode 100644 index 0000000000..888cae37af --- /dev/null +++ b/test/src/utils/__data__/meaning-of-life.js @@ -0,0 +1 @@ +module.exports = 42; diff --git a/test/src/utils/__data__/meaning-of-life.mjs b/test/src/utils/__data__/meaning-of-life.mjs new file mode 100644 index 0000000000..7a4e8a723a --- /dev/null +++ b/test/src/utils/__data__/meaning-of-life.mjs @@ -0,0 +1 @@ +export default 42; diff --git a/test/src/utils/testRequireModule.js b/test/src/utils/testRequireModule.js new file mode 100644 index 0000000000..12b800cbfd --- /dev/null +++ b/test/src/utils/testRequireModule.js @@ -0,0 +1,21 @@ +const {strict: assert} = require('node:assert'); +const path = require('node:path'); + +const common = require('../../common.js'); +const requireModule = common.require('utils/requireModule.js'); + +describe('test requireModule', function () { + it('should load commonjs file', function () { + const modulePath = path.join(__dirname, './__data__/meaning-of-life.js'); + const meaningOfLife = requireModule(modulePath); + + assert.equal(meaningOfLife, 42); + }); + + it('should load es6 module', async function () { + const modulePath = path.join(__dirname, './__data__/meaning-of-life.mjs'); + const meaningOfLife = await requireModule(modulePath); + + assert.equal(meaningOfLife, 42); + }); +}); diff --git a/tsconfig.json b/tsconfig.json index 8a90298884..78c3204d8c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -25,7 +25,7 @@ // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ /* Modules */ - "module": "commonjs", /* Specify what module code is generated. */ + "module": "node16", /* Specify what module code is generated. */ // "rootDir": "./", /* Specify the root folder within your source files. */ // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ From 50c9dbf333751d29348db78d5bde047f334f1cc5 Mon Sep 17 00:00:00 2001 From: Priyansh Garg <39924567+garg3133@users.noreply.github.com> Date: Wed, 9 Aug 2023 20:59:30 +0530 Subject: [PATCH 22/38] Update a few eslint rules around spacing. (#3864) --- .eslintrc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.eslintrc b/.eslintrc index e44ffd7427..fb8f2e68f3 100644 --- a/.eslintrc +++ b/.eslintrc @@ -43,13 +43,13 @@ "omitLastInOneLineBlock": true } ], - "no-trailing-spaces": 0, + "no-trailing-spaces": 1, "no-else-return": 2, "no-extra-bind": 0, "no-implicit-coercion": 0, "no-useless-call": 0, "no-return-assign": 0, - "eol-last": 0, + "eol-last": 1, "no-unused-vars": 0, "no-extra-semi": 0, "comma-dangle": 2, @@ -86,6 +86,7 @@ "after": true } ], + "space-infix-ops": 1, "padding-line-between-statements": [ "error", { From 6e36f45b06dfb9d3fa3fd43d4c56fa5cf70bf623 Mon Sep 17 00:00:00 2001 From: Yogesh Saini <97088265+Ykumar1415@users.noreply.github.com> Date: Wed, 9 Aug 2023 21:00:11 +0530 Subject: [PATCH 23/38] Fix : Add tag_filter type to NightwatchOptions interface. #3825 (#3830) --- types/index.d.ts | 2 +- types/nightwatch-options.d.ts | 7 +++++++ types/tests/index.test-d.ts | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/types/index.d.ts b/types/index.d.ts index 42b7d9a7a6..ce2c48e2da 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -567,7 +567,7 @@ export interface NightwatchAPI */ setSessionId(sessionId: string): this; - options: NightwatchTestOptions; + options: NightwatchOptions & Pick; Keys: NightwatchKeys; diff --git a/types/nightwatch-options.d.ts b/types/nightwatch-options.d.ts index 009bec0331..6ba6e8aa23 100644 --- a/types/nightwatch-options.d.ts +++ b/types/nightwatch-options.d.ts @@ -129,6 +129,7 @@ export interface NightwatchScreenshotOptions { } export interface NightwatchOptions { + /** * Location(s) where custom commands will be loaded from. */ @@ -435,6 +436,12 @@ export interface NightwatchOptions { */ skiptags?: string; + /** + * Tag(s) used/to be used during test execution. + * Can be a single tag or an array of tags. + */ + tag_filter?: string | string[]; + /** * Use xpath as the default locator strategy. */ diff --git a/types/tests/index.test-d.ts b/types/tests/index.test-d.ts index 664a7c9540..b28baa5caa 100644 --- a/types/tests/index.test-d.ts +++ b/types/tests/index.test-d.ts @@ -34,6 +34,8 @@ const testGeneral: NightwatchTests = { 'Demo test Google 1': () => { browser.registerBasicAuth('test-username', 'test-password').navigateTo('https://google.com').pause(1000); + // check types on browser.options + expectType(browser.options.tag_filter); // expect element to be present in 1000ms browser.expect.element('body').to.be.present.before(1000); From 4d799009a229cde905fee3ee8cf6f29b913dcd7c Mon Sep 17 00:00:00 2001 From: Binayak Ghosh Date: Thu, 10 Aug 2023 15:59:51 +0530 Subject: [PATCH 24/38] Remove support for node 14 (#3873) --- .github/workflows/build-node.yaml | 2 +- lib/runner/concurrency/index.js | 2 +- lib/transport/selenium-webdriver/index.js | 6 +++--- package-lock.json | 2 +- package.json | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build-node.yaml b/.github/workflows/build-node.yaml index 1a732e528c..da45e9f946 100644 --- a/.github/workflows/build-node.yaml +++ b/.github/workflows/build-node.yaml @@ -17,7 +17,7 @@ jobs: strategy: fail-fast: false matrix: - node-version: [14.x, 16.x, 18.x] + node-version: [16.x, 18.x, 20.x] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ steps: diff --git a/lib/runner/concurrency/index.js b/lib/runner/concurrency/index.js index 5cb894fe2d..7a45f88495 100644 --- a/lib/runner/concurrency/index.js +++ b/lib/runner/concurrency/index.js @@ -15,7 +15,7 @@ class Concurrency extends EventEmitter { this.useChildProcess = settings.use_child_process; this.childProcessOutput = {}; this.globalExitCode = 0; - this.testWorkersEnabled = typeof isTestWorkerEnabled !== undefined ? isTestWorkerEnabled : settings.testWorkersEnabled; + this.testWorkersEnabled = typeof isTestWorkerEnabled !== 'undefined' ? isTestWorkerEnabled : settings.testWorkersEnabled; this.isSafariEnvPresent = isSafariEnvPresent; } diff --git a/lib/transport/selenium-webdriver/index.js b/lib/transport/selenium-webdriver/index.js index 71231c3249..0a08bf01a0 100644 --- a/lib/transport/selenium-webdriver/index.js +++ b/lib/transport/selenium-webdriver/index.js @@ -302,7 +302,7 @@ class Transport extends BaseTransport { capabilities }; } catch (err) { - const error = this.handleConnectError(err); + const error = this.handleConnectError(err, host, port); this.showConnectSpinner(colors.red(`Failed to connect to ${this.serviceName} on ${host} with ${colors.stack_trace(portStr)}.`), 'warn'); throw error; @@ -416,13 +416,13 @@ class Transport extends BaseTransport { return result.value && result.value.message; } - handleConnectError(err) { + handleConnectError(err, host, port) { const errMsg = `An error occurred while creating a new ${this.serviceName} session:`; switch (err.code) { case 'ECONNREFUSED': err.sessionCreate = true; - err.message = `${errMsg} ${err.message.replace('ECONNREFUSED connect ECONNREFUSED', 'Connection refused to')}. If the Webdriver/Selenium service is managed by Nightwatch, check if "start_process" is set to "true".`; + err.message = `${errMsg} Connection refused to ${host}:${port}. If the Webdriver/Selenium service is managed by Nightwatch, check if "start_process" is set to "true".`; break; default: err.message = `${errMsg} [${err.name}] ${err.message}`; diff --git a/package-lock.json b/package-lock.json index 7974b894a2..b43621bf4c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -80,7 +80,7 @@ "wait-on": "^7.0.1" }, "engines": { - "node": ">= 14.20.0" + "node": ">= 16" }, "peerDependencies": { "@cucumber/cucumber": "*" diff --git a/package.json b/package.json index 0cce13b1d6..cb1116a8e0 100644 --- a/package.json +++ b/package.json @@ -134,7 +134,7 @@ } }, "engines": { - "node": ">= 14.20.0" + "node": ">= 16" }, "keywords": [ "nightwatch", From 6bd77e2246785b64786e802e8c7b682082da848c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=B3bert=20Kiss?= Date: Mon, 14 Aug 2023 11:12:44 +0200 Subject: [PATCH 25/38] chore: bump mocha 9.2.2 => 10.2.0 (#3860) --- package-lock.json | 165 +++++++++++++++++----------------------------- package.json | 2 +- 2 files changed, 62 insertions(+), 105 deletions(-) diff --git a/package-lock.json b/package-lock.json index b43621bf4c..5f4d6210e9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,7 +36,7 @@ "lodash.pick": "4.4.0", "minimatch": "3.1.2", "minimist": "1.2.6", - "mocha": "9.2.2", + "mocha": "10.2.0", "nightwatch-axe-verbose": "^2.2.2", "open": "8.4.0", "ora": "5.4.1", @@ -1390,11 +1390,6 @@ "@types/node": "*" } }, - "node_modules/@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==" - }, "node_modules/@zeit/schemas": { "version": "2.29.0", "resolved": "https://registry.npmjs.org/@zeit/schemas/-/schemas-2.29.0.tgz", @@ -3726,14 +3721,6 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" }, - "node_modules/growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "engines": { - "node": ">=4.x" - } - }, "node_modules/hard-rejection": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", @@ -4494,7 +4481,8 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true }, "node_modules/istanbul-lib-coverage": { "version": "3.2.0", @@ -5686,41 +5674,38 @@ } }, "node_modules/mocha": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", - "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", "dependencies": { - "@ungap/promise-all-settled": "1.1.2", "ansi-colors": "4.1.1", "browser-stdout": "1.3.1", "chokidar": "3.5.3", - "debug": "4.3.3", + "debug": "4.3.4", "diff": "5.0.0", "escape-string-regexp": "4.0.0", "find-up": "5.0.0", "glob": "7.2.0", - "growl": "1.10.5", "he": "1.2.0", "js-yaml": "4.1.0", "log-symbols": "4.1.0", - "minimatch": "4.2.1", + "minimatch": "5.0.1", "ms": "2.1.3", - "nanoid": "3.3.1", + "nanoid": "3.3.3", "serialize-javascript": "6.0.0", "strip-json-comments": "3.1.1", "supports-color": "8.1.1", - "which": "2.0.2", - "workerpool": "6.2.0", + "workerpool": "6.2.1", "yargs": "16.2.0", "yargs-parser": "20.2.4", "yargs-unparser": "2.0.0" }, "bin": { "_mocha": "bin/_mocha", - "mocha": "bin/mocha" + "mocha": "bin/mocha.js" }, "engines": { - "node": ">= 12.0.0" + "node": ">= 14.0.0" }, "funding": { "type": "opencollective", @@ -5772,27 +5757,6 @@ "concat-map": "0.0.1" } }, - "node_modules/mocha/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/mocha/node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, "node_modules/mocha/node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -5846,16 +5810,24 @@ } }, "node_modules/mocha/node_modules/minimatch": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", - "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { "node": ">=10" } }, + "node_modules/mocha/node_modules/minimatch/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, "node_modules/mocha/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -6141,9 +6113,9 @@ "dev": true }, "node_modules/nanoid": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", - "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -8811,6 +8783,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, "dependencies": { "isexe": "^2.0.0" }, @@ -8887,9 +8860,9 @@ } }, "node_modules/workerpool": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", - "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==" + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==" }, "node_modules/wrap-ansi": { "version": "7.0.0", @@ -10110,11 +10083,6 @@ "@types/node": "*" } }, - "@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==" - }, "@zeit/schemas": { "version": "2.29.0", "resolved": "https://registry.npmjs.org/@zeit/schemas/-/schemas-2.29.0.tgz", @@ -11811,11 +11779,6 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" }, - "growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==" - }, "hard-rejection": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", @@ -12328,7 +12291,8 @@ "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true }, "istanbul-lib-coverage": { "version": "3.2.0", @@ -13275,31 +13239,28 @@ } }, "mocha": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", - "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", "requires": { - "@ungap/promise-all-settled": "1.1.2", "ansi-colors": "4.1.1", "browser-stdout": "1.3.1", "chokidar": "3.5.3", - "debug": "4.3.3", + "debug": "4.3.4", "diff": "5.0.0", "escape-string-regexp": "4.0.0", "find-up": "5.0.0", "glob": "7.2.0", - "growl": "1.10.5", "he": "1.2.0", "js-yaml": "4.1.0", "log-symbols": "4.1.0", - "minimatch": "4.2.1", + "minimatch": "5.0.1", "ms": "2.1.3", - "nanoid": "3.3.1", + "nanoid": "3.3.3", "serialize-javascript": "6.0.0", "strip-json-comments": "3.1.1", "supports-color": "8.1.1", - "which": "2.0.2", - "workerpool": "6.2.0", + "workerpool": "6.2.1", "yargs": "16.2.0", "yargs-parser": "20.2.4", "yargs-unparser": "2.0.0" @@ -13319,21 +13280,6 @@ "concat-map": "0.0.1" } }, - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "requires": { - "ms": "2.1.2" - }, - "dependencies": { - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, "escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -13371,11 +13317,21 @@ } }, "minimatch": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", - "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", "requires": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "requires": { + "balanced-match": "^1.0.0" + } + } } }, "ms": { @@ -13648,9 +13604,9 @@ "dev": true }, "nanoid": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", - "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==" + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==" }, "natural-compare": { "version": "1.4.0", @@ -15663,6 +15619,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, "requires": { "isexe": "^2.0.0" } @@ -15718,9 +15675,9 @@ } }, "workerpool": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", - "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==" + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==" }, "wrap-ansi": { "version": "7.0.0", diff --git a/package.json b/package.json index cb1116a8e0..3483c24158 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "lodash.pick": "4.4.0", "minimatch": "3.1.2", "minimist": "1.2.6", - "mocha": "9.2.2", + "mocha": "10.2.0", "nightwatch-axe-verbose": "^2.2.2", "open": "8.4.0", "ora": "5.4.1", From 87c3e90b3789070be62441723a154b8a8b8cfaaf Mon Sep 17 00:00:00 2001 From: Binayak Ghosh Date: Wed, 16 Aug 2023 18:42:56 +0530 Subject: [PATCH 26/38] Add more events for analytics (#3856) * add new events for analytics * remove unused variable --- lib/reporter/global-reporter.js | 2 +- lib/reporter/index.js | 3 + lib/reporter/summary.js | 3 +- lib/runner/cli/cli.js | 12 +-- lib/runner/process-listener.js | 2 +- lib/utils/analytics.js | 117 ++++++++++++++++------------ test/src/analytics/testAnalytics.js | 66 +++++++++++----- 7 files changed, 125 insertions(+), 80 deletions(-) diff --git a/lib/reporter/global-reporter.js b/lib/reporter/global-reporter.js index 8e79fef661..f415547d1d 100644 --- a/lib/reporter/global-reporter.js +++ b/lib/reporter/global-reporter.js @@ -5,7 +5,7 @@ const stripAnsi = require('strip-ansi'); const Concurrency = require('../runner/concurrency'); const DefaultSettings = require('../settings/defaults.js'); const Utils = require('../utils'); -const {Logger, beautifyStackTrace} = Utils; +const {Logger} = Utils; const Results = require('./results.js'); const AxeReport = require('./axe-report.js'); const Summary = require('./summary.js'); diff --git a/lib/reporter/index.js b/lib/reporter/index.js index 3411961e63..a403239824 100644 --- a/lib/reporter/index.js +++ b/lib/reporter/index.js @@ -3,6 +3,7 @@ const TestResults = require('./results.js'); const SimplifiedReporter = require('./simplified.js'); const {Logger, Screenshots} = Utils; const {colors} = Logger; +const analyticsCollector = require('../utils/analytics.js'); class Reporter extends SimplifiedReporter { static printAssertions(testcase) { @@ -269,6 +270,8 @@ class Reporter extends SimplifiedReporter { return; } + analyticsCollector.collectErrorEvent(err); + super.registerTestError(err); const incrementTotal = this.shouldIncrementTotalCount(err); diff --git a/lib/reporter/summary.js b/lib/reporter/summary.js index a0aef38ef0..9d4e5170c4 100644 --- a/lib/reporter/summary.js +++ b/lib/reporter/summary.js @@ -1,7 +1,6 @@ const Utils = require('../utils'); -const {Logger, beautifyStackTrace} = Utils; +const {Logger} = Utils; const {colors} = Logger; -const stripAnsi = require('strip-ansi'); module.exports = class Summary { static failed(test) { diff --git a/lib/runner/cli/cli.js b/lib/runner/cli/cli.js index bc42fffc46..6c23a2ac8e 100644 --- a/lib/runner/cli/cli.js +++ b/lib/runner/cli/cli.js @@ -256,13 +256,13 @@ class CliRunner { analyticsCollector.updateSettings(this.test_settings); analyticsCollector.updateLogger(Logger); - analyticsCollector.event('nw_test_run', { + analyticsCollector.collectEvent('nw_test_run', { arg_parallel: this.argv.parallel, - browserName: this.test_settings.desiredCapabilities.browserName, - testWorkersEnabled: this.test_settings.testWorkersEnabled, + browser_name: this.test_settings.desiredCapabilities.browserName, + test_workers_enabled: this.test_settings.testWorkersEnabled, use_xpath: this.test_settings.use_xpath, - isBstack: this.test_settings.desiredCapabilities['bstack:options'] !== undefined, - test_runner: this.test_settings.test_runner ? this.test_settings.test_runner.type : null + is_bstack: this.test_settings.desiredCapabilities['bstack:options'] !== undefined, + test_runner: this.test_settings.test_runner ? this.test_settings.test_runner.type : null }); } @@ -627,6 +627,8 @@ class CliRunner { killSimulator(this.test_settings.deviceUDID); } + analyticsCollector.__flush(); + return errorOrFailed; }); } diff --git a/lib/runner/process-listener.js b/lib/runner/process-listener.js index 07c0fcb676..697851e42a 100644 --- a/lib/runner/process-listener.js +++ b/lib/runner/process-listener.js @@ -84,7 +84,7 @@ module.exports = class { Logger.enable(); Logger.error(`${type}: ${err.message}\n${err.stack}`); - analyticsCollector.exception(err); + analyticsCollector.collectErrorEvent(err, true); if (['TimeoutError', 'NoSuchElementError'].includes(err.name) && this.testRunner.type !== 'cucumber') { this.closeProcess(err); diff --git a/lib/utils/analytics.js b/lib/utils/analytics.js index 974bd6079f..80f10cc03d 100644 --- a/lib/utils/analytics.js +++ b/lib/utils/analytics.js @@ -4,7 +4,7 @@ */ const os = require('os'); -const HttpRequest = require('../http/request.js'); +const https = require('https'); const uuid = require('uuid'); const fs = require('fs').promises; @@ -28,7 +28,8 @@ const RESERVED_EVENT_NAMES = ['ad_activeview', 'ad_click', 'ad_exposure', 'ad_im 'notification_dismiss', 'notification_foreground', 'notification_open', 'notification_receive', 'os_update', 'screen_view', 'session_start', 'user_engagement']; -const ALLOWED_ERRORS = ['Error', 'SyntaxError', 'TypeError', 'ReferenceError']; +const ALLOWED_ERRORS = ['Error', 'SyntaxError', 'TypeError', 'ReferenceError', 'WebDriverError', 'TimeoutError', 'NotFoundError', 'NoSuchElementError', + 'IosSessionNotCreatedError', 'AndroidConnectionError', 'AndroidBinaryError', 'RealIosDeviceIdError', 'AndroidHomeError']; const RESERVED_EVENT_PARAMETERS = ['firebase_conversion']; @@ -44,6 +45,8 @@ class AnalyticsCollector { this.queueLength = 0; this.parameters = {}; this.logger = Logger; + this.userAgentString = buildUserAgentString(); + this.runId = uuid.v4(); // This identifies unique users and helps us separate out sessions. this.parameters['client_id'] = uuid.v4(); @@ -78,6 +81,7 @@ class AnalyticsCollector { this.settings.usage_analytics = defaultSettings; } + this.testEnv = settings.testEnv; // update client_id this.parameters['client_id'] = this.settings.usage_analytics.client_id; } @@ -86,7 +90,7 @@ class AnalyticsCollector { this.logger = logger; } - async event(name, parameters = {}) { + async collectEvent(name, parameters = {}) { if (!this.settings.usage_analytics.enabled) { return; } @@ -100,39 +104,46 @@ class AnalyticsCollector { parameters['event_time'] = new Date().getTime() * 1000; // Add environment information. - parameters['env_os'] = buildUserAgentString(); + parameters['env_os'] = this.userAgentString; parameters['env_lang'] = SYSTEM_LANGUAGE; parameters['env_nw_version'] = VERSION.full; parameters['env_node_version'] = `node ${process.version}`; - - // Add call location. - parameters.callLocation = getCallLocation(); + parameters['test_env'] = this.testEnv; + parameters['run_id'] = this.runId; return await this.__addToQueue(name, parameters); } - async exception(error) { - await this.initialize(); - + async collectErrorEvent(error, isUncaught = false) { if (!error) { return; } - if (!ALLOWED_ERRORS.includes(error.name)) { - error.name = 'CustomError'; + await this.initialize(); + + let errorName = error.name; + if (!ALLOWED_ERRORS.includes(errorName)) { + errorName = 'UserGeneratedError'; } try { const parameters = { + env_os: this.userAgentString, env_nw_version: VERSION.full, env_node_version: `node ${process.version}`, - errorName: error.name, - errorMessage: error.message + test_env: this.testEnv, + err_name: errorName, + is_uncaught: isUncaught, + run_id: this.runId }; - - this.__validateEvent('nw_exception', parameters); - - return await this.__addToQueue('nw_exception', parameters); + + this.__validateEvent('nw_test_err', parameters); + + await this.__addToQueue('nw_test_err', parameters); + + if (isUncaught) { + await this.__flush(); + } } catch (e) { // Ignore } @@ -143,9 +154,7 @@ class AnalyticsCollector { return; } - const pending = this.queueLength > 0; - - if (!pending) { + if (this.queueLength === 0) { return; } @@ -183,9 +192,9 @@ class AnalyticsCollector { return; } + this.queueLength++; const writeLogPromise = await this.__logAnalyticsEvents({name: eventType, params: parameters}); - this.queueLength++; // periodically flush if (this.queueLength > 5) { await this.__flush(); @@ -206,32 +215,38 @@ class AnalyticsCollector { const serverUrl = new URL(this.settings.usage_analytics.serverUrl || GA_SERVER_URL) ; const serverPort = serverUrl.port || this.settings.usage_analytics.serverPort || GA_SERVER_PORT; - const request = new HttpRequest({ - host: serverUrl.hostname, + const payload = JSON.stringify(data); + + const request = new https.request({ + hostname: serverUrl.hostname, port: serverPort, method: 'POST', - use_ssl: true, path, - data + headers: { + 'Content-Type': 'application/json', + 'Content-Length': payload.length + } }); - return new Promise((resolve, reject) => { - request - .on('success', (result, response) => { - if (response.statusCode !== 204) { - reject( - new Error(`Analytics reporting failed with status code: ${response.statusCode}.`) - ); - } else { - resolve(result); - } - }) - .on('error', (result) => { - new Error(`Failed to send usage metric: ${result.code}.`); - reject(result); - }) - .send(); + request.write(payload); + + request.once('response', (response) => { + if (response.statusCode !== 204) { + reject( + new Error(`Analytics reporting failed with status code: ${response.statusCode}.`) + ); + } else { + resolve(response); + } + }); + + request.on('error', (result) => { + new Error(`Failed to send usage metric: ${result.code}.`); + reject(result); + }); + + request.end(); }); } @@ -246,8 +261,11 @@ class AnalyticsCollector { const logfile = this.__getLogFileLocation(); const hasAnalyticsLog = await fileExists(logfile); - + if (!hasAnalyticsLog) { + data.params = data.params ? data.params : {}; + data.params['first_run'] = true; + await fs.mkdir(path.dirname(logfile), {recursive: true}); } @@ -256,6 +274,10 @@ class AnalyticsCollector { try { await writeFn(logfile, JSON.stringify(data) + '\n'); + // Always send data for first runs, this helps us detect CI builds also. + if (!hasAnalyticsLog) { + await this.__flush(); + } } catch (err) { this.logger.warn('Failed to log usage data:', err.message); } @@ -278,7 +300,7 @@ class AnalyticsCollector { if (RESERVED_EVENT_NAMES.includes(name)) { throw Error(`Analytics event name ${name} is reserved.`); } - + Object.keys(parameters).forEach(key => { if (RESERVED_EVENT_PARAMETERS.includes(key)) { throw Error(`Parameter name ${key} is reserved.`); @@ -305,13 +327,6 @@ function getLanguage() { getWindowsLanguageCode() || '??'); } - -function getCallLocation() { - const stackTrace = {}; - Error.captureStackTrace(stackTrace); - - return stackTrace.stack.split('\n')[3]; -} /** * Attempt to get the Windows Language Code string. diff --git a/test/src/analytics/testAnalytics.js b/test/src/analytics/testAnalytics.js index 0bbb297edb..3b26f5c617 100644 --- a/test/src/analytics/testAnalytics.js +++ b/test/src/analytics/testAnalytics.js @@ -37,7 +37,7 @@ describe('test analytics utility', function() { it('should throw error if event parameters contain objects or arrays', function() { assert.rejects(async function() { - await analytics.event('test', { + await analytics.collectEvent('test', { foo: { bar: 'bas' } @@ -45,28 +45,43 @@ describe('test analytics utility', function() { }); assert.rejects(async function() { - await analytics.event('test', { + await analytics.collectEvent('test', { foo: [1, 2, 3] }); }); }); it('should write events to a log file', async function() { - await analytics.event('test', { + const flushFn = analytics.__flush; + let flushCalled = false; + analytics.__flush = function() { + flushCalled = true; + }; + + await analytics.collectEvent('test', { foo: 'bar' }); const logFile = analytics.__getLogFileLocation(); - + try { const stats = await fs.stat(logFile); assert.ok(stats.size > 0); + assert.ok(flushCalled); } catch (e) { assert.fail(e); } + + analytics.__flush = flushFn; }); it('should have default parameters', async function() { - await analytics.event('test', { + const flushFn = analytics.__flush; + let flushCalled = false; + analytics.__flush = function() { + flushCalled = true; + }; + + await analytics.collectEvent('test', { foo: 'bar' }); @@ -79,12 +94,15 @@ describe('test analytics utility', function() { assert.ok(logFileJson.params.env_os); assert.ok(logFileJson.params.env_nw_version); assert.ok(logFileJson.params.env_node_version); + assert.ok(flushCalled); + + analytics.__flush = flushFn; }); it('should send analytics data to GA', async function() { const analyticsNock = Nocks.analyticsCollector(analytics.__getGoogleAnalyticsPath()); - await analytics.event('test', {log: 'log'}); + await analytics.collectEvent('test', {log: 'log'}); await analytics.__flush().then((res) => { analyticsNock.done(); @@ -103,12 +121,12 @@ describe('test analytics utility', function() { called = true; }; - await analytics.event('test', {log: 'log'}); - await analytics.event('test', {log: 'log'}); - await analytics.event('test', {log: 'log'}); - await analytics.event('test', {log: 'log'}); - await analytics.event('test', {log: 'log'}); - await analytics.event('test', {log: 'log'}); + await analytics.collectEvent('test', {log: 'log'}); + await analytics.collectEvent('test', {log: 'log'}); + await analytics.collectEvent('test', {log: 'log'}); + await analytics.collectEvent('test', {log: 'log'}); + await analytics.collectEvent('test', {log: 'log'}); + await analytics.collectEvent('test', {log: 'log'}); assert.ok(called); analytics.__flush = flushBack; @@ -137,7 +155,7 @@ describe('test analytics utility', function() { called = true; }; analytics.updateSettings(settings); - await analytics.event('test', {log: 'log'}); + await analytics.collectEvent('test', {log: 'log'}); } assert.ok(called); @@ -147,34 +165,42 @@ describe('test analytics utility', function() { }); it('should report only allowed exceptions', async function() { + const flushFn = analytics.__flush; + let flushCalled = false; + analytics.__flush = function() { + flushCalled = true; + }; + const analyticsNock = Nocks.analyticsCollector(analytics.__getGoogleAnalyticsPath()); const err = new Error('test'); err.name ='UserGeneratedError'; - await analytics.exception(err); + await analytics.collectErrorEvent(err); + + assert.ok(flushCalled); + analytics.__flush = flushFn; const logFile = analytics.__getLogFileLocation(); let logFileContent = await fs.readFile(logFile, 'utf8'); let logFileJson = JSON.parse(logFileContent); - assert.ok(logFileJson.params.errorName === 'CustomError'); + assert.equal(logFileJson.params.err_name, 'UserGeneratedError'); await analytics.__flush().then((res) => { analyticsNock.done(); }).catch((err) => { assert.strictEqual(err, undefined); }); - const analyticsNock2 = Nocks.analyticsCollector(analytics.__getGoogleAnalyticsPath()); err.name = 'SyntaxError'; - await analytics.exception(err); - + await analytics.collectErrorEvent(err); + logFileContent = await fs.readFile(logFile, 'utf8'); logFileJson = JSON.parse(logFileContent); - - assert.ok(logFileJson.params.errorName === 'SyntaxError'); + + assert.equal(logFileJson.params.err_name, 'SyntaxError'); await analytics.__flush().then((res) => { analyticsNock2.done(); From 6976c6a1b1f1a4143152c8d7857b9a85e0d04550 Mon Sep 17 00:00:00 2001 From: Priyansh Garg <39924567+garg3133@users.noreply.github.com> Date: Wed, 16 Aug 2023 18:51:43 +0530 Subject: [PATCH 27/38] Move log related commands to `.logs` namespaces. (#3796) --- lib/api/client-commands/_base-command.js | 4 + lib/api/client-commands/getLog.js | 1 + lib/api/client-commands/getLogTypes.js | 1 + lib/api/client-commands/isLogAvailable.js | 1 + .../{ => logs}/captureBrowserConsoleLogs.js | 8 +- .../{ => logs}/captureBrowserExceptions.js | 8 +- lib/api/client-commands/logs/getSessionLog.js | 54 ++++ .../logs/getSessionLogTypes.js | 34 +++ .../logs/isSessionLogAvailable.js | 67 +++++ lib/api/protocol/sessionLog.js | 1 + lib/api/protocol/sessionLogTypes.js | 1 + .../testCaptureBrowserConsoleLogs.js} | 50 +++- .../testCaptureBrowserExceptions.js | 50 +++- test/src/api/commands/logs/testGetLog.js | 95 +++++++ .../{element => logs}/testGetLogTypes.js | 27 +- .../api/commands/logs/testIsLogAvailable.js | 58 +++++ types/index.d.ts | 234 +++++++++++++----- types/tests/chromiumClientCommands.test-d.ts | 29 +++ types/tests/namespaceCommands.test-d.ts | 90 +++++++ 19 files changed, 731 insertions(+), 82 deletions(-) rename lib/api/client-commands/{ => logs}/captureBrowserConsoleLogs.js (90%) rename lib/api/client-commands/{ => logs}/captureBrowserExceptions.js (91%) create mode 100644 lib/api/client-commands/logs/getSessionLog.js create mode 100644 lib/api/client-commands/logs/getSessionLogTypes.js create mode 100644 lib/api/client-commands/logs/isSessionLogAvailable.js rename test/src/api/commands/{client/testCaptureConsoleLogs.js => logs/testCaptureBrowserConsoleLogs.js} (72%) rename test/src/api/commands/{client => logs}/testCaptureBrowserExceptions.js (72%) rename test/src/api/commands/{element => logs}/testGetLogTypes.js (50%) create mode 100644 types/tests/namespaceCommands.test-d.ts diff --git a/lib/api/client-commands/_base-command.js b/lib/api/client-commands/_base-command.js index d190d231a7..e98a24b3eb 100644 --- a/lib/api/client-commands/_base-command.js +++ b/lib/api/client-commands/_base-command.js @@ -35,6 +35,10 @@ module.exports = class ClientCommand { promise = Promise.resolve(promise); } + // the final result returned in the test would be same irrespective of + // the value of fullPromiseResolve, thanks to `getResult` method in + // lib/core/treenode.js but the result value everywhere else in Nightwatch + // would appear to be the value of resolveValue below. const resolveValue = fullPromiseResolve ? result : result.value; promise.then(_ => resolve(resolveValue)).catch(err => reject(err)); } catch (e) { diff --git a/lib/api/client-commands/getLog.js b/lib/api/client-commands/getLog.js index 849e23d932..acd263afbf 100644 --- a/lib/api/client-commands/getLog.js +++ b/lib/api/client-commands/getLog.js @@ -20,6 +20,7 @@ const ClientCommand = require('./_base-command.js'); * @param {function} callback Callback function which is called with the result value. * @api protocol.sessions * @see getLogTypes + * @deprecated In favour of `.logs.getSessionLog()`. */ class GetLog extends ClientCommand { get returnsFullResultObject() { diff --git a/lib/api/client-commands/getLogTypes.js b/lib/api/client-commands/getLogTypes.js index 7ce75ed067..f45eab1717 100644 --- a/lib/api/client-commands/getLogTypes.js +++ b/lib/api/client-commands/getLogTypes.js @@ -17,6 +17,7 @@ const ClientCommand = require('./_base-command.js'); * @returns {Array} Available log types * @api protocol.sessions * @see sessionLogTypes + * @deprecated In favour of `.logs.getSessionLogTypes()`. */ class GetLogTypes extends ClientCommand { get returnsFullResultObject() { diff --git a/lib/api/client-commands/isLogAvailable.js b/lib/api/client-commands/isLogAvailable.js index ab4668e2bf..664c4a026c 100644 --- a/lib/api/client-commands/isLogAvailable.js +++ b/lib/api/client-commands/isLogAvailable.js @@ -17,6 +17,7 @@ const ClientCommand = require('./_base-command.js'); * @param {function} callback Callback function which is called with the result value. * @api protocol.sessions * @see getLogTypes + * @deprecated In favour of `.logs.isSessionLogAvailable()`. */ class IsLogAvailable extends ClientCommand { performAction(actionCallback) { diff --git a/lib/api/client-commands/captureBrowserConsoleLogs.js b/lib/api/client-commands/logs/captureBrowserConsoleLogs.js similarity index 90% rename from lib/api/client-commands/captureBrowserConsoleLogs.js rename to lib/api/client-commands/logs/captureBrowserConsoleLogs.js index df9344b999..aea9312591 100644 --- a/lib/api/client-commands/captureBrowserConsoleLogs.js +++ b/lib/api/client-commands/logs/captureBrowserConsoleLogs.js @@ -1,5 +1,5 @@ -const ClientCommand = require('./_base-command.js'); -const {Logger} = require('../../utils'); +const ClientCommand = require('../_base-command.js'); +const {Logger} = require('../../../utils'); /** * Listen to the `console` events (ex. `console.log` event) and register callback to process the same. @@ -26,9 +26,11 @@ const {Logger} = require('../../utils'); * @moreinfo nightwatchjs.org/guide/running-tests/capture-console-messages.html */ class StartCapturingLogs extends ClientCommand { + static get namespacedAliases() { + return 'captureBrowserConsoleLogs'; + } performAction(callback) { - if (!this.api.isChrome() && !this.api.isEdge()) { const error = new Error('The command .captureBrowserConsoleLogs() is only supported in Chrome and Edge drivers'); Logger.error(error); diff --git a/lib/api/client-commands/captureBrowserExceptions.js b/lib/api/client-commands/logs/captureBrowserExceptions.js similarity index 91% rename from lib/api/client-commands/captureBrowserExceptions.js rename to lib/api/client-commands/logs/captureBrowserExceptions.js index f7f6a2c556..39adb9fe1c 100644 --- a/lib/api/client-commands/captureBrowserExceptions.js +++ b/lib/api/client-commands/logs/captureBrowserExceptions.js @@ -1,5 +1,5 @@ -const ClientCommand = require('./_base-command.js'); -const {Logger} = require('../../utils'); +const ClientCommand = require('../_base-command.js'); +const {Logger} = require('../../../utils'); /** * Catch the JavaScript exceptions thrown in the browser. @@ -30,9 +30,11 @@ const {Logger} = require('../../utils'); * @moreinfo nightwatchjs.org/guide/running-tests/catch-js-exceptions.html */ class CatchJsExceptions extends ClientCommand { + static get namespacedAliases() { + return 'captureBrowserExceptions'; + } performAction(callback) { - if (!this.api.isChrome() && !this.api.isEdge()) { const error = new Error('The command .captureBrowserExceptions() is only supported in Chrome and Edge drivers'); Logger.error(error); diff --git a/lib/api/client-commands/logs/getSessionLog.js b/lib/api/client-commands/logs/getSessionLog.js new file mode 100644 index 0000000000..a22f9f94ec --- /dev/null +++ b/lib/api/client-commands/logs/getSessionLog.js @@ -0,0 +1,54 @@ +const ClientCommand = require('../_base-command.js'); + +/** + * Gets a log from Selenium. + * + * @example + * describe('get log from Selenium', function() { + * it('get browser log (default)', function(browser) { + * browser.logs.getSessionLog(function(result) { + * const logEntriesArray = result.value; + * console.log('Log length: ' + logEntriesArray.length); + * logEntriesArray.forEach(function(log) { + * console.log('[' + log.level + '] ' + log.timestamp + ' : ' + log.message); + * }); + * }); + * }); + * + * it('get driver log with ES6 async/await', async function(browser) { + * const driverLogAvailable = await browser.logs.isSessionLogAvailable('driver'); + * if (driverLogAvailable) { + * const logEntriesArray = await browser.logs.getSessionLog('driver'); + * logEntriesArray.forEach(function(log) { + * console.log('[' + log.level + '] ' + log.timestamp + ' : ' + log.message); + * }); + * } + * }); + * }); + * + * @syntax .logs.getSessionLog([typeString], [callback]) + * @method logs.getSessionLog + * @param {string} typeString Log type to request. Default: 'browser'. Use `.logs.getLogTypes()` command to get all available log types. + * @param {function} [callback] Callback function which is called with the result value. + * @returns {Array} An array of log Entry objects with properties as defined [here](https://www.selenium.dev/selenium/docs/api/javascript/module/selenium-webdriver/lib/logging_exports_Entry.html) (see Instance Properties). + * @see logs.getSessionLogTypes + * @api protocol.sessions + */ +class GetSessionLog extends ClientCommand { + performAction(callback) { + this.transportActions.getLogContents(this.typeString, callback); + } + + command(typeString = 'browser', callback) { + if (arguments.length === 1 && typeof arguments[0] == 'function') { + callback = arguments[0]; + typeString = 'browser'; + } + + this.typeString = typeString; + + return super.command(callback); + } +} + +module.exports = GetSessionLog; diff --git a/lib/api/client-commands/logs/getSessionLogTypes.js b/lib/api/client-commands/logs/getSessionLogTypes.js new file mode 100644 index 0000000000..c2fd265ea4 --- /dev/null +++ b/lib/api/client-commands/logs/getSessionLogTypes.js @@ -0,0 +1,34 @@ +const ClientCommand = require('../_base-command.js'); + +/** + * Gets the available log types. More info about log types in WebDriver can be found here: https://github.com/SeleniumHQ/selenium/wiki/Logging + * + * @example + * describe('get available log types', function() { + * it('get log types', function(browser) { + * browser.logs.getSessionLogTypes(function(result) { + * const logTypes = result.value; + * console.log('Log types available:', logTypes); + * }); + * }); + * + * it('get log types with ES6 async/await', async function(browser) { + * const logTypes = await browser.logs.getSessionLogTypes(); + * console.log('Log types available:', logTypes); + * }); + * }); + * + * @syntax .logs.getSessionLogTypes([callback]) + * @method logs.getSessionLogTypes + * @param {function} [callback] Callback function which is called with the result value. + * @returns {Array} Available log types. + * @see logs.getSessionLog + * @api protocol.sessions + */ +class GetSessionLogTypes extends ClientCommand { + performAction(callback) { + this.transportActions.getSessionLogTypes(callback); + } +} + +module.exports = GetSessionLogTypes; diff --git a/lib/api/client-commands/logs/isSessionLogAvailable.js b/lib/api/client-commands/logs/isSessionLogAvailable.js new file mode 100644 index 0000000000..163e2e7c00 --- /dev/null +++ b/lib/api/client-commands/logs/isSessionLogAvailable.js @@ -0,0 +1,67 @@ +const ClientCommand = require('../_base-command.js'); + +/** + * Utility command to test if the log type is available. + * + * @example + * describe('test if the log type is available', function() { + * it('test browser log type', function(browser) { + * browser.logs.isSessionLogAvailable('browser', function(result) { + * const isAvailable = result.value; + * if (isAvailable) { + * // do something more in here + * } + * }); + * }); + * + * it('test driver log type with ES6 async/await', async function(browser) { + * const isAvailable = await browser.logs.isSessionLogAvailable('driver'); + * if (isAvailable) { + * // do something more in here + * } + * }); + * }); + * + * @syntax .logs.isSessionLogAvailable([typeString], [callback]) + * @method logs.isSessionLogAvailable + * @param {string} typeString Type of log to test. Default: 'browser'. + * @param {function} [callback] Callback function which is called with the result value. + * @returns {boolean} True if log type is available. + * @see logs.getSessionLogTypes + * @api protocol.sessions + */ +class IsSessionLogAvailable extends ClientCommand { + performAction(callback) { + const {typeString} = this; + + this.transportActions.getSessionLogTypes(function(result) { + if (result.status === 0) { + const types = result.value; + let isAvailable; + + try { + isAvailable = Array.isArray(types) && types.indexOf(typeString) >= 0; + } catch (err) { + isAvailable = false; + } + + result.value = isAvailable; + } + + callback.call(this, result); + }); + } + + command(typeString = 'browser', callback) { + if (arguments.length === 1 && typeof arguments[0] == 'function') { + callback = arguments[0]; + typeString = 'browser'; + } + + this.typeString = typeString; + + return super.command(callback); + } +} + +module.exports = IsSessionLogAvailable; diff --git a/lib/api/protocol/sessionLog.js b/lib/api/protocol/sessionLog.js index 503e245242..b283f356c2 100644 --- a/lib/api/protocol/sessionLog.js +++ b/lib/api/protocol/sessionLog.js @@ -17,6 +17,7 @@ const ProtocolAction = require('./_base-action.js'); * @param {function} callback Callback function which is called with the result value. * @returns {Array} Array of the text entries of the log. * @api protocol.sessions + * @deprecated In favour of `.logs.getSessionLog()`. */ module.exports = class Action extends ProtocolAction { command(typeString, callback) { diff --git a/lib/api/protocol/sessionLogTypes.js b/lib/api/protocol/sessionLogTypes.js index f2826f582b..7ce1aa6a9b 100644 --- a/lib/api/protocol/sessionLogTypes.js +++ b/lib/api/protocol/sessionLogTypes.js @@ -12,6 +12,7 @@ const ProtocolAction = require('./_base-action.js'); * * @param {function} callback Callback function which is called with the result value. * @api protocol.sessions + * @deprecated In favour of `.logs.getSessionLogTypes()`. */ module.exports = class Action extends ProtocolAction { command(callback) { diff --git a/test/src/api/commands/client/testCaptureConsoleLogs.js b/test/src/api/commands/logs/testCaptureBrowserConsoleLogs.js similarity index 72% rename from test/src/api/commands/client/testCaptureConsoleLogs.js rename to test/src/api/commands/logs/testCaptureBrowserConsoleLogs.js index 90173e4b15..434181ac39 100644 --- a/test/src/api/commands/client/testCaptureConsoleLogs.js +++ b/test/src/api/commands/logs/testCaptureBrowserConsoleLogs.js @@ -19,7 +19,6 @@ describe('.captureBrowserConsoleLogs()', function () { }); it('browser.captureBrowserConsoleLogs()', function (done) { - MockServer.addMock({ url: '/session', response: { @@ -67,8 +66,54 @@ describe('.captureBrowserConsoleLogs()', function () { }); }); - it('throws error without callback', function (done) { + it('browser.logs.captureBrowserConsoleLogs()', function (done) { + MockServer.addMock({ + url: '/session', + response: { + value: { + sessionId: '13521-10219-202', + capabilities: { + browserName: 'chrome', + browserVersion: '92.0' + } + } + }, + method: 'POST', + statusCode: 201 + }, true); + + Nightwatch.initW3CClient({ + desiredCapabilities: { + browserName: 'chrome', + 'goog:chromeOptions': {} + }, + output: process.env.VERBOSE === '1', + silent: false + }).then(client => { + let expectedCdpConnection; + let expectedUserCallback; + + cdp.resetConnection(); + client.transport.driver.createCDPConnection = function() { + return Promise.resolve(); + }; + client.transport.driver.onLogEvent = (cdpConnection, userCallback) => { + expectedCdpConnection = cdpConnection; + expectedUserCallback = userCallback; + }; + //eslint-disable-next-line + const userCallback = (event) => {console.log(event)}; + client.api.logs.captureBrowserConsoleLogs(userCallback, function () { + assert.strictEqual(expectedCdpConnection, undefined); // cdpConnection is mocked + assert.strictEqual(expectedUserCallback, userCallback); + }); + + client.start(done); + }); + }); + + it('throws error without callback', function (done) { MockServer.addMock({ url: '/session', response: { @@ -119,5 +164,4 @@ describe('.captureBrowserConsoleLogs()', function () { client.start(done); }); }); - }); diff --git a/test/src/api/commands/client/testCaptureBrowserExceptions.js b/test/src/api/commands/logs/testCaptureBrowserExceptions.js similarity index 72% rename from test/src/api/commands/client/testCaptureBrowserExceptions.js rename to test/src/api/commands/logs/testCaptureBrowserExceptions.js index 44de217440..35aea3b03c 100644 --- a/test/src/api/commands/client/testCaptureBrowserExceptions.js +++ b/test/src/api/commands/logs/testCaptureBrowserExceptions.js @@ -19,7 +19,6 @@ describe('.captureBrowserExceptions()', function () { }); it('browser.captureBrowserExceptions(callback)', function (done) { - MockServer.addMock({ url: '/session', response: { @@ -67,8 +66,54 @@ describe('.captureBrowserExceptions()', function () { }); }); - it('throws error without callback', function (done) { + it('browser.logs.captureBrowserExceptions(callback)', function (done) { + MockServer.addMock({ + url: '/session', + response: { + value: { + sessionId: '13521-10219-202', + capabilities: { + browserName: 'chrome', + browserVersion: '92.0' + } + } + }, + method: 'POST', + statusCode: 201 + }, true); + + Nightwatch.initW3CClient({ + desiredCapabilities: { + browserName: 'chrome', + 'goog:chromeOptions': {} + }, + output: process.env.VERBOSE === '1', + silent: false + }).then(client => { + let expectedCdpConnection; + let expectedUserCallback; + + cdp.resetConnection(); + client.transport.driver.createCDPConnection = function() { + return Promise.resolve(); + }; + client.transport.driver.onLogException = (cdpConnection, userCallback) => { + expectedCdpConnection = cdpConnection; + expectedUserCallback = userCallback; + }; + //eslint-disable-next-line + const userCallback = (event) => {console.log(event)}; + client.api.logs.captureBrowserExceptions(userCallback, function () { + assert.strictEqual(expectedCdpConnection, undefined); // cdpConnection is mocked + assert.strictEqual(expectedUserCallback, userCallback); + }); + + client.start(done); + }); + }); + + it('throws error without callback', function (done) { MockServer.addMock({ url: '/session', response: { @@ -119,5 +164,4 @@ describe('.captureBrowserExceptions()', function () { client.start(done); }); }); - }); \ No newline at end of file diff --git a/test/src/api/commands/logs/testGetLog.js b/test/src/api/commands/logs/testGetLog.js index 88cb153cab..d36df50e7e 100644 --- a/test/src/api/commands/logs/testGetLog.js +++ b/test/src/api/commands/logs/testGetLog.js @@ -1,4 +1,5 @@ const assert = require('assert'); +const MockServer = require('../../../../lib/mockserver.js'); const CommandGlobals = require('../../../../lib/globals/commands.js'); describe('getLog', function() { @@ -10,6 +11,100 @@ describe('getLog', function() { CommandGlobals.afterEach.call(this, done); }); + it('client.logs.getSessionLog()', function(done) { + MockServer.addMock({ + url: '/wd/hub/session/1352110219202/se/log', + postdata: { + type: 'driver' + }, + method: 'POST', + response: JSON.stringify({ + status: 0, + value: [ + {level: 'INFO', timestamp: 534557932, message: 'Driver log 1'}, + {level: 650, timestamp: 534563132, message: 'Driver log 2'} + ] + }) + }, true); + + let logsReceived; + const api = this.client.api; + + this.client.api.logs.getSessionLog('driver', function(result) { + logsReceived = result.value; + + assert.strictEqual(this, api); + }); + + this.client.start(function(err) { + try { + assert.strictEqual(err, undefined); + + assert.strictEqual(Array.isArray(logsReceived), true, 'result is array'); + assert.strictEqual(logsReceived.length, 2); + assert.strictEqual(logsReceived[0].level.name, 'INFO'); + assert.strictEqual(logsReceived[0].level.value, 800); + assert.strictEqual(logsReceived[1].level.name, 'FINE'); + assert.strictEqual(logsReceived[1].level.value, 500); + assert.strictEqual(logsReceived[0].message, 'Driver log 1'); + assert.strictEqual(logsReceived[1].message, 'Driver log 2'); + + done(); + } catch (e) { + done(e); + } + }); + }); + + it('client.logs.getSessionLog() implicit', function(done) { + let logsReceived; + this.client.api.logs.getSessionLog(function(result) { + logsReceived = result.value; + }); + + this.client.start(function(err) { + try { + assert.strictEqual(err, undefined); + assert.strictEqual(logsReceived.length, 2); + assert.strictEqual(Array.isArray(logsReceived), true, 'result is array'); + assert.strictEqual(logsReceived[0].message, 'Test log'); + + done(); + } catch (e) { + done(e); + } + }); + }); + + it('client.logs.getSessionLog() with callback rejecting a Promise', function() { + this.client.api.logs.getSessionLog('browser', function(result) { + return new Promise((resolve, reject) => { + reject(new Error('test error')); + }); + }); + + return this.client.start(function(err) { + assert.ok(err instanceof Error); + assert.strictEqual(err.message, 'Error while running "logs.getSessionLog" command: test error'); + }); + }); + + it('client.logs.getSessionLog() with callback returning a Promise', function() { + let logsResult; + this.client.api.logs.getSessionLog('browser', function(result) { + logsResult = result.value; + + return new Promise((resolve) => { + resolve(); + }); + }); + + return this.client.start(function() { + assert.strictEqual(Array.isArray(logsResult), true, 'result is array'); + assert.strictEqual(logsResult.length, 2); + }); + }); + it('client.getLog()', function(done) { const api = this.client.api; this.client.api.getLog('browser', function(result) { diff --git a/test/src/api/commands/element/testGetLogTypes.js b/test/src/api/commands/logs/testGetLogTypes.js similarity index 50% rename from test/src/api/commands/element/testGetLogTypes.js rename to test/src/api/commands/logs/testGetLogTypes.js index 3e17ce0265..1ccc2bc917 100644 --- a/test/src/api/commands/element/testGetLogTypes.js +++ b/test/src/api/commands/logs/testGetLogTypes.js @@ -20,16 +20,27 @@ describe('getLogTypes', function () { status: 0, value: ['browser', 'har'] }) - }); + }, true, true); const api = this.client.api; - this.client.api.getLogTypes(function callback(result) { - assert.strictEqual(this, api); - assert.ok(Array.isArray(result)); - assert.strictEqual(result.length, 2); - assert.strictEqual(result[0], 'browser'); - assert.strictEqual(result[1], 'har'); - }); + + this.client.api + .getLogTypes(function callback(result) { + assert.strictEqual(this, api); + assert.ok(Array.isArray(result)); + assert.strictEqual(result.length, 2); + assert.strictEqual(result[0], 'browser'); + assert.strictEqual(result[1], 'har'); + }) + .logs.getSessionLogTypes(function callback(result) { + const availableLogTypes = result.value; + + assert.strictEqual(this, api); + assert.ok(Array.isArray(availableLogTypes)); + assert.strictEqual(availableLogTypes.length, 2); + assert.strictEqual(availableLogTypes[0], 'browser'); + assert.strictEqual(availableLogTypes[1], 'har'); + }); this.client.start(done); }); diff --git a/test/src/api/commands/logs/testIsLogAvailable.js b/test/src/api/commands/logs/testIsLogAvailable.js index b6eb1adda9..f95c584f56 100644 --- a/test/src/api/commands/logs/testIsLogAvailable.js +++ b/test/src/api/commands/logs/testIsLogAvailable.js @@ -18,6 +18,64 @@ describe('isLogAvailable', function () { CommandGlobals.afterEach.call(this, done); }); + it('client.logs.isSessionLogAvailable()', function (done) { + MockServer.addMock({ + url: '/wd/hub/session/1352110219202/se/log/types', + method: 'GET', + response: JSON.stringify({ + sessionId: '1352110219202', + status: 0, + value: ['browser', 'har'] + }) + }); + + const api = this.client.api; + + this.client.api + .logs.isSessionLogAvailable('unknown', function callback(result) { + const isAvailable = result.value; + + assert.strictEqual(this, api); + assert.strictEqual(isAvailable, false); + }) + .logs.isSessionLogAvailable('browser', function callback(result) { + const isAvailable = result.value; + + assert.strictEqual(typeof isAvailable, 'boolean'); + assert.strictEqual(isAvailable, true); + }); + + this.client.start(done); + }); + + it('client.logs.isSessionLogAvailable() failure', function (done) { + MockServer.addMock({ + url: '/wd/hub/session/1352110219202/se/log/types', + method: 'GET', + response: JSON.stringify({ + sessionId: '1352110219202', + status: 0, + value: {'message': 'Session not started or terminated'} + }) + }); + + this.client.api + .logs.isSessionLogAvailable('unknown', function callback(result) { + const isAvailable = result.value; + + assert.strictEqual(typeof isAvailable === 'boolean', true); + assert.strictEqual(isAvailable, false); + }) + .logs.isSessionLogAvailable('browser', function callback(result) { + const isAvailable = result.value; + + assert.strictEqual(typeof isAvailable === 'boolean', true); + assert.strictEqual(isAvailable, false); + }); + + this.client.start(done); + }); + it('client.isLogAvailable()', function (done) { MockServer.addMock({ url: '/wd/hub/session/1352110219202/se/log/types', diff --git a/types/index.d.ts b/types/index.d.ts index ce2c48e2da..b41610774f 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -514,6 +514,7 @@ export interface NamespacedApi { cookies: CookiesNsCommands; alerts: AlertsNsCommands; document: DocumentNsCommands; + logs: LogsNsCommands; window: WindowNsCommands; firefox: FirefoxNsCommands; network: NetworkNsCommands; @@ -1519,69 +1520,9 @@ export interface ChromiumClientCommands { setNetworkConditions: NetworkNsCommands['setConditions']; - /** - * Listen to the `console` events (ex. `console.log` event) and - * register callback to process the same. - * - * @example - * describe('capture console events', function() { - * it('captures and logs console.log event', function() { - * browser - * .captureBrowserConsoleLogs((event) => { - * console.log(event.type, event.timestamp, event.args[0].value); - * }) - * .navigateTo('https://www.google.com') - * .executeScript(function() { - * console.log('here'); - * }, []); - * }); - * }); - * - * @see https://nightwatchjs.org/guide/running-tests/capture-console-messages.html - */ - captureBrowserConsoleLogs( - onEventCallback: ( - event: Pick< - Protocol.Runtime.ConsoleAPICalledEvent, - 'type' | 'timestamp' | 'args' - > - ) => void, - callback?: ( - this: NightwatchAPI, - result: NightwatchCallbackResult - ) => void - ): Awaitable; + captureBrowserConsoleLogs: LogsNsCommands['captureBrowserConsoleLogs']; - /** - * Catch the JavaScript exceptions thrown in the browser. - * - * @example - * describe('catch browser exceptions', function() { - * it('captures the js exceptions thrown in the browser', async function() { - * await browser.captureBrowserExceptions((event) => { - * console.log('>>> Exception:', event); - * }); - * - * await browser.navigateTo('https://duckduckgo.com/'); - * - * const searchBoxElement = await browser.findElement('input[name=q]'); - * await browser.executeScript(function(_searchBoxElement) { - * _searchBoxElement.setAttribute('onclick', 'throw new Error("Hello world!")'); - * }, [searchBoxElement]); - * - * await browser.elementIdClick(searchBoxElement.getId()); - * }); - * }); - * - * @see https://nightwatchjs.org/guide/running-tests/catch-js-exceptions.html - */ - captureBrowserExceptions( - onExceptionCallback: (event: Protocol.Runtime.ExceptionThrownEvent) => void, - callback?: ( - this: NightwatchAPI, - result: NightwatchCallbackResult - ) => void - ): Awaitable; + captureBrowserExceptions: LogsNsCommands['captureBrowserExceptions']; } export interface ClientCommands extends ChromiumClientCommands { @@ -5419,6 +5360,175 @@ export interface DocumentNsCommands { ): Awaitable, string>; } +export interface LogsNsCommands { + /** + * Gets a log from Selenium. + * + * @example + * describe('get log from Selenium', function() { + * it('get browser log (default)', function(browser) { + * browser.logs.getSessionLog(function(result) { + * if (result.status === 0) { + * const logEntriesArray = result.value; + * console.log('Log length: ' + logEntriesArray.length); + * logEntriesArray.forEach(function(log) { + * console.log('[' + log.level + '] ' + log.timestamp + ' : ' + log.message); + * }); + * } + * }); + * }); + * + * it('get driver log with ES6 async/await', async function(browser) { + * const driverLogAvailable = await browser.logs.isAvailable('driver'); + * if (driverLogAvailable) { + * const logEntriesArray = await browser.logs.getSessionLog('driver'); + * logEntriesArray.forEach(function(log) { + * console.log('[' + log.level + '] ' + log.timestamp + ' : ' + log.message); + * }); + * } + * }); + * }); + * + * @see https://nightwatchjs.org/api/logs/getSessionLog.html + */ + getSessionLog( + callback?: (this: NightwatchAPI, result: NightwatchCallbackResult) => void + ): Awaitable, NightwatchLogEntry[]>; + getSessionLog( + typeString: NightwatchLogTypes, + callback?: (this: NightwatchAPI, result: NightwatchCallbackResult) => void + ): Awaitable, NightwatchLogEntry[]>; + + /** + * Gets the available log types. More info about log types in WebDriver can be found here: https://github.com/SeleniumHQ/selenium/wiki/Logging + * + * @example + * describe('get available log types', function() { + * it('get log types', function(browser) { + * browser.logs.getSessionLogTypes(function(result) { + * if (result.status === 0) { + * const logTypes = result.value; + * console.log('Log types available:', logTypes); + * } + * }); + * }); + * + * it('get log types with ES6 async/await', async function(browser) { + * const logTypes = await browser.logs.getSessionLogTypes(); + * console.log('Log types available:', logTypes); + * }); + * }); + * + * @see https://nightwatchjs.org/api/logs/getSessionLogTypes.html + */ + getSessionLogTypes( + callback?: ( + this: NightwatchAPI, + result: NightwatchCallbackResult + ) => void + ): Awaitable< + IfUnknown, + NightwatchLogTypes[] + >; + + /** + * Utility command to test if the log type is available. + * + * @example + * describe('test if the log type is available', function() { + * it('test browser log type', function(browser) { + * browser.logs.isSessionLogAvailable('browser', function(result) { + * if (result.status === 0) { + * const isAvailable = result.value; + * if (isAvailable) { + * // do something more in here + * } + * } + * }); + * }); + * + * it('test driver log type with ES6 async/await', async function(browser) { + * const isAvailable = await browser.logs.isSessionLogAvailable('driver'); + * if (isAvailable) { + * // do something more in here + * } + * }); + * }); + * + * @see https://nightwatchjs.org/api/logs/isSessionLogAvailable.html + */ + isSessionLogAvailable( + callback?: (this: NightwatchAPI, result: NightwatchCallbackResult) => void + ): Awaitable, boolean>; + isSessionLogAvailable( + typeString: NightwatchLogTypes, + callback?: (this: NightwatchAPI, result: NightwatchCallbackResult) => void + ): Awaitable, boolean>; + + /** + * Listen to the `console` events (ex. `console.log` event) and + * register callback to process the same. + * + * @example + * describe('capture console events', function() { + * it('captures and logs console.log event', function() { + * browser + * .captureBrowserConsoleLogs((event) => { + * console.log(event.type, event.timestamp, event.args[0].value); + * }) + * .navigateTo('https://www.google.com') + * .executeScript(function() { + * console.log('here'); + * }, []); + * }); + * }); + * + * @see https://nightwatchjs.org/guide/running-tests/capture-console-messages.html + */ + captureBrowserConsoleLogs( + onEventCallback: ( + event: Pick< + Protocol.Runtime.ConsoleAPICalledEvent, + 'type' | 'timestamp' | 'args' + > + ) => void, + callback?: ( + this: NightwatchAPI, + result: NightwatchCallbackResult + ) => void + ): Awaitable, null>; + + /** + * Catch the JavaScript exceptions thrown in the browser. + * + * @example + * describe('catch browser exceptions', function() { + * it('captures the js exceptions thrown in the browser', async function() { + * await browser.captureBrowserExceptions((event) => { + * console.log('>>> Exception:', event); + * }); + * + * await browser.navigateTo('https://duckduckgo.com/'); + * + * const searchBoxElement = await browser.findElement('input[name=q]'); + * await browser.executeScript(function(_searchBoxElement) { + * _searchBoxElement.setAttribute('onclick', 'throw new Error("Hello world!")'); + * }, [searchBoxElement]); + * + * await browser.elementIdClick(searchBoxElement.getId()); + * }); + * }); + * + * @see https://nightwatchjs.org/guide/running-tests/catch-js-exceptions.html + */ + captureBrowserExceptions( + onExceptionCallback: (event: Protocol.Runtime.ExceptionThrownEvent) => void, + callback?: ( + this: NightwatchAPI, + result: NightwatchCallbackResult + ) => void + ): Awaitable, null>; +} export interface WindowNsCommands { /** * Close the current window or tab. This can be useful when you're working with multiple windows/tabs open (e.g. an OAuth login). diff --git a/types/tests/chromiumClientCommands.test-d.ts b/types/tests/chromiumClientCommands.test-d.ts index a0ec87531f..95c0cfa2ab 100644 --- a/types/tests/chromiumClientCommands.test-d.ts +++ b/types/tests/chromiumClientCommands.test-d.ts @@ -558,6 +558,17 @@ describe('capture console events', function () { }, []); }); + it('captures and logs console.log event using logs ns', function () { + browser + .logs.captureBrowserConsoleLogs((event) => { + console.log(event.type, event.timestamp, event.args[0].value); + }) + .navigateTo('https://www.google.com') + .executeScript(function () { + console.log('here'); + }, []); + }); + it('tests different ways of using captureBrowserConsoleLogs', () => { // with all parameters browser.captureBrowserConsoleLogs( @@ -604,6 +615,24 @@ describe('catch browser exceptions', function () { await browser.elementIdClick(searchBoxElement.getId()); }); + it('captures the js exceptions thrown in the browser ', async function () { + await browser + .logs.captureBrowserExceptions((event) => { + console.log('>>> Exception:', event); + }) + .navigateTo('https://duckduckgo.com/'); + + const searchBoxElement = await browser.findElement('input[name=q]'); + await browser.executeScript( + function (_searchBoxElement) { + expectError(_searchBoxElement.setAttribute('onclick', 'throw new Error("Hello world!")')) + }, + [searchBoxElement] + ); + + await browser.elementIdClick(searchBoxElement.getId()); + }); + it('tests different ways of using captureBrowserExceptions', () => { // with all parameters browser.captureBrowserExceptions( diff --git a/types/tests/namespaceCommands.test-d.ts b/types/tests/namespaceCommands.test-d.ts new file mode 100644 index 0000000000..97bac91122 --- /dev/null +++ b/types/tests/namespaceCommands.test-d.ts @@ -0,0 +1,90 @@ +import { expectAssignable, expectType } from 'tsd'; +import { NightwatchAPI, NightwatchLogEntry, NightwatchLogTypes } from '..'; + + +// +// .logs.getSessionLog +// +describe('get log from Selenium', function() { + it('get browser log (default)', function(browser) { + const result = browser.logs.getSessionLog(function(result) { + expectType(this); + if (result.status === 0) { + const logEntriesArray = result.value; + expectType(logEntriesArray); + } + }); + expectAssignable(result); + + browser.logs.getSessionLog('client', function(result) { + expectType(this); + if (result.status === 0) { + const logEntriesArray = result.value; + expectType(logEntriesArray); + } + }); + }); + + it('get driver log with ES6 async/await', async function(browser) { + const driverLogAvailable = await browser.logs.isSessionLogAvailable('driver'); + expectType(driverLogAvailable); + + if (driverLogAvailable) { + const logEntriesArray = await browser.logs.getSessionLog('driver'); + expectType(logEntriesArray); + } + }); +}); + +// +// .logs.getSessionLogTypes +// +describe('get available log types', function() { + it('get log types', function(browser) { + const result = browser.logs.getSessionLogTypes(function(result) { + expectType(this); + if (result.status === 0) { + const logTypes = result.value; + expectType(logTypes); + } + }); + expectAssignable(result); + }); + + it('get log types with ES6 async/await', async function(browser) { + const logTypes = await browser.logs.getSessionLogTypes(); + expectType(logTypes); + }); +}); + +// +// .logs.isSessionLogAvailable +// +describe('test if the log type is available', function() { + it('test browser log type', function(browser) { + const result = browser.logs.isSessionLogAvailable(function(result) { + expectType(this); + if (result.status === 0) { + const isAvailable = result.value; + expectType(isAvailable); + } + }); + expectAssignable(result); + + browser.logs.isSessionLogAvailable('performance', function(result) { + expectType(this); + if (result.status === 0) { + const isAvailable = result.value; + expectType(isAvailable); + } + }); + }); + + it('test driver log type with ES6 async/await', async function(browser) { + const isAvailable = await browser.logs.isSessionLogAvailable('driver'); + expectType(isAvailable); + if (isAvailable) { + // do something more in here + } + }); +}); From 1c54cab25188b2b7f6cc7672fbbe50b3e215c358 Mon Sep 17 00:00:00 2001 From: David Burns Date: Thu, 17 Aug 2023 15:43:20 +0100 Subject: [PATCH 28/38] Update Selenium to 4.11 (#3882) * Update Selenium to 4.11 * fix safari driver tests --------- Co-authored-by: Ravi Sawlani --- package-lock.json | 14 +++++----- package.json | 2 +- test/src/service-builders/testSafariDriver.js | 26 +++++++++---------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5f4d6210e9..50dbc3f77f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,7 +41,7 @@ "open": "8.4.0", "ora": "5.4.1", "piscina": "^3.2.0", - "selenium-webdriver": "~4.10.0", + "selenium-webdriver": "~4.11.0", "semver": "7.5.2", "stacktrace-parser": "0.1.10", "strip-ansi": "6.0.1", @@ -7545,9 +7545,9 @@ "dev": true }, "node_modules/selenium-webdriver": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.10.0.tgz", - "integrity": "sha512-hSQPw6jgc+ej/UEcdQPG/iBwwMeCEgZr9HByY/J8ToyXztEqXzU9aLsIyrlj1BywBcStO4JQK/zMUWWrV8+riA==", + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.11.1.tgz", + "integrity": "sha512-bvrnr3UZlLScErOmn8gV6cqc+1PYDHn0575CxUR2U14fMWt7OKxSy0lAThhZq4sq4d1HqP8ebz11oiHSlAQ2WA==", "dependencies": { "jszip": "^3.10.1", "tmp": "^0.2.1", @@ -14695,9 +14695,9 @@ "dev": true }, "selenium-webdriver": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.10.0.tgz", - "integrity": "sha512-hSQPw6jgc+ej/UEcdQPG/iBwwMeCEgZr9HByY/J8ToyXztEqXzU9aLsIyrlj1BywBcStO4JQK/zMUWWrV8+riA==", + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.11.1.tgz", + "integrity": "sha512-bvrnr3UZlLScErOmn8gV6cqc+1PYDHn0575CxUR2U14fMWt7OKxSy0lAThhZq4sq4d1HqP8ebz11oiHSlAQ2WA==", "requires": { "jszip": "^3.10.1", "tmp": "^0.2.1", diff --git a/package.json b/package.json index 3483c24158..c0c959b46c 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "open": "8.4.0", "ora": "5.4.1", "piscina": "^3.2.0", - "selenium-webdriver": "~4.10.0", + "selenium-webdriver": "~4.11.0", "semver": "7.5.2", "stacktrace-parser": "0.1.10", "strip-ansi": "6.0.1", diff --git a/test/src/service-builders/testSafariDriver.js b/test/src/service-builders/testSafariDriver.js index e53e224d18..2604b2291e 100644 --- a/test/src/service-builders/testSafariDriver.js +++ b/test/src/service-builders/testSafariDriver.js @@ -94,9 +94,9 @@ describe('SafariDriver Transport Tests', function () { }, async start() { - return 'http://localhost' + return 'http://localhost'; } - } + }; } } @@ -110,12 +110,12 @@ describe('SafariDriver Transport Tests', function () { mockExecutor({ sessionId: '111', getId() { - return '1111' + return '1111'; }, getCapabilities() { return { getPlatform() { - return 'MAC' + return 'MAC'; }, getBrowserName() { return 'safari'; @@ -129,7 +129,7 @@ describe('SafariDriver Transport Tests', function () { keys() { return new Map(); } - } + }; } }); @@ -198,7 +198,7 @@ describe('SafariDriver Transport Tests', function () { session, serverPath, serverPort - } + }; } it('test create session with safari driver', async function() { @@ -264,7 +264,7 @@ describe('SafariDriver Transport Tests', function () { it('session create should throw error after max retryAttempts', function() { - let testsPath = [ + const testsPath = [ path.join(__dirname, '../../sampletests/async') ]; @@ -272,7 +272,7 @@ describe('SafariDriver Transport Tests', function () { url: '/session', statusCode: 500, postdata: JSON.stringify({ - 'capabilities': {'firstMatch': [{}], 'alwaysMatch': {'browserName': 'safari'}} + 'capabilities': {'firstMatch': [{}], 'alwaysMatch': {'browserName': 'safari', 'safari:options': {}}} }), response: JSON.stringify({ value: { @@ -283,7 +283,7 @@ describe('SafariDriver Transport Tests', function () { times: 2 }); - let globals = { + const globals = { reporter(results) { const sep = path.sep; assert.strictEqual(results.errors, 1); @@ -314,7 +314,7 @@ describe('SafariDriver Transport Tests', function () { }); it('session create should retry on internal server error (500)', function() { - let testsPath = [ + const testsPath = [ path.join(__dirname, '../../sampletests/async') ]; @@ -322,7 +322,7 @@ describe('SafariDriver Transport Tests', function () { url: '/session', statusCode: 500, postdata: JSON.stringify({ - 'capabilities': {'firstMatch': [{}], 'alwaysMatch': {'browserName': 'safari'}} + 'capabilities': {'firstMatch': [{}], 'alwaysMatch': {'browserName': 'safari', 'safari:options': {}}} }), response: JSON.stringify({ value: { @@ -337,7 +337,7 @@ describe('SafariDriver Transport Tests', function () { url: '/session', statusCode: 200, postdata: JSON.stringify({ - 'capabilities': {'firstMatch': [{}], 'alwaysMatch': {'browserName': 'safari'}} + 'capabilities': {'firstMatch': [{}], 'alwaysMatch': {'browserName': 'safari', 'safari:options': {}}} }), response: JSON.stringify({ value: { @@ -351,7 +351,7 @@ describe('SafariDriver Transport Tests', function () { times: 1 }); - let globals = { + const globals = { reporter(results) { const sep = path.sep; assert.strictEqual(results.errors, 0); From 0c796df4bed0aa21579fda042858a6107a461ea4 Mon Sep 17 00:00:00 2001 From: Priyansh Garg <39924567+garg3133@users.noreply.github.com> Date: Thu, 17 Aug 2023 20:13:42 +0530 Subject: [PATCH 29/38] Deprecate colors.js module in favour of chalk.js (#3852) --- lib/http/request.js | 2 +- lib/reporter/index.js | 12 +- lib/runner/concurrency/child-process.js | 6 +- lib/runner/concurrency/index.js | 34 ++--- lib/runner/concurrency/worker-task.js | 12 +- .../service-builders/base-service.js | 12 +- lib/utils/beautifyStackTrace.js | 14 +- lib/utils/chalkColors.js | 54 +++++++ lib/utils/colors.js | 133 ------------------ lib/utils/logger/index.js | 70 +++++---- lib/utils/stackTrace.js | 10 +- package-lock.json | 1 + package.json | 1 + test/src/utils/testStackTrace.js | 37 ++--- 14 files changed, 166 insertions(+), 232 deletions(-) create mode 100644 lib/utils/chalkColors.js delete mode 100644 lib/utils/colors.js diff --git a/lib/http/request.js b/lib/http/request.js index 1bc00fe8fa..c03d7f14e8 100644 --- a/lib/http/request.js +++ b/lib/http/request.js @@ -249,7 +249,7 @@ class HttpRequest extends EventEmitter { }); } - const content = ` Request ${Logger.colors.light_cyan([this.reqOptions.method, this.hostname + this.reqOptions.path, retryStr + ' '].join(' '))}`; + const content = ` Request ${[this.reqOptions.method, this.hostname + this.reqOptions.path, retryStr + ' '].join(' ')}`; const paramsStr = this.redact ? '' : params; Logger.request(content, paramsStr); diff --git a/lib/reporter/index.js b/lib/reporter/index.js index a403239824..e004785061 100644 --- a/lib/reporter/index.js +++ b/lib/reporter/index.js @@ -49,7 +49,7 @@ class Reporter extends SimplifiedReporter { get currentTest() { return this.testResults.currentTest; } - + get currentSection() { return this.testResults.currentSection; } @@ -209,8 +209,8 @@ class Reporter extends SimplifiedReporter { stack, beautifiedStack }; - } - + } + if (this.shouldLogCommand(node)) { this.testResults.logCommand({ name: node.fullName, @@ -240,7 +240,7 @@ class Reporter extends SimplifiedReporter { if (!node.parent) { //root node return false; } - + if (node.parent.isRootNode) { return true; } @@ -330,7 +330,7 @@ class Reporter extends SimplifiedReporter { const result = [colors[ok ? 'green': 'red'](Utils.symbols[ok ? 'ok' : 'fail'])]; if (!this.unitTestsMode) { if (isWorker) { - result.push(colors.white(this.settings.testEnv, colors.background.black)); + result.push(colors.bgBlack.white.bold(this.settings.testEnv)); } result.push(colors.cyan('[' + this.suiteName + ']')); @@ -340,7 +340,7 @@ class Reporter extends SimplifiedReporter { result.push(ok ? testName : colors.red(testName)); if (elapsedTime > 20) { - result.push(colors.yellow('(' + Utils.formatElapsedTime(elapsedTime, true) + ')')); + result.push(colors.yellow.bold('(' + Utils.formatElapsedTime(elapsedTime, true) + ')')); } // eslint-disable-next-line no-console diff --git a/lib/runner/concurrency/child-process.js b/lib/runner/concurrency/child-process.js index 5b231ca6ca..4fcf7539ad 100644 --- a/lib/runner/concurrency/child-process.js +++ b/lib/runner/concurrency/child-process.js @@ -37,7 +37,7 @@ class ChildProcess extends EventEmitter { setLabel(label) { this.env_itemKey = label; - this.env_label = this.settings.disable_colors ? ` ${label} ` : Logger.colors.yellow(` ${label} `, Logger.colors.background.black); + this.env_label = this.settings.disable_colors ? ` ${label} ` : Logger.colors.bgBlack.yellow.bold(` ${label} `); return this; } @@ -97,7 +97,7 @@ class ChildProcess extends EventEmitter { childProcessLabel = ' ' + this.environment + ' '; } else { childProcessLabel = ''; - this.env_label = Logger.colors[color_pair[1]](` ${this.environment} `, Logger.colors.background[color_pair[0]]); + this.env_label = Logger.colors[color_pair[0]][color_pair[1]](` ${this.environment} `); } const lines = data.split('\n').map(line => { @@ -150,7 +150,7 @@ class ChildProcess extends EventEmitter { const color_pair = this.availColors[this.index%4]; - this.printLog(' Running: ' + Logger.colors[color_pair[1]](` ${this.env_itemKey} `, Logger.colors.background[color_pair[0]])); + this.printLog(' Running: ' + Logger.colors[color_pair[0]][color_pair[1]](` ${this.env_itemKey} `)); this.child.stdout.on('data', data => { this.writeToStdout(data); diff --git a/lib/runner/concurrency/index.js b/lib/runner/concurrency/index.js index 7a45f88495..1caa4580df 100644 --- a/lib/runner/concurrency/index.js +++ b/lib/runner/concurrency/index.js @@ -47,12 +47,12 @@ class Concurrency extends EventEmitter { createChildProcess(label, args = [], extraArgs = [], index = 0) { this.childProcessOutput[label] = []; const childArgs = args.slice().concat(extraArgs); - + const childProcess = new ChildProcess(label, index, this.childProcessOutput[label], this.settings, childArgs); childProcess.on('message', data => { this.emit('message', data); }); - + return childProcess; } @@ -84,7 +84,7 @@ class Concurrency extends EventEmitter { runChildProcesses(envs, modules) { const availColors = Concurrency.getAvailableColors(); const args = Concurrency.getChildProcessArgs(envs); - + if (this.testWorkersEnabled) { const jobs = []; if (envs.length > 0) { @@ -106,10 +106,10 @@ class Concurrency extends EventEmitter { }); jobs.push(...jobList); } - + return this.runMultipleTestProcess(jobs, args, availColors); } - + return this.runProcessTestEnvironment(envs, args, availColors); } @@ -220,7 +220,7 @@ class Concurrency extends EventEmitter { Promise.allSettled(workerPool.tasks) .then(values => { values.some(({status}) => status === 'rejected') ? reject() : resolve(); - }); + }); }); } @@ -287,7 +287,7 @@ class Concurrency extends EventEmitter { modules.forEach(({module, env}) => { let outputLabel = Utils.getModuleKey(module, this.settings.src_folders, modules); outputLabel = env ? `${env}: ${outputLabel}` : outputLabel; - + const workerArgv = {...this.argv}; workerArgv._source = [module]; workerArgv.env = env; @@ -301,21 +301,21 @@ class Concurrency extends EventEmitter { }); }); - + return new Promise((resolve, reject) => { Promise.allSettled(workerPool.tasks) .then(values => { values.some(({status}) => status === 'rejected') ? reject() : resolve(); - }); + }); }); } /** - * - * @param {Array} args - * @param {Object} settings - * @param {Number} maxWorkerCount + * + * @param {Array} args + * @param {Object} settings + * @param {Number} maxWorkerCount */ setupWorkerPool(args, settings, maxWorkerCount) { const workerPool = new WorkerPool(args, settings, maxWorkerCount); @@ -407,10 +407,10 @@ class Concurrency extends EventEmitter { static getAvailableColors() { const availColorPairs = [ - ['red', 'light_gray'], - ['green', 'black'], - ['blue', 'light_gray'], - ['magenta', 'light_gray'] + ['bgRed', 'white'], + ['bgGreen', 'black'], + ['bgBlue', 'white'], + ['bgMagenta', 'white'] ]; let currentIndex = availColorPairs.length; let temporaryValue; diff --git a/lib/runner/concurrency/worker-task.js b/lib/runner/concurrency/worker-task.js index f752b3946b..94aefc6e58 100644 --- a/lib/runner/concurrency/worker-task.js +++ b/lib/runner/concurrency/worker-task.js @@ -37,14 +37,14 @@ class WorkerTask extends EventEmitter { } setlabel(colorPair) { - this.task_label = this.settings.disable_colors ? ` ${this.label} ` : Logger.colors[colorPair[1]](` ${this.label} `, Logger.colors.background[colorPair[0]]); + this.task_label = this.settings.disable_colors ? ` ${this.label} ` : Logger.colors[colorPair[0]][colorPair[1]](` ${this.label} `); } writeToStdOut(data) { let output = ''; if (WorkerTask.prevIndex !== this.index) { - WorkerTask.prevIndex = this.index; + WorkerTask.prevIndex = this.index; if (this.settings.live_output) { output += '\n'; } @@ -68,9 +68,9 @@ class WorkerTask extends EventEmitter { this.availColors = colors; const colorPair = this.availColors[this.index%4]; this.setlabel(colorPair); - - this.printLog('Running '+ Logger.colors[colorPair[1]](` ${this.task_label} `, Logger.colors.background[colorPair[0]])); - + + this.printLog('Running '+ Logger.colors[colorPair[0]][colorPair[1]](` ${this.task_label} `)); + const {port1, port2} = new MessageChannel(); port2.onmessage = ({data: result}) => { if (isString(result)) { @@ -86,7 +86,7 @@ class WorkerTask extends EventEmitter { this.emit('message', result); break; - case 'stdout': + case 'stdout': this.writeToStdOut(result.data); break; } diff --git a/lib/transport/selenium-webdriver/service-builders/base-service.js b/lib/transport/selenium-webdriver/service-builders/base-service.js index fee27a5520..fca9a27829 100644 --- a/lib/transport/selenium-webdriver/service-builders/base-service.js +++ b/lib/transport/selenium-webdriver/service-builders/base-service.js @@ -38,7 +38,7 @@ class BaseService { let binaryMissing = `${this.serviceName} cannot be found in the current project.`; if (this.npmPackageName) { - binaryMissing += '\n\n ' + Logger.colors.yellow(`You can either install ${this.npmPackageName} from NPM with: \n\n npm install ${this.npmPackageName} --save-dev\n\n`) + ' or '; + binaryMissing += '\n\n ' + Logger.colors.yellow.bold(`You can either install ${this.npmPackageName} from NPM with: \n\n npm install ${this.npmPackageName} --save-dev\n\n`) + ' or '; } else { binaryMissing += '\n\n Please '; } @@ -51,7 +51,7 @@ class BaseService { } get errorOutput() { - let errorOut = this.error_out.split('\n'); + const errorOut = this.error_out.split('\n'); return errorOut.reduce(function(prev, message) { if (prev.indexOf(message) < 0) { @@ -148,7 +148,7 @@ class BaseService { this.processExited = true; if (code > 0) { - let err = this.createError(null, code); + const err = this.createError(null, code); err.detailedErr = this.error_out || this.output; } } @@ -182,7 +182,7 @@ class BaseService { message = this.createErrorMessage(code); } - let err = new Error(message); + const err = new Error(message); err.code = code; err.errorOut = this.errorOutput; @@ -308,7 +308,7 @@ class BaseService { this.process.kill(); } catch (err) { Logger.error(err); - + return Promise.reject(err); } } @@ -324,7 +324,7 @@ class BaseService { } getLogPath() { - let {log_path = 'logs'} = this.settings.webdriver; + const {log_path = 'logs'} = this.settings.webdriver; if (log_path === false) { return null; } diff --git a/lib/utils/beautifyStackTrace.js b/lib/utils/beautifyStackTrace.js index d7ef4f1859..a50f0d1099 100644 --- a/lib/utils/beautifyStackTrace.js +++ b/lib/utils/beautifyStackTrace.js @@ -3,12 +3,12 @@ const stackTraceParser = require('stacktrace-parser'); const AssertionError = require('assertion-error'); const {filterStackTrace} = require('./stackTrace.js'); const alwaysDisplayError = require('./alwaysDisplayError.js'); -const {colors} = require('./colors.js'); +const {colors} = require('./chalkColors.js'); /** * Read the User file from the stackTrace and create a string with highlighting the line with error * @param {Error} err - */ + */ function beautifyStackTrace(err, errStackPassed = false, modulepath, cli = true) { if ((err instanceof AssertionError) || alwaysDisplayError(err) || errStackPassed) { try { @@ -20,7 +20,7 @@ function beautifyStackTrace(err, errStackPassed = false, modulepath, cli = true) if (!parsedStack) { parsedStack = parsedStacks[0]; } - + const file = fs.readFileSync(parsedStack.file, 'utf-8'); const errorLinesofFile = file.split(/\r?\n/); @@ -32,11 +32,11 @@ function beautifyStackTrace(err, errStackPassed = false, modulepath, cli = true) const desiredLines = formattedStack.codeSnippet.reduce(function(lines, newLine) { const currentLine = newLine.line_number; if (currentLine === formattedStack.error_line_number) { - lines += '\n ' + colors.light_gray(` ${currentLine} | ${newLine.code} `, colors.background.red); + lines += '\n ' + colors.bgRed.white(` ${currentLine} | ${newLine.code} `); } else if (currentLine <= (formattedStack.error_line_number + 2) && currentLine >= (formattedStack.error_line_number - 2)) { lines += `\n ${currentLine} | ${newLine.code}`; } - + return lines; }, ''); @@ -54,7 +54,7 @@ function beautifyStackTrace(err, errStackPassed = false, modulepath, cli = true) /** * Read the User file from the stackTrace and create a string with highlighting the line with error * @param {Error} err - */ + */ function formatStackTrace(errorLinesofFile, parsedStack) { const result = { @@ -74,7 +74,7 @@ function formatStackTrace(errorLinesofFile, parsedStack) { return result; - + } module.exports = beautifyStackTrace; diff --git a/lib/utils/chalkColors.js b/lib/utils/chalkColors.js new file mode 100644 index 0000000000..94ab50bfe8 --- /dev/null +++ b/lib/utils/chalkColors.js @@ -0,0 +1,54 @@ +const chalk = require('chalk'); + +class ChalkColors { + constructor() { + this.instance = new chalk.Instance(); + this.origLevel = this.instance.level; + + this.loadCustomColors(); // for backward compatibility + + if (process.env.COLORS === '0') { + this.disable(); + } + } + + loadCustomColors() { + const colorsInstance = this.instance; + + // foreground colors + colorsInstance.dark_gray = colorsInstance.black.bold; + colorsInstance.light_blue = colorsInstance.blue.bold; + colorsInstance.light_green = colorsInstance.green.bold; + colorsInstance.light_cyan = colorsInstance.cyan.bold; + colorsInstance.light_red = colorsInstance.red.bold; + colorsInstance.light_purple = colorsInstance.magenta.bold; + colorsInstance.light_gray = colorsInstance.white; + + colorsInstance.purple = colorsInstance.magenta; + colorsInstance.brown = colorsInstance.yellow; + colorsInstance.stack_trace = colorsInstance.gray; + } + + get colors() { + return this.instance; + } + + get colorsEnabled() { + return this.instance.level !== 0; + } + + disable() { + this.prevLevel = this.instance.level; + this.instance.level = 0; + } + + enable() { + this.instance.level = this.prevLevel; + } + + reset() { + this.instance.level = this.origLevel; + } +} + +module.exports = new ChalkColors(); diff --git a/lib/utils/colors.js b/lib/utils/colors.js deleted file mode 100644 index 73670f1903..0000000000 --- a/lib/utils/colors.js +++ /dev/null @@ -1,133 +0,0 @@ -const Settings = { - enabled: process.env.COLORS !== '0' -}; - -function Background() { - return this; -} - -function ConsoleColor() { - this.background = new Background(); - - const foregroundColors = { - black: '0;30', - dark_gray: '1;30', - blue: '0;34', - light_blue: '1;34', - green: '0;32', - light_green: '1;32', - cyan: '0;36', - light_cyan: '1;36', - red: '0;31', - light_red: '1;31', - purple: '0;35', - light_purple: '1;35', - brown: '0;33', - yellow: '1;33', - light_gray: '0;37', - white: '1;37', - stack_trace: '0;90' - }; - - const backgroundColors = { - black: '40', - red: '41', - green: '42', - yellow: '43', - blue: '44', - magenta: '45', - cyan: '46', - light_gray: '47' - }; - - Object.keys(foregroundColors).forEach(k => { - ConsoleColor.prototype[k.toLowerCase()] = (text, background) => { - if (!Settings.enabled) { - return text; - } - - let string = `\u{1b}[${foregroundColors[k.toLowerCase()]}m`; - if (background !== undefined) { - string += background(); - } - - string += `${text}\u{1b}[0m`; - - return string; - }; - }); - - Object.keys(backgroundColors).forEach(k => { - Background.prototype[k.toLowerCase()] = (text) => { - return `\u{1b}[${backgroundColors[k.toLowerCase()]}m`; - }; - }); - - return this; -} - -module.exports = new (function() { - let instance; - - const disable = function() { - Settings.enabled = false; - - Object.keys(ConsoleColor.prototype).forEach(function (color) { - ConsoleColor.prototype[color] = function (text) { - return text; - }; - }); - }; - - const enable = function() { - Settings.enabled = true; - }; - - const setup = function() { - instance = new ConsoleColor(); - }; - - const initialize = function() { - if (!Settings.enabled) { - disable(); - } - - setup(); - }; - - //////////////////////////////////////////////////////////// - // Public methods - //////////////////////////////////////////////////////////// - const exported = { - disableColors() { - disable(); - setup(); - }, - disable() { - disable(); - setup(); - }, - enable() { - enable(); - setup(); - } - }; - - Object.defineProperty(exported, 'colors', { - configurable: true, - get: function() { - return instance; - } - }); - - Object.defineProperty(exported, 'colorsEnabled', { - configurable: true, - get: function() { - return Settings.enabled; - } - }); - - initialize(); - - return exported; -}); diff --git a/lib/utils/logger/index.js b/lib/utils/logger/index.js index 965c5af04e..fe310c5b46 100644 --- a/lib/utils/logger/index.js +++ b/lib/utils/logger/index.js @@ -5,7 +5,7 @@ const AssertionError = require('assertion-error'); const lodashEscape = require('lodash.escape'); const LogSettings = require('./log_settings.js'); -const {colors, colorsEnabled, disableColors} = require('../colors.js'); +const chalkColors = require('../chalkColors.js'); const addDetailedError = require('../addDetailedError.js'); @@ -49,7 +49,7 @@ function inspectObject(obj) { return util.inspect(obj, { showHidden: false, depth: 4, - colors: colorsEnabled + colors: chalkColors.colorsEnabled }) .replace(/^\s{2}/gm, ' ') .replace(/^}$/m, ' }'); @@ -62,7 +62,7 @@ function logObject(obj) { function logTimestamp(d) { if (LogSettings.isLogTimestamp()) { - return colors.white(timestamp(d, LogSettings.timestampFormat)); + return chalkColors.colors.white.bold(timestamp(d, LogSettings.timestampFormat)); } return ''; @@ -73,6 +73,7 @@ function logMessage(type, message, args, alwaysShow) { return; } + const colors = chalkColors.colors; let messageStr = ''; let logMethod = 'log'; let prefix; @@ -82,24 +83,28 @@ function logMessage(type, message, args, alwaysShow) { switch (type) { case Severity.ERROR: - prefix = colors.yellow(type, colors.background.black); - messageStr = colors.light_red(message); + prefix = colors.bgBlack.yellow.bold(type); + // eslint-disable-next-line no-control-regex + messageStr = message.match(/\u001b\[.*?m/) ? message : colors.red.bold(message); logMethod = 'error'; break; case Severity.INFO: - prefix = colors.light_purple(type, colors.background.black); - messageStr = colors.light_cyan(message); + prefix = colors.bgBlack.magenta.bold(type); + // eslint-disable-next-line no-control-regex + messageStr = message.match(/\u001b\[.*?m/) ? message : colors.cyan.bold(message); break; case Severity.LOG: - prefix = colors.white(type + ' ', colors.background.black); - messageStr = colors.white(message); + prefix = colors.bgBlack.white.bold(type + ' '); + // eslint-disable-next-line no-control-regex + messageStr = message.match(/\u001b\[.*?m/) ? message : colors.white.bold(message); break; case Severity.WARN: - prefix = colors.light_green(type, colors.background.black); - messageStr = colors.light_green(message); + prefix = colors.bgBlack.green.bold(type); + // eslint-disable-next-line no-control-regex + messageStr = message.match(/\u001b\[.*?m/) ? message : colors.green.bold(message); logMethod = 'warn'; break; } @@ -182,7 +187,8 @@ class Logger { } constructor() { - this.colors = colors; + this.colors = chalkColors.colors; + this.output = []; this.testSectionOutput = []; } @@ -248,8 +254,7 @@ class Logger { } disableColors() { - disableColors(); - this.colors = colors; + chalkColors.disable(); } setHtmlReporterEnabled(value) { @@ -328,7 +333,7 @@ class Logger { getFailedAssertions(assertions, modulepath) { return assertions.reduce((prev, a) => { if (a.failure !== false) { - prev.push(' ' + colors.light_red(`→${this.getErrorContent(a, modulepath)}`)); + prev.push(` ${this.colors.red.bold('→') + this.getErrorContent(a, modulepath)}`); } return prev; @@ -351,20 +356,23 @@ class Logger { const content = []; - let errorTitle = ` ${colors.light_red(errorObj.name)}`; + let errorTitle = ` ${this.colors.light_red(errorObj.name)}`; if (this.isAssertionError(error) || alwaysDisplayError(error)) { - errorTitle = ` ✖${errorTitle}`; + errorTitle = ` ${this.colors.red.bold('✖') + errorTitle}`; } const message = []; if (errorObj.message || errorObj.fullMsg) { - message.push(colors.red(errorObj.message)); + let errorObjMessage = errorObj.message; + // eslint-disable-next-line no-control-regex + errorObjMessage = errorObjMessage.match(/\u001b\[.*?m/) ? errorObjMessage : this.colors.red(errorObjMessage); + message.push(errorObjMessage); if (errorObj.detailedErr) { - message.push(colors.light_green(errorObj.detailedErr)); + message.push(this.colors.light_green(errorObj.detailedErr)); if (errorObj.extraDetail) { - message.push(colors.light_green(errorObj.extraDetail)); + message.push(this.colors.light_green(errorObj.extraDetail)); } } } @@ -375,7 +383,7 @@ class Logger { if (!showStack && errorObj.reportShown) { return ' ' + message.join('\n '); } - + if (!showStack && !this.isAssertionError(error) && !error.help) { return '\n' + boxen(`${message.join('\n')}\n`, {padding: 1, borderColor: 'red'}) + '\n'; } @@ -390,14 +398,14 @@ class Logger { } if (errorObj.help) { - content.push(colors.brown('\n Try fixing by :')); + content.push(this.colors.brown('\n Try fixing by :')); errorObj.help.forEach((step, index) => { - content.push(` ${colors.blue(index+1)}. ${step}`); + content.push(` ${this.colors.blue(index+1)}. ${step}`); }); } - + if (errorObj.link){ - content.push(`\n ${colors.brown('Read More')} : \n ${colors.cyan(errorObj.link)} `); + content.push(`\n ${this.colors.brown('Read More')} : \n ${this.colors.cyan(errorObj.link)} `); } let stack = error.stack || error.stackTrace; @@ -406,20 +414,20 @@ class Logger { const beautified = beautifyStackTrace(stack, true, modulepath); if (beautified) { - content.push(colors.brown('\n Error location:')); + content.push(this.colors.brown('\n Error location:')); content.push(beautified); } - + if (alwaysDisplayError(errorObj)) { - content.push(colors.brown(' Stack Trace :')); - const coloredStack = stack.split('\n').map((line) => colors.stack_trace(line)).join('\n'); + content.push(this.colors.brown(' Stack Trace :')); + const coloredStack = stack.split('\n').map((line) => this.colors.stack_trace(line)).join('\n'); content.push(`${coloredStack}\n`); } } if (content.length === 2) { if (content[0].includes('WebDriverError')) { - return content.join(colors.light_red(':')); + return content.join(this.colors.light_red(':')); } if (content[0].includes('Error') && content[1].includes('Error while')) { @@ -434,7 +442,7 @@ class Logger { formatMessage(msg, ...args) { args = args.map(val => { - return colors.brown(val); + return this.colors.brown(val); }); return util.format(msg, ...args); diff --git a/lib/utils/stackTrace.js b/lib/utils/stackTrace.js index a1314123f5..a12a8b748c 100644 --- a/lib/utils/stackTrace.js +++ b/lib/utils/stackTrace.js @@ -1,11 +1,11 @@ const boxen = require('boxen'); -const {colors} = require('./colors.js'); +const {colors} = require('./chalkColors.js'); const isErrorObject = require('./isErrorObject.js'); const addDetailedError = require('./addDetailedError.js'); const indentRegex = /^/gm; const stackTraceFilter = function (parts) { - let stack = parts.reduce(function(list, line) { + const stack = parts.reduce(function(list, line) { if (contains(line, [ 'node_modules', '(node.js:', @@ -61,13 +61,13 @@ const filterStackTrace = function(stackTrace = '') { }; const showStackTrace = function (stack) { - let parts = stack.split('\n'); - let headline = parts.shift(); + const parts = stack.split('\n'); + const headline = parts.shift(); console.error(colors.red(headline.replace(indentRegex, ' '))); if (parts.length > 0) { - let result = stackTraceFilter(parts); + const result = stackTraceFilter(parts); console.error(colors.stack_trace(result.replace(indentRegex, ' '))); } }; diff --git a/package-lock.json b/package-lock.json index 50dbc3f77f..f8cfbe6ae1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "assertion-error": "1.1.0", "boxen": "5.1.2", "chai-nightwatch": "0.5.3", + "chalk": "^4.1.2", "ci-info": "3.3.0", "cli-table3": "^0.6.3", "devtools-protocol": "^0.0.1140464", diff --git a/package.json b/package.json index c0c959b46c..43ca38a4b3 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "assertion-error": "1.1.0", "boxen": "5.1.2", "chai-nightwatch": "0.5.3", + "chalk": "^4.1.2", "ci-info": "3.3.0", "cli-table3": "^0.6.3", "devtools-protocol": "^0.0.1140464", diff --git a/test/src/utils/testStackTrace.js b/test/src/utils/testStackTrace.js index 857222517f..488091782f 100644 --- a/test/src/utils/testStackTrace.js +++ b/test/src/utils/testStackTrace.js @@ -4,12 +4,15 @@ const AssertionError = require('assertion-error'); const common = require('../../common.js'); const Utils = common.require('utils'); const beautifyStackTrace = common.require('utils/beautifyStackTrace.js'); -const colors = common.require('utils/colors.js'); +const colors = common.require('utils/chalkColors.js'); const {Logger} = common.require('utils'); describe('test stackTrace parse', function() { - before(() => colors.disable()); + before(() => { + colors.colors.level = 3; + colors.disable(); + }); after(() => colors.enable()); it('filterStackTrace', function() { @@ -121,29 +124,29 @@ describe('test stackTrace parse', function() { const errorMessage = Logger.getErrorContent(error); assert.ok(!errorMessage.includes('\t')); - assert.strictEqual(errorMessage, ` ✖ TypeError - Unknown method - - Error location: + assert.strictEqual(errorMessage, ` \x1B[31m\x1B[1m✖\x1B[22m\x1B[39m \x1B[31m\x1B[1mTypeError\x1B[22m\x1B[39m + \x1B[31mUnknown method\x1B[39m +\x1B[33m\x1B[39m +\x1B[33m Error location:\x1B[39m ${errorFilePath}: –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– 2 | it('failure stack trace', function() { 3 | -  4 | browser.url('http://localhost')  + \x1B[41m\x1B[37m 4 | browser.url('http://localhost') \x1B[39m\x1B[49m 5 | .assert.elementPresen('#badElement'); // mispelled API method 6 | }); –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– - Stack Trace : - at DescribeInstance. (${errorFilePath}:${lineNumber}:21) - at Context.call (/Users/BarnOwl/Documents/Projects/Nightwatch-tests/node_modules/nightwatch/lib/testsuite/context.js:430:35) - at TestCase.run (/Users/BarnOwl/Documents/Projects/Nightwatch-tests/node_modules/nightwatch/lib/testsuite/testcase.js:58:31) - at Runnable.__runFn (/Users/BarnOwl/Documents/Projects/Nightwatch-tests/node_modules/nightwatch/lib/testsuite/index.js:669:80) - at Runnable.run (/Users/BarnOwl/Documents/Projects/Nightwatch-tests/node_modules/nightwatch/lib/testsuite/runnable.js:126:21) - at TestSuite.createRunnable (/Users/BarnOwl/Documents/Projects/Nightwatch-tests/node_modules/nightwatch/lib/testsuite/index.js:776:33) - at TestSuite.handleRunnable (/Users/BarnOwl/Documents/Projects/Nightwatch-tests/node_modules/nightwatch/lib/testsuite/index.js:781:33) - at /Users/BarnOwl/Documents/Projects/Nightwatch-tests/node_modules/nightwatch/lib/testsuite/index.js:669:21 - at processTicksAndRejections (node:internal/process/task_queues:96:5) +\x1B[33m Stack Trace :\x1B[39m +\x1B[90m at DescribeInstance. (${errorFilePath}:${lineNumber}:21)\x1B[39m +\x1B[90m at Context.call (/Users/BarnOwl/Documents/Projects/Nightwatch-tests/node_modules/nightwatch/lib/testsuite/context.js:430:35)\x1B[39m +\x1B[90m at TestCase.run (/Users/BarnOwl/Documents/Projects/Nightwatch-tests/node_modules/nightwatch/lib/testsuite/testcase.js:58:31)\x1B[39m +\x1B[90m at Runnable.__runFn (/Users/BarnOwl/Documents/Projects/Nightwatch-tests/node_modules/nightwatch/lib/testsuite/index.js:669:80)\x1B[39m +\x1B[90m at Runnable.run (/Users/BarnOwl/Documents/Projects/Nightwatch-tests/node_modules/nightwatch/lib/testsuite/runnable.js:126:21)\x1B[39m +\x1B[90m at TestSuite.createRunnable (/Users/BarnOwl/Documents/Projects/Nightwatch-tests/node_modules/nightwatch/lib/testsuite/index.js:776:33)\x1B[39m +\x1B[90m at TestSuite.handleRunnable (/Users/BarnOwl/Documents/Projects/Nightwatch-tests/node_modules/nightwatch/lib/testsuite/index.js:781:33)\x1B[39m +\x1B[90m at /Users/BarnOwl/Documents/Projects/Nightwatch-tests/node_modules/nightwatch/lib/testsuite/index.js:669:21\x1B[39m +\x1B[90m at processTicksAndRejections (node:internal/process/task_queues:96:5)\x1B[39m `); }); }); From 2b7c29ef40e4c01d5d0246402b9525811432cdd5 Mon Sep 17 00:00:00 2001 From: AutomatedTester Date: Thu, 17 Aug 2023 15:54:45 +0100 Subject: [PATCH 30/38] 3.1.3 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index f8cfbe6ae1..16b262d3ec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "nightwatch", - "version": "3.1.2", + "version": "3.1.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "nightwatch", - "version": "3.1.2", + "version": "3.1.3", "license": "MIT", "dependencies": { "@nightwatch/chai": "5.0.2", diff --git a/package.json b/package.json index 43ca38a4b3..b904d9bdf4 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nightwatch", "description": "Easy to use Node.js based end-to-end testing solution for web applications using the W3C WebDriver API.", - "version": "3.1.2", + "version": "3.1.3", "author": "Andrei Rusu", "homepage": "https://nightwatchjs.org", "main": "./dist/index.js", From 79367cd719a947392f3cb83e88efe75fc2462407 Mon Sep 17 00:00:00 2001 From: Priyansh Garg <39924567+garg3133@users.noreply.github.com> Date: Tue, 22 Aug 2023 14:10:43 +0530 Subject: [PATCH 31/38] Migrate utils modules to TS. (#3869) --------- Co-authored-by: Ravi Sawlani --- .eslintrc | 28 + ...ddDetailedError.js => addDetailedError.ts} | 19 +- ...sDisplayError.js => alwaysDisplayError.ts} | 4 +- lib/utils/beautifyStackTrace.js | 2 +- lib/utils/{browsername.js => browsername.ts} | 16 +- lib/utils/createPromise.js | 17 - lib/utils/createPromise.ts | 16 + lib/utils/{getFreePort.js => getFreePort.ts} | 21 +- lib/utils/index.js | 11 +- .../{isErrorObject.js => isErrorObject.ts} | 4 +- lib/utils/logger/index.js | 4 +- lib/utils/periodic-promise.js | 2 +- lib/utils/stackTrace.js | 4 +- lib/utils/types/index.ts | 5 + package-lock.json | 518 +++++++++++++++++- package.json | 4 +- 16 files changed, 591 insertions(+), 84 deletions(-) rename lib/utils/{addDetailedError.js => addDetailedError.ts} (85%) rename lib/utils/{alwaysDisplayError.js => alwaysDisplayError.ts} (77%) rename lib/utils/{browsername.js => browsername.ts} (73%) delete mode 100644 lib/utils/createPromise.js create mode 100644 lib/utils/createPromise.ts rename lib/utils/{getFreePort.js => getFreePort.ts} (56%) rename lib/utils/{isErrorObject.js => isErrorObject.ts} (71%) create mode 100644 lib/utils/types/index.ts diff --git a/.eslintrc b/.eslintrc index fb8f2e68f3..08cfe8583f 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,4 +1,5 @@ { + "root": true, "extends": [ "eslint:recommended" ], @@ -13,6 +14,33 @@ "mocha": true, "node": true }, + "overrides": [ + { + "files": [ + "**/*.ts" + ], + "excludedFiles": [ + "test/**/*.ts" + ], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended" + ], + "parser": "@typescript-eslint/parser", + "plugins": [ + "@typescript-eslint" + ], + "parserOptions": { + "ecmaVersion": 2020, + "sourceType": "module", + "ecmaFeatures": { + "jsx": false + }, + "project": "./tsconfig.json" + } + } + ], "rules": { "eqeqeq": [ "error", diff --git a/lib/utils/addDetailedError.js b/lib/utils/addDetailedError.ts similarity index 85% rename from lib/utils/addDetailedError.js rename to lib/utils/addDetailedError.ts index d31983ccac..0977c1ee66 100644 --- a/lib/utils/addDetailedError.js +++ b/lib/utils/addDetailedError.ts @@ -1,9 +1,10 @@ +import {NightwatchError} from './types'; + /** * @method addDetailedError - * @param {Error} err */ -module.exports = function(err) { - let detailedErr; +export = function(err: NightwatchError) { + let detailedErr: string | undefined; if (err instanceof TypeError) { if (err.detailedErr && /browser\..+ is not a function$/.test(err.detailedErr)) { @@ -25,14 +26,14 @@ module.exports = function(err) { detailedErr = ' - writing an ES6 async test case? - keep in mind that commands return a Promise; \n - writing unit tests? - make sure to specify "unit_tests_mode=true" in your config.'; } } else if (err instanceof SyntaxError) { - const stackParts = err.stack.split('SyntaxError:'); - detailedErr = stackParts[0]; - let modulePath = err.stack.split('\n')[0]; - if (modulePath.includes(':')) { + const stackParts = err.stack?.split('SyntaxError:'); + detailedErr = stackParts?.[0]; + let modulePath = err.stack?.split('\n')[0]; + if (modulePath?.includes(':')) { modulePath = modulePath.split(':')[0]; } - if (stackParts[1]) { + if (stackParts?.[1]) { if (detailedErr) { err.stack = ''; } @@ -46,7 +47,7 @@ module.exports = function(err) { detailedErr = header + detailedErr; } - if (modulePath.endsWith('.jsx') || modulePath.endsWith('.tsx')) { + if (modulePath?.endsWith('.jsx') || modulePath?.endsWith('.tsx')) { detailedErr = `\n In order to be able to load JSX files, one of these plugins is needed: - @nightwatch/react - @nightwatch/storybook (only if using Storybook in your project) diff --git a/lib/utils/alwaysDisplayError.js b/lib/utils/alwaysDisplayError.ts similarity index 77% rename from lib/utils/alwaysDisplayError.js rename to lib/utils/alwaysDisplayError.ts index 5d14565524..0f292b24c4 100644 --- a/lib/utils/alwaysDisplayError.js +++ b/lib/utils/alwaysDisplayError.ts @@ -1,5 +1,5 @@ -module.exports = function(err) { +export = function(err: unknown) { return (err instanceof Error) && [ 'TypeError', 'SyntaxError', 'ReferenceError', 'RangeError' ].includes(err.name); -}; \ No newline at end of file +}; diff --git a/lib/utils/beautifyStackTrace.js b/lib/utils/beautifyStackTrace.js index a50f0d1099..98d5f64596 100644 --- a/lib/utils/beautifyStackTrace.js +++ b/lib/utils/beautifyStackTrace.js @@ -2,7 +2,7 @@ const fs = require('fs'); const stackTraceParser = require('stacktrace-parser'); const AssertionError = require('assertion-error'); const {filterStackTrace} = require('./stackTrace.js'); -const alwaysDisplayError = require('./alwaysDisplayError.js'); +const alwaysDisplayError = require('./alwaysDisplayError'); const {colors} = require('./chalkColors.js'); /** diff --git a/lib/utils/browsername.js b/lib/utils/browsername.ts similarity index 73% rename from lib/utils/browsername.js rename to lib/utils/browsername.ts index eda7ab1537..c313aea2ee 100644 --- a/lib/utils/browsername.js +++ b/lib/utils/browsername.ts @@ -1,27 +1,27 @@ -const BrowserName = module.exports = { +class BrowserName { get CHROME() { return 'chrome'; - }, + } get FIREFOX() { return 'firefox'; - }, + } get SAFARI() { return 'safari'; - }, + } get EDGE() { return 'MicrosoftEdge'; - }, + } get INTERNET_EXPLORER() { return 'internet explorer'; - }, + } get OPERA() { return 'opera'; } -}; +} -Object.freeze(BrowserName); +export = new BrowserName(); diff --git a/lib/utils/createPromise.js b/lib/utils/createPromise.js deleted file mode 100644 index 3ec3afaf8c..0000000000 --- a/lib/utils/createPromise.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @return {{resolve, reject, promise}} - */ -module.exports = function createPromise() { - const deferred = { - resolve: null, - reject: null, - promise: null - }; - - deferred.promise = new Promise((resolve, reject) => { - deferred.resolve = resolve; - deferred.reject = reject; - }); - - return deferred; -}; diff --git a/lib/utils/createPromise.ts b/lib/utils/createPromise.ts new file mode 100644 index 0000000000..5a8d5ec4cc --- /dev/null +++ b/lib/utils/createPromise.ts @@ -0,0 +1,16 @@ +interface Deferred { + promise: Promise; + resolve: ((value: T | PromiseLike) => void); + reject: ((reason?: unknown) => void); +} + +export = function createPromise(): Deferred { + const deferred = > {}; + + deferred.promise = new Promise((resolve, reject) => { + deferred.resolve = resolve; + deferred.reject = reject; + }); + + return deferred; +}; diff --git a/lib/utils/getFreePort.js b/lib/utils/getFreePort.ts similarity index 56% rename from lib/utils/getFreePort.js rename to lib/utils/getFreePort.ts index deb3878eff..485b70db6e 100644 --- a/lib/utils/getFreePort.js +++ b/lib/utils/getFreePort.ts @@ -1,20 +1,25 @@ +import * as net from 'net'; + /** * @method getFreePort - * @param host - * @returns {Promise} */ -module.exports = function(host = 'localhost') { - const net = require('net'); - +export = function(host = 'localhost'): Promise { return new Promise((resolve, reject) => { const server = net.createServer(); server.on('listening', function () { - resolve(server.address().port); + const serverAddress = server.address(); + + if (!serverAddress || typeof serverAddress === 'string') { + reject(new Error('Unable to get port from server address.')); + } else { + resolve(serverAddress.port); + } + server.close(); }); - server.on('error', (e) => { + server.on('error', (e: NodeJS.ErrnoException) => { let err; if (e.code === 'EADDRINUSE' || e.code === 'EACCES') { err = new Error('Unable to find a free port'); @@ -28,4 +33,4 @@ module.exports = function(host = 'localhost') { // By providing 0 we let the operative system find an arbitrary port server.listen(0, host); }); -}; \ No newline at end of file +}; diff --git a/lib/utils/index.js b/lib/utils/index.js index 5384994693..fe4b6d7feb 100644 --- a/lib/utils/index.js +++ b/lib/utils/index.js @@ -6,16 +6,16 @@ const {By, Capabilities} = require('selenium-webdriver'); const {inspect} = require('util'); const Logger = require('./logger'); -const BrowserName = require('./browsername.js'); +const BrowserName = require('./browsername'); const LocateStrategy = require('./locatestrategy.js'); const PeriodicPromise = require('./periodic-promise.js'); -const createPromise = require('./createPromise.js'); -const isErrorObject = require('./isErrorObject.js'); -const alwaysDisplayError = require('./alwaysDisplayError.js'); +const createPromise = require('./createPromise'); +const isErrorObject = require('./isErrorObject'); +const alwaysDisplayError = require('./alwaysDisplayError'); const Screenshots = require('./screenshots.js'); const Snapshots = require('./snapshots.js'); const TimedCallback = require('./timed-callback.js'); -const getFreePort = require('./getFreePort.js'); +const getFreePort = require('./getFreePort'); const requireModule = require('./requireModule.js'); const getAllClassMethodNames = require('./getAllClassMethodNames.js'); const VERSION = require('./version.js'); @@ -715,7 +715,6 @@ lodashMerge(Utils, { Screenshots, Snapshots, TimedCallback, - getFreePort, VERSION, diff --git a/lib/utils/isErrorObject.js b/lib/utils/isErrorObject.ts similarity index 71% rename from lib/utils/isErrorObject.js rename to lib/utils/isErrorObject.ts index bb2955ff71..7b3a827cb5 100644 --- a/lib/utils/isErrorObject.js +++ b/lib/utils/isErrorObject.ts @@ -1,3 +1,3 @@ -module.exports = function(err) { +export = function(err: unknown) { return err instanceof Error || Object.prototype.toString.call(err) === '[object Error]'; -}; \ No newline at end of file +}; diff --git a/lib/utils/logger/index.js b/lib/utils/logger/index.js index fe310c5b46..afd03c3fd8 100644 --- a/lib/utils/logger/index.js +++ b/lib/utils/logger/index.js @@ -7,12 +7,12 @@ const lodashEscape = require('lodash.escape'); const LogSettings = require('./log_settings.js'); const chalkColors = require('../chalkColors.js'); -const addDetailedError = require('../addDetailedError.js'); +const addDetailedError = require('../addDetailedError'); const Errors = require('../../transport/errors'); const beautifyStackTrace = require('../beautifyStackTrace'); -const alwaysDisplayError = require('../alwaysDisplayError.js'); +const alwaysDisplayError = require('../alwaysDisplayError'); const Severity = { LOG: 'LOG', diff --git a/lib/utils/periodic-promise.js b/lib/utils/periodic-promise.js index 685fa02943..d77cc2492b 100644 --- a/lib/utils/periodic-promise.js +++ b/lib/utils/periodic-promise.js @@ -1,5 +1,5 @@ const EventEmitter = require('events'); -const createPromise = require('./createPromise.js'); +const createPromise = require('./createPromise'); class PeriodicPromise extends EventEmitter { get rescheduleInterval() { diff --git a/lib/utils/stackTrace.js b/lib/utils/stackTrace.js index a12a8b748c..b257c1e218 100644 --- a/lib/utils/stackTrace.js +++ b/lib/utils/stackTrace.js @@ -1,7 +1,7 @@ const boxen = require('boxen'); const {colors} = require('./chalkColors.js'); -const isErrorObject = require('./isErrorObject.js'); -const addDetailedError = require('./addDetailedError.js'); +const isErrorObject = require('./isErrorObject'); +const addDetailedError = require('./addDetailedError'); const indentRegex = /^/gm; const stackTraceFilter = function (parts) { diff --git a/lib/utils/types/index.ts b/lib/utils/types/index.ts new file mode 100644 index 0000000000..9ed3824b82 --- /dev/null +++ b/lib/utils/types/index.ts @@ -0,0 +1,5 @@ +export interface NightwatchError extends Error { + detailedErr: string; + link: string; + help: string[]; +} diff --git a/package-lock.json b/package-lock.json index 16b262d3ec..349de22fe5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -55,7 +55,9 @@ "devDependencies": { "@cucumber/cucumber": "^8.2.1", "@swc/core": "^1.3.67", - "@types/node": "^18.11.7", + "@types/node": "^18.17.3", + "@typescript-eslint/eslint-plugin": "^6.3.0", + "@typescript-eslint/parser": "^6.3.0", "copyfiles": "^2.4.1", "cross-env": "^7.0.3", "eslint": "^8.9.0", @@ -789,6 +791,30 @@ "integrity": "sha512-N43uWud8ZXuVjza423T9ZCIJsaZhFekmakt7S9bvogTxqdVGbRobjR663s0+uW0Rz9e+Pa8I6jUuWtoBLQD2Mw==", "dev": true }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.6.2.tgz", + "integrity": "sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, "node_modules/@eslint/eslintrc": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", @@ -1341,9 +1367,9 @@ "dev": true }, "node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", + "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", "dev": true }, "node_modules/@types/lodash": { @@ -1359,9 +1385,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.11.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.11.tgz", - "integrity": "sha512-KJ021B1nlQUBLopzZmPBVuGU9un7WJd/W4ya7Ih02B4Uwky5Nja0yGYav2EfYIk0RR2Q9oVhf60S2XR1BCWJ2g==" + "version": "18.17.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.17.3.tgz", + "integrity": "sha512-2x8HWtFk0S99zqVQABU9wTpr8wPoaDHZUcAkoTKH+nL7kPv3WUI9cRi/Kk5Mz4xdqXSqTkKP7IWNoQQYCnDsTA==" }, "node_modules/@types/normalize-package-data": { "version": "2.4.1", @@ -1377,6 +1403,12 @@ "@types/ws": "*" } }, + "node_modules/@types/semver": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", + "dev": true + }, "node_modules/@types/uuid": { "version": "8.3.4", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", @@ -1391,6 +1423,241 @@ "@types/node": "*" } }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.3.0.tgz", + "integrity": "sha512-IZYjYZ0ifGSLZbwMqIip/nOamFiWJ9AH+T/GYNZBWkVcyNQOFGtSMoWV7RvY4poYCMZ/4lHzNl796WOSNxmk8A==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.3.0", + "@typescript-eslint/type-utils": "6.3.0", + "@typescript-eslint/utils": "6.3.0", + "@typescript-eslint/visitor-keys": "6.3.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "natural-compare-lite": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.3.0.tgz", + "integrity": "sha512-ibP+y2Gr6p0qsUkhs7InMdXrwldjxZw66wpcQq9/PzAroM45wdwyu81T+7RibNCh8oc0AgrsyCwJByncY0Ongg==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "6.3.0", + "@typescript-eslint/types": "6.3.0", + "@typescript-eslint/typescript-estree": "6.3.0", + "@typescript-eslint/visitor-keys": "6.3.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.3.0.tgz", + "integrity": "sha512-WlNFgBEuGu74ahrXzgefiz/QlVb+qg8KDTpknKwR7hMH+lQygWyx0CQFoUmMn1zDkQjTBBIn75IxtWss77iBIQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.3.0", + "@typescript-eslint/visitor-keys": "6.3.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.3.0.tgz", + "integrity": "sha512-7Oj+1ox1T2Yc8PKpBvOKWhoI/4rWFd1j7FA/rPE0lbBPXTKjdbtC+7Ev0SeBjEKkIhKWVeZSP+mR7y1Db1CdfQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "6.3.0", + "@typescript-eslint/utils": "6.3.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.3.0.tgz", + "integrity": "sha512-K6TZOvfVyc7MO9j60MkRNWyFSf86IbOatTKGrpTQnzarDZPYPVy0oe3myTMq7VjhfsUAbNUW8I5s+2lZvtx1gg==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.3.0.tgz", + "integrity": "sha512-Xh4NVDaC4eYKY4O3QGPuQNp5NxBAlEvNQYOqJquR2MePNxO11E5K3t5x4M4Mx53IZvtpW+mBxIT0s274fLUocg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.3.0", + "@typescript-eslint/visitor-keys": "6.3.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.3.0.tgz", + "integrity": "sha512-hLLg3BZE07XHnpzglNBG8P/IXq/ZVXraEbgY7FM0Cnc1ehM8RMdn9mat3LubJ3KBeYXXPxV1nugWbQPjGeJk6Q==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.3.0", + "@typescript-eslint/types": "6.3.0", + "@typescript-eslint/typescript-estree": "6.3.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.3.0.tgz", + "integrity": "sha512-kEhRRj7HnvaSjux1J9+7dBen15CdWmDnwrpyiHsFX6Qx2iW5LOBUgNefOFeh2PjWPlNwN8TOn6+4eBU3J/gupw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.3.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@zeit/schemas": { "version": "2.29.0", "resolved": "https://registry.npmjs.org/@zeit/schemas/-/schemas-2.29.0.tgz", @@ -3106,12 +3373,15 @@ } }, "node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.2.tgz", + "integrity": "sha512-8drBzUEyZ2llkpCA67iYrgEssKDUu68V8ChqqOfFupIaG/LCVPUT+CoGJpT77zJprs4T/W7p07LP7zAIMuweVw==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint/node_modules/argparse": { @@ -3722,6 +3992,12 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, "node_modules/hard-rejection": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", @@ -3972,9 +4248,9 @@ ] }, "node_modules/ignore": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz", - "integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", "dev": true, "engines": { "node": ">= 4" @@ -6130,6 +6406,12 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -8386,6 +8668,18 @@ "node": ">=8" } }, + "node_modules/ts-api-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.1.tgz", + "integrity": "sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A==", + "dev": true, + "engines": { + "node": ">=16.13.0" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, "node_modules/ts-node": { "version": "10.9.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", @@ -9642,6 +9936,21 @@ "integrity": "sha512-N43uWud8ZXuVjza423T9ZCIJsaZhFekmakt7S9bvogTxqdVGbRobjR663s0+uW0Rz9e+Pa8I6jUuWtoBLQD2Mw==", "dev": true }, + "@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^3.3.0" + } + }, + "@eslint-community/regexpp": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.6.2.tgz", + "integrity": "sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==", + "dev": true + }, "@eslint/eslintrc": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", @@ -10034,9 +10343,9 @@ "dev": true }, "@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", + "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", "dev": true }, "@types/lodash": { @@ -10052,9 +10361,9 @@ "dev": true }, "@types/node": { - "version": "18.11.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.11.tgz", - "integrity": "sha512-KJ021B1nlQUBLopzZmPBVuGU9un7WJd/W4ya7Ih02B4Uwky5Nja0yGYav2EfYIk0RR2Q9oVhf60S2XR1BCWJ2g==" + "version": "18.17.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.17.3.tgz", + "integrity": "sha512-2x8HWtFk0S99zqVQABU9wTpr8wPoaDHZUcAkoTKH+nL7kPv3WUI9cRi/Kk5Mz4xdqXSqTkKP7IWNoQQYCnDsTA==" }, "@types/normalize-package-data": { "version": "2.4.1", @@ -10070,6 +10379,12 @@ "@types/ws": "*" } }, + "@types/semver": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", + "dev": true + }, "@types/uuid": { "version": "8.3.4", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", @@ -10084,6 +10399,140 @@ "@types/node": "*" } }, + "@typescript-eslint/eslint-plugin": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.3.0.tgz", + "integrity": "sha512-IZYjYZ0ifGSLZbwMqIip/nOamFiWJ9AH+T/GYNZBWkVcyNQOFGtSMoWV7RvY4poYCMZ/4lHzNl796WOSNxmk8A==", + "dev": true, + "requires": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.3.0", + "@typescript-eslint/type-utils": "6.3.0", + "@typescript-eslint/utils": "6.3.0", + "@typescript-eslint/visitor-keys": "6.3.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "natural-compare-lite": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "dependencies": { + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@typescript-eslint/parser": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.3.0.tgz", + "integrity": "sha512-ibP+y2Gr6p0qsUkhs7InMdXrwldjxZw66wpcQq9/PzAroM45wdwyu81T+7RibNCh8oc0AgrsyCwJByncY0Ongg==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "6.3.0", + "@typescript-eslint/types": "6.3.0", + "@typescript-eslint/typescript-estree": "6.3.0", + "@typescript-eslint/visitor-keys": "6.3.0", + "debug": "^4.3.4" + } + }, + "@typescript-eslint/scope-manager": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.3.0.tgz", + "integrity": "sha512-WlNFgBEuGu74ahrXzgefiz/QlVb+qg8KDTpknKwR7hMH+lQygWyx0CQFoUmMn1zDkQjTBBIn75IxtWss77iBIQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "6.3.0", + "@typescript-eslint/visitor-keys": "6.3.0" + } + }, + "@typescript-eslint/type-utils": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.3.0.tgz", + "integrity": "sha512-7Oj+1ox1T2Yc8PKpBvOKWhoI/4rWFd1j7FA/rPE0lbBPXTKjdbtC+7Ev0SeBjEKkIhKWVeZSP+mR7y1Db1CdfQ==", + "dev": true, + "requires": { + "@typescript-eslint/typescript-estree": "6.3.0", + "@typescript-eslint/utils": "6.3.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + } + }, + "@typescript-eslint/types": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.3.0.tgz", + "integrity": "sha512-K6TZOvfVyc7MO9j60MkRNWyFSf86IbOatTKGrpTQnzarDZPYPVy0oe3myTMq7VjhfsUAbNUW8I5s+2lZvtx1gg==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.3.0.tgz", + "integrity": "sha512-Xh4NVDaC4eYKY4O3QGPuQNp5NxBAlEvNQYOqJquR2MePNxO11E5K3t5x4M4Mx53IZvtpW+mBxIT0s274fLUocg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "6.3.0", + "@typescript-eslint/visitor-keys": "6.3.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "dependencies": { + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@typescript-eslint/utils": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.3.0.tgz", + "integrity": "sha512-hLLg3BZE07XHnpzglNBG8P/IXq/ZVXraEbgY7FM0Cnc1ehM8RMdn9mat3LubJ3KBeYXXPxV1nugWbQPjGeJk6Q==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.3.0", + "@typescript-eslint/types": "6.3.0", + "@typescript-eslint/typescript-estree": "6.3.0", + "semver": "^7.5.4" + }, + "dependencies": { + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@typescript-eslint/visitor-keys": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.3.0.tgz", + "integrity": "sha512-kEhRRj7HnvaSjux1J9+7dBen15CdWmDnwrpyiHsFX6Qx2iW5LOBUgNefOFeh2PjWPlNwN8TOn6+4eBU3J/gupw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "6.3.0", + "eslint-visitor-keys": "^3.4.1" + } + }, "@zeit/schemas": { "version": "2.29.0", "resolved": "https://registry.npmjs.org/@zeit/schemas/-/schemas-2.29.0.tgz", @@ -11371,9 +11820,9 @@ } }, "eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.2.tgz", + "integrity": "sha512-8drBzUEyZ2llkpCA67iYrgEssKDUu68V8ChqqOfFupIaG/LCVPUT+CoGJpT77zJprs4T/W7p07LP7zAIMuweVw==", "dev": true }, "espree": { @@ -11780,6 +12229,12 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" }, + "graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, "hard-rejection": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", @@ -11948,9 +12403,9 @@ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" }, "ignore": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz", - "integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", "dev": true }, "immediate": { @@ -13615,6 +14070,12 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, "negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -15329,6 +15790,13 @@ "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", "dev": true }, + "ts-api-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.1.tgz", + "integrity": "sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A==", + "dev": true, + "requires": {} + }, "ts-node": { "version": "10.9.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", diff --git a/package.json b/package.json index b904d9bdf4..6b9a8268d0 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,9 @@ "devDependencies": { "@cucumber/cucumber": "^8.2.1", "@swc/core": "^1.3.67", - "@types/node": "^18.11.7", + "@types/node": "^18.17.3", + "@typescript-eslint/eslint-plugin": "^6.3.0", + "@typescript-eslint/parser": "^6.3.0", "copyfiles": "^2.4.1", "cross-env": "^7.0.3", "eslint": "^8.9.0", From 649dc84808b3a9304cba053c2502d60095408bb2 Mon Sep 17 00:00:00 2001 From: Binayak Ghosh Date: Thu, 24 Aug 2023 23:17:23 +0530 Subject: [PATCH 32/38] use correct settings parameter for trace (#3890) --- lib/utils/snapshots.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/utils/snapshots.js b/lib/utils/snapshots.js index b1226deb6f..ec718eb1af 100644 --- a/lib/utils/snapshots.js +++ b/lib/utils/snapshots.js @@ -15,7 +15,7 @@ class Snapshots { if (typeof traceSettings.filename_format == 'function') { filename_format = traceSettings.filename_format.bind(traceSettings); } else { - filename_format = Defaults.snapshots.filename_format; + filename_format = Defaults.trace.filename_format; } const base_path = traceSettings.path || `${output_folder}/snapshots`; From 8ae7e0a0f630ca1dc85e6dbef54aa462b317596b Mon Sep 17 00:00:00 2001 From: Priyansh Garg <39924567+garg3133@users.noreply.github.com> Date: Wed, 30 Aug 2023 17:43:59 +0530 Subject: [PATCH 33/38] Allow `WebElement` as a possible selector in type declarations. (#3896) --- types/assertions.d.ts | 6 ++-- types/custom-assertion.d.ts | 4 +-- types/expect.d.ts | 10 +++---- types/index.d.ts | 23 +++++++++------- types/page-object.d.ts | 38 ++++++++++++++++++++++---- types/tests/globalElementApi.test-d.ts | 12 +++++++- types/tests/index.test-d.ts | 10 ++++++- types/web-element.d.ts | 6 ++-- 8 files changed, 79 insertions(+), 30 deletions(-) diff --git a/types/assertions.d.ts b/types/assertions.d.ts index 2231b3a6b9..8cae94b424 100644 --- a/types/assertions.d.ts +++ b/types/assertions.d.ts @@ -1,5 +1,5 @@ import {NightwatchCustomAssertions} from './custom-assertion'; -import {Awaitable, Definition, ElementResult, JSON_WEB_OBJECT} from './index'; +import {Awaitable, Definition, ElementResult, JSON_WEB_OBJECT, ScopedSelector} from './index'; import { IfUnknown } from './utils'; export interface NightwatchAssertionsError { @@ -124,7 +124,7 @@ export interface NightwatchCommonAssertions { * */ elementsCount( - selector: Definition, + selector: ScopedSelector, count: number, msg?: string ): Awaitable< @@ -144,7 +144,7 @@ export interface NightwatchCommonAssertions { * ``` */ elementPresent( - selector: Definition, + selector: ScopedSelector, msg?: string ): Awaitable< IfUnknown, diff --git a/types/custom-assertion.d.ts b/types/custom-assertion.d.ts index a93a6e4f06..027cefbeee 100644 --- a/types/custom-assertion.d.ts +++ b/types/custom-assertion.d.ts @@ -11,9 +11,9 @@ interface NightwatchAssertionFailedResult { /** * @example - * import {Definition, NightwatchAssertion} from 'nightwatch'; + * import {ScopedSelector, NightwatchAssertion} from 'nightwatch'; * - * export const assertion = function ElementHasCount(this: NightwatchAssertion, selector: Definition, count: number) { + * export const assertion = function ElementHasCount(this: NightwatchAssertion, selector: ScopedSelector, count: number) { * this.message = `Testing if element <${selector}> has count: ${count}`; * * this.expected = count; diff --git a/types/expect.d.ts b/types/expect.d.ts index 2d4a095cc2..3063ee898a 100644 --- a/types/expect.d.ts +++ b/types/expect.d.ts @@ -1,5 +1,5 @@ import { By, WebElement } from 'selenium-webdriver'; -import {Definition, NightwatchAPI, Awaitable, Element, ELEMENT_KEY} from './index'; +import {Definition, NightwatchAPI, Awaitable, Element, ELEMENT_KEY, ScopedSelector} from './index'; export interface NightwatchExpectResult { value: null; @@ -196,23 +196,23 @@ export interface Expect { /** * Expect assertions operating on a single element, specified by its CSS/Xpath selector. */ - element(property: Definition | WebElement): ExpectElement; + element(property: Definition): ExpectElement; /** * Expect assertions operating on a single component. */ - component(property: Definition | WebElement): ExpectElement; + component(property: Definition): ExpectElement; /** * Expect assertions operating on a page-object section, specified by '`@section_name`'. */ - section(property: Definition): ExpectSection; + section(property: ScopedSelector): ExpectSection; /** * Expect assertions operating on a collection of elements, specified by a CSS/Xpath selector. * So far only .count is available. */ - elements(property: Definition): ExpectElements; + elements(property: ScopedSelector): ExpectElements; /** * Retrieves the page title value in order to be used for performing equal, match or contains assertions on it. diff --git a/types/index.d.ts b/types/index.d.ts index b41610774f..947ee2dd1c 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -55,7 +55,8 @@ export interface JSON_WEB_OBJECT extends ElementResult { getId: () => string; } -export type Definition = string | ElementProperties | Element | SeleniumBy | RelativeBy; +export type ScopedSelector = string | ElementProperties | Element | SeleniumBy | RelativeBy; +export type Definition = ScopedSelector | WebElement; export type Awaitable = Omit & PromiseLike; @@ -687,6 +688,8 @@ export class Element { timeout?: number; } +type ElementGlobalDefinition = string | SeleniumBy | RelativeBy | {selector: string; locateStrategy?: string} | {using: string, value: string}; + export interface ElementGlobal extends Element { /** * Get the server-assigned opaque ID assigned to this element. @@ -698,24 +701,24 @@ export interface ElementGlobal extends Element { /** * Locates the descendants of this element that match the given search criteria, and returns the first one. * - * If no `selector` is passed, returns the[WebElement](https://www.selenium.dev/selenium/docs/api/javascript/module/selenium-webdriver/index_exports_WebElement.html) + * If no `selector` is passed, returns the [WebElement](https://www.selenium.dev/selenium/docs/api/javascript/module/selenium-webdriver/index_exports_WebElement.html) * instance for this element. */ findElement(): Awaitable; findElement( - selector: Definition, + selector: ElementGlobalDefinition, callback?: (this: NightwatchAPI, result: NightwatchCallbackResult) => void ): Awaitable; /** * Locates and wraps the first element, that match the given search criteria in the descendants of this element, in global element() api object. * - * If no `selector` is passed, returns the[WebElement](https://www.selenium.dev/selenium/docs/api/javascript/module/selenium-webdriver/index_exports_WebElement.html) + * If no `selector` is passed, returns the [WebElement](https://www.selenium.dev/selenium/docs/api/javascript/module/selenium-webdriver/index_exports_WebElement.html) * instance for this element. */ find(): Awaitable; find( - selector: Definition, + selector: ElementGlobalDefinition, callback?: (this: NightwatchAPI, result: NightwatchCallbackResult) => void ): Awaitable; @@ -726,12 +729,12 @@ export interface ElementGlobal extends Element { * Locates all of the descendants of this element that match the given search criteria. */ findElements( - selector: Definition, + selector: ElementGlobalDefinition, callback?: (this: NightwatchAPI, result: NightwatchCallbackResult) => void ): Awaitable; findAll( - selector: Definition, + selector: ElementGlobalDefinition, callback?: (this: NightwatchAPI, result: NightwatchCallbackResult) => void ): Awaitable; @@ -926,7 +929,7 @@ export interface ElementGlobal extends Element { } export function globalElement( - locator: Definition | WebElement, + locator: Definition, options?: { isComponent?: boolean; type: string; @@ -4173,7 +4176,7 @@ export interface ElementCommands { * @see https://nightwatchjs.org/api/getShadowRoot.html */ getShadowRoot( - selector: Definition | WebElement, + selector: Definition, callback?: ( this: NightwatchAPI, result: NightwatchCallbackResult @@ -4181,7 +4184,7 @@ export interface ElementCommands { ): Awaitable; getShadowRoot( using: LocateStrategy, - selector: Definition | WebElement, + selector: Definition, callback?: ( this: NightwatchAPI, result: NightwatchCallbackResult diff --git a/types/page-object.d.ts b/types/page-object.d.ts index 13c8339f36..1e663c135d 100644 --- a/types/page-object.d.ts +++ b/types/page-object.d.ts @@ -19,7 +19,7 @@ import { export interface SectionProperties { /** - * The element selector name + * The selector string to be used to find the section in the DOM. * * @example * sections: { @@ -30,6 +30,19 @@ export interface SectionProperties { */ selector: string; + /** + * The locate strategy to be used with `selector` when finding the section within the DOM. + * - css selector + * - link text + * - partial link text + * - tag name + * - xpath + * + * @example + * 'css selector' + */ + locateStrategy?: LocateStrategy; + /** * An object, or array of objects, of named element definitions to be used * as element selectors within element commands. @@ -196,12 +209,25 @@ export interface EnhancedPageObjectSections< Props > { /** - * The element selector name + * The selector string used to find the section in the DOM. * * @example - * '@searchBar' + * '#searchBar' */ selector: string; + + /** + * The locate strategy used with `selector` when finding the section within the DOM. + * - css selector + * - link text + * - partial link text + * - tag name + * - xpath + * + * @example + * 'css selector' + */ + locateStrategy: LocateStrategy; } interface EnhancedPageObjectSharedFields< @@ -272,15 +298,15 @@ interface EnhancedPageObjectSharedFields< export interface ElementProperties { /** - * The element selector name + * The selector string to be used to find the element in the DOM. * * @example - * '@searchBar' + * '#searchBar' */ selector: string; /** - * locator strategy can be one of + * The locate strategy to be used with `selector` when finding the element within the DOM. * - css selector * - link text * - partial link text diff --git a/types/tests/globalElementApi.test-d.ts b/types/tests/globalElementApi.test-d.ts index b999339bde..87b4e5e9ae 100644 --- a/types/tests/globalElementApi.test-d.ts +++ b/types/tests/globalElementApi.test-d.ts @@ -1,4 +1,4 @@ -import { expectAssignable, expectType } from "tsd"; +import { expectAssignable, expectError, expectType } from "tsd"; import { ElementGlobal, NightwatchAPI, NightwatchCallbackResult, NightwatchSizeAndPosition } from ".."; import { WebElement } from "selenium-webdriver"; @@ -55,6 +55,16 @@ describe('global element() api', function () { })); expectType(await elem.find('child-selector')); + elem.find({using: 'css selector', value: 'child-selector'}); + expectError(elem.find({value: 'child-selector'})); + expectError(elem.find({using: 'css selector', value: 'child-selector', abortOnFailure: true})); + + const elemProp = {locateStrategy: 'css selector', selector: 'child-selector', abortOnFailure: true}; + elem.find(elemProp); + expectError(elem.find({locateStrategy: 'css selector', selector: 'child-selector', abortOnFailure: true})); + + expectError(elem.find({locateStrategy: 'css selector', value: 'child-selector'})); + // .get() expectAssignable(elem.get()); expectType(await elem.get()); diff --git a/types/tests/index.test-d.ts b/types/tests/index.test-d.ts index b28baa5caa..da52325807 100644 --- a/types/tests/index.test-d.ts +++ b/types/tests/index.test-d.ts @@ -17,7 +17,8 @@ import { ElementResult, Awaitable, SectionProperties, - ScopedElement + ScopedElement, + LocateStrategy } from '..'; import { element as elementNamedExport } from '..'; import { WebElement } from 'selenium-webdriver'; @@ -381,6 +382,7 @@ const appsSection = { const menuSection = { selector: '#gb', + locateStrategy: 'css selector', commands: [ { // add section commands here @@ -507,6 +509,12 @@ const testPage = { const menuSection = google.section.menu; + expectType(menuSection.selector); + expectType(menuSection.locateStrategy); + + google.expect.section('@menu').to.be.visible; + google.expect.section(menuSection).to.be.visible; + const result = menuSection .assert.visible('@mail') .assert.visible('@images'); diff --git a/types/web-element.d.ts b/types/web-element.d.ts index fe1bdb9a7b..6590d5d716 100644 --- a/types/web-element.d.ts +++ b/types/web-element.d.ts @@ -67,8 +67,8 @@ export interface ScopedElement extends Element, PromiseLike { } ): ScopedElement; - findAll(selector: ScopedElementSelector): Elements; - getAll(selector: ScopedElementSelector): Elements; + findAll(selector: ScopedSelector | Promise): Elements; + getAll(selector: ScopedSelector | Promise): Elements; findAllByText( text: string, @@ -167,6 +167,8 @@ export interface ScopedElement extends Element, PromiseLike { update(...keys: E): Promise; + upload(file: string): Promise; + getAccessibleName(): ElementValue; getAriaRole(): ElementValue; From a632e83038269a28bc90f990d12b39ec5a6b2eee Mon Sep 17 00:00:00 2001 From: Priyansh Garg <39924567+garg3133@users.noreply.github.com> Date: Wed, 30 Aug 2023 18:33:38 +0530 Subject: [PATCH 34/38] Change file names for execute commands. (#3898) --- .../document/{executeAsync.js => executeAsyncScript.js} | 4 ++-- .../client-commands/document/{execute.js => executeScript.js} | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) rename lib/api/client-commands/document/{executeAsync.js => executeAsyncScript.js} (95%) rename lib/api/client-commands/document/{execute.js => executeScript.js} (96%) diff --git a/lib/api/client-commands/document/executeAsync.js b/lib/api/client-commands/document/executeAsyncScript.js similarity index 95% rename from lib/api/client-commands/document/executeAsync.js rename to lib/api/client-commands/document/executeAsyncScript.js index 2719ae29c6..935a3e902b 100644 --- a/lib/api/client-commands/document/executeAsync.js +++ b/lib/api/client-commands/document/executeAsyncScript.js @@ -1,5 +1,5 @@ const ClientCommand = require('../_base-command.js'); -const {isFunction} = require('../../../utils'); +const {isFunction} = require('../../../utils/index.js'); /** * Inject a snippet of JavaScript into the page for execution in the context of the currently selected frame. The executed script is assumed to be asynchronous. @@ -52,7 +52,7 @@ const {isFunction} = require('../../../utils'); */ class ExecuteAsyncScript extends ClientCommand { static get namespacedAliases() { - return ['document.executeAsyncScript', 'executeAsync', 'executeAsyncScript']; + return ['document.executeAsync', 'executeAsync', 'executeAsyncScript']; } static get isTraceable() { diff --git a/lib/api/client-commands/document/execute.js b/lib/api/client-commands/document/executeScript.js similarity index 96% rename from lib/api/client-commands/document/execute.js rename to lib/api/client-commands/document/executeScript.js index f3af809ddf..165d8358ae 100644 --- a/lib/api/client-commands/document/execute.js +++ b/lib/api/client-commands/document/executeScript.js @@ -1,5 +1,5 @@ const ClientCommand = require('../_base-command.js'); -const {isFunction} = require('../../../utils'); +const {isFunction} = require('../../../utils/index.js'); /** * Inject a snippet of JavaScript into the page for execution in the context of the currently selected frame. The executed script is assumed to be synchronous. @@ -53,7 +53,7 @@ const {isFunction} = require('../../../utils'); */ class ExecuteScript extends ClientCommand { static get namespacedAliases() { - return ['document.executeScript', 'execute', 'executeScript']; + return ['document.execute', 'execute', 'executeScript']; } static get isTraceable() { From f60b34a60fa65560ad06dbbbd5d3c5530e414d20 Mon Sep 17 00:00:00 2001 From: Priyansh Garg <39924567+garg3133@users.noreply.github.com> Date: Wed, 30 Aug 2023 18:34:53 +0530 Subject: [PATCH 35/38] Fix eslint rules (#3891) * Fix trailing spaces. * Fix eol-last rule. * Fix space-infix-ops rule. --- api/index.js | 4 +-- .../features/step_definitions/nightwatch.js | 2 +- examples/custom-commands/strictClick.js | 2 +- examples/pages/google/search.js | 2 +- examples/pages/google/searchResults.js | 4 +-- examples/tests/chromeCDP_example.js | 4 +-- examples/tests/duckDuckGo.js | 2 +- examples/tests/element/elementapi-tests.js | 2 +- .../tests/sample-with-relative-locators.js | 2 +- examples/tests/selectElement.js | 2 +- examples/tests/shadowRootExample.js | 2 +- examples/unittests/testUtils.js | 2 +- examples/unittests/testUtilsWithChai.js | 2 +- lib/api/_loaders/_base-loader.js | 10 +++--- lib/api/_loaders/command.js | 14 ++++---- lib/api/_loaders/element-global.js | 4 +-- lib/api/_loaders/expect.js | 2 +- lib/api/_loaders/static.js | 2 +- lib/api/assertions/_assertionInstance.js | 2 +- lib/api/assertions/domPropertyMatches.js | 10 +++--- lib/api/assertions/elementsCount.js | 2 +- lib/api/assertions/enabled.js | 4 +-- lib/api/assertions/hasAttribute.js | 12 +++---- lib/api/assertions/hasClass.js | 25 +++++++------- lib/api/assertions/selected.js | 2 +- lib/api/assertions/textEquals.js | 12 +++---- lib/api/assertions/textMatches.js | 2 +- lib/api/assertions/titleEquals.js | 2 +- lib/api/assertions/titleMatches.js | 2 +- lib/api/assertions/urlMatches.js | 2 +- lib/api/assertions/valueEquals.js | 4 +-- lib/api/client-commands/alerts/setText.js | 2 +- lib/api/client-commands/axeInject.js | 2 +- lib/api/client-commands/debug.js | 6 ++-- .../client-commands/document/injectScript.js | 2 +- .../enablePerformanceMetrics.js | 2 +- .../client-commands/getPerformanceMetrics.js | 2 +- .../logs/captureBrowserConsoleLogs.js | 2 +- .../logs/captureBrowserExceptions.js | 2 +- .../logs/getSessionLogTypes.js | 2 +- .../logs/isSessionLogAvailable.js | 2 +- .../network/captureRequests.js | 4 +-- .../client-commands/network/mockResponse.js | 2 +- .../client-commands/network/setConditions.js | 2 +- lib/api/client-commands/pause.js | 6 ++-- lib/api/client-commands/registerBasicAuth.js | 2 +- lib/api/client-commands/saveSnapshot.js | 2 +- .../client-commands/setDeviceDimensions.js | 2 +- lib/api/client-commands/takeHeapSnapshot.js | 2 +- lib/api/client-commands/within.js | 2 +- lib/api/element-commands/click.js | 2 +- .../element-commands/getFirstElementChild.js | 4 +-- .../element-commands/getLastElementChild.js | 4 +-- lib/api/element-commands/getNextSibling.js | 6 ++-- .../element-commands/getPreviousSibling.js | 6 ++-- lib/api/element-commands/isEnabled.js | 2 +- lib/api/element-commands/isPresent.js | 4 +-- lib/api/element-commands/isSelected.js | 2 +- lib/api/element-commands/setPassword.js | 2 +- lib/api/element-commands/uploadFile.js | 2 +- lib/api/expect/assertions/_baseAssertion.js | 14 ++++---- lib/api/expect/assertions/element/type.js | 2 +- lib/api/protocol/elementIdDoubleClick.js | 4 +-- lib/api/protocol/frame.js | 2 +- lib/api/protocol/moveTo.js | 4 +-- lib/api/protocol/releaseMouseButton.js | 2 +- .../web-element/assert/element-assertions.js | 2 +- .../web-element/commands/getAccessibleName.js | 2 +- lib/api/web-element/commands/getAriaRole.js | 2 +- lib/api/web-element/commands/getAttribute.js | 2 +- .../web-element/commands/getCssProperty.js | 2 +- lib/api/web-element/commands/getId.js | 2 +- lib/api/web-element/commands/getProperty.js | 2 +- lib/api/web-element/commands/getRect.js | 2 +- lib/api/web-element/commands/getTagName.js | 2 +- lib/api/web-element/commands/getText.js | 2 +- lib/api/web-element/commands/getValue.js | 2 +- lib/api/web-element/commands/rightClick.js | 2 +- lib/api/web-element/commands/setAttribute.js | 2 +- lib/api/web-element/commands/setProperty.js | 2 +- lib/api/web-element/commands/submit.js | 2 +- .../web-element/commands/takeScreenshot.js | 2 +- lib/api/web-element/commands/upload.js | 2 +- lib/api/web-element/factory.js | 4 +-- lib/api/web-element/index.js | 2 +- lib/api/web-element/waitUntil.js | 30 ++++++++-------- lib/core/asynctree.js | 2 +- lib/core/client.js | 6 ++-- lib/core/queue.js | 4 +-- lib/element/command.js | 4 +-- lib/http/formatter.js | 14 ++++---- lib/http/request.js | 2 +- lib/index.js | 6 ++-- lib/page-object/command-wrapper.js | 2 +- lib/reporter/axe-report.js | 2 +- lib/reporter/base-reporter.js | 2 +- lib/reporter/global-reporter.js | 6 ++-- lib/reporter/index.js | 6 ++-- lib/reporter/reporters/html.js | 2 +- lib/reporter/results.js | 20 +++++------ lib/reporter/summary.js | 2 +- lib/runner/androidEmulator.js | 2 +- lib/runner/cli/argv-setup.js | 4 +-- lib/runner/cli/cli.js | 20 +++++------ lib/runner/concurrency/child-process.js | 4 +-- lib/runner/concurrency/index.js | 2 +- lib/runner/concurrency/task.js | 4 +-- lib/runner/concurrency/worker-process.js | 8 ++--- lib/runner/concurrency/worker-task.js | 6 ++-- lib/runner/folder-walk.js | 4 +-- lib/runner/matchers/tags.js | 4 +-- lib/runner/process-listener.js | 2 +- lib/runner/test-runners/cucumber.js | 4 +-- lib/runner/test-runners/mocha.js | 4 +-- .../test-runners/mocha/custom-runnable.js | 12 +++---- .../test-runners/mocha/custom-runner.js | 2 +- lib/runner/test-runners/mocha/extensions.js | 2 +- .../test-runners/mocha/nightwatchSuite.js | 2 +- lib/runner/test-source.js | 22 ++++++------ lib/settings/defaults.js | 2 +- lib/settings/settings.js | 2 +- lib/testsuite/hooks/afterAll.js | 2 +- lib/testsuite/hooks/afterEach.js | 2 +- lib/testsuite/hooks/beforeAll.js | 2 +- lib/testsuite/hooks/beforeEach.js | 2 +- lib/testsuite/index.js | 34 +++++++++---------- lib/testsuite/nightwatch-inspector/index.js | 6 ++-- .../nightwatch-inspector/websocket-server.js | 2 +- .../browserstack/appAutomate.js | 2 +- .../browserstack/browserstack.js | 6 ++-- lib/transport/selenium-webdriver/cdp.js | 2 +- .../selenium-webdriver/httpclient.js | 8 ++--- lib/transport/selenium-webdriver/index.js | 12 +++---- .../selenium-webdriver/method-mappings.js | 32 ++++++++--------- lib/transport/selenium-webdriver/session.js | 8 ++--- lib/utils/addDetailedError.ts | 2 +- lib/utils/analytics.js | 14 ++++---- lib/utils/debuggability.js | 2 +- lib/utils/getAllClassMethodNames.js | 2 +- lib/utils/index.js | 16 ++++----- lib/utils/locatestrategy.js | 2 +- lib/utils/logger/index.js | 2 +- lib/utils/logger/log_settings.js | 2 +- lib/utils/mobile.js | 24 ++++++------- lib/utils/printVersionInfo.js | 2 +- lib/utils/safeStringify.js | 10 +++--- lib/utils/stackTrace.js | 2 +- lib/utils/timed-callback.js | 4 +-- lib/utils/version.js | 2 +- .../commands/workingCommandsClass.js | 2 +- test/lib/command-mocks.js | 4 +-- test/lib/nightwatch.js | 4 +-- test/lib/nocks.js | 8 ++--- test/src/analytics/testAnalytics.js | 2 +- test/src/api/commands/client/testWaitUntil.js | 16 ++++----- .../element/testWaitForElementPresent.js | 2 +- test/src/cli/testParallelExecution.js | 34 +++++++++---------- test/src/runner/cli/testCliRunnerParallel.js | 2 +- .../cucumber-integration/testCliArgs.js | 16 ++++----- 159 files changed, 406 insertions(+), 407 deletions(-) diff --git a/api/index.js b/api/index.js index 2ca0a30a00..e2a0b033a0 100644 --- a/api/index.js +++ b/api/index.js @@ -16,7 +16,7 @@ const exportedCommands = [ const basePath = '../dist/api'; const Commands = {}; const props = exportedCommands.reduce((prev, fileName) => { - const commandName = fileName.substring(fileName.lastIndexOf('/')+1).replace('.js', ''); + const commandName = fileName.substring(fileName.lastIndexOf('/') + 1).replace('.js', ''); prev[commandName] = { configurable: true, get: function() { @@ -29,4 +29,4 @@ const props = exportedCommands.reduce((prev, fileName) => { Object.defineProperties(Commands, props); -module.exports = Commands; \ No newline at end of file +module.exports = Commands; diff --git a/examples/cucumber-js/features/step_definitions/nightwatch.js b/examples/cucumber-js/features/step_definitions/nightwatch.js index cbfffe3872..789cf23ad7 100644 --- a/examples/cucumber-js/features/step_definitions/nightwatch.js +++ b/examples/cucumber-js/features/step_definitions/nightwatch.js @@ -30,4 +30,4 @@ Then(/^the title is "([^"]*)"$/, function(title) { Then(/^Body contains "([^"]*)"$/, function(contains) { return browser.assert.textContains('.search-results', contains); -}); \ No newline at end of file +}); diff --git a/examples/custom-commands/strictClick.js b/examples/custom-commands/strictClick.js index 99afe91ffb..e5686811fd 100644 --- a/examples/custom-commands/strictClick.js +++ b/examples/custom-commands/strictClick.js @@ -3,4 +3,4 @@ module.exports = { return this.waitForElementVisible(selector) .click(selector); } -}; \ No newline at end of file +}; diff --git a/examples/pages/google/search.js b/examples/pages/google/search.js index 04df86b323..430d8dc1f0 100644 --- a/examples/pages/google/search.js +++ b/examples/pages/google/search.js @@ -2,7 +2,7 @@ const searchCommands = { submit() { this.waitForElementVisible('@submitButton', 1000) .click('@submitButton'); - + this.pause(1000); return this; // Return page object for chaining diff --git a/examples/pages/google/searchResults.js b/examples/pages/google/searchResults.js index 72684c1533..35061c08cf 100644 --- a/examples/pages/google/searchResults.js +++ b/examples/pages/google/searchResults.js @@ -6,7 +6,7 @@ const menuCommands = { var self = this; return this.getAttribute(product, 'class', function (result) { - let isSelected = result.value.indexOf('hdtb-msel') > -1; + const isSelected = result.value.indexOf('hdtb-msel') > -1; callback.call(self, isSelected); }); } @@ -44,4 +44,4 @@ module.exports = { } } } -}; \ No newline at end of file +}; diff --git a/examples/tests/chromeCDP_example.js b/examples/tests/chromeCDP_example.js index ea08a33063..4f6709faa2 100644 --- a/examples/tests/chromeCDP_example.js +++ b/examples/tests/chromeCDP_example.js @@ -1,7 +1,7 @@ describe('Chrome DevTools Example', function() { this.disabled = this.argv.env !== 'chrome'; - + it ('using CDP DOM Snapshot', async function(browser) { await browser.navigateTo('https://nightwatchjs.org'); @@ -11,4 +11,4 @@ describe('Chrome DevTools Example', function() { browser.assert.deepStrictEqual(Object.keys(dom), ['documents', 'strings']); }); -}); \ No newline at end of file +}); diff --git a/examples/tests/duckDuckGo.js b/examples/tests/duckDuckGo.js index 24863a7167..4c5c1c38c2 100644 --- a/examples/tests/duckDuckGo.js +++ b/examples/tests/duckDuckGo.js @@ -11,5 +11,5 @@ describe('duckduckgo example', function() { .assert.visible('button[type=submit]') .click('button[type=submit]') .assert.textContains('.react-results--main', 'Nightwatch.js'); - }); + }); }); diff --git a/examples/tests/element/elementapi-tests.js b/examples/tests/element/elementapi-tests.js index 99b37861b3..eba4b3652b 100644 --- a/examples/tests/element/elementapi-tests.js +++ b/examples/tests/element/elementapi-tests.js @@ -79,4 +79,4 @@ describe('queries tests', function() { }); -}); \ No newline at end of file +}); diff --git a/examples/tests/sample-with-relative-locators.js b/examples/tests/sample-with-relative-locators.js index b8f9d4f301..65d8f82a4c 100644 --- a/examples/tests/sample-with-relative-locators.js +++ b/examples/tests/sample-with-relative-locators.js @@ -22,4 +22,4 @@ describe('sample with relative locators', function () { }); after(browser => browser.end()); -}); \ No newline at end of file +}); diff --git a/examples/tests/selectElement.js b/examples/tests/selectElement.js index 0d7a0176ad..c026cd5465 100644 --- a/examples/tests/selectElement.js +++ b/examples/tests/selectElement.js @@ -13,4 +13,4 @@ module.exports = { }) .assert.selected(await selectElement.findElement('option[value=four]'), 'Forth option is selected'); } -}; \ No newline at end of file +}; diff --git a/examples/tests/shadowRootExample.js b/examples/tests/shadowRootExample.js index abe7d6dfce..462c875c34 100644 --- a/examples/tests/shadowRootExample.js +++ b/examples/tests/shadowRootExample.js @@ -50,4 +50,4 @@ describe('Shadow Root example test', function() { // await expect.element(firstElement).to.be.an('img'); }); -}); \ No newline at end of file +}); diff --git a/examples/unittests/testUtils.js b/examples/unittests/testUtils.js index bff4a13f2f..c091100170 100644 --- a/examples/unittests/testUtils.js +++ b/examples/unittests/testUtils.js @@ -19,4 +19,4 @@ module.exports = { assert.strictEqual(Utils.getTestSuiteName('test.case.one'), 'Test Case One'); assert.strictEqual(Utils.getTestSuiteName('testCaseOne'), 'Test Case One'); } -}; \ No newline at end of file +}; diff --git a/examples/unittests/testUtilsWithChai.js b/examples/unittests/testUtilsWithChai.js index 4e6adc8108..6f8d701800 100644 --- a/examples/unittests/testUtilsWithChai.js +++ b/examples/unittests/testUtilsWithChai.js @@ -16,4 +16,4 @@ module.exports = { var resultMs = Utils.formatElapsedTime(999); expect(resultMs).to.equal('999ms'); } -}; \ No newline at end of file +}; diff --git a/lib/api/_loaders/_base-loader.js b/lib/api/_loaders/_base-loader.js index 0942aba134..14c2a4c7d1 100644 --- a/lib/api/_loaders/_base-loader.js +++ b/lib/api/_loaders/_base-loader.js @@ -399,20 +399,20 @@ class BaseLoader extends EventEmitter { const options = this.getCommandOptions(); - if (args && args.length > 0 && Utils.isFunction(args[args.length-1])) { + if (args && args.length > 0 && Utils.isFunction(args[args.length - 1])) { const callback = args.pop(); - + const userCallbackWrapper = (function(context) { - + const proxyFn = new Proxy(callback, { apply: function(target, thisArg, argumentsList) { context.addedInsideCallback = true; - + return target.apply(thisArg, argumentsList); } }); proxyFn.originalTarget = callback; - + return proxyFn; })(this); diff --git a/lib/api/_loaders/command.js b/lib/api/_loaders/command.js index 2843a9cc2f..3afd576d5b 100644 --- a/lib/api/_loaders/command.js +++ b/lib/api/_loaders/command.js @@ -42,7 +42,7 @@ class CommandLoader extends BaseCommandLoader { return function(...args) { let callback; let method; - const isLastArgFunction = isFunction(args[args.length-1]); + const isLastArgFunction = isFunction(args[args.length - 1]); if (isLastArgFunction) { callback = args.pop(); @@ -74,8 +74,8 @@ class CommandLoader extends BaseCommandLoader { reportProtocolErrors(result) { if (opts.isUserDefined) { return true; - } - + } + return super.reportProtocolErrors(result); } @@ -85,11 +85,11 @@ class CommandLoader extends BaseCommandLoader { get reuseBrowser() { return nightwatchInstance.argv['reuse-browser'] || (nightwatchInstance.settings.globals && nightwatchInstance.settings.globals.reuseBrowserSession); - } - + } + get isES6AsyncCommand() { return isES6AsyncFn( - CommandLoader.isDeprecatedCommandStyle(CommandModule) ? CommandModule.command: this.command + CommandLoader.isDeprecatedCommandStyle(CommandModule) ? CommandModule.command : this.command ); } @@ -210,7 +210,7 @@ class CommandLoader extends BaseCommandLoader { if (result.stack) { err.stack = result.stack; } - + if (result.error instanceof Error) { result.error.registered = true; } else { diff --git a/lib/api/_loaders/element-global.js b/lib/api/_loaders/element-global.js index ebed36155d..30f7a53024 100644 --- a/lib/api/_loaders/element-global.js +++ b/lib/api/_loaders/element-global.js @@ -161,7 +161,7 @@ class ElementGlobal { value = { value: locator, using: this.client.locateStrategy - }; + }; } else { value = locator; } @@ -267,7 +267,7 @@ class ElementGlobal { }); } - const lastArg = args[args.length-1]; + const lastArg = args[args.length - 1]; if (isFunction(lastArg)) { if (error) { return lastArg.call(this.api, { diff --git a/lib/api/_loaders/expect.js b/lib/api/_loaders/expect.js index 24ee01f385..a186f083ad 100644 --- a/lib/api/_loaders/expect.js +++ b/lib/api/_loaders/expect.js @@ -115,7 +115,7 @@ class ExpectLoader extends BaseCommandLoader { deferred.reject(err); }); } - + return expectCommand.instance; }.bind(this)); } diff --git a/lib/api/_loaders/static.js b/lib/api/_loaders/static.js index 913a9dd14d..dc75f485ba 100644 --- a/lib/api/_loaders/static.js +++ b/lib/api/_loaders/static.js @@ -182,7 +182,7 @@ module.exports = class StaticAssert { Object.assign(node.deferred.promise, apiToReturn || this.api); - //prevent unhandled rejection + //prevent unhandled rejection node.deferred.promise.catch(err => { return StaticAssert.lastDeferred.reject(err); }); diff --git a/lib/api/assertions/_assertionInstance.js b/lib/api/assertions/_assertionInstance.js index 273671ee0c..7bca65cbab 100644 --- a/lib/api/assertions/_assertionInstance.js +++ b/lib/api/assertions/_assertionInstance.js @@ -21,7 +21,7 @@ class AssertionInstance { } static init({nightwatchInstance, args, fileName, options}) { - if (Utils.isFunction(args[args.length-1])) { + if (Utils.isFunction(args[args.length - 1])) { this.__doneCallback = args.pop(); } else { this.__doneCallback = function(result) { diff --git a/lib/api/assertions/domPropertyMatches.js b/lib/api/assertions/domPropertyMatches.js index be80463240..ff03f08e77 100644 --- a/lib/api/assertions/domPropertyMatches.js +++ b/lib/api/assertions/domPropertyMatches.js @@ -1,12 +1,12 @@ /** * Check if specified DOM property value of a given element matches a regex. For all the available DOM element properties, consult the [Element doc at MDN](https://developer.mozilla.org/en-US/docs/Web/API/element). - * - * + * + * * @example * this.demoTest = function (browser) { * browser.assert.domPropertyMatches('#main', 'tagName', /^frame/); * } - * + * * @method assert.domPropertyMatches * @param {string|object} definition The selector (CSS/Xpath) used to locate the element. Can either be a string or an object which specifies [element properties](https://nightwatchjs.org/guide#element-properties). * @param {string} domProperty The DOM property name. @@ -41,10 +41,10 @@ exports.assertion = function (definition, domProperty, regexExpression, msg) { if (!Array.isArray(value)) { return regex.test(value); - } + } return false; - }; + }; this.value = function(result = {}) { return result.value || ''; diff --git a/lib/api/assertions/elementsCount.js b/lib/api/assertions/elementsCount.js index 68d0e244a7..c8b5285817 100644 --- a/lib/api/assertions/elementsCount.js +++ b/lib/api/assertions/elementsCount.js @@ -50,7 +50,7 @@ exports.assertion = function (definition, count, msg) { this.command = async function(callback) { - + await this.api.findElements(definition, callback); }; }; diff --git a/lib/api/assertions/enabled.js b/lib/api/assertions/enabled.js index 686542abf5..9e42334314 100644 --- a/lib/api/assertions/enabled.js +++ b/lib/api/assertions/enabled.js @@ -21,7 +21,7 @@ exports.assertion = function(definition, msg) { this.formatMessage = function() { const message = msg || `Testing if element %s ${this.negate ? 'is not enabled' : 'is enabled'}`; - + return { message, args: [this.elementSelector] @@ -43,5 +43,5 @@ exports.assertion = function(definition, msg) { this.command = function(callback) { this.api.isEnabled(definition, callback); }; - + }; diff --git a/lib/api/assertions/hasAttribute.js b/lib/api/assertions/hasAttribute.js index c05de41cd0..8143b300d4 100644 --- a/lib/api/assertions/hasAttribute.js +++ b/lib/api/assertions/hasAttribute.js @@ -3,12 +3,12 @@ * Checks if the given element contains the specified DOM attribute. * * Equivalent of: https://developer.mozilla.org/en-US/docs/Web/API/Element/hasAttribute - * + * * @example * this.demoTest = function (browser) { * browser.assert.hasAttribute('#main', 'data-track'); * }; - * + * * @method assert.hasAttribute * @param {string|object} definition The selector (CSS/Xpath) used to locate the element. Can either be a string or an object which specifies [element properties](https://nightwatchjs.org/guide#element-properties). * @param {string} expectedAttribute The DOM attribute to look for. @@ -26,15 +26,15 @@ exports.assertion = function(definition, expectedAttribute, msg) { this.expected = function() { return this.negate ? `has not ${expectedAttribute}` : `has ${expectedAttribute}`; }; - + this.formatMessage = function() { if (!isString(expectedAttribute)) { throw new Error('Expected attribute must be a string'); } - let message = msg || `Testing if element %s ${this.negate ? 'doesn\'t have attribute %s' : 'has attribute %s'}`; - + const message = msg || `Testing if element %s ${this.negate ? 'doesn\'t have attribute %s' : 'has attribute %s'}`; + return { message, args: [this.elementSelector, `'${expectedAttribute}'`] @@ -47,7 +47,7 @@ exports.assertion = function(definition, expectedAttribute, msg) { if (!result || !result.value) { return false; } - + return true; }; diff --git a/lib/api/assertions/hasClass.js b/lib/api/assertions/hasClass.js index 077ff18ab6..fa115dd5b3 100644 --- a/lib/api/assertions/hasClass.js +++ b/lib/api/assertions/hasClass.js @@ -1,6 +1,6 @@ /** * Checks if the given element has the specified CSS class. - * + * * @example * this.demoTest = function (browser) { * browser.assert.hasClass('#main', 'container'); @@ -18,7 +18,7 @@ const classListRegexp = /\s/; const classNameRegexp = /\w/; const {containsMultiple, setElementSelectorProps} = require('../../utils'); - + exports.assertion = function(definition, expected, msg) { this.options = { elementSelector: true @@ -27,41 +27,40 @@ exports.assertion = function(definition, expected, msg) { this.expected = function() { return this.negate ? `has not ${expected}` : `has ${expected}`; }; - + this.formatMessage = function() { - let message = msg || `Testing if element %s ${this.negate ? 'doesn\'t have css class %s' : 'has css class %s'}`; - + const message = msg || `Testing if element %s ${this.negate ? 'doesn\'t have css class %s' : 'has css class %s'}`; + return { message, args: [this.elementSelector, `'${Array.isArray(expected) ? expected.join(' ') : expected}'`] }; }; - - + + this.evaluate = function() { if (!this.classList) { return false; } - + return containsMultiple(this.classList, expected, ' '); }; - + this.value = function(result) { if (!result || !result.value) { return ''; } - + this.classList = result.value .split(classListRegexp) .filter(item => classNameRegexp.test(item)); - + return result.value; }; - + this.command = function(callback) { this.api.getAttribute(setElementSelectorProps(definition, { suppressNotFoundErrors: true }), 'class', callback); }; }; - \ No newline at end of file diff --git a/lib/api/assertions/selected.js b/lib/api/assertions/selected.js index 296c01549d..90528945a4 100644 --- a/lib/api/assertions/selected.js +++ b/lib/api/assertions/selected.js @@ -44,4 +44,4 @@ exports.assertion = function(definition, msg) { this.api.isSelected(definition, callback); }; -}; \ No newline at end of file +}; diff --git a/lib/api/assertions/textEquals.js b/lib/api/assertions/textEquals.js index 17fe92fdc5..4d83a80eef 100644 --- a/lib/api/assertions/textEquals.js +++ b/lib/api/assertions/textEquals.js @@ -5,7 +5,7 @@ * this.demoTest = function (browser) { * browser.assert.textEquals('#main', 'The Night Watch'); * }; - * + * * @method assert.textEquals * @param {string|object} definition The selector (CSS/Xpath) used to locate the element. Can either be a string or an object which specifies [element properties](https://nightwatchjs.org/guide#element-properties). * @param {string} expected text to match text. @@ -19,20 +19,20 @@ exports.assertion = function(definition, expected, msg) { this.options = { elementSelector: true }; - + this.formatMessage = function() { const message = msg || `Testing if element's %s inner text ${this.negate ? 'doesn\'t equal %s' : 'equals %s'}`; - + return { message, args: [this.elementSelector, `'${expected}'`] }; }; - + this.expected = function() { return this.negate ? `doesn't equal '${expected}'` : `equals '${expected}'`; }; - + this.evaluate = function(value) { if (typeof value != 'string') { return false; @@ -67,4 +67,4 @@ exports.assertion = function(definition, expected, msg) { suppressNotFoundErrors: true }), callback); }; -}; \ No newline at end of file +}; diff --git a/lib/api/assertions/textMatches.js b/lib/api/assertions/textMatches.js index 9adb84e3f0..d09e14a790 100644 --- a/lib/api/assertions/textMatches.js +++ b/lib/api/assertions/textMatches.js @@ -5,7 +5,7 @@ * this.demoTest = function (browser) { * browser.assert.textMatches('#main', '^Nightwatch'); * }; - * + * * @method assert.textMatches * @param {string|object} definition The selector (CSS/Xpath) used to locate the element. Can either be a string or an object which specifies [element properties](https://nightwatchjs.org/guide#element-properties). * @param {string|RegExp} regexExpression Regex expression to match text. diff --git a/lib/api/assertions/titleEquals.js b/lib/api/assertions/titleEquals.js index 2897d6ed58..7ac6865b22 100644 --- a/lib/api/assertions/titleEquals.js +++ b/lib/api/assertions/titleEquals.js @@ -1,6 +1,6 @@ /** * Checks if the page title equals the given value. - * + * * @example * this.demoTest = function (client) { * browser.assert.titleEquals('https://www.google.com'); diff --git a/lib/api/assertions/titleMatches.js b/lib/api/assertions/titleMatches.js index 445f414993..35a89d8bd5 100644 --- a/lib/api/assertions/titleMatches.js +++ b/lib/api/assertions/titleMatches.js @@ -5,7 +5,7 @@ * this.demoTest = function (client) { * browser.assert.titleMatches('^Nightwatch'); * }; - * + * * @method assert.titleMatches * @param {string|RegExp} regexExpression Regex expression to match current title of a page * @param {string} [msg] Optional log message to display in the output. If missing, one is displayed by default. diff --git a/lib/api/assertions/urlMatches.js b/lib/api/assertions/urlMatches.js index 5b5d05a20a..a33910fc5c 100644 --- a/lib/api/assertions/urlMatches.js +++ b/lib/api/assertions/urlMatches.js @@ -5,7 +5,7 @@ * this.demoTest = function (client) { * browser.assert.urlMatches('^https'); * }; - * + * * @method assert.urlMatches * @param {string|RegExp} regexExpression Regex expression to match URL * @param {string} [msg] Optional log message to display in the output. If missing, one is displayed by default. diff --git a/lib/api/assertions/valueEquals.js b/lib/api/assertions/valueEquals.js index 011070c457..14a3d291e5 100644 --- a/lib/api/assertions/valueEquals.js +++ b/lib/api/assertions/valueEquals.js @@ -1,10 +1,10 @@ /** * Checks if the given form element's value equals the expected value. - * + * * The existing .assert.value() command. * - * + * * @example * this.demoTest = function (browser) { * browser.assert.valueEquals("form.login input[type=text]", "username"); diff --git a/lib/api/client-commands/alerts/setText.js b/lib/api/client-commands/alerts/setText.js index 5b2e06b792..4f817d8f8d 100644 --- a/lib/api/client-commands/alerts/setText.js +++ b/lib/api/client-commands/alerts/setText.js @@ -44,7 +44,7 @@ class SetAlertText extends ClientCommand { } this.alertText = value; - + return super.command(callback); } } diff --git a/lib/api/client-commands/axeInject.js b/lib/api/client-commands/axeInject.js index 4a72d758db..99332b6147 100644 --- a/lib/api/client-commands/axeInject.js +++ b/lib/api/client-commands/axeInject.js @@ -25,4 +25,4 @@ module.exports = class AxeInjectAbstract { static get allowOverride() { return true; } -}; \ No newline at end of file +}; diff --git a/lib/api/client-commands/debug.js b/lib/api/client-commands/debug.js index 76e1477b56..f2c313017a 100644 --- a/lib/api/client-commands/debug.js +++ b/lib/api/client-commands/debug.js @@ -7,7 +7,7 @@ const Debuggability = require('../../utils/debuggability.js'); * This command halts the test execution and provides users with a REPL interface where they can type * any of the available Nightwatch commands and the command will be executed in the running browser * in real-time. - * + * * This can be used to debug why a certain command in not working as expected, find the correct * locators for your assertions or just play around with the available Nightwatch commands. * @@ -16,10 +16,10 @@ const Debuggability = require('../../utils/debuggability.js'); * // command to get the correct result as output. * this.demoTest = async function (browser) { * browser.debug(); - * + * * // with no auto-complete * browser.debug({preview: false}); - * + * * // with a timeout of 6000 ms (time for which the interface * // would wait for a result). * browser.debug({timeout: 6000}) diff --git a/lib/api/client-commands/document/injectScript.js b/lib/api/client-commands/document/injectScript.js index 9954cf28ed..790dc88339 100644 --- a/lib/api/client-commands/document/injectScript.js +++ b/lib/api/client-commands/document/injectScript.js @@ -50,7 +50,7 @@ class InjectScript extends ClientCommand { this.scriptFn = 'var passedArgs = Array.prototype.slice.call(arguments,0); return (' + script.toString() + ').apply(window, passedArgs);'; - this.scriptArgs = args; + this.scriptArgs = args; return super.command(callback); } diff --git a/lib/api/client-commands/enablePerformanceMetrics.js b/lib/api/client-commands/enablePerformanceMetrics.js index 1494188522..3439346cb1 100644 --- a/lib/api/client-commands/enablePerformanceMetrics.js +++ b/lib/api/client-commands/enablePerformanceMetrics.js @@ -40,7 +40,7 @@ class EnablePerformanceMetrics extends ClientCommand { } const {enable = true} = this; - + this.transportActions.enablePerformanceMetrics(enable, callback); } diff --git a/lib/api/client-commands/getPerformanceMetrics.js b/lib/api/client-commands/getPerformanceMetrics.js index be396c9684..9ed95aeefb 100644 --- a/lib/api/client-commands/getPerformanceMetrics.js +++ b/lib/api/client-commands/getPerformanceMetrics.js @@ -38,7 +38,7 @@ class GetPerformanceMetrics extends ClientCommand { return callback(error); } - + this.transportActions.getPerformanceMetrics(callback); } diff --git a/lib/api/client-commands/logs/captureBrowserConsoleLogs.js b/lib/api/client-commands/logs/captureBrowserConsoleLogs.js index aea9312591..e7756ae636 100644 --- a/lib/api/client-commands/logs/captureBrowserConsoleLogs.js +++ b/lib/api/client-commands/logs/captureBrowserConsoleLogs.js @@ -45,7 +45,7 @@ class StartCapturingLogs extends ClientCommand { return callback(error); } - + this.transportActions.startLogsCapture(userCallback, callback); } diff --git a/lib/api/client-commands/logs/captureBrowserExceptions.js b/lib/api/client-commands/logs/captureBrowserExceptions.js index 39adb9fe1c..43bfeafebd 100644 --- a/lib/api/client-commands/logs/captureBrowserExceptions.js +++ b/lib/api/client-commands/logs/captureBrowserExceptions.js @@ -60,4 +60,4 @@ class CatchJsExceptions extends ClientCommand { } } -module.exports = CatchJsExceptions; \ No newline at end of file +module.exports = CatchJsExceptions; diff --git a/lib/api/client-commands/logs/getSessionLogTypes.js b/lib/api/client-commands/logs/getSessionLogTypes.js index c2fd265ea4..13cda02d8f 100644 --- a/lib/api/client-commands/logs/getSessionLogTypes.js +++ b/lib/api/client-commands/logs/getSessionLogTypes.js @@ -9,7 +9,7 @@ const ClientCommand = require('../_base-command.js'); * browser.logs.getSessionLogTypes(function(result) { * const logTypes = result.value; * console.log('Log types available:', logTypes); - * }); + * }); * }); * * it('get log types with ES6 async/await', async function(browser) { diff --git a/lib/api/client-commands/logs/isSessionLogAvailable.js b/lib/api/client-commands/logs/isSessionLogAvailable.js index 163e2e7c00..14231b5123 100644 --- a/lib/api/client-commands/logs/isSessionLogAvailable.js +++ b/lib/api/client-commands/logs/isSessionLogAvailable.js @@ -11,7 +11,7 @@ const ClientCommand = require('../_base-command.js'); * if (isAvailable) { * // do something more in here * } - * }); + * }); * }); * * it('test driver log type with ES6 async/await', async function(browser) { diff --git a/lib/api/client-commands/network/captureRequests.js b/lib/api/client-commands/network/captureRequests.js index 658aab01f2..77aa01312f 100644 --- a/lib/api/client-commands/network/captureRequests.js +++ b/lib/api/client-commands/network/captureRequests.js @@ -49,7 +49,7 @@ class CaptureNetworkCalls extends ClientCommand { return callback(error); } - + this.transportActions.interceptNetworkCalls(userCallback, callback); } @@ -60,4 +60,4 @@ class CaptureNetworkCalls extends ClientCommand { } } -module.exports = CaptureNetworkCalls; \ No newline at end of file +module.exports = CaptureNetworkCalls; diff --git a/lib/api/client-commands/network/mockResponse.js b/lib/api/client-commands/network/mockResponse.js index e38bcbd54b..0ce0977cad 100644 --- a/lib/api/client-commands/network/mockResponse.js +++ b/lib/api/client-commands/network/mockResponse.js @@ -54,7 +54,7 @@ class MockNetworkResponse extends ClientCommand { const slashDel = needsSlash ? '/' : ''; urlToIntercept = `${launchUrl}${slashDel}${urlToIntercept}`; } - + this.transportActions.mockNetworkResponse(urlToIntercept, response, callback); } diff --git a/lib/api/client-commands/network/setConditions.js b/lib/api/client-commands/network/setConditions.js index a3f8f34b70..64e80df09f 100644 --- a/lib/api/client-commands/network/setConditions.js +++ b/lib/api/client-commands/network/setConditions.js @@ -2,7 +2,7 @@ const ClientCommand = require('../_base-command.js'); const {Logger} = require('../../../utils'); /** - * + * * Command to set Chrome network emulation settings. * * @example diff --git a/lib/api/client-commands/pause.js b/lib/api/client-commands/pause.js index 6accd2dadc..695d8a4a18 100644 --- a/lib/api/client-commands/pause.js +++ b/lib/api/client-commands/pause.js @@ -9,11 +9,11 @@ const Debuggability = require('../../utils/debuggability.js'); * - Pause the test execution for the given time in milliseconds. * - Pause the test execution indefinitely, until resumed by pressing a key in terminal. * - Pause the test execution, and then step over to the next test command (execute the next test command) and pause again. - * + * * This command will allow you to pause the test execution in between, hop on to the browser to check the state of your * application (or use DevTools to debug), and once satisfied, either resume the test execution from where it was left * off or step over to the next test command (execute the next test command) and pause again. - * + * * Stepping over to the next test command would allow you to see what exactly changed in your application when the next * test command was executed. You can also use DevTools to monitor those changes, like the network calls that were made * during the execution of that command, etc. @@ -84,7 +84,7 @@ Pause.prototype.command = function(ms, cb) { if (cb) { cb.call(this.client.api); } - + this.emit('complete'); }, ms); } diff --git a/lib/api/client-commands/registerBasicAuth.js b/lib/api/client-commands/registerBasicAuth.js index 715a123534..1b660128d2 100644 --- a/lib/api/client-commands/registerBasicAuth.js +++ b/lib/api/client-commands/registerBasicAuth.js @@ -35,7 +35,7 @@ class RegisterBasicAuth extends ClientCommand { } const {username, password} = this; - + this.transportActions .registerAuth(username, password, callback) .catch(err => { diff --git a/lib/api/client-commands/saveSnapshot.js b/lib/api/client-commands/saveSnapshot.js index dbc37e2920..2c3fceb909 100644 --- a/lib/api/client-commands/saveSnapshot.js +++ b/lib/api/client-commands/saveSnapshot.js @@ -84,4 +84,4 @@ class SaveSnapshot extends ClientCommand { } } -module.exports = SaveSnapshot; \ No newline at end of file +module.exports = SaveSnapshot; diff --git a/lib/api/client-commands/setDeviceDimensions.js b/lib/api/client-commands/setDeviceDimensions.js index e5f16c1583..ddfc94ce89 100644 --- a/lib/api/client-commands/setDeviceDimensions.js +++ b/lib/api/client-commands/setDeviceDimensions.js @@ -59,4 +59,4 @@ class SetDeviceDimensions extends ClientCommand { } } -module.exports = SetDeviceDimensions; \ No newline at end of file +module.exports = SetDeviceDimensions; diff --git a/lib/api/client-commands/takeHeapSnapshot.js b/lib/api/client-commands/takeHeapSnapshot.js index a5e6348d2a..11724d1e88 100644 --- a/lib/api/client-commands/takeHeapSnapshot.js +++ b/lib/api/client-commands/takeHeapSnapshot.js @@ -38,7 +38,7 @@ class TakeHeapSnapshot extends ClientCommand { } const {heapSnapshotLocation} = this; - + this.transportActions.takeHeapSnapshot(heapSnapshotLocation, callback); } diff --git a/lib/api/client-commands/within.js b/lib/api/client-commands/within.js index 872ecc5fda..60931fe6bc 100644 --- a/lib/api/client-commands/within.js +++ b/lib/api/client-commands/within.js @@ -20,4 +20,4 @@ module.exports = class WithinAbstract { static get allowOverride() { return true; } -}; \ No newline at end of file +}; diff --git a/lib/api/element-commands/click.js b/lib/api/element-commands/click.js index 96763ce5ac..7a7a6006a0 100644 --- a/lib/api/element-commands/click.js +++ b/lib/api/element-commands/click.js @@ -66,4 +66,4 @@ class ClickElement extends BaseElementCommand { } } -module.exports = ClickElement; \ No newline at end of file +module.exports = ClickElement; diff --git a/lib/api/element-commands/getFirstElementChild.js b/lib/api/element-commands/getFirstElementChild.js index 35e0445b02..6aff20a5f4 100644 --- a/lib/api/element-commands/getFirstElementChild.js +++ b/lib/api/element-commands/getFirstElementChild.js @@ -23,7 +23,7 @@ const BaseElementCommand = require('./_baseElementCommand.js'); * @api protocol.elements */ class GetFirstElementChild extends BaseElementCommand { - + get extraArgsCount() { return 0; } @@ -35,4 +35,4 @@ class GetFirstElementChild extends BaseElementCommand { } } -module.exports = GetFirstElementChild; \ No newline at end of file +module.exports = GetFirstElementChild; diff --git a/lib/api/element-commands/getLastElementChild.js b/lib/api/element-commands/getLastElementChild.js index b3640414bf..a73cbcf4b3 100644 --- a/lib/api/element-commands/getLastElementChild.js +++ b/lib/api/element-commands/getLastElementChild.js @@ -28,10 +28,10 @@ class GetLastElementChild extends BaseElementCommand { get extraArgsCount() { return 0; } - + async protocolAction() { return this.executeProtocolAction('getLastElementChild'); } } -module.exports = GetLastElementChild; \ No newline at end of file +module.exports = GetLastElementChild; diff --git a/lib/api/element-commands/getNextSibling.js b/lib/api/element-commands/getNextSibling.js index cf54871c85..4f89748939 100644 --- a/lib/api/element-commands/getNextSibling.js +++ b/lib/api/element-commands/getNextSibling.js @@ -23,14 +23,14 @@ const BaseElementCommand = require('./_baseElementCommand.js'); * @exampleLink /api/getNextSibling.js */ class GetNextSibling extends BaseElementCommand { - + get extraArgsCount() { return 0; } - + async protocolAction() { return await this.executeProtocolAction('getNextSibling'); } } -module.exports = GetNextSibling; \ No newline at end of file +module.exports = GetNextSibling; diff --git a/lib/api/element-commands/getPreviousSibling.js b/lib/api/element-commands/getPreviousSibling.js index e0daef3556..953d4d84b6 100644 --- a/lib/api/element-commands/getPreviousSibling.js +++ b/lib/api/element-commands/getPreviousSibling.js @@ -43,14 +43,14 @@ const BaseElementCommand = require('./_baseElementCommand.js'); * @api protocol.elements */ class GetPreviousSibling extends BaseElementCommand { - + get extraArgsCount() { return 0; } - + async protocolAction() { return this.executeProtocolAction('getPreviousSibling'); } } -module.exports = GetPreviousSibling; \ No newline at end of file +module.exports = GetPreviousSibling; diff --git a/lib/api/element-commands/isEnabled.js b/lib/api/element-commands/isEnabled.js index e270d852f1..d0a03a8ebd 100644 --- a/lib/api/element-commands/isEnabled.js +++ b/lib/api/element-commands/isEnabled.js @@ -54,4 +54,4 @@ class IsEnabled extends BaseElementCommand { } -module.exports = IsEnabled; \ No newline at end of file +module.exports = IsEnabled; diff --git a/lib/api/element-commands/isPresent.js b/lib/api/element-commands/isPresent.js index 011127bda9..8bac2f5041 100644 --- a/lib/api/element-commands/isPresent.js +++ b/lib/api/element-commands/isPresent.js @@ -2,7 +2,7 @@ const BaseElementCommand = require('./_baseElementCommand.js'); const {Logger, filterStackTrace} = require('../../utils'); /** * Determines if an element is present in the DOM. - * + * * @example * module.exports = { * demoTest(browser) { @@ -70,4 +70,4 @@ class isPresent extends BaseElementCommand { } -module.exports = isPresent; \ No newline at end of file +module.exports = isPresent; diff --git a/lib/api/element-commands/isSelected.js b/lib/api/element-commands/isSelected.js index 23514aac99..48c97880ca 100644 --- a/lib/api/element-commands/isSelected.js +++ b/lib/api/element-commands/isSelected.js @@ -54,4 +54,4 @@ class IsSelected extends BaseElementCommand { } -module.exports = IsSelected; \ No newline at end of file +module.exports = IsSelected; diff --git a/lib/api/element-commands/setPassword.js b/lib/api/element-commands/setPassword.js index 43dbcd6716..c71a9d0193 100644 --- a/lib/api/element-commands/setPassword.js +++ b/lib/api/element-commands/setPassword.js @@ -47,4 +47,4 @@ class SetPassword extends BaseElementCommand { } } -module.exports = SetPassword; \ No newline at end of file +module.exports = SetPassword; diff --git a/lib/api/element-commands/uploadFile.js b/lib/api/element-commands/uploadFile.js index 2eaa39bc72..ec715406f5 100644 --- a/lib/api/element-commands/uploadFile.js +++ b/lib/api/element-commands/uploadFile.js @@ -32,4 +32,4 @@ class UploadFile extends BaseElementCommand { } -module.exports = UploadFile; \ No newline at end of file +module.exports = UploadFile; diff --git a/lib/api/expect/assertions/_baseAssertion.js b/lib/api/expect/assertions/_baseAssertion.js index 756b1dd7cf..bc492b0926 100644 --- a/lib/api/expect/assertions/_baseAssertion.js +++ b/lib/api/expect/assertions/_baseAssertion.js @@ -147,7 +147,7 @@ class BaseAssertion { init() { const {waitForConditionTimeout, waitForConditionPollInterval, abortOnAssertionFailure} = this.client.api.globals; - let assertions = this.flag('assertions') || 0; + const assertions = this.flag('assertions') || 0; this.flag('assertions', assertions + 1); this.promise = this.flag('promise'); @@ -340,7 +340,7 @@ class BaseAssertion { } getResult(value, fn) { - let result = fn.call(this); + const result = fn.call(this); this.setNegate(); return this.negate ? !result : result; @@ -357,7 +357,7 @@ class BaseAssertion { } getElapsedTime() { - let timeNow = new Date().getTime(); + const timeNow = new Date().getTime(); return timeNow - this.emitter.startTime; } @@ -467,8 +467,8 @@ class BaseAssertion { } '@matchesFlag'(re) { - let adverb = this.hasFlag('that') || this.hasFlag('which'); - let verb = adverb ? 'matches' : 'match'; + const adverb = this.hasFlag('that') || this.hasFlag('which'); + const verb = adverb ? 'matches' : 'match'; this.conditionFlag(re, function() { return re.test(this.resultValue); @@ -483,7 +483,7 @@ class BaseAssertion { conditionFlag(value, conditionFn, arrverb) { this.passed = this.getResult(value, conditionFn); - let verb = this.negate ? arrverb[0]: arrverb[1]; + let verb = this.negate ? arrverb[0] : arrverb[1]; this.expected = `${verb} '${value}'`; this.actual = this.resultValue; @@ -491,7 +491,7 @@ class BaseAssertion { return; } - let needsSpace = this.messageParts.length === 0 ? true : this.messageParts[this.messageParts.length-1].slice(-1) !== ' '; + const needsSpace = this.messageParts.length === 0 ? true : this.messageParts[this.messageParts.length - 1].slice(-1) !== ' '; if (needsSpace) { verb = ' ' + verb; } diff --git a/lib/api/expect/assertions/element/type.js b/lib/api/expect/assertions/element/type.js index f7ec379fab..b02d4f02f2 100644 --- a/lib/api/expect/assertions/element/type.js +++ b/lib/api/expect/assertions/element/type.js @@ -34,7 +34,7 @@ class TypeAssertion extends BaseAssertion { this.article = ['a', 'e', 'i', 'o'].indexOf(type.toString().substring(0, 1)) > -1 ? 'an' : 'a'; this.hasCustomMessage = typeof msg != 'undefined'; this.flag('typeFlag', true); - this.message = msg || 'Expected element %s to ' + (this.negate ? 'not be' : 'be') + ' ' + this.article +' ' + type; + this.message = msg || 'Expected element %s to ' + (this.negate ? 'not be' : 'be') + ' ' + this.article + ' ' + type; this.start(); } diff --git a/lib/api/protocol/elementIdDoubleClick.js b/lib/api/protocol/elementIdDoubleClick.js index ccfbc91b35..3649bfeba3 100644 --- a/lib/api/protocol/elementIdDoubleClick.js +++ b/lib/api/protocol/elementIdDoubleClick.js @@ -5,7 +5,7 @@ const {isFunction} = require('../../utils'); * Move to the element and performs a double-click in the middle of the given element if element is given else double-clicks at the current mouse coordinates (set by `.moveTo()`). * * @method elementIdDoubleClick - * @param {string} webElementId The [Web Element ID](https://www.w3.org/TR/webdriver1/#dfn-web-elements) of the element to route the command to. + * @param {string} webElementId The [Web Element ID](https://www.w3.org/TR/webdriver1/#dfn-web-elements) of the element to route the command to. * @param {function} [callback] Optional callback function to be called when the command finishes. * @api protocol.useractions */ @@ -13,7 +13,7 @@ module.exports = class elementIdDoubleClick extends ProtocolAction { static get isTraceable() { return true; } - + command(webElementId, callback) { if (isFunction(webElementId)) { diff --git a/lib/api/protocol/frame.js b/lib/api/protocol/frame.js index 8c9d78d9b5..00a542c939 100644 --- a/lib/api/protocol/frame.js +++ b/lib/api/protocol/frame.js @@ -28,7 +28,7 @@ const ProtocolAction = require('./_base-action.js'); * @api protocol.frames */ const findElement = function(selector) { - + return new Promise((resolve, reject) => { this.api.findElement({selector, suppressNotFoundErrors: true}, function(res) { if (res.status === -1 && res.error) { diff --git a/lib/api/protocol/moveTo.js b/lib/api/protocol/moveTo.js index 11ca2a01e5..3131b1730a 100644 --- a/lib/api/protocol/moveTo.js +++ b/lib/api/protocol/moveTo.js @@ -48,7 +48,7 @@ module.exports = class Command extends ProtocolAction { ProtocolAction.validateElementId(webElementId); } } - + if (args.length === 1 && isNumber(args[0]) && !isNaN(args[0])) { xoffset = args[0]; } else if (args.length === 2 && isNumber(args[0]) && !isNaN(args[0]) && isNumber(args[1]) && !isNaN(args[1])) { @@ -63,6 +63,6 @@ module.exports = class Command extends ProtocolAction { } return this.transportActions.moveTo(webElementId, xoffset, yoffset, callback); - + } }; diff --git a/lib/api/protocol/releaseMouseButton.js b/lib/api/protocol/releaseMouseButton.js index 2ef6a66120..96e72ba36d 100644 --- a/lib/api/protocol/releaseMouseButton.js +++ b/lib/api/protocol/releaseMouseButton.js @@ -1,7 +1,7 @@ const ProtocolAction = require('./_base-action.js'); /** * Release the depressed left mouse button at the current mouse coordinates (set by `.moveTo()`). - * + * * * @param {function} [callback] Optional callback function to be called when the command finishes. * @api protocol.useractions diff --git a/lib/api/web-element/assert/element-assertions.js b/lib/api/web-element/assert/element-assertions.js index 138b39d5bb..59360c48bc 100644 --- a/lib/api/web-element/assert/element-assertions.js +++ b/lib/api/web-element/assert/element-assertions.js @@ -11,7 +11,7 @@ class ScopedElementAssertions { const assert = this.nightwatchInstance.api.assert; await callback(this.negated ? assert.not : assert, this.scopedElement.webElement); - + return this.scopedElement; } diff --git a/lib/api/web-element/commands/getAccessibleName.js b/lib/api/web-element/commands/getAccessibleName.js index 361180f918..202e2a3d26 100644 --- a/lib/api/web-element/commands/getAccessibleName.js +++ b/lib/api/web-element/commands/getAccessibleName.js @@ -26,4 +26,4 @@ */ module.exports.command = function() { return this.runQueuedCommandScoped('getElementAccessibleName'); -}; \ No newline at end of file +}; diff --git a/lib/api/web-element/commands/getAriaRole.js b/lib/api/web-element/commands/getAriaRole.js index e670d425c8..0f32df12a7 100644 --- a/lib/api/web-element/commands/getAriaRole.js +++ b/lib/api/web-element/commands/getAriaRole.js @@ -25,4 +25,4 @@ */ module.exports.command = function() { return this.runQueuedCommandScoped('getElementAriaRole'); -}; \ No newline at end of file +}; diff --git a/lib/api/web-element/commands/getAttribute.js b/lib/api/web-element/commands/getAttribute.js index 3dcd4a952b..2d47d223cd 100644 --- a/lib/api/web-element/commands/getAttribute.js +++ b/lib/api/web-element/commands/getAttribute.js @@ -29,4 +29,4 @@ */ module.exports.command = function(name) { return this.runQueuedCommandScoped('getElementValue', name); -}; \ No newline at end of file +}; diff --git a/lib/api/web-element/commands/getCssProperty.js b/lib/api/web-element/commands/getCssProperty.js index 254bc13d5b..cbdb1d83cd 100644 --- a/lib/api/web-element/commands/getCssProperty.js +++ b/lib/api/web-element/commands/getCssProperty.js @@ -40,4 +40,4 @@ */ module.exports.command = function(cssProperty) { return this.runQueuedCommandScoped('getElementCSSValue', cssProperty); -}; \ No newline at end of file +}; diff --git a/lib/api/web-element/commands/getId.js b/lib/api/web-element/commands/getId.js index c756229a5e..a73b53923e 100644 --- a/lib/api/web-element/commands/getId.js +++ b/lib/api/web-element/commands/getId.js @@ -25,4 +25,4 @@ module.exports.command = function() { return this.runQueuedCommandScoped(function (webElement) { return webElement.getId(); }); -}; \ No newline at end of file +}; diff --git a/lib/api/web-element/commands/getProperty.js b/lib/api/web-element/commands/getProperty.js index 0c3f2773b2..934f7b158d 100644 --- a/lib/api/web-element/commands/getProperty.js +++ b/lib/api/web-element/commands/getProperty.js @@ -42,4 +42,4 @@ */ module.exports.command = function(name) { return this.runQueuedCommandScoped('getElementProperty', name); -}; \ No newline at end of file +}; diff --git a/lib/api/web-element/commands/getRect.js b/lib/api/web-element/commands/getRect.js index ab4be35e54..9ecdaaf5ab 100644 --- a/lib/api/web-element/commands/getRect.js +++ b/lib/api/web-element/commands/getRect.js @@ -32,4 +32,4 @@ */ module.exports.command = function() { return this.runQueuedCommandScoped('getElementRect'); -}; \ No newline at end of file +}; diff --git a/lib/api/web-element/commands/getTagName.js b/lib/api/web-element/commands/getTagName.js index 2d6a62c408..f2a06e56cd 100644 --- a/lib/api/web-element/commands/getTagName.js +++ b/lib/api/web-element/commands/getTagName.js @@ -26,4 +26,4 @@ */ module.exports.command = function() { return this.runQueuedCommandScoped('getElementTagName'); -}; \ No newline at end of file +}; diff --git a/lib/api/web-element/commands/getText.js b/lib/api/web-element/commands/getText.js index 78cac96931..f4d56d9420 100644 --- a/lib/api/web-element/commands/getText.js +++ b/lib/api/web-element/commands/getText.js @@ -26,4 +26,4 @@ */ module.exports.command = function() { return this.runQueuedCommandScoped('getElementText'); -}; \ No newline at end of file +}; diff --git a/lib/api/web-element/commands/getValue.js b/lib/api/web-element/commands/getValue.js index da0c4a9fe9..a1ea155c71 100644 --- a/lib/api/web-element/commands/getValue.js +++ b/lib/api/web-element/commands/getValue.js @@ -26,4 +26,4 @@ */ module.exports.command = function () { return this.getProperty('value'); -}; \ No newline at end of file +}; diff --git a/lib/api/web-element/commands/rightClick.js b/lib/api/web-element/commands/rightClick.js index d9b0eb9a7b..a31f0e14b4 100644 --- a/lib/api/web-element/commands/rightClick.js +++ b/lib/api/web-element/commands/rightClick.js @@ -24,4 +24,4 @@ */ module.exports.command = function() { return this.runQueuedCommand('contextClick'); -}; \ No newline at end of file +}; diff --git a/lib/api/web-element/commands/setAttribute.js b/lib/api/web-element/commands/setAttribute.js index 01aeeddfd7..c5464a8a07 100644 --- a/lib/api/web-element/commands/setAttribute.js +++ b/lib/api/web-element/commands/setAttribute.js @@ -27,4 +27,4 @@ module.exports.command = function(name, value) { return this.runQueuedCommand('setElementAttribute', { args: [name, value] }); -}; \ No newline at end of file +}; diff --git a/lib/api/web-element/commands/setProperty.js b/lib/api/web-element/commands/setProperty.js index b21153d373..27339bfaf6 100644 --- a/lib/api/web-element/commands/setProperty.js +++ b/lib/api/web-element/commands/setProperty.js @@ -25,4 +25,4 @@ module.exports.command = function(name, value) { return this.runQueuedCommand('setElementProperty', { args: [name, value] }); -}; \ No newline at end of file +}; diff --git a/lib/api/web-element/commands/submit.js b/lib/api/web-element/commands/submit.js index 8348b70c3a..0582d00112 100644 --- a/lib/api/web-element/commands/submit.js +++ b/lib/api/web-element/commands/submit.js @@ -25,4 +25,4 @@ */ module.exports.command = function() { return this.runQueuedCommand('elementSubmit'); -}; \ No newline at end of file +}; diff --git a/lib/api/web-element/commands/takeScreenshot.js b/lib/api/web-element/commands/takeScreenshot.js index 5512e909d5..9f4ab1b200 100644 --- a/lib/api/web-element/commands/takeScreenshot.js +++ b/lib/api/web-element/commands/takeScreenshot.js @@ -26,4 +26,4 @@ */ module.exports.command = function() { return this.runQueuedCommandScoped('takeElementScreenshot'); -}; \ No newline at end of file +}; diff --git a/lib/api/web-element/commands/upload.js b/lib/api/web-element/commands/upload.js index 63cd51871d..f4ec3b1b95 100644 --- a/lib/api/web-element/commands/upload.js +++ b/lib/api/web-element/commands/upload.js @@ -27,4 +27,4 @@ module.exports.command = function(file) { return this.runQueuedCommand('uploadFile', { args: [file] }); -}; \ No newline at end of file +}; diff --git a/lib/api/web-element/factory.js b/lib/api/web-element/factory.js index a67a728737..b7e557831d 100644 --- a/lib/api/web-element/factory.js +++ b/lib/api/web-element/factory.js @@ -60,11 +60,11 @@ const createScopedWebElement = function(selector, parentElement, nightwatchInsta nightwatchInstance, ...args }); - + return waitUntil.wait().then(element => resolve(element)); }.bind(instance)), parentElement, nightwatchInstance); } - + }); Object.defineProperty(exported, 'then', { diff --git a/lib/api/web-element/index.js b/lib/api/web-element/index.js index 7a71bb6d1e..4f39928242 100644 --- a/lib/api/web-element/index.js +++ b/lib/api/web-element/index.js @@ -17,4 +17,4 @@ module.exports.root = function(nightwatchInstance) { }; module.exports.createScopedWebElements = Factory.createScopedWebElements; -module.exports.create = Factory.create; \ No newline at end of file +module.exports.create = Factory.create; diff --git a/lib/api/web-element/waitUntil.js b/lib/api/web-element/waitUntil.js index 257e772eef..c6f3a6446f 100644 --- a/lib/api/web-element/waitUntil.js +++ b/lib/api/web-element/waitUntil.js @@ -24,31 +24,31 @@ const mapToSeleniumFunction = { * it ('wait for container', async function(browser){ * // with default implicit timeout of 5000ms (can be overwritten in settings under 'globals.waitForConditionTimeout') * await browser.element.find('#index-container').waitUntil('visible'); - * + * * // with explicit timeout (in milliseconds) * await browser.element.find('#index-container').waitUntil('visible', {timeout: 1000}); - * + * * // continue if failed * await browser.element.find('#index-container').waitUntil('visible', {timeout: 1000, abortOnFailure: false}); - * + * * // with negative assertion * await browser.element.find('#index-container').waitUntil('not.visible'); - * + * * // with xpath as the locate strategy * await browser.element.find(by.xpath('//*[@id="index-container"]')).waitUntil('visible', {message: 'The index container is found.'}); - * + * * // with custom message * await browser.element.find('#index-container').waitUntil('visible', {message: 'The index container is found.'}); * }); - * - * + * + * * it('page object demo Test', async function (browser) { * const nightwatchPage = browser.page.nightwatch(); - * + * * nightwatchPage * .navigate() * .assert.titleContains('Nightwatch.js'); - * + * * await nightwatchPage.element.find('@featuresList').waitUntil('visible'); * }); * }); @@ -98,7 +98,7 @@ class WaitUntil { return result; }); }.bind(this); - + const node = this.scopedElement.queueAction({name: 'waitUntil', createAction}); return node; @@ -110,7 +110,7 @@ class WaitUntil { try { const node = this.createNode(); - + return this.scopedElement.waitFor(node.deferred.promise); } catch (err) { assertApi.ok(false, err.message); @@ -119,13 +119,13 @@ class WaitUntil { formatMsg(message, timeMs) { const defaultMsg = this.message || message; - + return format(defaultMsg, this.selector, timeMs); } assert({result, passed, err, message, elapsedTime}) { const {reporter} = this.scopedElement; - + const runner = new AssertionRunner({abortOnFailure: this.abortOnFailure, passed, err, message, reporter, elapsedTime}); return runner.run(result); @@ -149,7 +149,7 @@ class WaitUntil { fail(result, actual, elapsedTime) { const sliceAction = this.action.split('.'); - + actual = actual ? actual : sliceAction[0] === 'not' ? sliceAction[1] : `not ${this.action}`; const expected = sliceAction[0] === 'not' ? `not ${sliceAction[1]}` : this.action; const message = this.formatMsg(`Timed out while waiting for element <%s> to be ${expected} for %d milliseconds`, this.timeout); @@ -167,4 +167,4 @@ class WaitUntil { } } -module.exports = WaitUntil; \ No newline at end of file +module.exports = WaitUntil; diff --git a/lib/core/asynctree.js b/lib/core/asynctree.js index 317310c494..72152e56b9 100644 --- a/lib/core/asynctree.js +++ b/lib/core/asynctree.js @@ -92,7 +92,7 @@ class AsyncTree extends EventEmitter{ } shouldRejectNodePromise(err, node = this.currentNode) { - if ((err.isExpect|| node.namespace === 'assert') && this.currentNode.isES6Async) { + if ((err.isExpect || node.namespace === 'assert') && this.currentNode.isES6Async) { return true; } diff --git a/lib/core/client.js b/lib/core/client.js index e98e4fbc2b..c25cd030f6 100644 --- a/lib/core/client.js +++ b/lib/core/client.js @@ -85,7 +85,7 @@ class NightwatchAPI { return false; } - return this.platformName.toLowerCase() === platform.toLowerCase(); + return this.platformName.toLowerCase() === platform.toLowerCase(); } isIOS() { @@ -277,7 +277,7 @@ class NightwatchClient extends EventEmitter { let callback; let method; let sessionId = api.sessionId; - const lastArg = args[args.length-1]; + const lastArg = args[args.length - 1]; const isLastArgFunction = Utils.isFunction(lastArg); if (isLastArgFunction) { @@ -528,7 +528,7 @@ class NightwatchClient extends EventEmitter { let value = this.settings.baseUrl || this.settings.launchUrl || this.settings.launch_url || null; // For e2e and component testing on android emulator - if (value && !this.settings.desiredCapabilities.real_mobile && this.settings.desiredCapabilities.avd) { + if (value && !this.settings.desiredCapabilities.real_mobile && this.settings.desiredCapabilities.avd) { value = value.replace('localhost', '10.0.2.2').replace('127.0.0.1', '10.0.2.2'); } diff --git a/lib/core/queue.js b/lib/core/queue.js index 34a973eca6..3e8b3a71bb 100644 --- a/lib/core/queue.js +++ b/lib/core/queue.js @@ -61,7 +61,7 @@ class CommandQueue extends EventEmitter { if (context && context.module && context.module.autoInvoke) { return node; } - + this.tree.addNode(node); if (this.currentNode.done || !this.currentNode.started || initialChildNode) { @@ -119,7 +119,7 @@ class CommandQueue extends EventEmitter { get inProgress() { return this.tree.rootNode.childNodes.length > 0; } - + done(err) { if (this.tree.rootNode.childNodes.length > 0) { return this; diff --git a/lib/element/command.js b/lib/element/command.js index 8fda88135b..5a71187be5 100644 --- a/lib/element/command.js +++ b/lib/element/command.js @@ -274,7 +274,7 @@ class ElementCommand extends EventEmitter { } if (passedArgs < expectedArgs - 1 || passedArgs > expectedArgs) { - const error = new Error(`${this.commandName} method expects ${(expectedArgs - 1)} `+ + const error = new Error(`${this.commandName} method expects ${(expectedArgs - 1)} ` + `(or ${expectedArgs} if using implicit "css selector" strategy) arguments - ${passedArgs} given.`); error.rejectPromise = rejectPromise; @@ -339,7 +339,7 @@ class ElementCommand extends EventEmitter { this.__retryOnFailure = retryAction; } - let {WebdriverElementId} = this.selector; + const {WebdriverElementId} = this.selector; if (WebdriverElementId) { this.WebdriverElementId = WebdriverElementId; } diff --git a/lib/http/formatter.js b/lib/http/formatter.js index fe720e6efd..3d9013d6f2 100644 --- a/lib/http/formatter.js +++ b/lib/http/formatter.js @@ -12,10 +12,10 @@ class ResponseFormatter { */ static jsonStringify(s) { try { - let json = JSON.stringify(s); + const json = JSON.stringify(s); if (json) { return json.replace(jsonRegex, function jsonRegexReplace(c) { - return '\\u'+('0000'+c.charCodeAt(0).toString(16)).slice(-4); + return '\\u' + ('0000' + c.charCodeAt(0).toString(16)).slice(-4); }); } @@ -29,9 +29,9 @@ class ResponseFormatter { } static stripUnknownChars(str) { - let x = []; + const x = []; let i = 0; - let length = str.length; + const length = str.length; for (i; i < length; i++) { if (str.charCodeAt(i)) { @@ -43,9 +43,9 @@ class ResponseFormatter { } static formatHostname(hostname, port, useSSL) { - let isLocalHost = ['127.0.0.1', 'localhost'].indexOf(hostname) > -1; - let protocol = useSSL ? 'https://' : 'http://'; - let isPortDefault = [80, 443].indexOf(port) > -1; + const isLocalHost = ['127.0.0.1', 'localhost'].indexOf(hostname) > -1; + const protocol = useSSL ? 'https://' : 'http://'; + const isPortDefault = [80, 443].indexOf(port) > -1; if (isLocalHost) { return ''; diff --git a/lib/http/request.js b/lib/http/request.js index c03d7f14e8..ce14072ecc 100644 --- a/lib/http/request.js +++ b/lib/http/request.js @@ -218,7 +218,7 @@ class HttpRequest extends EventEmitter { createHttpRequest() { try { - const req = (this.use_ssl ? https: http).request(this.reqOptions, response => { + const req = (this.use_ssl ? https : http).request(this.reqOptions, response => { this.httpResponse = new HttpResponse(response, this); this.httpResponse.on('complete', this.onRequestComplete.bind(this)); this.proxyEvents(this.httpResponse, ['response', 'error', 'success']); diff --git a/lib/index.js b/lib/index.js index f8503c500f..106552e02a 100644 --- a/lib/index.js +++ b/lib/index.js @@ -107,10 +107,10 @@ module.exports.createClient = function({ }); cliRunner.test_settings.disable_global_apis = cliRunner.test_settings.disable_global_apis || !enable_global_apis; - - //merge settings recieved from testsuite to cli runner settings (this might have changed in hooks) + + //merge settings recieved from testsuite to cli runner settings (this might have changed in hooks) lodashMerge(cliRunner.test_settings, test_settings); - + const client = Nightwatch.client(cliRunner.test_settings, reporter, cliRunner.argv, true); // TODO: Do we need this (global `element` api will only be available on diff --git a/lib/page-object/command-wrapper.js b/lib/page-object/command-wrapper.js index 9e640538af..0b40a54bcf 100644 --- a/lib/page-object/command-wrapper.js +++ b/lib/page-object/command-wrapper.js @@ -392,7 +392,7 @@ class CommandLoader { } return originalFn.apply(targetApi, args); - }; + }; } /** diff --git a/lib/reporter/axe-report.js b/lib/reporter/axe-report.js index a3842c56dc..8b5af97479 100644 --- a/lib/reporter/axe-report.js +++ b/lib/reporter/axe-report.js @@ -185,4 +185,4 @@ module.exports = class AxeReport { // eslint-disable-next-line no-console console.log(table.toString()); } -}; \ No newline at end of file +}; diff --git a/lib/reporter/base-reporter.js b/lib/reporter/base-reporter.js index bcc6322f42..618572f1a1 100644 --- a/lib/reporter/base-reporter.js +++ b/lib/reporter/base-reporter.js @@ -39,7 +39,7 @@ module.exports = class BaseReporter { }, {}); module.completedSections = Object.keys(module.completedSections).reduce(function(prev, item) { - if ((module.skippedAtRuntime && module.skippedAtRuntime.includes(item)) || + if ((module.skippedAtRuntime && module.skippedAtRuntime.includes(item)) || (module.skippedByUser && module.skippedByUser.includes(item)) ) { return prev; diff --git a/lib/reporter/global-reporter.js b/lib/reporter/global-reporter.js index f415547d1d..f45f4e8265 100644 --- a/lib/reporter/global-reporter.js +++ b/lib/reporter/global-reporter.js @@ -98,9 +98,9 @@ module.exports = class GlobalReporter { const endTime = new Date().getTime(); this.elapsedTime = endTime - startTime; - + this.globalResults = Results.createGlobalReport(this.suiteResults, initialReport); - this.globalResults.elapsedTime = (this.elapsedTime/1000).toPrecision(4); + this.globalResults.elapsedTime = (this.elapsedTime / 1000).toPrecision(4); this.globalResults.startTimestamp = new Date(startTime).toUTCString(); this.globalResults.endTimestamp = new Date(endTime).toUTCString(); @@ -300,7 +300,7 @@ module.exports = class GlobalReporter { if (!hasCount) { const passedCount = Math.max(0, totalTests - this.globalResults.failed - this.globalResults.errors); // testcases passed - passedMsg = '\n - '+ colors.green(passedCount + '/' + (totalTests > 0 ? totalTests : 'NA')) + ' tests passed'; + passedMsg = '\n - ' + colors.green(passedCount + '/' + (totalTests > 0 ? totalTests : 'NA')) + ' tests passed'; } let skipped = ''; diff --git a/lib/reporter/index.js b/lib/reporter/index.js index e004785061..35d49f54f8 100644 --- a/lib/reporter/index.js +++ b/lib/reporter/index.js @@ -160,11 +160,11 @@ class Reporter extends SimplifiedReporter { logTestCase(testName) { if (this.settings.live_output || !this.settings.parallel_mode) { // eslint-disable-next-line no-console - console.log(`${(!this.settings.silent?'\n\n':'')}\n Running ${colors.green(testName)}${colors.stack_trace(':')}`); + console.log(`${(!this.settings.silent ? '\n\n' : '')}\n Running ${colors.green(testName)}${colors.stack_trace(':')}`); const {columns = 100} = process.stdout; // eslint-disable-next-line no-console - console.log(colors.stack_trace(new Array(Math.max(100, Math.floor(columns/2))).join('─'))); + console.log(colors.stack_trace(new Array(Math.max(100, Math.floor(columns / 2))).join('─'))); //} } else { // eslint-disable-next-line no-console @@ -327,7 +327,7 @@ class Reporter extends SimplifiedReporter { printSimplifiedTestResult(ok, elapsedTime, isWorker) { const {currentTest} = this; - const result = [colors[ok ? 'green': 'red'](Utils.symbols[ok ? 'ok' : 'fail'])]; + const result = [colors[ok ? 'green' : 'red'](Utils.symbols[ok ? 'ok' : 'fail'])]; if (!this.unitTestsMode) { if (isWorker) { result.push(colors.bgBlack.white.bold(this.settings.testEnv)); diff --git a/lib/reporter/reporters/html.js b/lib/reporter/reporters/html.js index c611699251..d168ed3ae4 100644 --- a/lib/reporter/reporters/html.js +++ b/lib/reporter/reporters/html.js @@ -41,7 +41,7 @@ class HtmlReporter extends BaseReporter { getFileName() { let fileName = 'index'; const {filename_format} = this.options; - if (filename_format) { + if (filename_format) { if (typeof filename_format === 'function') { fileName = filename_format(this.results); } else if (typeof filename_format === 'string') { diff --git a/lib/reporter/results.js b/lib/reporter/results.js index c88ea48fc9..1c804d3942 100644 --- a/lib/reporter/results.js +++ b/lib/reporter/results.js @@ -16,7 +16,7 @@ module.exports = class Results { return 'skip'; } - constructor(tests = [], opts, settings, skippedTests=[], allScreenedTests=[]) { + constructor(tests = [], opts, settings, skippedTests = [], allScreenedTests = []) { this.skippedByUser = skippedTests; this.skippedAtRuntime = tests.slice(0); this.testcases = {}; @@ -286,7 +286,7 @@ module.exports = class Results { get retryTest() { return this.__retryTest; } - + /** * @param {TestCase} testcase * @return {Object} @@ -410,7 +410,7 @@ module.exports = class Results { return this; } - + initCount(allScreenedTests) { this.__passedCount = 0; this.__failedCount = 0; @@ -432,7 +432,7 @@ module.exports = class Results { this.time += elapsedTime; if (currentTest) { - this.currentTestResult.time = (elapsedTime/1000).toPrecision(4); + this.currentTestResult.time = (elapsedTime / 1000).toPrecision(4); this.currentTestResult.timeMs = elapsedTime; this.currentTestResult.startTimestamp = new Date(startTime).toUTCString(); this.currentTestResult.endTimestamp = new Date(endTime).toUTCString(); @@ -452,7 +452,7 @@ module.exports = class Results { this.time += elapsedTime; if (currentSection) { - currentSection.time = (elapsedTime/1000).toPrecision(4); + currentSection.time = (elapsedTime / 1000).toPrecision(4); currentSection.timeMs = elapsedTime; currentSection.startTimestamp = startTime; currentSection.endTimestamp = endTime; @@ -466,7 +466,7 @@ module.exports = class Results { const currentTest = this.getCurrentTest(); const currentSection = this.getTestSection(this.currentSectionName); if (!currentTest) { - return; + return; } if (this.hasFailures()) { @@ -489,7 +489,7 @@ module.exports = class Results { setTotalElapsedTime() { this.timeMs = this.time; - this.time = (this.time/1000).toPrecision(4); + this.time = (this.time / 1000).toPrecision(4); return this; } @@ -544,7 +544,7 @@ module.exports = class Results { getTestStatus() { if (this.failedCount > 0 || this.errorsCount > 0) { return Results.TEST_FAIL; - } + } if (this.passedCount > 0) { return Results.TEST_PASS; @@ -556,8 +556,8 @@ module.exports = class Results { /** * Appends data in current testSections data. - * - * @param {Object} data + * + * @param {Object} data */ appendTestResult(data) { lodashMerge(this.testSections, data); diff --git a/lib/reporter/summary.js b/lib/reporter/summary.js index 9d4e5170c4..fdf022f35a 100644 --- a/lib/reporter/summary.js +++ b/lib/reporter/summary.js @@ -26,7 +26,7 @@ module.exports = class Summary { */ static getFailedSuiteContent({testSuite, testSuiteName, index = 0, startSessionEnabled = true}) { const testcases = Object.keys(testSuite.completed); - const initial = [colors.red(` ${Utils.symbols.fail} ${index+1}) ${testSuiteName}`)]; + const initial = [colors.red(` ${Utils.symbols.fail} ${index + 1}) ${testSuiteName}`)]; return testcases.reduce((prev, name) => { const testcase = testSuite.completed[name]; diff --git a/lib/runner/androidEmulator.js b/lib/runner/androidEmulator.js index 4379cca285..e1fe8be1a3 100644 --- a/lib/runner/androidEmulator.js +++ b/lib/runner/androidEmulator.js @@ -13,7 +13,7 @@ module.exports = class AndroidServer { async killEmulator() { return killEmulatorWithoutWait(this.sdkRoot, getPlatformName(), this.emulatorId); } - + async launchEmulator() { try { const emulatorId = await getAlreadyRunningAvd(this.sdkRoot, getPlatformName(), this.avd); diff --git a/lib/runner/cli/argv-setup.js b/lib/runner/cli/argv-setup.js index 36effbf52e..5acad8f487 100644 --- a/lib/runner/cli/argv-setup.js +++ b/lib/runner/cli/argv-setup.js @@ -213,7 +213,7 @@ module.exports = new (function () { : null, this.options.default[key] !== undefined ? '[default: ' + JSON.stringify(this.options.default[key]) + ']' - : null + : null ].filter(Boolean).join(' '); const body = [desc, extra].filter(Boolean).join(' '); @@ -399,7 +399,7 @@ module.exports = new (function () { group: 'Reporting', descriptions: 'Record trace information during nightwatch execution.' }); - + // $ nightwatch --open this.option('open', { group: 'Reporting', diff --git a/lib/runner/cli/cli.js b/lib/runner/cli/cli.js index 6c23a2ac8e..c2de0cac04 100644 --- a/lib/runner/cli/cli.js +++ b/lib/runner/cli/cli.js @@ -24,7 +24,7 @@ class CliRunner { static get CONFIG_FILE_TS() { return './nightwatch.conf.ts'; } - + static createDefaultConfig(destFileName) { // eslint-disable-next-line no-console console.log(Logger.colors.cyan('No config file found in the current working directory, creating nightwatch.conf.js in the current folder...')); @@ -149,7 +149,7 @@ class CliRunner { } } } - + setMobileOptions(argv) { const {desiredCapabilities, selenium = {}} = this.test_settings; @@ -194,7 +194,7 @@ class CliRunner { if (!this.baseSettings) { return this; - } + } this.availableTestEnvs = Object.keys(this.baseSettings.test_settings).filter(key => { return Utils.isObject(this.baseSettings.test_settings[key]); @@ -262,7 +262,7 @@ class CliRunner { test_workers_enabled: this.test_settings.testWorkersEnabled, use_xpath: this.test_settings.use_xpath, is_bstack: this.test_settings.desiredCapabilities['bstack:options'] !== undefined, - test_runner: this.test_settings.test_runner ? this.test_settings.test_runner.type : null + test_runner: this.test_settings.test_runner ? this.test_settings.test_runner.type : null }); } @@ -297,7 +297,7 @@ class CliRunner { if (usingTS) { return path.resolve(CliRunner.CONFIG_FILE_TS); } - + return path.resolve(CliRunner.CONFIG_FILE_JS); } @@ -402,13 +402,13 @@ class CliRunner { for (const env of this.testEnvArray) { const {webdriver = {}} = this.testEnvSettings[env]; const desiredCapabilities = this.testEnvSettings[env].capabilities || this.testEnvSettings[env].desiredCapabilities; - + if (isMobile(desiredCapabilities)) { - + if (Concurrency.isWorker()) { Logger.info('Disabling parallelism while running tests on mobile platform'); } - + return false; } @@ -492,7 +492,7 @@ class CliRunner { return this.runGlobalHook('before', [this.test_settings]) .then(_ => { return this.runGlobalHook('beforeChildProcess', [this.test_settings], true); - }) + }) .then(_ => { return this.getTestsFiles(); }) @@ -628,7 +628,7 @@ class CliRunner { } analyticsCollector.__flush(); - + return errorOrFailed; }); } diff --git a/lib/runner/concurrency/child-process.js b/lib/runner/concurrency/child-process.js index 4fcf7539ad..1eddf4edfa 100644 --- a/lib/runner/concurrency/child-process.js +++ b/lib/runner/concurrency/child-process.js @@ -81,7 +81,7 @@ class ChildProcess extends EventEmitter { writeToStdout(data) { data = data.toString().trim(); - const color_pair = this.availColors[this.index%4]; + const color_pair = this.availColors[this.index % 4]; let output = ''; if (ChildProcess.prevIndex !== this.index) { @@ -148,7 +148,7 @@ class ChildProcess extends EventEmitter { })); } - const color_pair = this.availColors[this.index%4]; + const color_pair = this.availColors[this.index % 4]; this.printLog(' Running: ' + Logger.colors[color_pair[0]][color_pair[1]](` ${this.env_itemKey} `)); diff --git a/lib/runner/concurrency/index.js b/lib/runner/concurrency/index.js index 1caa4580df..fa64d842c7 100644 --- a/lib/runner/concurrency/index.js +++ b/lib/runner/concurrency/index.js @@ -255,7 +255,7 @@ class Concurrency extends EventEmitter { return this.runChildProcess(childProcess, outputLabel, availColors, 'workers') .then(_ => { - remaining -=1; + remaining -= 1; if (remaining > 0) { next(); diff --git a/lib/runner/concurrency/task.js b/lib/runner/concurrency/task.js index 25b89aaf44..f1dc8b0b27 100644 --- a/lib/runner/concurrency/task.js +++ b/lib/runner/concurrency/task.js @@ -16,8 +16,8 @@ function runWorkerTask({argv, port1}) { //send reports to main thread using message port process.port = port1; - + return Nightwatch.runTests(argv, {}); } -module.exports = runWorkerTask; \ No newline at end of file +module.exports = runWorkerTask; diff --git a/lib/runner/concurrency/worker-process.js b/lib/runner/concurrency/worker-process.js index bb6bc9e148..389d6887ff 100644 --- a/lib/runner/concurrency/worker-process.js +++ b/lib/runner/concurrency/worker-process.js @@ -1,5 +1,5 @@ const path = require('path'); -const Piscina= require('piscina'); +const Piscina = require('piscina'); const {isWorkerThread} = Piscina; const EventEmitter = require('events'); const WorkerTask = require('./worker-task'); @@ -20,7 +20,7 @@ class WorkerPool extends EventEmitter { set tasks(tasks) { this.__tasks = tasks; } - + constructor(args, settings, maxWorkerCount) { super(); @@ -44,14 +44,14 @@ class WorkerPool extends EventEmitter { */ addTask({label, argv, colors} = {}) { const workerTask = new WorkerTask({piscina: this.piscina, index: this.index, label, argv, settings: this.settings}); - + workerTask.on('message', (data) => { this.emit('message', data); }); this.index++; this.__tasks.push(workerTask.runWorkerTask(colors)); - + } } diff --git a/lib/runner/concurrency/worker-task.js b/lib/runner/concurrency/worker-task.js index 94aefc6e58..f41a293ffd 100644 --- a/lib/runner/concurrency/worker-task.js +++ b/lib/runner/concurrency/worker-task.js @@ -66,10 +66,10 @@ class WorkerTask extends EventEmitter { async runWorkerTask(colors, type) { this.availColors = colors; - const colorPair = this.availColors[this.index%4]; + const colorPair = this.availColors[this.index % 4]; this.setlabel(colorPair); - this.printLog('Running '+ Logger.colors[colorPair[0]][colorPair[1]](` ${this.task_label} `)); + this.printLog('Running ' + Logger.colors[colorPair[0]][colorPair[1]](` ${this.task_label} `)); const {port1, port2} = new MessageChannel(); port2.onmessage = ({data: result}) => { @@ -112,4 +112,4 @@ class WorkerTask extends EventEmitter { } } -module.exports = WorkerTask; \ No newline at end of file +module.exports = WorkerTask; diff --git a/lib/runner/folder-walk.js b/lib/runner/folder-walk.js index a829ed10dd..d55d046d70 100644 --- a/lib/runner/folder-walk.js +++ b/lib/runner/folder-walk.js @@ -173,7 +173,7 @@ class Walker { if (stat && stat.isFile()) { return fullPath; } - + if (stat && !stat.isDirectory()) { return null; } @@ -273,7 +273,7 @@ class Walker { if (this.disableTs && Utils.isTsFile(resource)) { return null; } - + if (stat && stat.isFile() && Utils.isFileNameValid(resource)) { return path.join(folderPath, resource); } diff --git a/lib/runner/matchers/tags.js b/lib/runner/matchers/tags.js index 3556614a48..cd75571edd 100644 --- a/lib/runner/matchers/tags.js +++ b/lib/runner/matchers/tags.js @@ -44,7 +44,7 @@ class TagsMatcher { const context = new Context({modulePath, settings}); context.setReloadModuleCache(); - + // Defining global browser object to make it available before nightwatch client created. // To avoid errors like browser is not defined if testsuits has tags Object.defineProperty(global, 'browser', { @@ -147,7 +147,7 @@ class TagsMatcher { // when multiple --tag arguments are passed (e.g.: --tag a --tag b) // the resulting array is [a, b], otherwise it is [a] - let tagsArray = Array.isArray(tags) ? tags : [tags]; + const tagsArray = Array.isArray(tags) ? tags : [tags]; // now parse each --tag argument return tagsArray.map(t => TagsMatcher.convertTags(t)); diff --git a/lib/runner/process-listener.js b/lib/runner/process-listener.js index 697851e42a..af5784144e 100644 --- a/lib/runner/process-listener.js +++ b/lib/runner/process-listener.js @@ -111,7 +111,7 @@ module.exports = class { exit() { this.process.exit && this.process.exit(this.exitCode); - + return this; } }; diff --git a/lib/runner/test-runners/cucumber.js b/lib/runner/test-runners/cucumber.js index cf4f79dbe1..6402ec3478 100644 --- a/lib/runner/test-runners/cucumber.js +++ b/lib/runner/test-runners/cucumber.js @@ -96,7 +96,7 @@ class CucumberSuite extends TestSuite { options.feature_path = [options.feature_path]; } const {feature_path = ''} = options; - const parallelArgs = this.usingCucumberWorkers ? ['--parallel', this.usingCucumberWorkers]: []; + const parallelArgs = this.usingCucumberWorkers ? ['--parallel', this.usingCucumberWorkers] : []; const additionalOptions = this.buildArgvValue(['tags', 'retry-tag-filter', 'profile', 'format', 'format-options', 'dry-run', 'fail-fast', ['retry', 'retries'], 'no-strict', 'name']); const extraParams = ['--world-parameters', JSON.stringify({...this.argv, settings: this.settings})]; @@ -147,7 +147,7 @@ class CucumberSuite extends TestSuite { ...this.argv }; - if ((isDefined(allArgv[argName]) && allArgv[argName] !== '') || + if ((isDefined(allArgv[argName]) && allArgv[argName] !== '') || (isDefined(allArgv[key]) && allArgv[key] !== '') ) { let argValues = allArgv[argName] || allArgv[key]; diff --git a/lib/runner/test-runners/mocha.js b/lib/runner/test-runners/mocha.js index d601b02e4a..3af11a28be 100644 --- a/lib/runner/test-runners/mocha.js +++ b/lib/runner/test-runners/mocha.js @@ -118,7 +118,7 @@ class MochaRunner { if (this.isTestWorker()) { const filePath = this.argv.test; - const reportFilename = filePath.substring(filePath.lastIndexOf('/')+1).split('.')[0]; + const reportFilename = filePath.substring(filePath.lastIndexOf('/') + 1).split('.')[0]; this.mochaOpts.isWorker = true; if (argv.reporter.includes('mocha-junit-reporter')) { @@ -194,7 +194,7 @@ class MochaRunner { const client = mochaSuite && mochaSuite.client; if (client && client.sessionId) { - let request = client.transport.createHttpRequest({ + const request = client.transport.createHttpRequest({ path: `/session/${client.sessionId}` }); diff --git a/lib/runner/test-runners/mocha/custom-runnable.js b/lib/runner/test-runners/mocha/custom-runnable.js index 1deb22eea0..6ee53db00b 100644 --- a/lib/runner/test-runners/mocha/custom-runnable.js +++ b/lib/runner/test-runners/mocha/custom-runnable.js @@ -1,7 +1,7 @@ module.exports = async function(fn, isHook = false) { - let self = this; - let start = new Date(); - let ctx = this.ctx; + const self = this; + const start = new Date(); + const ctx = this.ctx; let finished; if (this.isPending()) { @@ -24,7 +24,7 @@ module.exports = async function(fn, isHook = false) { return; } emitted = true; - let msg = 'done() called multiple times'; + const msg = 'done() called multiple times'; if (err && err.message) { err.message += ` (and Mocha's ${msg})`; self.emit('error', err); @@ -35,7 +35,7 @@ module.exports = async function(fn, isHook = false) { // finished function done(err) { - let ms = self.timeout(); + const ms = self.timeout(); if (self.timedOut) { return; } @@ -125,4 +125,4 @@ module.exports = async function(fn, isHook = false) { done(err); emitted = true; } -}; \ No newline at end of file +}; diff --git a/lib/runner/test-runners/mocha/custom-runner.js b/lib/runner/test-runners/mocha/custom-runner.js index b9efc84732..f2c546c054 100644 --- a/lib/runner/test-runners/mocha/custom-runner.js +++ b/lib/runner/test-runners/mocha/custom-runner.js @@ -76,4 +76,4 @@ module.exports = class CustomRunner extends Mocha.Runner { super.run(fn); } -}; \ No newline at end of file +}; diff --git a/lib/runner/test-runners/mocha/extensions.js b/lib/runner/test-runners/mocha/extensions.js index 882b65cdba..62deab2134 100644 --- a/lib/runner/test-runners/mocha/extensions.js +++ b/lib/runner/test-runners/mocha/extensions.js @@ -100,4 +100,4 @@ module.exports = class Extensions { suite.timeout(30000); } } -}; \ No newline at end of file +}; diff --git a/lib/runner/test-runners/mocha/nightwatchSuite.js b/lib/runner/test-runners/mocha/nightwatchSuite.js index a7a7573777..53d65422e8 100644 --- a/lib/runner/test-runners/mocha/nightwatchSuite.js +++ b/lib/runner/test-runners/mocha/nightwatchSuite.js @@ -121,4 +121,4 @@ module.exports.init = function({suite, nightwatchSuite}) { console.error(err); process.exit(1); }); -}; \ No newline at end of file +}; diff --git a/lib/runner/test-source.js b/lib/runner/test-source.js index b764cd4824..7bdcaa4db0 100644 --- a/lib/runner/test-source.js +++ b/lib/runner/test-source.js @@ -66,15 +66,15 @@ class TestSource { return jsonFile; } - + getTestSourceForRerunFailed() { const {reporter_options: {minimal_report_file_path}} = this.settings; const minimalJsonFile = this.getRerunFailedFile(minimal_report_file_path); - + try { const {modules = {}} = require(minimalJsonFile); const testsource = []; - + Object.keys(modules).forEach(moduleKey => { if (modules[moduleKey] && modules[moduleKey].status === 'fail') { testsource.push(modules[moduleKey].modulePath); @@ -111,7 +111,7 @@ class TestSource { if ((process.env.NIGHTWATCH_RERUN_FAILED === 'true' || this.argv['rerun-failed']) && Concurrency.isMasterProcess()) { return this.getTestSourceForRerunFailed(this.argv); } - + if (this.argv['test-worker'] || singleSourceFile(this.argv)) { return this.getTestSourceForSingle(this.argv.test || this.argv._source); } @@ -140,10 +140,10 @@ class TestSource { return groupTestsource; } // only when all groups fail to match will there be a run error - let testsource = groupTestsource.filter(Utils.dirExistsSync); + const testsource = groupTestsource.filter(Utils.dirExistsSync); if (!this.settings.silent) { - let ignoredSource = groupTestsource.filter(entry => testsource.indexOf(entry) === -1); + const ignoredSource = groupTestsource.filter(entry => testsource.indexOf(entry) === -1); if (ignoredSource.length) { Logger.warn('The following group paths were not found and will be excluded from the run:\n - ' + @@ -168,11 +168,11 @@ class TestSource { } if (this.settings.exclude) { - let arrExclude = Array.isArray(this.settings.exclude) ? this.settings.exclude : [this.settings.exclude]; - let resolvedExclude = arrExclude.map(item => path.resolve(item)); + const arrExclude = Array.isArray(this.settings.exclude) ? this.settings.exclude : [this.settings.exclude]; + const resolvedExclude = arrExclude.map(item => path.resolve(item)); this.src_folders = this.src_folders.filter(item => { - let resolvedPath = path.resolve(item); + const resolvedPath = path.resolve(item); let match = true; resolvedExclude.forEach(function(pattern) { @@ -191,13 +191,13 @@ class TestSource { * @return {Array} */ findGroupPath(groupName) { - let fullGroupPath = path.resolve(groupName); + const fullGroupPath = path.resolve(groupName); // for each src folder, append the group to the path // to resolve the full test path return this.src_folders.map(function(srcFolder) { - let fullSrcFolder = path.resolve(srcFolder); + const fullSrcFolder = path.resolve(srcFolder); if (fullGroupPath.indexOf(fullSrcFolder) === 0) { return groupName; } diff --git a/lib/settings/defaults.js b/lib/settings/defaults.js index d7aed546c0..7eeb82b2fe 100644 --- a/lib/settings/defaults.js +++ b/lib/settings/defaults.js @@ -60,7 +60,7 @@ module.exports = { // An object which will be made available on the main test api, throughout the test execution globals: { - + // 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, diff --git a/lib/settings/settings.js b/lib/settings/settings.js index cbaaef6ea4..de6901211d 100644 --- a/lib/settings/settings.js +++ b/lib/settings/settings.js @@ -398,7 +398,7 @@ class Settings { } inheritFromSuperEnv(testEnvSettings) { - if (testEnvSettings.extends) { + if (testEnvSettings.extends) { const superEnv = this.baseSettings.test_settings[testEnvSettings.extends] || {}; delete testEnvSettings.extends; defaultsDeep(testEnvSettings, superEnv); diff --git a/lib/testsuite/hooks/afterAll.js b/lib/testsuite/hooks/afterAll.js index 9e5a54804d..1b58eed586 100644 --- a/lib/testsuite/hooks/afterAll.js +++ b/lib/testsuite/hooks/afterAll.js @@ -6,4 +6,4 @@ class AfterAll extends BaseHook { } } -module.exports = AfterAll; \ No newline at end of file +module.exports = AfterAll; diff --git a/lib/testsuite/hooks/afterEach.js b/lib/testsuite/hooks/afterEach.js index 077d513828..bcb49c490d 100644 --- a/lib/testsuite/hooks/afterEach.js +++ b/lib/testsuite/hooks/afterEach.js @@ -6,4 +6,4 @@ class AfterEach extends BaseHook { } } -module.exports = AfterEach; \ No newline at end of file +module.exports = AfterEach; diff --git a/lib/testsuite/hooks/beforeAll.js b/lib/testsuite/hooks/beforeAll.js index 2a1d766b61..b97945ce06 100644 --- a/lib/testsuite/hooks/beforeAll.js +++ b/lib/testsuite/hooks/beforeAll.js @@ -10,4 +10,4 @@ class BeforeAll extends BaseHook { } } -module.exports = BeforeAll; \ No newline at end of file +module.exports = BeforeAll; diff --git a/lib/testsuite/hooks/beforeEach.js b/lib/testsuite/hooks/beforeEach.js index 3b2b0c62a3..1a301c9576 100644 --- a/lib/testsuite/hooks/beforeEach.js +++ b/lib/testsuite/hooks/beforeEach.js @@ -10,4 +10,4 @@ class BeforeAll extends BaseHook { } } -module.exports = BeforeAll; \ No newline at end of file +module.exports = BeforeAll; diff --git a/lib/testsuite/index.js b/lib/testsuite/index.js index e8e7c85a65..df45206fbe 100644 --- a/lib/testsuite/index.js +++ b/lib/testsuite/index.js @@ -144,8 +144,8 @@ class TestSuite { validateNightwatchInspectorCriteria() { return ( - this.argv.debug && - Concurrency.isMasterProcess() && + this.argv.debug && + Concurrency.isMasterProcess() && this.client.api.isChrome() ); } @@ -451,7 +451,7 @@ class TestSuite { runHook(hookName) { Logger.log(`${Logger.colors.green('→')} Running [${hookName}]:`); - + if (hookName === 'before' || hookName === 'after') { this.client.reporter.setCurrentSection({testName: `__${hookName}_hook`}); } @@ -471,14 +471,14 @@ class TestSuite { } this.client.reporter.setCurrentSection({testName: `__global_${hookName}_hook`}); - + return this.handleRunnable(hookName, async () => { if (this.globalsInstance) { await this.globalsInstance.runPluginHook(hookName, [this.settings]); } const result = await this.globalHooks[hookName].run(this.client); - + this.onTestSectionFinished(); return result; @@ -547,7 +547,7 @@ class TestSuite { .then(() => this.runHook('before')) .then(result => { this.onTestSectionFinished(); - + if (result instanceof Error) { Logger.error(result); } @@ -683,13 +683,13 @@ class TestSuite { if (Concurrency.isWorker()) { this.sendReportToParentWorker(); } - + return failures; } - + async sessionFinished(reason) { let lastError = null; - + if (reason === 'FAILED' || reason === 'RETRY_SUITE') { lastError = this.reporter.testResults.lastError; } @@ -719,7 +719,7 @@ class TestSuite { return potentialError; } - + if (endSession) { const runnable = new Runnable('terminate', _ => { if (this.api && isFunction(this.api.end)) { @@ -805,7 +805,7 @@ class TestSuite { if (this.transport.driverService && this.reporter.testResults) { this.reporter.testResults.setSeleniumLogFile(this.transport.driverService.getSeleniumOutputFilePath()); } - + // if there was an error in the testcase and skip_testcases_on_fail, we must send it forward, but after we run afterEach and after hooks return this.runHook('afterEach') .then(() => this.testCaseFinished()) @@ -876,10 +876,10 @@ class TestSuite { if (!err && this.transport.isResultSuccess(result)) { const assertions = this.api.currentTest.results.assertions || []; const commands = this.reporter.currentSection.commands || []; - + if (assertions.length > 0) { - const currentAssertion = assertions[assertions.length-1]; - const currentCommand = commands[commands.length-1]; + const currentAssertion = assertions[assertions.length - 1]; + const currentCommand = commands[commands.length - 1]; if (currentAssertion) { currentAssertion.screenshots = currentAssertion.screenshots || []; @@ -903,7 +903,7 @@ class TestSuite { takeSnapshot(node) { const commands = this.reporter.currentSection.commands || []; - const currentCommand = commands[commands.length-1]; + const currentCommand = commands[commands.length - 1]; if (this.settings.trace.enabled && node.isTraceable) { const snapShotPath = Snapshots.getFileName({ @@ -1047,11 +1047,11 @@ class TestSuite { // eslint-disable-next-line no-console (this.context.isDisabled() ? Logger.info : console.log)(Logger.colors.cyan('[' + this.context.moduleKey + ']')); } else { - Logger[this.context.isDisabled() ? 'info': 'logDetailedMessage'](`\n${Logger.colors.cyan(testSuiteDisplay)}`); + Logger[this.context.isDisabled() ? 'info' : 'logDetailedMessage'](`\n${Logger.colors.cyan(testSuiteDisplay)}`); } if (!this.context.unitTestingMode) { - Logger[this.context.isDisabled() ? 'info': 'logDetailedMessage'](Logger.colors.purple(new Array(Math.min(testSuiteDisplay.length*2 + 1, 80)).join('─'))); + Logger[this.context.isDisabled() ? 'info' : 'logDetailedMessage'](Logger.colors.purple(new Array(Math.min(testSuiteDisplay.length * 2 + 1, 80)).join('─'))); } } diff --git a/lib/testsuite/nightwatch-inspector/index.js b/lib/testsuite/nightwatch-inspector/index.js index 5c977a5ac6..379f343b80 100644 --- a/lib/testsuite/nightwatch-inspector/index.js +++ b/lib/testsuite/nightwatch-inspector/index.js @@ -21,7 +21,7 @@ module.exports = class NightwatchInspectorServer extends WebSocket { const {desiredCapabilities} = this.client.settings; const chromeOptions = desiredCapabilities['goog:chromeOptions']; const {args = []} = chromeOptions || {}; - + desiredCapabilities['goog:chromeOptions'] = { ...chromeOptions, extensions: [crxfile], @@ -55,13 +55,13 @@ module.exports = class NightwatchInspectorServer extends WebSocket { getNightwatchCommands() { const {api} = this.client; const {assert, expect, verify, ensure} = api; - + return [ 'browser', ...[api, assert, expect, verify, ensure].reduce((keys, obj) => keys.concat(Object.keys(obj)), []) ]; } - + async executeCommands(data) { let result; const context = {browser: this.client.api}; diff --git a/lib/testsuite/nightwatch-inspector/websocket-server.js b/lib/testsuite/nightwatch-inspector/websocket-server.js index eaff5583a6..b814c70094 100644 --- a/lib/testsuite/nightwatch-inspector/websocket-server.js +++ b/lib/testsuite/nightwatch-inspector/websocket-server.js @@ -21,7 +21,7 @@ module.exports = class Websocket { this._wss.on('error', (error) => { this.handleSocketError(error, cb); }); - + this._wss.on('listening', () => { Logger.log(`WebSocket server is listening on port ${this.portNumber}`); }); diff --git a/lib/transport/selenium-webdriver/browserstack/appAutomate.js b/lib/transport/selenium-webdriver/browserstack/appAutomate.js index 988a57e766..dcb44e6a8a 100644 --- a/lib/transport/selenium-webdriver/browserstack/appAutomate.js +++ b/lib/transport/selenium-webdriver/browserstack/appAutomate.js @@ -74,7 +74,7 @@ class AppAutomate extends BrowserStack { // eslint-disable-next-line no-console console.log(Logger.colors.green(Utils.symbols.ok), Logger.colors.stack_trace('App upload successful!'), '\n'); - + if (!response.custom_id) { // custom_id not being used options['appium:app'] = response.app_url; diff --git a/lib/transport/selenium-webdriver/browserstack/browserstack.js b/lib/transport/selenium-webdriver/browserstack/browserstack.js index d757c790c9..f20eae6ace 100644 --- a/lib/transport/selenium-webdriver/browserstack/browserstack.js +++ b/lib/transport/selenium-webdriver/browserstack/browserstack.js @@ -48,8 +48,8 @@ class Browserstack extends AppiumBaseServer { // checking for legacy-ways for providing config this.settings.desiredCapabilities['bstack:options'] = defaultsDeep(this.settings.desiredCapabilities['bstack:options'], { - userName: desiredCapabilities['browserstack.user'], - accessKey: desiredCapabilities['browserstack.key'], + userName: desiredCapabilities['browserstack.user'], + accessKey: desiredCapabilities['browserstack.key'], buildName: desiredCapabilities.build || desiredCapabilities.buildName, local: desiredCapabilities['browserstack.local'], sessionName: desiredCapabilities['name'] @@ -141,7 +141,7 @@ class Browserstack extends AppiumBaseServer { super.sessionFinished(reason); await this.testSuiteFinished(err); } - + async testSuiteFinished(err) { try { if (this.sessionId) { diff --git a/lib/transport/selenium-webdriver/cdp.js b/lib/transport/selenium-webdriver/cdp.js index d48a8a42e9..06bf9c20a9 100644 --- a/lib/transport/selenium-webdriver/cdp.js +++ b/lib/transport/selenium-webdriver/cdp.js @@ -1,5 +1,5 @@ class Cdp { - async getConnection(driver, reset=false) { + async getConnection(driver, reset = false) { if (!reset && this._connection) { return this._connection; } diff --git a/lib/transport/selenium-webdriver/httpclient.js b/lib/transport/selenium-webdriver/httpclient.js index d4084ecdfa..c7c9f0129b 100644 --- a/lib/transport/selenium-webdriver/httpclient.js +++ b/lib/transport/selenium-webdriver/httpclient.js @@ -18,12 +18,12 @@ module.exports = function(settings, HttpResponse) { const {log_screenshot_data} = settings; let {port} = options; if (port) { - port = Number(port); + port = Number(port); HttpRequest.updateGlobalSettings({port}); } else { - port = protocol === 'https' ? 443 : 80; + port = protocol === 'https' ? 443 : 80; } - + this.options = { host, port, @@ -34,7 +34,7 @@ module.exports = function(settings, HttpResponse) { use_ssl: protocol === 'https:' }; this.errorTimeoutId = null; - + } /** @override */ diff --git a/lib/transport/selenium-webdriver/index.js b/lib/transport/selenium-webdriver/index.js index 0a08bf01a0..76ad5d92ee 100644 --- a/lib/transport/selenium-webdriver/index.js +++ b/lib/transport/selenium-webdriver/index.js @@ -64,7 +64,7 @@ class Transport extends BaseTransport { static set driverService(value) { _driverService = value; } - + /** * @override @@ -222,9 +222,9 @@ class Transport extends BaseTransport { if (value) { return Transport.driver; } - + Transport.driver = await this.createDriver({options}); - + return Transport.driver; } @@ -235,7 +235,7 @@ class Transport extends BaseTransport { } try { await Transport.driver.getSession(); - + return true; } catch (err) { return false; @@ -293,10 +293,10 @@ class Transport extends BaseTransport { const session = new Session(this.driver); const sessionExports = await session.exported(); const {sessionInfo, sessionId, capabilities, elementKey} = sessionExports; - + this.__elementKey = elementKey; await this.showConnectInfo({startTime, host, port, start_process, sessionInfo}); - + return { sessionId, capabilities diff --git a/lib/transport/selenium-webdriver/method-mappings.js b/lib/transport/selenium-webdriver/method-mappings.js index eef70c1b3c..33a6a1dff5 100644 --- a/lib/transport/selenium-webdriver/method-mappings.js +++ b/lib/transport/selenium-webdriver/method-mappings.js @@ -647,7 +647,7 @@ module.exports = class MethodMappings { async clickElement(webElementOrId) { const element = this.getWebElement(webElementOrId); await element.click(); - + return null; }, @@ -881,7 +881,7 @@ module.exports = class MethodMappings { return null; }, - async contextClick(webElementOrId) { + async contextClick(webElementOrId) { const element = this.getWebElement(webElementOrId); await this.driver.actions({async: true}).contextClick(element).perform(); @@ -889,17 +889,17 @@ module.exports = class MethodMappings { }, async pressAndHold(webElementOrId) { - + const element = this.getWebElement(webElementOrId); await this.driver.actions({async: true}).move({origin: element}).press().perform(); - + return null; }, async release(webElementOrId) { await this.driver.actions({async: true}).release().perform(); - - return null; + + return null; }, /////////////////////////////////////////////////////////// // User Prompts @@ -1155,7 +1155,7 @@ module.exports = class MethodMappings { async mockNetworkResponse(urlToIntercept, response) { const cdpConnection = await cdp.getConnection(this.driver); - const {status=200, headers: headersObject, body: bodyPlain=''} = response; + const {status = 200, headers: headersObject, body: bodyPlain = ''} = response; const headers = []; if (headersObject) { for (const [name, value] of Object.entries(headersObject)) { @@ -1209,29 +1209,29 @@ module.exports = class MethodMappings { async takeHeapSnapshot(heapSnapshotLocation) { const cdpConnection = await cdp.getConnection(this.driver); - + const chunks = []; cdpConnection._wsConnection.on('message', (message) => { const params = JSON.parse(message); if (params.method === 'HeapProfiler.addHeapSnapshotChunk') { const chunk = params['params']['chunk']; - + chunks.push(chunk); } }); - + await cdpConnection.execute( 'HeapProfiler.enable', {} ); - + await cdpConnection.execute( 'HeapProfiler.takeHeapSnapshot', {} ); - + let prevChunks = []; - + return new Promise((resolve) => { const intervalId = setInterval(() => { if (prevChunks.length !== 0 && prevChunks.length === chunks.length) { @@ -1239,15 +1239,15 @@ module.exports = class MethodMappings { } prevChunks = [...chunks]; }, 100); - + const resolveAndClearInterval = () => { clearInterval(intervalId); - + const heapSnapshot = chunks.join(''); if (heapSnapshotLocation) { fs.writeFileSync(heapSnapshotLocation, heapSnapshot); } - + resolve({value: heapSnapshot}); }; }); diff --git a/lib/transport/selenium-webdriver/session.js b/lib/transport/selenium-webdriver/session.js index 02d1dab6ed..9062246be6 100644 --- a/lib/transport/selenium-webdriver/session.js +++ b/lib/transport/selenium-webdriver/session.js @@ -4,9 +4,9 @@ module.exports = class Session { } static serializeCapabilities(caps) { - let ret = {}; - for (let key of caps.keys()) { - let cap = caps.get(key); + const ret = {}; + for (const key of caps.keys()) { + const cap = caps.get(key); if (cap !== undefined && cap !== null) { ret[key] = cap; } @@ -45,4 +45,4 @@ module.exports = class Session { capabilities: Session.serializeCapabilities(sessionCapabilities) }; } -}; \ No newline at end of file +}; diff --git a/lib/utils/addDetailedError.ts b/lib/utils/addDetailedError.ts index 0977c1ee66..dbaee47a4d 100644 --- a/lib/utils/addDetailedError.ts +++ b/lib/utils/addDetailedError.ts @@ -58,4 +58,4 @@ export = function(err: NightwatchError) { if (detailedErr) { err.detailedErr = detailedErr; } -}; \ No newline at end of file +}; diff --git a/lib/utils/analytics.js b/lib/utils/analytics.js index 80f10cc03d..890b4b87fc 100644 --- a/lib/utils/analytics.js +++ b/lib/utils/analytics.js @@ -40,7 +40,7 @@ const SYSTEM_LANGUAGE = getLanguage(); /** * See: https://developers.google.com/analytics/devguides/collection/protocol/v1/devguide */ -class AnalyticsCollector { +class AnalyticsCollector { constructor() { this.queueLength = 0; this.parameters = {}; @@ -113,7 +113,7 @@ class AnalyticsCollector { return await this.__addToQueue(name, parameters); } - + async collectErrorEvent(error, isUncaught = false) { if (!error) { return; @@ -186,7 +186,7 @@ class AnalyticsCollector { this.logger.info('Analytics flush error:', error.message); } } - + async __addToQueue(eventType, parameters) { if (!this.settings.usage_analytics.enabled) { return; @@ -256,7 +256,7 @@ class AnalyticsCollector { return `/mp/collect?api_secret=${apiKey}&measurement_id=${trackingId}`; } - + async __logAnalyticsEvents(data) { const logfile = this.__getLogFileLocation(); @@ -267,7 +267,7 @@ class AnalyticsCollector { data.params['first_run'] = true; await fs.mkdir(path.dirname(logfile), {recursive: true}); - } + } const writeFn = hasAnalyticsLog ? fs.appendFile : fs.writeFile; @@ -327,7 +327,7 @@ function getLanguage() { getWindowsLanguageCode() || '??'); } - + /** * Attempt to get the Windows Language Code string. */ @@ -356,4 +356,4 @@ function buildUserAgentString() { } // export singleton instance -module.exports = new AnalyticsCollector();; \ No newline at end of file +module.exports = new AnalyticsCollector();; diff --git a/lib/utils/debuggability.js b/lib/utils/debuggability.js index aa9455bfc4..ed291e2640 100644 --- a/lib/utils/debuggability.js +++ b/lib/utils/debuggability.js @@ -6,7 +6,7 @@ class Debuggability { static set stepOverAndPause(value) { this._stepOverAndPause = value; } - + static reset() { this._stepOverAndPause = false; } diff --git a/lib/utils/getAllClassMethodNames.js b/lib/utils/getAllClassMethodNames.js index 1cf79b0a95..127bb49dba 100644 --- a/lib/utils/getAllClassMethodNames.js +++ b/lib/utils/getAllClassMethodNames.js @@ -24,4 +24,4 @@ module.exports = function(instance, additionalReserved = []) { } return [...result]; -}; \ No newline at end of file +}; diff --git a/lib/utils/index.js b/lib/utils/index.js index fe4b6d7feb..3b5d031d42 100644 --- a/lib/utils/index.js +++ b/lib/utils/index.js @@ -151,11 +151,11 @@ class Utils { } static formatElapsedTime(timeMs, includeMs = false) { - const seconds = timeMs/1000; + const seconds = timeMs / 1000; return (seconds < 1 && timeMs + 'ms') || (seconds > 1 && seconds < 60 && (seconds + 's')) || - (Math.floor(seconds/60) + 'm' + ' ' + Math.floor(seconds%60) + 's' + (includeMs ? (' / ' + timeMs + 'ms') : '')); + (Math.floor(seconds / 60) + 'm' + ' ' + Math.floor(seconds % 60) + 's' + (includeMs ? (' / ' + timeMs + 'ms') : '')); } /** @@ -200,7 +200,7 @@ class Utils { return ''; } - return (offset > 0 && (string.charAt(offset-1) !== ' ') ? ' ':'') + $1; + return (offset > 0 && (string.charAt(offset - 1) !== ' ') ? ' ' : '') + $1; }); const words = moduleName.split(nameSeparatorRegxp).map(function(word, index, matches) { @@ -261,7 +261,7 @@ class Utils { } } parentFolder = this.isFileNameValid(parentFolder) ? '' : parentFolder; - + return path.join(parentFolder, diffInFolder, moduleName); } @@ -526,7 +526,7 @@ class Utils { /** * Writes content to file. Creates parent folders if the folders do not exist. * @param {string} filePath - * @param {string} data + * @param {string} data */ static writeToFile(filePath, data, encoding = null) { const dir = path.resolve(filePath, '..'); @@ -578,7 +578,7 @@ class Utils { if (Utils.fileExistsSync(projectTsFileLocation1)) { return projectTsFileLocation1; - } + } if (Utils.fileExistsSync(projectTsFileLocation2)) { return projectTsFileLocation2; } @@ -630,7 +630,7 @@ class Utils { static isLocalhost(webdriver = {}) { const {host} = webdriver; - + return ['127.0.0.1', 'localhost'].indexOf(host) > -1; } @@ -644,7 +644,7 @@ class Utils { return fn; } - + static stringifyObject(objects) { const objectString = Utils.isObject(objects) ? inspect(objects) : objects; diff --git a/lib/utils/locatestrategy.js b/lib/utils/locatestrategy.js index 65e8862a85..fdb88d16d5 100644 --- a/lib/utils/locatestrategy.js +++ b/lib/utils/locatestrategy.js @@ -46,4 +46,4 @@ class LocateStrategy { } } -module.exports = LocateStrategy; \ No newline at end of file +module.exports = LocateStrategy; diff --git a/lib/utils/logger/index.js b/lib/utils/logger/index.js index afd03c3fd8..455770520a 100644 --- a/lib/utils/logger/index.js +++ b/lib/utils/logger/index.js @@ -400,7 +400,7 @@ class Logger { if (errorObj.help) { content.push(this.colors.brown('\n Try fixing by :')); errorObj.help.forEach((step, index) => { - content.push(` ${this.colors.blue(index+1)}. ${step}`); + content.push(` ${this.colors.blue(index + 1)}. ${step}`); }); } diff --git a/lib/utils/logger/log_settings.js b/lib/utils/logger/log_settings.js index ae38580660..378cd9f47c 100644 --- a/lib/utils/logger/log_settings.js +++ b/lib/utils/logger/log_settings.js @@ -100,4 +100,4 @@ module.exports = new (function() { } return new LogSettings(); -})(); \ No newline at end of file +})(); diff --git a/lib/utils/mobile.js b/lib/utils/mobile.js index 9d74c08cd4..2799b3b298 100644 --- a/lib/utils/mobile.js +++ b/lib/utils/mobile.js @@ -16,7 +16,7 @@ function requireMobileHelper() { } else if (!semver.satisfies(process.version, '>=14.0.0')) { err.message = 'You are using Node ' + process.version + ', but @nightwatch/mobile-helper requires Node >= v14.0.0.\nPlease upgrade your Node version.'; } - + err.showTrace = false; err.displayed = false; @@ -26,7 +26,7 @@ function requireMobileHelper() { /** * check if target is Android - * @param {Object} desiredCapabilities + * @param {Object} desiredCapabilities * @returns {Boolean} */ function isAndroid(desiredCapabilities = {}){ @@ -47,7 +47,7 @@ function isAndroid(desiredCapabilities = {}){ /** * check if target is iOS Device - * @param {Object} desiredCapabilities + * @param {Object} desiredCapabilities * @returns {Boolean} */ function isIos(desiredCapabilities = {}) { @@ -62,7 +62,7 @@ function isIos(desiredCapabilities = {}) { /** * check if target is Simulator - * @param {Object} desiredCapabilities + * @param {Object} desiredCapabilities * @returns {Boolean} */ function isSimulator(desiredCapabilities){ @@ -75,7 +75,7 @@ function isSimulator(desiredCapabilities){ /** * check if target is Real iOS Device - * @param {Object} desiredCapabilities + * @param {Object} desiredCapabilities * @returns {Boolean} */ function isRealIos(desiredCapabilities) { @@ -88,7 +88,7 @@ function isRealIos(desiredCapabilities) { /** * check if the target is a mobile platform - * @param {Object} desiredCapabilities + * @param {Object} desiredCapabilities * @returns {Boolean} */ function isMobile(desiredCapabilities){ @@ -101,14 +101,14 @@ function isMobile(desiredCapabilities){ /** * Check if Real iOS device UDID is correct - * @param {String} udid + * @param {String} udid * @returns {String} */ function iosRealDeviceUDID(udid){ if (udid.length > 25) { return udid; - } - + } + if (udid.length < 24) { throw new Error('Incorrect UDID provided for real iOS device'); } @@ -117,7 +117,7 @@ function iosRealDeviceUDID(udid){ }; /** - * Function to kill iOS Simulator + * Function to kill iOS Simulator * @param {String} udid */ function killSimulator(udid) { @@ -233,7 +233,7 @@ class AndroidConnectionError extends Error { help = [ `${Logger.colors.cyan('adb')} binary not found. Run command ${Logger.colors.cyan('npx @nightwatch/mobile-helper android')} to setup the missing requirements.` ]; - } else { + } else { if (binaryLocation === 'PATH') { binaryLocation = 'adb'; } @@ -287,7 +287,7 @@ class IosSessionNotCreatedError extends Error { `If it doesn't work, try running: ${Logger.colors.cyan('npx run @nightwatch/mobile-helper ios')}` ]; } else { - help= [ + help = [ `Make sure you have passed correct ${Logger.colors.green('deviceId')} in the command (for e.g : ${Logger.colors.cyan('--deviceId 00008030-00024C2C3453402E')})`, `Or pass ${Logger.colors.green('safari:deviceUDID')} capability in config`, `To verify the deviceId run, ${Logger.colors.cyan('system_profiler SPUSBDataType | sed -n \'/iPhone/,/Serial/p\' | grep \'Serial Number:\' | awk -F \': \' \'{print $2}')}`, diff --git a/lib/utils/printVersionInfo.js b/lib/utils/printVersionInfo.js index 44b5c33368..0322f67a5a 100644 --- a/lib/utils/printVersionInfo.js +++ b/lib/utils/printVersionInfo.js @@ -8,4 +8,4 @@ module.exports = function() { console.log(' version: ' + VERSION.full); // eslint-disable-next-line no-console console.log(' changelog: https://github.com/nightwatchjs/nightwatch/releases/tag/v' + VERSION.full + '\n'); -}; \ No newline at end of file +}; diff --git a/lib/utils/safeStringify.js b/lib/utils/safeStringify.js index 7d19ff2e19..86a33b6007 100644 --- a/lib/utils/safeStringify.js +++ b/lib/utils/safeStringify.js @@ -28,17 +28,17 @@ class SafeStringify { const result = Object.keys(obj).reduce((result, prop) => { result[prop] = this.visit(obj[prop], seen); - + return result; }, {}); seen.pop(); - + return result; } static safeJSON(obj) { - const seen = []; - + const seen = []; + return this.visit(obj, seen); } @@ -47,4 +47,4 @@ class SafeStringify { } } -module.exports = SafeStringify; \ No newline at end of file +module.exports = SafeStringify; diff --git a/lib/utils/stackTrace.js b/lib/utils/stackTrace.js index b257c1e218..ba60877744 100644 --- a/lib/utils/stackTrace.js +++ b/lib/utils/stackTrace.js @@ -116,4 +116,4 @@ module.exports = { filterStack, filterStackTrace, showStackTrace -}; \ No newline at end of file +}; diff --git a/lib/utils/timed-callback.js b/lib/utils/timed-callback.js index 084094613a..2d9fe34586 100644 --- a/lib/utils/timed-callback.js +++ b/lib/utils/timed-callback.js @@ -49,7 +49,7 @@ class TimedCallback { createTimeout() { this.timeoutId = setTimeout(() => { - let err = new TimeoutError(`done() callback timeout of ${this.timeoutMs}ms was reached while executing "${this.name}".` + + const err = new TimeoutError(`done() callback timeout of ${this.timeoutMs}ms was reached while executing "${this.name}".` + ' Make sure to call the done() callback when the operation finishes.'); this.onTimeoutExpired(err, this.name, this.timeoutMs); }, this.timeoutMs); @@ -58,4 +58,4 @@ class TimedCallback { } } -module.exports = TimedCallback; \ No newline at end of file +module.exports = TimedCallback; diff --git a/lib/utils/version.js b/lib/utils/version.js index 7641f27ba0..7c7bf9e384 100644 --- a/lib/utils/version.js +++ b/lib/utils/version.js @@ -6,4 +6,4 @@ module.exports = { major: fullVersion.split('.')[0], minor: fullVersion.split('.')[1], patch: fullVersion.split('.').slice(2).join('.') -}; \ No newline at end of file +}; diff --git a/test/extra/pageobjects/commands/workingCommandsClass.js b/test/extra/pageobjects/commands/workingCommandsClass.js index a0074cc355..cd12a7e53b 100644 --- a/test/extra/pageobjects/commands/workingCommandsClass.js +++ b/test/extra/pageobjects/commands/workingCommandsClass.js @@ -5,7 +5,7 @@ module.exports = class RealCommands { selector, suppressNotFoundErrors: true }, function(result) { - return callback(result ? result.value: []); + return callback(result ? result.value : []); }); } diff --git a/test/lib/command-mocks.js b/test/lib/command-mocks.js index 8c08da65b3..4f79dcc93a 100644 --- a/test/lib/command-mocks.js +++ b/test/lib/command-mocks.js @@ -269,7 +269,7 @@ module.exports = { }, true); }, - w3cSelected(elementId ='5cc459b8-36a8-3042-8b4a-258883ea642b', value = true) { + w3cSelected(elementId = '5cc459b8-36a8-3042-8b4a-258883ea642b', value = true) { MockServer.addMock({ url: `/session/13521-10219-202/element/${elementId}/selected`, method: 'GET', @@ -279,7 +279,7 @@ module.exports = { }, true); }, - w3cEnabled(elementId ='5cc459b8-36a8-3042-8b4a-258883ea642b', value = true) { + w3cEnabled(elementId = '5cc459b8-36a8-3042-8b4a-258883ea642b', value = true) { MockServer.addMock({ url: `/session/13521-10219-202/element/${elementId}/enabled`, method: 'GET', diff --git a/test/lib/nightwatch.js b/test/lib/nightwatch.js index db72dfc1a7..85d8e218ee 100644 --- a/test/lib/nightwatch.js +++ b/test/lib/nightwatch.js @@ -46,7 +46,7 @@ module.exports = new function () { } this.createClient = function(options = {}, reporter = null, argv = {}) { - let opts = { + const opts = { selenium: { port: 10195, host: 'localhost', @@ -118,7 +118,7 @@ module.exports = new function () { }); }; - this.initW3CClient = function(opts = {}, argv={}) { + this.initW3CClient = function(opts = {}, argv = {}) { const settings = Object.assign({ selenium: { version2: false, diff --git a/test/lib/nocks.js b/test/lib/nocks.js index e40d4f5195..34820bf6e3 100644 --- a/test/lib/nocks.js +++ b/test/lib/nocks.js @@ -191,7 +191,7 @@ module.exports = { return this; }, - childElementsNotFound(selector='#badElement') { + childElementsNotFound(selector = '#badElement') { nock('http://localhost:10195') .post('/wd/hub/session/1352110219202/element/0/elements', {'using': 'css selector', 'value': selector}) .reply(200, { @@ -203,14 +203,14 @@ module.exports = { return this; }, - childElementsFound(selector='#weblogin') { + childElementsFound(selector = '#weblogin') { nock('http://localhost:10195') .post('/wd/hub/session/1352110219202/element/0/elements', {'using': 'css selector', 'value': selector}) .reply(200, { status: 0, state: 'success', value: [{'element-6066-11e4-a52e-4f735466cecf': '0'}] - }) + }); return this; }, @@ -589,7 +589,7 @@ module.exports = { .reply(200, { status: 0, state: 'success', - value : { + value: { domain: 'cookie-domain', name: name, value: value diff --git a/test/src/analytics/testAnalytics.js b/test/src/analytics/testAnalytics.js index 3b26f5c617..fa5d869f6f 100644 --- a/test/src/analytics/testAnalytics.js +++ b/test/src/analytics/testAnalytics.js @@ -173,7 +173,7 @@ describe('test analytics utility', function() { const analyticsNock = Nocks.analyticsCollector(analytics.__getGoogleAnalyticsPath()); const err = new Error('test'); - err.name ='UserGeneratedError'; + err.name = 'UserGeneratedError'; await analytics.collectErrorEvent(err); diff --git a/test/src/api/commands/client/testWaitUntil.js b/test/src/api/commands/client/testWaitUntil.js index d04108b2ad..f0873298a4 100644 --- a/test/src/api/commands/client/testWaitUntil.js +++ b/test/src/api/commands/client/testWaitUntil.js @@ -105,7 +105,7 @@ describe('.waitUntil()', function () { it('client.waitUntil() function failure with custom timeout', function (done) { let tries = 0; - let startTime = new Date().valueOf(); + const startTime = new Date().valueOf(); let timeDiff; const maxTimeout = 100; const client = this.client.api; @@ -123,7 +123,7 @@ describe('.waitUntil()', function () { this.client.start(err => { try { - assert.ok(timeDiff <= maxTimeout+100, `Expected lower than ${maxTimeout}, but got ${timeDiff}`); + assert.ok(timeDiff <= maxTimeout + 100, `Expected lower than ${maxTimeout}, but got ${timeDiff}`); assert.strictEqual(result.status, -1); assert.strictEqual(tries, 3); assert.ok(err instanceof Error); @@ -136,7 +136,7 @@ describe('.waitUntil()', function () { it('client.waitUntil() function failure with custom timeout, interval, message, and callback', function (done) { let tries = 0; - let startTime = new Date().valueOf(); + const startTime = new Date().valueOf(); let timeDiff; const maxTimeout = 100; const client = this.client.api; @@ -154,7 +154,7 @@ describe('.waitUntil()', function () { this.client.start(err => { try { - assert.ok(timeDiff <= maxTimeout+100, `Expected lower than ${maxTimeout}, but got ${timeDiff}`); + assert.ok(timeDiff <= maxTimeout + 100, `Expected lower than ${maxTimeout}, but got ${timeDiff}`); assert.strictEqual(result.status, -1); assert.ok(err instanceof Error); const messageParts = err.message.split('\n'); @@ -196,7 +196,7 @@ describe('.waitUntil()', function () { it('client.waitUntil() function failure with custom timeout and default interval', function (done) { let tries = 0; - let startTime = new Date().valueOf(); + const startTime = new Date().valueOf(); let timeDiff; const maxTimeout = 100; const client = this.client.api; @@ -215,7 +215,7 @@ describe('.waitUntil()', function () { this.client.start(err => { try { assert.ok(err instanceof Error); - assert.ok(timeDiff <= maxTimeout+100, `Expected lower than ${maxTimeout}, but got ${timeDiff}`); + assert.ok(timeDiff <= maxTimeout + 100, `Expected lower than ${maxTimeout}, but got ${timeDiff}`); assert.strictEqual(result.status, -1); assert.strictEqual(tries, 3); done(); @@ -255,7 +255,7 @@ describe('.waitUntil()', function () { it('client.waitUntil() function failure with custom waitForConditionPollInterval', function (done) { let tries = 0; - let startTime = new Date().valueOf(); + const startTime = new Date().valueOf(); let timeDiff; const maxTimeout = 100; const client = this.client.api; @@ -276,7 +276,7 @@ describe('.waitUntil()', function () { this.client.start(err => { try { assert.ok(err instanceof Error); - assert.ok(timeDiff <= maxTimeout+100, `Expected lower than ${maxTimeout}, but got ${timeDiff}`); + assert.ok(timeDiff <= maxTimeout + 100, `Expected lower than ${maxTimeout}, but got ${timeDiff}`); assert.strictEqual(result.status, -1); assert.ok(tries > 5); done(); diff --git a/test/src/api/commands/element/testWaitForElementPresent.js b/test/src/api/commands/element/testWaitForElementPresent.js index 0b5b031388..c1d80f88b1 100644 --- a/test/src/api/commands/element/testWaitForElementPresent.js +++ b/test/src/api/commands/element/testWaitForElementPresent.js @@ -55,7 +55,7 @@ describe('waitForElementPresent', function() { }); it('client.waitForElementPresent() failure with custom time message', function(done){ - this.client.api.globals.waitForConditionPollInterval=10; + this.client.api.globals.waitForConditionPollInterval = 10; this.client.api.waitForElementPresent('.weblogin', 15, function callback(result, instance){ assert.strictEqual(instance.message, 'Element .weblogin found in 15 milliseconds'); }, 'Element %s found in %d milliseconds'); diff --git a/test/src/cli/testParallelExecution.js b/test/src/cli/testParallelExecution.js index a4b899a093..7039476279 100644 --- a/test/src/cli/testParallelExecution.js +++ b/test/src/cli/testParallelExecution.js @@ -7,7 +7,7 @@ const Nightwatch = require('../../lib/nightwatch.js'); describe('test Parallel Execution', function() { const workerPoolArgv = []; - const taskArgv= []; + const taskArgv = []; const allArgs = []; const allOpts = []; @@ -88,9 +88,9 @@ describe('test Parallel Execution', function() { it('testParallelExecution - child-process', function() { const CliRunner = common.require('runner/cli/cli.js'); - let originalCwd = process.cwd(); + const originalCwd = process.cwd(); process.chdir(path.join(__dirname, '../../extra/')); - let runner = new CliRunner({ + const runner = new CliRunner({ config: './nightwatch.json', env: 'default,mixed', reporter: 'junit' @@ -167,7 +167,7 @@ describe('test Parallel Execution', function() { it('test parallel execution with workers defaults -- worker thread', function() { const CliRunner = common.require('runner/cli/cli.js'); - let runner = new CliRunner({ + const runner = new CliRunner({ reporter: 'junit', config: path.join(__dirname, '../../extra/parallelism.json') }); @@ -187,10 +187,10 @@ describe('test Parallel Execution', function() { }); it('testParallelExecutionSameEnv - child-process', function() { - let originalCwd = process.cwd(); + const originalCwd = process.cwd(); process.chdir(path.join(__dirname, '../../extra/')); const CliRunner = common.require('runner/cli/cli.js'); - let runner = new CliRunner({ + const runner = new CliRunner({ config: './nightwatch.json', reporter: 'junit', env: 'mixed,mixed' @@ -211,11 +211,11 @@ describe('test Parallel Execution', function() { }); it('testParallelExecutionSameEnv - worker threads', function() { - let originalCwd = process.cwd(); + const originalCwd = process.cwd(); process.chdir(path.join(__dirname, '../../extra/')); const CliRunner = common.require('runner/cli/cli.js'); - let runner = new CliRunner({ + const runner = new CliRunner({ config: './nightwatch.json', reporter: 'junit', env: 'mixed,mixed' @@ -279,7 +279,7 @@ describe('test Parallel Execution', function() { it('testParallelExecutionWithWorkers and multiple environments - child process', function() { const CliRunner = common.require('runner/cli/cli.js'); - let runner = new CliRunner({ + const runner = new CliRunner({ reporter: 'junit', config: path.join(__dirname, '../../extra/parallelism-auto.json'), env: 'default,default' @@ -294,7 +294,7 @@ describe('test Parallel Execution', function() { it('testParallelExecutionWithWorkers and multiple environments - worker threads', function() { const CliRunner = common.require('runner/cli/cli.js'); - let runner = new CliRunner({ + const runner = new CliRunner({ reporter: 'junit', config: path.join(__dirname, '../../extra/parallelism-auto.json'), env: 'default,default' @@ -310,7 +310,7 @@ describe('test Parallel Execution', function() { it('test parallel execution with workers count - child process', function() { const CliRunner = common.require('runner/cli/cli.js'); - let runner = new CliRunner({ + const runner = new CliRunner({ reporter: 'junit', config: path.join(__dirname, '../../extra/parallelism-count.json') }); @@ -329,7 +329,7 @@ describe('test Parallel Execution', function() { it('test parallel execution with workers count - worker threads', function() { const CliRunner = common.require('runner/cli/cli.js'); - let runner = new CliRunner({ + const runner = new CliRunner({ reporter: 'junit', config: path.join(__dirname, '../../extra/parallelism-count.json') }); @@ -349,7 +349,7 @@ describe('test Parallel Execution', function() { it('test parallel execution with workers=count arg', function() { const CliRunner = common.require('runner/cli/cli.js'); - let runner = new CliRunner({ + const runner = new CliRunner({ reporter: 'junit', config: path.join(__dirname, '../../extra/parallelism-count.json'), workers: 2 @@ -364,7 +364,7 @@ describe('test Parallel Execution', function() { it('test parallel execution with workers count and extended envs', function() { const CliRunner = common.require('runner/cli/cli.js'); - let runner = new CliRunner({ + const runner = new CliRunner({ reporter: 'junit', config: path.join(__dirname, '../../extra/parallelism-workers.conf.js'), env: 'chrome' @@ -382,7 +382,7 @@ describe('test Parallel Execution', function() { it('test parallel execution with workers disabled per environment', function() { const CliRunner = common.require('runner/cli/cli.js'); - let runner = new CliRunner({ + const runner = new CliRunner({ reporter: 'junit', config: path.join(__dirname, '../../extra/parallelism-disabled.json') }); @@ -394,7 +394,7 @@ describe('test Parallel Execution', function() { it('test parallel execution with workers and single source file', function() { const CliRunner = common.require('runner/cli/cli.js'); - let runner = new CliRunner({ + const runner = new CliRunner({ reporter: 'junit', config: path.join(__dirname, '../../extra/parallelism.json'), _source: [path.join(__dirname, '../../../sampletests/async/test/sample.js')] @@ -408,7 +408,7 @@ describe('test Parallel Execution', function() { it('test parallel execution with workers and single source folder', function() { const CliRunner = common.require('runner/cli/cli.js'); - let runner = new CliRunner({ + const runner = new CliRunner({ reporter: 'junit', config: path.join(__dirname, '../../extra/parallelism.json'), _source: path.join(__dirname, '../../../sampletests/before-after') diff --git a/test/src/runner/cli/testCliRunnerParallel.js b/test/src/runner/cli/testCliRunnerParallel.js index 31e45a4252..13ecb1dde7 100644 --- a/test/src/runner/cli/testCliRunnerParallel.js +++ b/test/src/runner/cli/testCliRunnerParallel.js @@ -126,7 +126,7 @@ describe('Test CLI Runner in Parallel', function () { setTimeout(()=>{ numberOfTasks++; reject(new Error('Nigtwatch custom error')); - }, 10*(numberOfTasks+1)); + }, 10 * (numberOfTasks + 1)); })); return Promise.resolve(0); diff --git a/test/src/runner/cucumber-integration/testCliArgs.js b/test/src/runner/cucumber-integration/testCliArgs.js index c87ca2e4db..cf16847624 100644 --- a/test/src/runner/cucumber-integration/testCliArgs.js +++ b/test/src/runner/cucumber-integration/testCliArgs.js @@ -42,7 +42,7 @@ describe('Cucumber cli arguments', function(){ let index = cliArgs.indexOf('--require-module') + 1; assert.strictEqual(cliArgs[index], 'coffeescript/register'); - index = cliArgs.indexOf('--require-module', index)+1; + index = cliArgs.indexOf('--require-module', index) + 1; assert.strictEqual(cliArgs[index], 'ts-node/register'); }); @@ -59,17 +59,17 @@ describe('Cucumber cli arguments', function(){ assert.strictEqual(cliArgs.length, 21); assert.ok(cliArgs.includes('--name')); - assert.strictEqual(cliArgs[cliArgs.indexOf('--name')+1], 'sample'); + assert.strictEqual(cliArgs[cliArgs.indexOf('--name') + 1], 'sample'); assert.ok(cliArgs.includes('--fail-fast')); assert.ok(cliArgs.includes('--retry')); - assert.strictEqual(cliArgs[cliArgs.indexOf('--retry')+1], 2); + assert.strictEqual(cliArgs[cliArgs.indexOf('--retry') + 1], 2); assert.ok(cliArgs.includes('--retry-tag-filter')); - assert.strictEqual(cliArgs[cliArgs.indexOf('--retry-tag-filter')+1], '@nightwatch'); + assert.strictEqual(cliArgs[cliArgs.indexOf('--retry-tag-filter') + 1], '@nightwatch'); assert.ok(cliArgs.includes('--profile')); - assert.strictEqual(cliArgs[cliArgs.indexOf('--profile')+1], 'local'); + assert.strictEqual(cliArgs[cliArgs.indexOf('--profile') + 1], 'local'); assert.ok(cliArgs.includes('--no-strict')); assert.ok(cliArgs.includes('--parallel')); - assert.strictEqual(cliArgs[cliArgs.indexOf('--parallel')+1], 3); + assert.strictEqual(cliArgs[cliArgs.indexOf('--parallel') + 1], 3); assert.ok(cliArgs.includes('--require')); }); @@ -127,8 +127,8 @@ describe('Cucumber cli arguments', function(){ assert.ok(cliArgs.includes('--retry')); assert.ok(cliArgs.includes('--format')); - assert.strictEqual(cliArgs[cliArgs.indexOf('--retry')+1], 3); - assert.strictEqual(cliArgs[cliArgs.indexOf('--format')+1], '@cucumber/pretty-formatter'); + assert.strictEqual(cliArgs[cliArgs.indexOf('--retry') + 1], 3); + assert.strictEqual(cliArgs[cliArgs.indexOf('--format') + 1], '@cucumber/pretty-formatter'); }); it('Cucumber cli arg --enable-esm', function(){ From 0822095d05824dbcd02ef8004018d6bdb1fd0f87 Mon Sep 17 00:00:00 2001 From: Priyansh Garg <39924567+garg3133@users.noreply.github.com> Date: Wed, 30 Aug 2023 18:37:29 +0530 Subject: [PATCH 36/38] Refactor utils modules before migrating to TS. (#3870) --- .eslintrc | 2 +- lib/utils/logger/log_settings.js | 163 ++++++++-------- package-lock.json | 309 +++++++++++++------------------ package.json | 2 +- 4 files changed, 217 insertions(+), 259 deletions(-) diff --git a/.eslintrc b/.eslintrc index 08cfe8583f..6b7091c1ac 100644 --- a/.eslintrc +++ b/.eslintrc @@ -4,7 +4,7 @@ "eslint:recommended" ], "parserOptions": { - "ecmaVersion": 2020, + "ecmaVersion": 13, "sourceType": "module", "ecmaFeatures": { "jsx": false diff --git a/lib/utils/logger/log_settings.js b/lib/utils/logger/log_settings.js index 378cd9f47c..7906ced82c 100644 --- a/lib/utils/logger/log_settings.js +++ b/lib/utils/logger/log_settings.js @@ -1,103 +1,106 @@ -const lodashClone = require('lodash.clone'); - -const Settings = { - outputEnabled: true, - showResponseHeaders: false, - showRequestData: { - enabled: true, - trimLongScripts: true - }, - detailedOutput: true, - disableErrorLog: false, - log_timestamp: false, - timestamp_format: null, - enabled: true -}; - -module.exports = new (function() { - const logSettings = lodashClone(Settings, true); - - class LogSettings { - get outputEnabled() { - return logSettings.outputEnabled; - } - - get detailedOutput() { - return logSettings.detailedOutput; - } +class LogSettings { + #outputEnabled; + #showResponseHeaders; + #showRequestData; + #detailedOutput; + #disableErrorLog; + #log_timestamp; + #timestamp_format; + #enabled; + #htmlReporterEnabled; + + constructor() { + this.#outputEnabled = true; + this.#showResponseHeaders = false; + this.#showRequestData = { + enabled: true, + trimLongScripts: true + }, + this.#detailedOutput = true; + this.#disableErrorLog = false; + this.#log_timestamp = false; + this.#timestamp_format = null; + this.#enabled = true; + this.#htmlReporterEnabled = false; + } - get showRequestData() { - return logSettings.showRequestData; - } + get outputEnabled() { + return this.#outputEnabled; + } - get enabled() { - return logSettings.enabled; - } + get detailedOutput() { + return this.#detailedOutput; + } - get showResponseHeaders() { - return logSettings.showResponseHeaders; - } + get showRequestData() { + return this.#showRequestData; + } - get timestampFormat() { - return logSettings.timestamp_format; - } + get enabled() { + return this.#enabled; + } - set outputEnabled(value) { - if (typeof value == 'undefined') { - value = true; - } + get showResponseHeaders() { + return this.#showResponseHeaders; + } - logSettings.outputEnabled = value; - } + get timestampFormat() { + return this.#timestamp_format; + } - set detailedOutput(value) { - logSettings.detailedOutput = value; + set outputEnabled(value) { + if (typeof value === 'undefined') { + value = true; } - set disableErrorLog(value) { - if (typeof value == 'undefined') { - value = true; - } + this.#outputEnabled = value; + } - logSettings.disableErrorLog = value; - } + set detailedOutput(value) { + this.#detailedOutput = value; + } - set htmlReporterEnabled(value) { - logSettings.htmlReporterEnabled = value; + set disableErrorLog(value) { + if (typeof value === 'undefined') { + value = true; } - get htmlReporterEnabled() { - return logSettings.htmlReporterEnabled; - } + this.#disableErrorLog = value; + } - isLogTimestamp() { - return logSettings.log_timestamp; - } + set htmlReporterEnabled(value) { + this.#htmlReporterEnabled = value; + } - isErrorLogEnabled() { - return !logSettings.disableErrorLog; - } + get htmlReporterEnabled() { + return this.#htmlReporterEnabled; + } - disable() { - logSettings.enabled = false; - } + isLogTimestamp() { + return this.#log_timestamp; + } - enable() { - logSettings.enabled = true; - } + isErrorLogEnabled() { + return !this.#disableErrorLog; + } - setLogTimestamp(val, format) { - logSettings.log_timestamp = val; - logSettings.timestamp_format = format; - } + disable() { + this.#enabled = false; + } - setHttpLogOptions({showRequestData, showResponseHeaders}) { - logSettings.showRequestData = showRequestData; - logSettings.showResponseHeaders = showResponseHeaders; - } + enable() { + this.#enabled = true; + } + setLogTimestamp(val, format) { + this.#log_timestamp = val; + this.#timestamp_format = format; + } + setHttpLogOptions({showRequestData, showResponseHeaders}) { + this.#showRequestData = showRequestData; + this.#showResponseHeaders = showResponseHeaders; } +} - return new LogSettings(); -})(); +module.exports = new LogSettings(); diff --git a/package-lock.json b/package-lock.json index 349de22fe5..a11201d58d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -60,7 +60,7 @@ "@typescript-eslint/parser": "^6.3.0", "copyfiles": "^2.4.1", "cross-env": "^7.0.3", - "eslint": "^8.9.0", + "eslint": "^8.46.0", "husky": "^8.0.0", "is-ci": "^3.0.1", "js-yaml": "^3.13.1", @@ -816,15 +816,15 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", - "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.1.tgz", + "integrity": "sha512-9t7ZA7NGGK8ckelF0PQCfcxIUzs1Md5rrO6U/c+FIQNanea5UZC0wqKXH4vHBccmu4ZJgZ2idtPeW7+Q2npOEA==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.4.0", - "globals": "^13.15.0", + "espree": "^9.6.0", + "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -856,6 +856,15 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/@eslint/js": { + "version": "8.46.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.46.0.tgz", + "integrity": "sha512-a8TLtmPi8xzPkCbp/OGFUo5yhRkHM2Ko9kOWP4znJr0WAhWyThaw3PnwX4vOTWOAMsV2uRt32PPDcEz63esSaA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, "node_modules/@hapi/hoek": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", @@ -872,19 +881,32 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", - "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", + "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", - "minimatch": "^3.0.4" + "minimatch": "^3.0.5" }, "engines": { "node": ">=10.10.0" } }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@humanwhocodes/object-schema": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", @@ -3253,46 +3275,48 @@ } }, "node_modules/eslint": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.9.0.tgz", - "integrity": "sha512-PB09IGwv4F4b0/atrbcMFboF/giawbBLVC7fyDamk5Wtey4Jh2K+rYaBhCAbUyEI4QzB1ly09Uglc9iCtFaG2Q==", - "dev": true, - "dependencies": { - "@eslint/eslintrc": "^1.1.0", - "@humanwhocodes/config-array": "^0.9.2", - "ajv": "^6.10.0", + "version": "8.46.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.46.0.tgz", + "integrity": "sha512-cIO74PvbW0qU8e0mIvk5IV3ToWdCq5FYG6gWPHHkx6gNdjlbAYvtfHmlCMXxjcoVaIdwy/IAt3+mDkZkfvb2Dg==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.1", + "@eslint/js": "^8.46.0", + "@humanwhocodes/config-array": "^0.11.10", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.1", - "esquery": "^1.4.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.2", + "espree": "^9.6.1", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^6.0.1", - "globals": "^13.6.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", "ignore": "^5.2.0", - "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", + "optionator": "^0.9.3", "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "text-table": "^0.2.0" }, "bin": { "eslint": "bin/eslint.js" @@ -3333,9 +3357,9 @@ "dev": true }, "node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", @@ -3343,33 +3367,9 @@ }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-visitor-keys": { @@ -3427,14 +3427,14 @@ } }, "node_modules/espree": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", - "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "dependencies": { - "acorn": "^8.8.0", + "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -3456,9 +3456,9 @@ } }, "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, "dependencies": { "estraverse": "^5.1.0" @@ -3814,12 +3814,6 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "dev": true - }, "node_modules/functions-have-names": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", @@ -3942,9 +3936,9 @@ } }, "node_modules/globals": { - "version": "13.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz", - "integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==", + "version": "13.21.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz", + "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -7591,18 +7585,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, "node_modules/registry-auth-token": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz", @@ -8910,12 +8892,6 @@ "uuid": "dist/bin/uuid" } }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", @@ -9952,15 +9928,15 @@ "dev": true }, "@eslint/eslintrc": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", - "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.1.tgz", + "integrity": "sha512-9t7ZA7NGGK8ckelF0PQCfcxIUzs1Md5rrO6U/c+FIQNanea5UZC0wqKXH4vHBccmu4ZJgZ2idtPeW7+Q2npOEA==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.4.0", - "globals": "^13.15.0", + "espree": "^9.6.0", + "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -9985,6 +9961,12 @@ } } }, + "@eslint/js": { + "version": "8.46.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.46.0.tgz", + "integrity": "sha512-a8TLtmPi8xzPkCbp/OGFUo5yhRkHM2Ko9kOWP4znJr0WAhWyThaw3PnwX4vOTWOAMsV2uRt32PPDcEz63esSaA==", + "dev": true + }, "@hapi/hoek": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", @@ -10001,16 +9983,22 @@ } }, "@humanwhocodes/config-array": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", - "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", + "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", "dev": true, "requires": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", - "minimatch": "^3.0.4" + "minimatch": "^3.0.5" } }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true + }, "@humanwhocodes/object-schema": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", @@ -11696,46 +11684,48 @@ } }, "eslint": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.9.0.tgz", - "integrity": "sha512-PB09IGwv4F4b0/atrbcMFboF/giawbBLVC7fyDamk5Wtey4Jh2K+rYaBhCAbUyEI4QzB1ly09Uglc9iCtFaG2Q==", - "dev": true, - "requires": { - "@eslint/eslintrc": "^1.1.0", - "@humanwhocodes/config-array": "^0.9.2", - "ajv": "^6.10.0", + "version": "8.46.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.46.0.tgz", + "integrity": "sha512-cIO74PvbW0qU8e0mIvk5IV3ToWdCq5FYG6gWPHHkx6gNdjlbAYvtfHmlCMXxjcoVaIdwy/IAt3+mDkZkfvb2Dg==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.1", + "@eslint/js": "^8.46.0", + "@humanwhocodes/config-array": "^0.11.10", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.1", - "esquery": "^1.4.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.2", + "espree": "^9.6.1", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^6.0.1", - "globals": "^13.6.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", "ignore": "^5.2.0", - "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", + "optionator": "^0.9.3", "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "text-table": "^0.2.0" }, "dependencies": { "argparse": { @@ -11793,32 +11783,15 @@ "dev": true }, "eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "requires": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^2.0.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - } - } - }, "eslint-visitor-keys": { "version": "3.4.2", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.2.tgz", @@ -11826,14 +11799,14 @@ "dev": true }, "espree": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", - "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "requires": { - "acorn": "^8.8.0", + "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.1" } }, "esprima": { @@ -11842,9 +11815,9 @@ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" }, "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, "requires": { "estraverse": "^5.1.0" @@ -12106,12 +12079,6 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "dev": true - }, "functions-have-names": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", @@ -12194,9 +12161,9 @@ } }, "globals": { - "version": "13.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz", - "integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==", + "version": "13.21.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz", + "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -14983,12 +14950,6 @@ "functions-have-names": "^1.2.2" } }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true - }, "registry-auth-token": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz", @@ -15954,12 +15915,6 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" }, - "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, "v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", diff --git a/package.json b/package.json index 6b9a8268d0..fafcb95d64 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "@typescript-eslint/parser": "^6.3.0", "copyfiles": "^2.4.1", "cross-env": "^7.0.3", - "eslint": "^8.9.0", + "eslint": "^8.46.0", "husky": "^8.0.0", "is-ci": "^3.0.1", "js-yaml": "^3.13.1", From 863d2c90480e216116cf4a01ffed195173041f13 Mon Sep 17 00:00:00 2001 From: Ravi Sawlani Date: Mon, 4 Sep 2023 16:10:41 +0530 Subject: [PATCH 37/38] Fixes/run mocha on child process workers (#3904) * use child process in mocha runner * added test --- lib/runner/cli/cli.js | 5 ++++ test/src/cli/testCliRunnerMocha.js | 44 ++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/lib/runner/cli/cli.js b/lib/runner/cli/cli.js index c2de0cac04..402ce6ba16 100644 --- a/lib/runner/cli/cli.js +++ b/lib/runner/cli/cli.js @@ -432,6 +432,11 @@ class CliRunner { } setupConcurrency() { + + if (this.testRunner?.type === Runner.MOCHA_RUNNER) { + this.test_settings.use_child_process = true; + } + this.concurrency = new Concurrency(this.test_settings, this.argv, this.isTestWorkersEnabled()); return this; diff --git a/test/src/cli/testCliRunnerMocha.js b/test/src/cli/testCliRunnerMocha.js index 07c7a8f56f..0f0244c2fd 100644 --- a/test/src/cli/testCliRunnerMocha.js +++ b/test/src/cli/testCliRunnerMocha.js @@ -26,6 +26,7 @@ describe('test CLI Runner Mocha', function() { resolve: function(a) { return a; }, + extname: path.extname, join: path.join }); @@ -89,6 +90,49 @@ describe('test CLI Runner Mocha', function() { }); }); + it('testRunWithMocha - parallelism', function() { + + const ChildProcess = common.require('runner/concurrency/child-process.js'); + let childProcessCreated = false; + class ChildProcessMock extends ChildProcess { + run(colors, type) { + childProcessCreated = true; + assert.strictEqual(colors.length, 4); + assert.strictEqual(type, 'workers'); + assert.deepStrictEqual(Object.keys(this._events), ['message']); + + return Promise.resolve(0); + } + } + + mockery.registerMock('./child-process.js', ChildProcessMock); + + mockery.registerMock('./withmocha.json', { + src_folders: ['tests'], + output_folder: false, + use_child_process: false, + test_settings: { + 'default': { + silent: true + } + }, + test_runner: 'mocha' + }); + + + const CliRunner = common.require('runner/cli/cli.js'); + const runner = new CliRunner({ + config: './withmocha.json', + env: 'default', + reporter: 'junit', + parallel: true + }).setup(); + + return runner.runTests().then(function() { + assert.ok(childProcessCreated, 'mocha runner with parallel threads should use child process'); + }); + }); + it('testRunWithMochaPerEnvironment', function() { const testFiles = []; const defaultOptions = {timeout: 20000, reporterOptions: {}}; From 17a5d7b675489c42fdfcd22c217a8eaa4e50af33 Mon Sep 17 00:00:00 2001 From: Ravi Sawlani Date: Tue, 5 Sep 2023 16:51:32 +0530 Subject: [PATCH 38/38] add element.waitUntil('present') command (#3897) --- lib/api/web-element/waitUntil.js | 61 +++++++++++-------- .../waitUntilElementNotPresent.js | 5 ++ test/apidemos/web-elements/waitUntilTest.js | 2 +- .../apidemos/web-elements/testWaitUntil.js | 33 ++++++++++ types/web-element.d.ts | 2 +- 5 files changed, 77 insertions(+), 26 deletions(-) create mode 100644 test/apidemos/web-elements/waitUntilElementNotPresent.js diff --git a/lib/api/web-element/waitUntil.js b/lib/api/web-element/waitUntil.js index c6f3a6446f..6c2bbf1da2 100644 --- a/lib/api/web-element/waitUntil.js +++ b/lib/api/web-element/waitUntil.js @@ -1,6 +1,8 @@ -const until = require('selenium-webdriver/lib/until'); +const {until, Condition} = require('selenium-webdriver'); const {AssertionRunner} = require('../../assertion'); const {isDefined, format} = require('../../utils'); +const {ScopedElementLocator} = require('./element-locator'); +const {NoSuchElementError} = require('../../element/locator'); const mapToSeleniumFunction = { 'selected': until.elementIsSelected, @@ -9,12 +11,14 @@ const mapToSeleniumFunction = { 'not.visible': until.elementIsNotVisible, 'enabled': until.elementIsEnabled, 'not.enabled': until.elementIsDisabled, - 'disabled': until.elementIsDisabled + 'disabled': until.elementIsDisabled, + 'present': (webElement, scopedElementLocator) => until.elementLocated(scopedElementLocator.condition), + 'not.present': (webElement, scopedElementLocator) => new Condition('until elmenet is not present', (driver) => driver.findElements(scopedElementLocator.condition).then(elements => elements.length ? false : true)) }; /** - * Waits a given time in milliseconds (default 5000ms) for an element to be present in a specified state in the page before performing any other commands or assertions. - * If the element fails to be present in the specified state within the given time, the test fails. You can change this by setting `abortOnFailure` to `false`. + * Waits a given time in milliseconds (default 5000ms) for an element to be in the action state provided before performing any other commands or assertions. + * If the element fails to be in the action state withing the given time, the test fails. You can change this by setting `abortOnFailure` to `false`. * * You can change the polling interval by defining a `waitForConditionPollInterval` property (in milliseconds) in as a global property in your `nightwatch.conf.js` or in your external globals file. * Similarly, the default timeout can be specified as a global `waitForConditionTimeout` property (in milliseconds). @@ -55,12 +59,13 @@ const mapToSeleniumFunction = { * * @method waitUntil * @syntax .waitUntil(action, {timeout, retryInterval, message, abortOnFailure}); - * @param {string} action The locator strategy to use. See [W3C Webdriver - locator strategies](https://www.w3.org/TR/webdriver/#locator-strategies) + * @param {string} action The action state. Should be one of the following: selected, not.selected, visible, not.visible, enabled, disabled, present, not.present * @param {number} [timeout] The total number of milliseconds to wait before failing. Can also be set using 'globals.waitForConditionTimeout' under settings. * @param {number} [retryInterval] The number of milliseconds to wait between retries. You can use this only if you also specify the time parameter. Can also be set using 'globals.waitForConditionPollInterval' under settings. * @param {string} [message] Optional message to be shown in the output. The message supports two placeholders: %s for current selector and %d for the time (e.g. Element %s was not in the page for %d ms). * @param {boolean} [abortOnFailure=abortOnAssertionFailure] By the default if the element is not found the test will fail. Set this to false if you wish for the test to continue even if the assertion fails. To set this globally you can define a property `abortOnAssertionFailure` in your globals. */ + class WaitUntil { constructor(scopedElement, {action, timeout, retryInterval, message, nightwatchInstance, selector, abortOnFailure}) { this.scopedElement = scopedElement; @@ -72,33 +77,41 @@ class WaitUntil { this.timeout = timeout || this.nightwatchInstance.settings.globals.waitForConditionTimeout; this.retryInterval = retryInterval || this.nightwatchInstance.settings.globals.waitForConditionPollInterval; this.abortOnFailure = isDefined(abortOnFailure) ? abortOnFailure : this.nightwatchInstance.settings.globals.abortOnAssertionFailure; + this.scopedElementLocator = ScopedElementLocator.create(selector, nightwatchInstance); } createNode() { - const createAction = (actions, webElement) => function() { - if (!this.conditionFn) { - throw new Error(`Invalid action ${this.action} for element.waitUntil command. Possible actions: ${Object.keys(mapToSeleniumFunction).toString()}`); - } + const createAction = (actions, webElementPromise) => async function() { - return actions.wait(this.conditionFn(webElement), this.timeout, this.message, this.retryInterval, ()=>{}) - .then(result => { - const elapsedTime = new Date().getTime() - node.startTime; - if (result.error) { - const actual = result.error.name === 'NightwatchElementError' ? 'not found' : null; + let result; + try { - return this.fail(result, actual, elapsedTime); - } + if (!this.conditionFn) { + throw new Error(`Invalid action ${this.action} for element.waitUntil command. Possible actions: ${Object.keys(mapToSeleniumFunction).toString()}`); + } - return this.pass(result, elapsedTime); - }) - .catch(err => err) - .then(result => { - node.deferred.resolve(result); + const webElement = await webElementPromise; - return result; - }); - }.bind(this); + if (!webElement && !['present', 'not.present'].includes(this.action)) { + throw new NoSuchElementError({element: this.scopedElementLocator, abortOnFailure: this.abortOnFailure}); + } + + const elapsedTime = new Date().getTime() - node.startTime; + const commandResult = await this.scopedElement.driver.wait(this.conditionFn(webElementPromise, this.scopedElementLocator), this.timeout, this.message, this.retryInterval, ()=>{}); + result = await this.pass(commandResult, elapsedTime).catch(err => err); + return result; + } catch (err) { + const elapsedTime = new Date().getTime() - node.startTime; + const actual = err instanceof NoSuchElementError ? 'not present' : null; + result = await this.fail(err, actual, elapsedTime).catch(err => err); + + return result; + } finally { + node.deferred.resolve(result); + } + }.bind(this); + const node = this.scopedElement.queueAction({name: 'waitUntil', createAction}); return node; diff --git a/test/apidemos/web-elements/waitUntilElementNotPresent.js b/test/apidemos/web-elements/waitUntilElementNotPresent.js new file mode 100644 index 0000000000..f19ea5ecc6 --- /dev/null +++ b/test/apidemos/web-elements/waitUntilElementNotPresent.js @@ -0,0 +1,5 @@ +describe('demo of failure of waitUntil element commands', function() { + it('waitUntil element is visible - element not present', function({element}) { + element.find('#badElement').waitUntil('visible'); + }); +}); \ No newline at end of file diff --git a/test/apidemos/web-elements/waitUntilTest.js b/test/apidemos/web-elements/waitUntilTest.js index c85c13220b..4abd1e3c4d 100644 --- a/test/apidemos/web-elements/waitUntilTest.js +++ b/test/apidemos/web-elements/waitUntilTest.js @@ -4,7 +4,7 @@ describe('demo tests using waitUntil element APIs', function() { }); it('wait until element is selected', function({element, state}) { - element('#weblogin').waitUntil('selected'); + element('#weblogin').waitUntil('present').waitUntil('selected'); }); it('wait until element is enabled', function({element}) { diff --git a/test/src/apidemos/web-elements/testWaitUntil.js b/test/src/apidemos/web-elements/testWaitUntil.js index f833d6b599..9fb74d4f3a 100644 --- a/test/src/apidemos/web-elements/testWaitUntil.js +++ b/test/src/apidemos/web-elements/testWaitUntil.js @@ -83,4 +83,37 @@ describe('waitUntil element command', function() { globals })); }); + + it('test waitUntil element command - element not present', function() { + const testsPath = path.join(__dirname, '../../../apidemos/web-elements/waitUntilElementNotPresent.js'); + + + const globals = { + waitForConditionPollInterval: 50, + waitForConditionTimeout: 120, + retryAssertionTimeout: 100, + + reporter(results) { + if (!results.lastError) { + assert.fail('Should result into failure'); + } + assert.ok(results.lastError.message.includes('not present'), 'err message should be element not present'); + } + }; + + return NightwatchClient.runTests(testsPath, settings({ + selenium: { + port: null, + start_process: false + }, + selenium_host: null, + webdriver: { + port: 10195, + start_process: false + }, + output: false, + skip_testcases_on_fail: false, + globals + })); + }); }); diff --git a/types/web-element.d.ts b/types/web-element.d.ts index 6590d5d716..05d68b02f2 100644 --- a/types/web-element.d.ts +++ b/types/web-element.d.ts @@ -199,7 +199,7 @@ type WaitUntilOptions = { abortOnFailure?: boolean; }; -type WaitUntilActions = 'selected' | 'visible' | 'disabled' | 'enabled' | 'not.selected' | 'not.visible' | 'not.enabled'; +type WaitUntilActions = 'selected' | 'visible' | 'disabled' | 'enabled' | 'not.selected' | 'not.visible' | 'not.enabled' | 'present' | 'not.present'; export class Elements implements PromiseLike { constructor(