Why do tests that share data go wrong?
The order queue in orders.js keeps its orders in one array at the top of the module. Every test in the file talks to that same array. The first test adds Ada's order, and it is still there when the second test runs, so the second test's order becomes number 2. The test passes, and its name even says number 2, but the only reason is that another test ran first.
That arrangement is fragile in three ways. Run the third test alone and it fails, because order 1 doesn't exist. Reorder the tests and the numbers shift. Add a new test near the top and tests further down break for no visible reason. Each of those failures points at a test that is fine, which wastes your time.
The fix is isolation: every test sets up what it needs and starts from the same clean state. A good check is to imagine running each test on its own. If it would fail, it depends on something it doesn't create.
What does beforeEach do?
beforeEach(fn) registers a function that the runner calls before every test in the file, or in the describe block it sits in. It is the place for shared setup that must be fresh every time: emptying a queue, creating a new basket, resetting a mock. The tests stay short, and none of them can forget the reset.
Add beforeEach(() => { clearOrders(); }) to the starting tests and two of them turn red. That is the hook doing its job. It has exposed two tests that were reading another test's leftovers. Each needs its own orders, added inside the test where a reader can see them.
beforeEach(() => {
clearOrders();
});
test('orders are numbered in the order they arrive', () => {
const first = addOrder('Ada', ['Rye']);
const second = addOrder('Ben', ['Bagel']);
expect(first.id).toBe(1);
expect(second.id).toBe(2);
});

Should the reset go before each test or after?
Both work, and each has a reason. beforeEach guarantees the state a test starts with, whatever happened earlier, including a test that crashed halfway. afterEach tidies up after a test, which suits things that must be undone, such as a spy on console.warn, a fake timer, or a global you replaced.
A practical rule: create and reset data in beforeEach, and undo changes to the outside world in afterEach. Vitest and Jest run afterEach even when the test fails, so a cleanup placed there still happens. A cleanup line at the bottom of a test body is skipped as soon as an assertion above it throws.
afterEach(() => {
vi.restoreAllMocks();
});When is beforeAll the right choice?
beforeAll(fn) runs once before all the tests in its file or block, and afterAll(fn) runs once after them. Use them for setup that is slow and that tests only read, never change: loading a large list of bird species from a file, starting a local test server, building a big price table.
The danger is data that tests modify. If beforeAll creates a basket and two tests add loaves to it, the second test sees the first test's loaf. That is the bug in the Break It challenge. When in doubt, use beforeEach; creating a small object for every test costs microseconds, and a shared object that drifts can cost an afternoon.
How do hooks behave inside describe blocks?
A hook inside describe only applies to the tests in that block. Hooks at the top of the file apply to every test. When blocks nest, the outer beforeEach runs first, then the inner one, then the test, then the inner afterEach, then the outer. That order lets you set up general data at the top and add details for one group.
Keep the nesting shallow. With three levels of hooks, a reader has to scroll up through each block to know what a test starts with. If one group needs a basket with a cake already in it, a short helper such as basketWithCake() called inside each test is often easier to follow than another layer of hooks.
describe('waiting list', () => {
beforeEach(() => {
addOrder('Ada', ['Rye']);
addOrder('Ben', ['Bagel']);
});
test('a ready order leaves the list', () => {
markReady(1);
expect(waiting()).toHaveLength(1);
});
});How do you find tests that depend on order?
Put .only on one test at a time and see whether it still passes alone. In the starting file, .only on the third test turns it red straight away. On a real project, Vitest can shuffle the order with vitest --sequence.shuffle, and Jest has --randomize. A suite that fails only in some orders has shared state somewhere.
The Results view helps too. If a test fails and its Received value looks like data from a different test, such as an order id one higher than expected or an extra line in a basket, look for state that lives outside the test: a module-level array, a variable declared above the tests, a global, or a mock that was never reset.
Remember to remove the .only afterwards. While it is in the file, every other test is skipped, and the suite can look healthy while checking almost nothing.
Does each test file start fresh?
In Vitest and Jest, yes: by default each test file runs in its own isolated module environment, so a module-level array in orders.js starts empty for each file. Within a file it is shared, which is why the hooks matter. The practice runner works the same way per run: the code file loads once, then every test in the file shares it.
The runner differs in one small way. It resets fake timers after every test for you, which real Vitest doesn't do. On your own projects, pair vi.useFakeTimers() with vi.useRealTimers() in an afterEach. The timers lesson covers that.
What do AI tools get wrong with setup?
Generated test files often declare one shared object at the top, fill it in beforeAll, and let every test change it. The tests pass in the order written, and the first time someone adds a test in the middle, unrelated ones break. Look for let variables above the tests and ask whether any test changes them.
The opposite problem also shows up: a beforeEach that does so much that no test makes sense on its own. If you have to read thirty lines of hooks to know what a test checks, move the details that matter for that test into the test itself.
- Reset shared data in
beforeEach - Undo spies, timers and globals in
afterEach - Keep
beforeAllfor slow setup that tests only read - Make the facts a test depends on visible inside it
Field notes
- Tests that share data can pass only because another test ran first.
beforeEachruns before every test, which suits resetting shared data.afterEachsuits undoing spies, fake timers and replaced globals.- Keep
beforeAllfor slow setup that tests read and never change.
Easy to get wrong
The first version only passes if another test added an order first. A test should create everything its expected value depends on.
Tests that add to the basket change it for every later test. beforeEach gives each one a new basket.
If an assertion fails, the restore line at the bottom never runs and the spy leaks into later tests. afterEach runs even after a failure.
Questions people ask
Can a `beforeEach` hook be async?
Yes. Make the function async and await inside it, and the runner waits for it to finish before the test starts. The same goes for afterEach, beforeAll and afterAll.
What happens if a hook throws?
The tests it was setting up are reported as failures with the hook's error. In the practice runner a failing beforeAll shows as its own failed entry, and the block's tests don't run.
Should I reset mocks in every file?
Either reset them in an afterEach, or set clearMocks: true (call history) and restoreMocks: true (spies) in the Vitest or Jest config so it happens everywhere. Since Vitest 3 and Jest 30, restoreMocks alone puts spies back but leaves the call history of vi.fn() mocks. Doing neither lets call counts from one test leak into the next.
Is copying the same two setup lines into each test bad?
Not necessarily. A little repetition that keeps each test readable on its own is fine. Move setup into a hook when it is identical everywhere and the details don't matter to the reader.