Jest · Unit tests that survive refactors
How should you handle setup and teardown in Jest?
Short answer
Create per-test state in beforeEach, clean it in afterEach, and restore mocks, timers and globals. Reserve beforeAll for expensive read-only resources and use globalSetup only for work outside the test runtime.
Good teardown is about removing everything that could leak into the next test. That includes fake timers, spies, mocked modules, global properties, opened handles and rows written to a shared database. If a test needs the same fresh state on its own, it must not depend on the previous test cleaning up correctly.
let server: TestServer;
beforeAll(async () => {
server = await startTestServer();
});
beforeEach(() => {
jest.useFakeTimers();
});
afterEach(() => {
jest.runOnlyPendingTimers();
jest.useRealTimers();
jest.restoreAllMocks();
jest.clearAllMocks();
});
afterAll(async () => {
await server.close();
});What must be cleaned up
- Spies and mocked implementations with
restoreAllMocksorresetAllMocks - Fake timers back to real timers
- Globals added to
globalThisorwindow - Database rows or files created by the test
- Subscriptions, intervals and open network handles
setupFiles runs before the test framework is installed, so it is a good place for environment stubs. setupFilesAfterEnv runs after the framework is available, which is where expect.extend, global matchers and shared beforeEach cleanup belong. globalSetup runs in a separate process and cannot share variables with tests.
setupFilesAfterEnv. A test that only works because of invisible global configuration is hard to move, debug or delete.Follow-ups you should expect
Interviewers use these to check whether the first answer was understanding or memorisation.
- 1What is the difference between setupFiles and setupFilesAfterEnv?
- 2Why can globalSetup not share variables with a test?
- 3Which mocks need to be restored between tests?
- 4When is a shared database fixture safe?
Say it in the interview
I create state per test in beforeEach and remove it in afterEach: timers, spies, globals, database rows and handles. Expensive read-only resources can live in beforeAll and be closed in afterAll. I use setupFilesAfterEnv for matcher registration and global cleanup, and globalSetup only for process-level work like starting a container. My rule is that any single test should pass when run alone.
Use this as a model, not a script. Saying it in your own words is what makes it survive follow-up pressure.
Related questions
Reading is step one
Now say it out loud.
Understanding an answer and delivering it under pressure are different skills. Rehearse this topic in a live Jest mock interview and get scored feedback on depth, clarity and confidence.