diff --git a/lib/api/_loaders/command.js b/lib/api/_loaders/command.js index da1ac05795..ee961116c3 100644 --- a/lib/api/_loaders/command.js +++ b/lib/api/_loaders/command.js @@ -151,6 +151,18 @@ class CommandLoader extends BaseCommandLoader { createWrapper() { if (this.module) { + // this place is only reached by client-commands, protocol commands and custom-commands (no assertions or element-commands). + if (this.isUserDefined) { + // only custom-commands will reach here. + // later extend this to client-commands and protocol commands as well. + Object.defineProperty(this.module, 'rejectNodeOnAbortFailure', { + configurable: true, + get() { + return true; + } + }); + } + this.commandFn = function commandFn({args, stackTrace}) { const instance = CommandLoader.createInstance(this.nightwatchInstance, this.module, { stackTrace, diff --git a/lib/core/asynctree.js b/lib/core/asynctree.js index 926a45a17f..d18f0033bc 100644 --- a/lib/core/asynctree.js +++ b/lib/core/asynctree.js @@ -106,7 +106,7 @@ class AsyncTree extends EventEmitter{ shouldRejectNodePromise(err, abortOnFailure, node = this.currentNode) { const rejectNodeOnAbortFailure = node.options?.rejectNodeOnAbortFailure; - if ((err.isExpect || node.namespace === 'assert' || (abortOnFailure && rejectNodeOnAbortFailure)) && this.currentNode.isES6Async) { + if ((err.isExpect || node.namespace === 'assert' || (abortOnFailure && rejectNodeOnAbortFailure)) && node.isES6Async) { return true; } @@ -134,7 +134,6 @@ class AsyncTree extends EventEmitter{ this.emit('asynctree:command:start', {node}); const result = await node.run(); - const {parent} = this.currentNode; let abortOnFailure = false; let err; @@ -155,7 +154,7 @@ class AsyncTree extends EventEmitter{ } if (this.shouldRejectParentNodePromise(err, node)) { - parent.reject(err); + node.parent.reject(err); } } else { node.resolveValue = result; diff --git a/test/extra/commands/customCommandWithFailureClass.js b/test/extra/commands/customCommandWithFailureClass.js new file mode 100644 index 0000000000..5c869a6c58 --- /dev/null +++ b/test/extra/commands/customCommandWithFailureClass.js @@ -0,0 +1,5 @@ +module.exports = class CustomCommandWithFailureClass{ + async command() { + await this.api.waitForElementPresent('#badElement', 100); + } +}; diff --git a/test/sampletests/withcustomcommands/sampleWithAsyncFailures.js b/test/sampletests/withcustomcommands/sampleWithAsyncFailures.js new file mode 100644 index 0000000000..c89c227a7c --- /dev/null +++ b/test/sampletests/withcustomcommands/sampleWithAsyncFailures.js @@ -0,0 +1,15 @@ +module.exports = { + before(client) { + client.globals.increment++; + }, + + async demoTestAsync(client) { + await client.url('http://localhost').customCommandWithFailureClass(); + // below statement should be unreachable because the custom command should be rejected + client.globals.increment++; + }, + + after(client) { + client.globals.increment++; + } +}; \ No newline at end of file diff --git a/test/src/runner/testRunWithCustomCommands.js b/test/src/runner/testRunWithCustomCommands.js index 79d12676f3..fcc7956d65 100644 --- a/test/src/runner/testRunWithCustomCommands.js +++ b/test/src/runner/testRunWithCustomCommands.js @@ -34,14 +34,14 @@ describe('testRunWithCustomCommands', function() { }); it('testRunner with custom command which has failures', function() { - let testsPath = path.join(__dirname, '../../sampletests/withcustomcommands'); - let globals = { + const testsPath = path.join(__dirname, '../../sampletests/withcustomcommands'); + const globals = { increment: 0, retryAssertionTimeout: 0, waitForConditionPollInterval: 10, waitForConditionTimeout: 20, reporter(results, cb) { - assert.strictEqual(globals.increment, 4); + assert.strictEqual(globals.increment, 6); cb(); } }; @@ -55,12 +55,12 @@ describe('testRunWithCustomCommands', function() { }); it('testRunner with ES6 Async custom commands', function() { - let testsPath = path.join(__dirname, '../../sampletests/withes6asynccommands'); + const testsPath = path.join(__dirname, '../../sampletests/withes6asynccommands'); let testResults; const origExit = process.exit; process.exit = function() {}; - let globals = { + const globals = { increment: 0, logResult: null, retryAssertionTimeout: 0, @@ -101,12 +101,12 @@ describe('testRunWithCustomCommands', function() { }); it('testRunner with ES6 Async custom commands', function() { - let testsPath = path.join(__dirname, '../../sampletests/withes6asynccommands'); + const testsPath = path.join(__dirname, '../../sampletests/withes6asynccommands'); let testResults; const origExit = process.exit; process.exit = function() {}; - let globals = { + const globals = { increment: 0, logResult: null, retryAssertionTimeout: 0, @@ -147,12 +147,12 @@ describe('testRunWithCustomCommands', function() { }); it('testRunner custom command which extends built-in command', function() { - let testsPath = path.join(__dirname, '../../sampletests/withcustomcommands/element'); + const testsPath = path.join(__dirname, '../../sampletests/withcustomcommands/element'); let testResults; const origExit = process.exit; process.exit = function() {}; - let globals = { + const globals = { increment: 0, logResult: null, retryAssertionTimeout: 0, @@ -229,12 +229,12 @@ describe('testRunWithCustomCommands', function() { }); it('testRunner custom command path as glob pattern', function() { - let testsPath = path.join(__dirname, '../../sampletests/withcustomcommands/element'); + const testsPath = path.join(__dirname, '../../sampletests/withcustomcommands/element'); let testResults; const origExit = process.exit; process.exit = function() {}; - let globals = { + const globals = { increment: 0, logResult: null, retryAssertionTimeout: 0,