Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Using async/await within context blocks don't work as expected #3593

Closed
1 of 4 tasks
hlimbo27 opened this issue Nov 29, 2018 · 4 comments
Closed
1 of 4 tasks

Using async/await within context blocks don't work as expected #3593

hlimbo27 opened this issue Nov 29, 2018 · 4 comments

Comments

@hlimbo27
Copy link

hlimbo27 commented Nov 29, 2018

Prerequisites

  • Checked that your issue hasn't already been filed by cross-referencing issues with the faq label
  • Checked next-gen ES issues and syntax problems by using the same environment and/or transpiler configuration without Mocha to ensure it isn't just a feature that actually isn't supported in the environment in question or a bug in your code.
  • 'Smoke tested' the code to be tested by running it outside the real test suite to get a better sense of whether the problem is in the code under test, your usage of Mocha, or Mocha itself
  • Ensured that there is no discrepancy between the locally and globally installed versions of Mocha. You can find them with: node node_modules/.bin/mocha --version(Local) and mocha --version(Global). We recommend avoiding the use of globally installed Mocha.

Description

When using async/await inside of a context block, the code order execution does not line up with my expectations. Based on a similar issue: #2975, is it possible to run the following code without the use of a before block? If it's not possible it would require me to wrap my for loop within my Sibling Context 1 in a it block for the code to function in the order I expect.

As a workaround, I've implemented the structure like so:

const Promise = require('bluebird');
const expect = require('chai').expect;

function waitingOnUsefulData() {
  return Promise.resolve([1,2,3,4,5]);
}

describe('The Master Describe block', () => {
  context('Sibling Context 1', async () => {

    //const data = await waitingOnUsefulData();

    let data;
    before(async () => {
      data = await waitingOnUsefulData();
    });

    it('a wrapper', () => {
      for(const element of data) {
        context(`Child context ${element}`, () => {
          before('setup', () => {
            console.log('setting up in the child context');
          });
          it('Example 1', () => {
            console.log('example 1');
            expect(true).to.be.true;
          });
          
          it('Example 2', () => {
            console.log('example 2');
            expect(true).to.be.true;
          });
  
          it('Example 3', () => {
            console.log('example 3');
            expect(true).to.be.true;
          });
        });
      }
    });
  });

  // context('Sibling Context 2', () => {
  //   it('Example a',() => {
  //     console.log('Example a');
  //     expect(true).to.be.true;
  //   });
  //   it('Example b', () => {
  //     console.log('Example b');
  //     expect(true).to.be.true;
  //   });
  // });
});

Note I understand that use of arrow functions is discouraged (https://mochajs.org/#arrow-functions) but my current team seems to prefer them over using function()

The following example in Steps to Reproduce appears to be a possible bug.

Steps to Reproduce

  1. Make sure to have bluebird and chai packages installed.
  2. Use the following code below:
const Promise = require('bluebird');
const expect = require('chai').expect;

function waitingOnUsefulData() {
  return Promise.resolve([1,2,3,4,5]);
}

describe('The Master Describe block', () => {
  context('Sibling Context 1', async () => {
    const data = await waitingOnUsefulData();

    for(const element of data) {
      context(`Child context ${element}`, () => {
        before('setup', () => {
          console.log('setting up in the child context');
        });
        it('Example 1', () => {
          console.log('example 1');
          expect(true).to.be.true;
        });
        
        it('Example 2', () => {
          console.log('example 2');
          expect(true).to.be.true;
        });

        it('Example 3', () => {
          console.log('example 3');
          expect(true).to.be.true;
        });
      });
    }
  });

  context('Sibling Context 2', () => {
    it('Example a',() => {
      console.log('Example a');
      expect(true).to.be.true;
    });
    it('Example b', () => {
      console.log('Example b');
      expect(true).to.be.true;
    });
  });
});
  1. run the code mocha test_file.js
    output: (Notice that Sibling Context 1 was not provided as an output when running the code)
  The Master Describe block
    Sibling Context 2
Example a
      ✓ Example a
Example b
      ✓ Example b

  Child context 1
setting up in the child context
example 1
    ✓ Example 1
example 2
    ✓ Example 2
example 3
    ✓ Example 3

  Child context 2
setting up in the child context
example 1
    ✓ Example 1
example 2
    ✓ Example 2
example 3
    ✓ Example 3

  Child context 3
setting up in the child context
example 1
    ✓ Example 1
example 2
    ✓ Example 2
example 3
    ✓ Example 3

  Child context 4
setting up in the child context
example 1
    ✓ Example 1
example 2
    ✓ Example 2
example 3
    ✓ Example 3

  Child context 5
setting up in the child context
example 1
    ✓ Example 1
example 2
    ✓ Example 2
example 3
    ✓ Example 3
  1. Comment out the following code
  context('Sibling Context 2', () => {
    it('Example a',() => {
      console.log('Example a');
      expect(true).to.be.true;
    });
    it('Example b', () => {
      console.log('Example b');
      expect(true).to.be.true;
    });
  });
  1. Run the code again mocha testfile.js
    output:
    0 passing

Expected behavior:

The Master Describe block
    Sibling Context 1
Child context 1
setting up in the child context
example 1
    ✓ Example 1
example 2
    ✓ Example 2
example 3
    ✓ Example 3
Child context 2
setting up in the child context
example 1
    ✓ Example 1
example 2
    ✓ Example 2
example 3
    ✓ Example 3
Child context 3
setting up in the child context
example 1
    ✓ Example 1
example 2
    ✓ Example 2
example 3
    ✓ Example 3
Child context 4
setting up in the child context
example 1
    ✓ Example 1
example 2
    ✓ Example 2
example 3
    ✓ Example 3
Child context 5
setting up in the child context
example 1
    ✓ Example 1
example 2
    ✓ Example 2
example 3
    ✓ Example 3

Actual behavior:
When the following block of code is commented out as described in step 3, the following output is displayed. No Tests are ran

 0 passing (2ms)

Reproduces how often: 100% of the time

Versions

  • The output of mocha --version and node node_modules/.bin/mocha --version: 5.2.0
  • The output of node --version: v10.11.0
  • The version and architecture of your operating system: macOS highSierra version 10.13.4
  • Your shell (bash, zsh, PowerShell, cmd, etc.): bash
  • Your browser and version (if running browser tests): n/a
  • Any other third party Mocha related modules (with versions): n/a
  • The code transpiler being used:

Additional Information

@WORMSS
Copy link

WORMSS commented Dec 6, 2018

Just to add to the discussion that our company got caught out by the non-async nature of describe when a developer changed from require to import to match the rest of the system. Sadly this caused no errors, and was only during the addition of .only() by myself that the test reported 0 Passed when I knew there should be 38 that either passed or failed.`

describe.only('aqs.utils', async () => {
  await import('./equals');
  await import('./gas');
  await import('./notEquals');
  await import('./startsWith');
  await import('./wordSearch');
});

We went back to the original and now works as expected, but I think we would prefer to use import

describe.only('aqs.utils', () => {
  require('./equals');
  require('./gas');
  require('./notEquals');
  require('./startsWith');
  require('./wordSearch');
});

@boneskull
Copy link
Member

duplicate of #3106
duplicate of #1431

Also --delay can help here. I realize this is not ideal, but Mocha currently doesn't support this behavior. It'd be nice to make this work, but I'd need to see a solid technical proposal that does it in a way that won't break a bunch of stuff.

@ernestostifano
Copy link

ernestostifano commented Nov 11, 2020

@boneskull have this issues been completely abandoned or there are plans to address them? I have recently encountered the same problem as @WORMSS.

Using dynamic import() is absolutely necessary after mocking a dependency by hooking into Module_load method (if static import is used, all dependencies will be already in memory by the time you try to mock them).

ES6 modules are a standard for us. Mixing ES6 modules syntax with CJS require() is not an option.

My tests are being ultimately run, even if placed inside an "async" describe. The problem is that hooks preceding that describe are not being executed at all. Maybe because nested tests are not 'found' during initial 'discovery'.

EDIT: Throwing a warning when a promise is returned to a describe suite would be a good start. It took me some time to understand why my test were not working.

@boneskull
Copy link
Member

I would entertain a PR to allow for async suites, but it's not on the top of my todo list. I think it's something that should get done, anyway, and would appreciate assistance

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants