Skip to content

Commit

Permalink
fixed an issue with expect not rejecting the promise correctly and ca…
Browse files Browse the repository at this point in the history
…using an unhandledRejection
  • Loading branch information
beatfactor committed Feb 1, 2022
1 parent 0922be1 commit a17a7ac
Show file tree
Hide file tree
Showing 18 changed files with 94 additions and 50 deletions.
4 changes: 3 additions & 1 deletion examples/tests/googlePageObject.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ module.exports = {

const resultsPage = browser.page.google.searchResults();
resultsPage.expect.element('@results').to.be.present;
resultsPage.expect.element('@results').text.toContain('Nightwatch.js');

await resultsPage.expect.element('@results').text.to.contain('Nightwatch.js');

resultsPage.expect.section('@menu').to.be.visible;

const menuSection = resultsPage.section.menu;
Expand Down
4 changes: 1 addition & 3 deletions lib/api/_loaders/expect-assertion.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,7 @@ class ExpectAssertionLoader extends BaseLoader {
assertion.init(...args);
this.assertion = assertion;

if (nightwatchInstance.usingCucumber && assertion.chaiExpect.deferred) {
return assertion.chaiExpect.deferred.promise;
}
return this;
};

if (!Array.isArray(aliases)) {
Expand Down
15 changes: 1 addition & 14 deletions lib/api/_loaders/expect.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ class ExpectLoader extends BaseCommandLoader {
const isAsyncCommand = this.isES6Async;
const isES6Async = Utils.isUndefined(this.isES6Async) ? (nightwatchInstance.isES6AsyncTestcase || nightwatchInstance.settings.always_async_commands) : isAsyncCommand;

const deferred = Utils.createPromise();
const {deferred} = expectCommand;
this.loadAssertions(expectCommand);

const node = commandQueue.add({
Expand All @@ -95,19 +95,6 @@ class ExpectLoader extends BaseCommandLoader {
stackTrace
});

if (isES6Async) {
expectCommand.instance.deferred = deferred;
expectCommand.instance.then = function(fn) {
Promise.prototype.then.call(node.deferred.promise, fn);
};

expectCommand.instance.catch = function(fn) {
Promise.prototype.catch.call(node.deferred.promise, fn);
};

return expectCommand.instance;
}

return expectCommand.instance;
}.bind(this));
}
Expand Down
20 changes: 15 additions & 5 deletions lib/api/expect/_baseExpect.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const EventEmitter = require('events');
const chaiNightwatch = require('chai-nightwatch');
const {Logger, format} = require('../../utils');
const {Logger, format, createPromise} = require('../../utils');

const BaseAssertion = require('./assertions/_baseAssertion.js');

Expand Down Expand Up @@ -136,16 +136,26 @@ class ExpectInstance extends EventEmitter {
this.handleCommandPromise(promise);
}

createPromise() {
createLocalPromise() {
return new Promise((resolve, reject) => {
this.resolve = resolve;
this.reject = reject;
});
}

createInstance() {
this.promise = this.createPromise();
this.__instance = chaiNightwatch.expect(this.promise);
this.promise = this.createLocalPromise();

this.deferred = {
commandName: this.commandFileName
};

this.__instance = chaiNightwatch.expect((resolve, reject) => {
this.deferred.resolve = resolve;
this.deferred.reject = reject;
});

this.flag('deferred', this.deferred);

if (!this.hasAssertions) {
this.flag('valueFlag', true);
Expand All @@ -156,7 +166,7 @@ class ExpectInstance extends EventEmitter {
}

createRetryPromise() {
this.promise = this.createPromise();
this.promise = this.createLocalPromise();
this.flag('promise', this.promise);

return this.promise;
Expand Down
4 changes: 3 additions & 1 deletion lib/api/expect/assertions/_baseAssertion.js
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,9 @@ class BaseAssertion {
const {passed, actual, expected, message, abortOnFailure} = this;

if (passed === undefined) {
this.emitter.emit('error', new Error(`Incomplete expect assertion for "expect.${this.emitter.commandFileName}()". Please consult the docs at https://nightwatchjs.org/api/expect/`));
const err = new Error(`Incomplete expect assertion for "expect.${this.emitter.commandFileName}()". Please consult the docs at https://nightwatchjs.org/api/expect/`);
err.isExpect = true;
this.emitter.emit('error', err);

return this;
}
Expand Down
6 changes: 3 additions & 3 deletions lib/core/asynctree.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,10 @@ class AsyncTree extends EventEmitter{
}

// if we reject here, an uncaught rejection error will occur later
if (this.foreignRunner && (!this.cucumberRunner || err.isExpect)) {
if (this.foreignRunner && (!this.cucumberRunner || err.isExpect) && this.currentNode.isES6Async) {
this.currentNode.reject(err);

if (this.currentNode.parent) {
if (this.currentNode.parent && !this.currentNode.parent.isRootNode) {
this.currentNode.parent.reject(err);
}
} else if (this.currentNode.rejectPromise) {
Expand All @@ -116,7 +116,7 @@ class AsyncTree extends EventEmitter{
}

// if assert error
if (err.name === 'NightwatchAssertError' && this.currentNode.parent && !this.currentNode.parent.isRootNode && !err.isExpect) {
if (err.name === 'NightwatchAssertError' && this.currentNode.parent && !this.currentNode.parent.isRootNode && !err.isExpect && this.currentNode.parent.isES6Async) {
this.currentNode.parent.reject(err);
}

Expand Down
4 changes: 2 additions & 2 deletions lib/core/treenode.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class TreeNode {
}

resolve(result) {
if (this.promiseSettled || !this.isES6Async) {
if (this.promiseSettled || !this.deferred) {
return;
}

Expand All @@ -95,7 +95,7 @@ class TreeNode {
}

reject(reason) {
if (this.promiseSettled || !this.isES6Async) {
if (this.promiseSettled || !this.deferred) {
return;
}

Expand Down
8 changes: 7 additions & 1 deletion lib/testsuite/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ class TestSuite {
}

get commandQueue() {
if (!this.client) {
return null;
}

return this.client.queue;
}

Expand Down Expand Up @@ -869,7 +873,9 @@ class TestSuite {
emptyQueue() {
this.resetQueue();

this.commandQueue.empty();
if (this.commandQueue) {
this.commandQueue.empty();
}

return this;
}
Expand Down
20 changes: 10 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"dependencies": {
"assertion-error": "1.1.0",
"boxen": "5.1.2",
"chai-nightwatch": "0.4.2",
"chai-nightwatch": "0.5.2",
"ci-info": "^3.2.0",
"didyoumean": "^1.2.2",
"dotenv": "10.0.0",
Expand Down
7 changes: 2 additions & 5 deletions test/apidemos/expect-global/expect.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@


describe('expect() tests ', function () {
describe('expect() tests ', function () {
const signupSection = element(by.css('#signupSection'));

after(browser => browser.end());


test('weblogin has class container ', async function() {
it('weblogin has class container ', async function() {
const weblogin = element('#weblogin');
expect(signupSection.isSelected()).to.be.true;
expect(weblogin.property('className')).to.be.an('array').and.contains('container');
Expand Down
5 changes: 5 additions & 0 deletions test/cucumbertests/sample.feature
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ Scenario: Sample Scenario
Given I navigate to localhost
Then I check if webdriver is present

@expect
Scenario: Sample Scenario with expect
Given I navigate to localhost
Then I check if webdriver is present and contains text

@fail
Scenario: Sample test with failures
Given I navigate to localhost
Expand Down
6 changes: 6 additions & 0 deletions test/cucumbertests/testSample.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ Then('I check if webdriver is present', function() {
return browser.assert.elementPresent('#webdriver');
});

Then('I check if webdriver is present and contains text', async function() {
browser.globals.test_calls++;

await browser.expect.element('#webdriver').text.to.contain('xx')
});

Then('I check if badElement is present', function() {
browser.globals.test_calls++;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ describe('custom commands with findElements es6 async', function() {
};

return NightwatchClient.runTests(testsPath, settings({
output: true,
output: false,
selenium_host: null,
custom_commands_path: [path.join(__dirname, '../../../extra/commands/es6async')],
globals
Expand Down
2 changes: 1 addition & 1 deletion test/src/element/testCommandsElementSelectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ describe('test commands element selectors', function() {
beforeEach(function (done) {
nocks.cleanAll().createSession();
Nightwatch.init({
output: true,
output: false,
silent: false,
globals: {
waitForConditionTimeout: 100,
Expand Down
2 changes: 1 addition & 1 deletion test/src/element/testExpectElementSelectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ describe('test expect element selectors', function() {

assert.throws(function() {
api.expect.element('.nock').to.be.hidden;
}, /Error: Unknown property: "hidden"\. Please consult docs at: http:\/\/nightwatchjs\.org\/api\./);
}, /Error: Unknown property: "hidden"\. Please consult docs at: https:\/\/nightwatchjs\.org\/api\/expect/);

Nightwatch.start();
});
Expand Down
31 changes: 31 additions & 0 deletions test/src/runner/cucumber-integration/testCucumberSampleTests.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const Globals = require('../../../lib/globals/commands.js');
const common = require('../../../common.js');
const MockServer = require('../../../lib/mockserver.js');
const {runTests} = common.require('index.js');
const {settings} = common;

describe('Cucumber integration', function() {
beforeEach(function(done) {
Expand All @@ -15,6 +16,36 @@ describe('Cucumber integration', function() {
Globals.afterEach.call(this, done);
});

xit('testCucumberSampleTests -- with expect async', function() {
MockServer.addMock({
url: '/wd/hub/session/1352110219202/element/5cc459b8-36a8-3042-8b4a-258883ea642b/text',
statusCode: 200,
method: 'GET',
response: {
value: 'jean sibelius'
},
times: 3
});

const source = [path.join(__dirname, '../../../cucumbertests/testSample.js')];

return runTests({
source,
tags: ['@expect'],
verbose: false,
config: path.join(__dirname, '../../../extra/cucumber-config.js')
}, settings({
silent: false,
output: false,
globals: {
waitForConditionTimeout: 10,
waitForConditionPollInterval: 50,
},
})).then(failures => {
assert.strictEqual(failures, true, 'Cucumber should have test failures');
});
});

it('testCucumberSampleTests', function() {
const source = [path.join(__dirname, '../../../cucumbertests/testSample.js')];

Expand Down
2 changes: 1 addition & 1 deletion test/src/runner/testRunWithCommandErrors.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ describe('testRunWithCommandErrors', function() {
retry_attempts: 2
}
},
output: true,
output: false,
report_command_errors: true,
skip_testcases_on_fail: false,
disable_error_log: 0,
Expand Down

0 comments on commit a17a7ac

Please sign in to comment.