Skip to content

beforeEach and afterEach

Repeating the same setup code in every test clutters your suite. This lesson covers beforeEach() and afterEach(), which run automatically before and after every test in their scope.

What beforeEach() and afterEach() Do

beforeEach(fn) registers a function that Jest runs immediately before every test in the current file or describe() block. afterEach(fn) does the same, but runs immediately after each test finishes (whether it passed or failed).

These hooks remove repetitive setup/teardown code from individual tests, keeping each test() focused purely on the behavior being verified.

let cart;

beforeEach(() => {
  cart = createEmptyCart();
});

afterEach(() => {
  cart = null;
});

test('starts empty', () => {
  expect(cart.items).toHaveLength(0);
});

test('adds an item', () => {
  cart.add({ sku: 'abc', price: 10 });
  expect(cart.items).toHaveLength(1);
});

cart is freshly created before every test, so tests can't accidentally leak state into one another.

beforeEach/afterEach Syntax

beforeEach(() => {
  // runs before every test in this scope
});

afterEach(() => {
  // runs after every test in this scope
});
  • Both accept a synchronous or async function.
  • If beforeEach()/afterEach() return a promise, Jest waits for it to resolve before continuing.
  • Hooks declared at the top of a file apply to every test in that file.
  • Hooks declared inside a describe() block only apply to tests inside that block.

beforeEach/afterEach Cheat Sheet

Quick reference for Jest's per-test setup and teardown hooks.

Hook Runs
beforeEach(fn) Before every test in scope
afterEach(fn) After every test in scope, pass or fail
beforeEach(async () => {}) Awaited before continuing
Hook in file scope Applies to all tests in the file
Hook in describe() scope Applies only to tests in that block

Scoping Hooks to a describe() Block

Hooks declared inside a describe() block only affect tests within that block, letting different sections of a file have different setup without interfering with each other.

describe('LoggedInUser', () => {
  beforeEach(() => {
    setAuthToken('valid-token');
  });

  test('can view the dashboard', () => { /* ... */ });
});

describe('LoggedOutUser', () => {
  beforeEach(() => {
    clearAuthToken();
  });

  test('is redirected to login', () => { /* ... */ });
});

Each describe() block's beforeEach() only runs for tests inside that same block.

Using afterEach() for Cleanup

afterEach() is the right place to reset global state, restore mocked functions, clear timers, or close resources opened during a test — anything that must happen regardless of whether the test passed or failed.

afterEach(() => {
  jest.clearAllMocks();
  jest.useRealTimers();
});

Common Mistakes

  • Duplicating the same setup code in every test() instead of moving it into beforeEach().
  • Forgetting to reset mocks or timers in afterEach(), causing state to leak between tests.
  • Not returning/awaiting an async beforeEach(), causing tests to run before setup finishes.
  • Declaring a hook at file scope when it should be scoped to a specific describe() block.

Key Takeaways

  • beforeEach() runs before every test in its scope; afterEach() runs after every test.
  • Both support async functions and promises, which Jest will wait for.
  • Scoping hooks inside describe() blocks limits them to that group of tests.
  • afterEach() is the standard place to reset mocks, timers, and other shared state.

Pro Tip

Add a global afterEach(() => jest.clearAllMocks()) in a setup file if your suite uses mocks heavily. It prevents a huge class of "test only fails when run with others" bugs.