Skip to content

beforeAll and afterAll

Some setup, like connecting to a test database or starting a server, is expensive and only needs to happen once. This lesson covers beforeAll() and afterAll(), which run a single time per scope instead of before/after every test.

beforeAll() and afterAll() Run Once Per Scope

beforeAll(fn) runs once, before any test in its scope executes. afterAll(fn) runs once, after every test in its scope has finished. This makes them ideal for expensive setup (connecting to a database, starting an in-memory server) and matching cleanup.

Because the setup only happens once, any state created in beforeAll() is shared across all tests in the scope — which means tests must not mutate that shared state in ways that would affect other tests.

let db;

beforeAll(async () => {
  db = await connectToTestDatabase();
});

afterAll(async () => {
  await db.close();
});

test('inserts a record', async () => {
  await db.insert({ id: 1 });
  expect(await db.count()).toBe(1);
});

The database connection opens once for the whole file and closes once at the end, instead of reconnecting for every test.

beforeAll/afterAll Syntax

beforeAll(async () => {
  // runs once, before any test in this scope
});

afterAll(async () => {
  // runs once, after all tests in this scope finish
});
  • Both accept synchronous or async functions, just like beforeEach()/afterEach().
  • Scoped inside a describe() block, they run once per block, not once per file.
  • Use them for expensive, shared resources: database connections, servers, temp files.
  • Combine with beforeEach() when you need both one-time setup and per-test resets.

beforeAll/afterAll Cheat Sheet

When to reach for each Jest lifecycle hook.

Hook Frequency Typical Use
beforeAll() Once per scope Open DB connection, start server
afterAll() Once per scope Close DB connection, stop server
beforeEach() Before every test Reset mocks, seed fresh data
afterEach() After every test Clear mocks, roll back a transaction

Combining beforeAll() with beforeEach()

A common, effective pattern: use beforeAll() to establish an expensive, shared connection once, and beforeEach() to reset or reseed data before each individual test so tests remain isolated from one another despite sharing the connection.

let db;

beforeAll(async () => {
  db = await connectToTestDatabase();
});

beforeEach(async () => {
  await db.clear();
  await db.seed(fixtureData);
});

afterAll(async () => {
  await db.close();
});

The connection opens once; the data resets before every test to keep tests independent.

File-Scoped vs. describe()-Scoped Hooks

When beforeAll()/afterAll() are declared inside a describe() block, they apply only to tests within that block, letting different sections of a large file each set up their own expensive resource independently.

describe('with a valid subscription', () => {
  beforeAll(() => seedSubscription({ active: true }));
  test('grants premium access', () => { /* ... */ });
});

describe('with an expired subscription', () => {
  beforeAll(() => seedSubscription({ active: false }));
  test('denies premium access', () => { /* ... */ });
});

Common Mistakes

  • Using beforeAll() for setup that must be fresh per test, causing tests to affect each other.
  • Forgetting afterAll() cleanup, leaving database connections or servers open after the suite finishes.
  • Not awaiting an async beforeAll(), causing tests to run against a connection that isn't ready yet.
  • Relying on test execution order for shared state instead of explicit setup in beforeEach().

Key Takeaways

  • beforeAll()/afterAll() run once per scope, ideal for expensive shared resources.
  • beforeEach()/afterEach() still run per test and can reset state on top of a one-time setup.
  • Scoping hooks inside describe() blocks isolates setup to just that section of tests.
  • Always close/cleanup expensive resources in afterAll() to avoid leaks between test files.

Pro Tip

If your beforeAll() setup is slow enough to notice, that's often a sign to consider an in-memory alternative (like an in-memory SQLite or Mongo instance) to keep your suite fast.