最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Jest global teardown runs before tests finish? - Stack Overflow

programmeradmin1浏览0评论

I'm trying to make sure my app gets properly destroyed after all my Jest tests have run, but I'm running into some very strange behaviour trying to use Jest's global teardown config value.

Here's the situation: my app creates a database connection. It also has a destroy method that closes the database connection. This works.

I have a single test that starts the server, runs a query against the database connection. In my global teardown function, I call app.destroy(), but the process hangs.

If I comment out the destroy call in the global teardown function and put app.destroy() in my test after the query, Jest doesn't hang and closes like it's supposed to. I can also put afterAll(() => app.destroy()) in my test file and things work properly.

Here is my jest.config.js

module.exports = {
  testEnvironment: 'node',
  roots: [
    '<rootDir>/src'
  ],
  transform: {
    '^.+\\.tsx?$': 'ts-jest'
  },
  testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$',
  moduleFileExtensions: [
    'ts',
    'tsx',
    'js',
    'jsx',
    'json',
    'node'
  ],
  globalSetup: '<rootDir>/src/testSetup.ts',
  globalTeardown: '<rootDir>/src/testTeardown.ts'
};

Here is the test (it's currently the only test in the app):

import app from '../..';

describe('User router', () => {
  it('Should respond with an array of user objects', async () => {
    await app.models.User.query();
  });
});

And here is the global teardown in <rootDir>/src/testTeardown.ts:

import app from './index';

module.exports = async function testTeardown() {
  await app.destroy();
};

Using the code above, the process hangs after tests finish. I've tried adding a console.log to testTeardown and the end of the test, and the logs happen in the correct order: test logs, then teardown logs. However if I move app.destroy() into my test it works perfectly:

import app from '../..';

describe('User router', () => {
  it('Should respond with an array of user objects', async () => {
    await app.models.User.query();
    await app.destroy();
  });
});

This also works:

import app from '../..';

afterAll(() => app.destroy());

describe('User router', () => {
  it('Should respond with an array of user objects', async () => {
    await app.models.User.query();
  });
});

Why is this happening?

Also just for shits and giggles I tried setting a global._app in the test and then checking it in the teardown handler, but it was undefined. Do Jest's setup/teardown functions even get run in the same process as the tests?

I'm trying to make sure my app gets properly destroyed after all my Jest tests have run, but I'm running into some very strange behaviour trying to use Jest's global teardown config value.

Here's the situation: my app creates a database connection. It also has a destroy method that closes the database connection. This works.

I have a single test that starts the server, runs a query against the database connection. In my global teardown function, I call app.destroy(), but the process hangs.

If I comment out the destroy call in the global teardown function and put app.destroy() in my test after the query, Jest doesn't hang and closes like it's supposed to. I can also put afterAll(() => app.destroy()) in my test file and things work properly.

Here is my jest.config.js

module.exports = {
  testEnvironment: 'node',
  roots: [
    '<rootDir>/src'
  ],
  transform: {
    '^.+\\.tsx?$': 'ts-jest'
  },
  testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$',
  moduleFileExtensions: [
    'ts',
    'tsx',
    'js',
    'jsx',
    'json',
    'node'
  ],
  globalSetup: '<rootDir>/src/testSetup.ts',
  globalTeardown: '<rootDir>/src/testTeardown.ts'
};

Here is the test (it's currently the only test in the app):

import app from '../..';

describe('User router', () => {
  it('Should respond with an array of user objects', async () => {
    await app.models.User.query();
  });
});

And here is the global teardown in <rootDir>/src/testTeardown.ts:

import app from './index';

module.exports = async function testTeardown() {
  await app.destroy();
};

Using the code above, the process hangs after tests finish. I've tried adding a console.log to testTeardown and the end of the test, and the logs happen in the correct order: test logs, then teardown logs. However if I move app.destroy() into my test it works perfectly:

import app from '../..';

describe('User router', () => {
  it('Should respond with an array of user objects', async () => {
    await app.models.User.query();
    await app.destroy();
  });
});

This also works:

import app from '../..';

afterAll(() => app.destroy());

describe('User router', () => {
  it('Should respond with an array of user objects', async () => {
    await app.models.User.query();
  });
});

Why is this happening?

Also just for shits and giggles I tried setting a global._app in the test and then checking it in the teardown handler, but it was undefined. Do Jest's setup/teardown functions even get run in the same process as the tests?

Share Improve this question edited Feb 4, 2019 at 9:09 skyboyer 23.7k7 gold badges61 silver badges71 bronze badges asked Feb 1, 2019 at 22:50 SimpleJSimpleJ 14.8k13 gold badges60 silver badges96 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 14

No, jest globalSetup and globalTeardown files don't necessarily get run in the same process as your tests. This is because jest parallelises your tests and runs each test file in a separate process, but there is only one global setup/teardown phase for the combined set of test files.

You can use setupFiles to add a file that gets run in process with each test file. In the setupFiles file you can put:

afterAll(() => app.destroy());

Your jest config is just

module.exports = {
  testEnvironment: 'node',
  roots: [
    '<rootDir>/src'
  ],
  transform: {
    '^.+\\.tsx?$': 'ts-jest'
  },
  testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$',
  moduleFileExtensions: [
    'ts',
    'tsx',
    'js',
    'jsx',
    'json',
    'node'
  ],
  setupFiles: ['<rootDir>/src/testSetup.ts']
};

For the latest version of Jest just include this configuration option in your jestconfiguration file:

// globalSetup: '<rootDir>/tests_setup/testSetup.ts',
// globalTeardown: '<rootDir>/tests_setup/testTearDown.ts',
setupFiles: [
    '<rootDir>/tests_setup/testSetup.ts',
    '<rootDir>/tests_setup/testTearDown.ts',
],

With this Jest will automatically load the setup and tearDown functions automatically All you need to do is to export a function that sets up and runs the beforeAll and another that runs the afterAll i.e

testSetup.ts:

const setupTests = async () => {
    beforeAll(async () => {
        console.log('Test setup');

        mockMongoose.prepareStorage().then(() => {
            mongoose.connect('mongodb://localhost/test');
            mongoose.connection.on('connected', () => {
                console.log('db connection is now open');
            });
        });
    });
};

export default setupTests;

and testTearDown.ts:

const tearDownTests = async () => {
    afterAll(async () => {
        console.log('Finished on tests');

        await mongoose.disconnect();
        await mockMongoose.killMongo();
    });
};

export default tearDownTests;
发布评论

评论列表(0)

  1. 暂无评论