Grouping Tests with describe()
describe('block name', () => { ... }) groups related test() calls under a shared label, which shows up as an indented heading in Jest's output and makes large test suites easier to scan — for example, describe('UserService', () => { test('creates a user', ...); test('rejects duplicate emails', ...); }). Grouping also lets you scope setup/teardown hooks and shared variables to just the tests inside that block, rather than affecting the entire file.
Cricket analogy: A describe() block is like grouping a bowler's figures by innings on a scorecard — 'Bumrah — 1st Innings' as a labeled section containing each individual delivery's outcome (test), rather than a flat unsorted list of every ball bowled all match.
Setup and Teardown Hooks
Jest provides beforeEach/afterEach to run code before or after every test in the enclosing describe() block (or the whole file if placed outside one), and beforeAll/afterAll to run code once before the first or after the last test in that scope — useful for expensive setup like opening a database connection, versus per-test setup like resetting a mock's call history. A common pattern is beforeEach(() => { jest.clearAllMocks(); }) to ensure mock call counts don't leak between tests, since Jest does not reset mocks automatically unless clearMocks: true is set in configuration.
Cricket analogy: beforeAll opening a database connection once is like a ground crew preparing the pitch once before a five-day Test match, while beforeEach resetting mocks per test is like the umpires checking the ball's condition before every single over.
describe('ShoppingCart', () => {
let cart;
beforeEach(() => {
cart = new ShoppingCart();
});
afterEach(() => {
jest.clearAllMocks();
});
test('starts empty', () => {
expect(cart.items).toHaveLength(0);
});
test('adds an item', () => {
cart.add({ id: 1, price: 10 });
expect(cart.items).toHaveLength(1);
});
});Hooks declared outside any describe() apply to the whole file. Hooks declared inside a describe() only apply to tests within that block, including nested describe()s — this scoping is what makes hooks composable in large suites.
Nesting describe() Blocks
describe() blocks can be nested to model sub-scenarios, such as describe('ShoppingCart', () => { describe('when empty', () => {...}); describe('with items', () => {...}); }), and Jest runs beforeEach hooks from outer blocks before inner ones, in declaration order — so an outer beforeEach that creates a cart runs before an inner beforeEach that adds items to it. This nesting is purely for organization and shared setup; it doesn't create test isolation between sibling describe blocks beyond what the hooks themselves establish.
Cricket analogy: Nested describe() blocks are like a scorecard organized by 'Match' containing nested 'Innings' sections, each containing individual 'Over' entries — the outer setup (venue/toss) applies before the inner-specific setup (which bowler is up) takes over.
Sibling describe() blocks do not share state by default, and test order should never be relied upon for correctness — Jest does not guarantee tests run in file order when using certain reporters or --shard/parallel configurations across files. Each test should set up everything it needs via hooks rather than depending on a previous test having run.
test.each and Parameterized Tests
When you need to run the same assertion logic against multiple input/output pairs, test.each([[input1, expected1], [input2, expected2]])('description with %s', (input, expected) => {...}) avoids copy-pasting near-identical test() blocks. The array form uses %s, %d, %i, %p etc. as printf-style placeholders in the description string, while a tagged-template form offers a more readable table layout for larger data sets.
Cricket analogy: test.each running the same check against multiple input pairs is like a bowling machine testing a batter's technique against a table of deliveries — different lengths, different lines — using one consistent evaluation method instead of writing a separate drill for every single delivery type.
- describe('name', callback) groups related test() calls and organizes output, and scopes shared hooks/variables.
- beforeEach/afterEach run around every test in scope; beforeAll/afterAll run once for the whole scope.
- Jest does not auto-reset mocks between tests unless you call jest.clearAllMocks() or set clearMocks: true.
- Hooks declared outside any describe() apply file-wide; hooks inside one apply only to that block and its nested blocks.
- Outer beforeEach hooks run before inner ones, in declaration order, when describe() blocks are nested.
- Sibling describe()/test() blocks should never depend on execution order or shared mutable state.
- test.each (array or tagged-template form) runs the same test logic against multiple data rows without duplicating code.
Practice what you learned
1. What is the primary purpose of describe()?
2. What's the difference between beforeEach and beforeAll?
3. Does Jest automatically reset mock call counts between tests?
4. When describe() blocks are nested, in what order do beforeEach hooks run?
5. What problem does test.each solve?
Was this page helpful?
You May Also Like
Writing Your First Test
A hands-on walkthrough of writing, running, and understanding your first Jest test file.
What Is Jest?
An introduction to Jest, the all-in-one JavaScript testing framework built by Meta for unit, integration, and snapshot testing.
Running and Watching Tests
How to run Jest from the command line, use watch mode for fast feedback, and interpret coverage output.