Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

beforeEach does not run if test doesn't contain any lifecycle hooks #3847

Open
kumarchandresh opened this issue Jul 31, 2023 · 4 comments
Open
Assignees

Comments

@kumarchandresh
Copy link

Description of the bug/issue

When I write a command in beforeEach hook in globals.js and don't write any before or after hooks in the test suite, I expected that command to be executed but nightwatch skips it instead.

Steps to reproduce

  1. Create new nightwatch project using npm nightwatch init command.
  2. Create and configure globals.js file.
// globals.js
module.exports = {

    beforeEach(browser, done) {
        browser.window.maximize();
        done();
    }

}

// nightwatch.conf.js
module.exports = {

    // ...

    globals_path: 'globals.js',

    // ...

}
  1. Run the duckDuckGo.js test from examples using npx nightwatch nightwatch/examples/basic/duckDuckGo.js.
    • Note that the window does't maximize for this test.
// duckDuckGo.js
describe('duckduckgo example', function() {
  it('Search Nightwatch.js and check results', function(browser) {
    browser
      .navigateTo('https://duckduckgo.com')
      .waitForElementVisible('input[name=q]')
      .sendKeys('input[name=q]', ['Nightwatch.js'])
      .click('*[type="submit"]')
      .assert.visible('.results--main')
      .assert.textContains('.results--main', 'Nightwatch.js');
  }); 
});
  1. Run the ecosia.js test from examples using npx nightwatch nightwatch/examples/basic/ecosia.js.
    • Note that the window does maximize for this test
// ecosia.js
describe('Ecosia.org Demo', function() {
  before(browser => browser.navigateTo('https://www.ecosia.org/'));

  it('Demo test ecosia.org', function(browser) {
    browser
      .waitForElementVisible('body')
      .assert.titleContains('Ecosia')
      .assert.visible('input[type=search]')
      .setValue('input[type=search]', 'nightwatch')
      .assert.visible('button[type=submit]')
      .click('button[type=submit]')
      .assert.textContains('.layout__content', 'Nightwatch.js');
  });

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

Sample test

No response

Command to run

No response

Verbose Output

No response

Nightwatch Configuration

No response

Nightwatch.js Version

3.1.1

Node Version

18.17.0

Browser

Chrome 115.0.0

Operating System

Windows 11 Pro version 10.0.22621

Additional Information

No response

@emouawad
Copy link

+1

@garg3133
Copy link
Member

garg3133 commented Feb 11, 2024

A workaround for this is to define beforeEach function in globals.js to be async.

The following would work fine even without a before hook in the actual test:

// globals.js
module.exports = {

    async beforeEach(browser, done) {
        browser.window.maximize();
        done();
    }

}

// nightwatch.conf.js
module.exports = {

    // ...

    globals_path: 'globals.js',

    // ...

}

So, the actual issue here is that the beforeEach global hook doesn't function when not defined as a async function, unless the test suite itself contains a before hook.

EDIT

The main issue here is that the global hooks (only looked at the working of beforeEach global hook right now) do not run in their own slot (during the execution of their runnable) and their runnable gets resolved even before the NW queue for the hook could start executing. So, the beforeEach global hook only starts running during the execution of the runnable of normal before hook. And, if even that hook is not defined, the global beforeEach hook won't run at all.

The fact that it runs if defined with async syntax is actually due to a bug here. The isES6Async passed here do not correspond to the current testcase/hook to be run but it corresponds to the previous hook/testcase that ran. So, if we define global beforeEach hook with async syntax, then during the execution of before hook (which may or may not be defined), the value of isES6Async will be passed as true. So, even if the before hook is not defined, this timeout will be called for the before hook which will give the current NW queue some time to start executing before the deferredFn is called. And hence, the global beforeEach hook executes when defined with async syntax.

But because this is all dependent on the bug, if that bug is fixed, the value of isES6Async will be passed as false for the before hook (since the before hook is not defined). In this case, the deferredFn will be called immediately without giving the queue a chance to start executing, and so the runnable for the before hook will also be resolved, clearing the NW queue after it.

To be clear, if the before hook is actually defined in the testsuite, the global beforeEach hook will always run because when the commands for the before hook are added to the queue, the commands from the global beforeEach hook would already be there and they will run when the queue execution of the before hook starts.

Now, the root cause of this issue is this line. For global hooks, the this.context does not represent the normal context of the testsuite but a special GlobalContext. And the queue is never set on this GlobalContext due to which the control always goes to the else block, leading to immediate resolution of the promise returned by the this.runFn() call in runnable.js and thus leading to the resolution of the runnable for the global beforeEach hook (through deferredFn) before the execution of the NW queue could even begin.

NOTE: When fixing the above root cause, also fix #4325 for global hooks.

@bkhanale
Copy link

This is not an issue when using mocha as the test runner.

@garg3133
Copy link
Member

A temporary fix for this has been added in #4381 after which mandatorily using the async syntax for global beforeEach wouldn't be required.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
Status: No status
Development

No branches or pull requests

4 participants