node.jstypescripttestingmocha.js

Mocha beforeEach, afterEach etc. hooks running outside describe


My mocha hooks beforeEach, afterEach defined in specific 'describe' blocks are running before 'it' blocks in other 'describe' blocks and files.

I have the following test setup:

A global test file - global.spec.ts

before(async function () {
 // set up stuff here
});

describe('Test suite', async () => {
  it('is just here to execute the before and after', async () => {

  });
});

after(async function () {
  // tear down stuff here
});

Then the tests themselves

foo.spec.ts

describe('Foo describe', async () => {

  beforeEach(async () => {
    console.log('prepare some stuff for each foo test');
  });

  afterEach(async () => {
    console.log('clean up after each foo test');
  });

  it(`should test some foo case`, async () => {
    // test something
  });

});

bar.spec.ts

describe('Bar describe', async () => {

  beforeEach(async () => {
    console.log('prepare some stuff for each bar test');
  });

  afterEach(async () => {
    console.log('clean up after each bar test');
  });

  it(`should test some bar case`, async () => {
    // test something
  });

});

And what I see in the console

prepare some stuff for each foo test
prepare some stuff for each bar test
should test some foo case
clean up after each foo test
clean up after each bar test
prepare some stuff for each foo test
prepare some stuff for each bar test
should test some bar case
clean up after each foo test
clean up after each bar test

My mocharc.json looks like this


{
  "require": ["ts-node/register"],
  "spec": ["src/test/global.spec.ts", "src/**/*.spec.ts"],
  "timeout": 5000
}

I have no idea what causes this behaviour, but these hooks should only run for tests in their relevant describe.

I have another project with essentially the same set up, and the issue does not persist there. In the other project mocha is version 10.2.0, so I tried downgrading, but to no avail. My current mocha version is 10.4.0.

I also tried running the tests on another device, and I have the same problem.


Solution

  • The problem turned out to be awaiting promises in the 'describe' itself. So if you have something like this below, it will cause the hooks to run on all test files / 'describes':

    describe('Foo describe', async () => {
      await new Promise(f => setTimeout(f, 100));
      
      beforeEach(async () => {
        console.log('prepare some stuff for each foo test');
      });
    
      afterEach(async () => {
        console.log('clean up after each foo test');
      });
    
      it(`should test some foo case`, async () => {
        // test something
      });
    
    });
    

    The solution is to await any promises in the 'before' hook.

    describe('Foo describe', async () => {
      
      before(async () => {
        await new Promise(f => setTimeout(f, 100));
      });
      
      beforeEach(async () => {
        console.log('prepare some stuff for each foo test');
      });
    
      afterEach(async () => {
        console.log('clean up after each foo test');
      });
    
      it(`should test some foo case`, async () => {
        // test something
      });
    
    });