Skip to content

useTestHooksInOrder

biome.json
{
"linter": {
"rules": {
"nursery": {
"useTestHooksInOrder": "error"
}
}
}
}

Enforce that test lifecycle hooks are declared in the order they execute.

Jest and Vitest always execute lifecycle hooks in the following order, regardless of how they are written in the file:

  1. beforeAll (or before if you are using node:test)
  2. beforeEach
  3. afterEach
  4. afterAll (or after if you are using node:test)

Writing the hooks in a different order creates a discrepancy between the visual order in the source and the actual execution order, which makes test code harder to reason about.

This rule flags any hook that appears after a hook that runs later in the execution order. Only consecutive groups of hooks in the same block are compared — test cases and other statements between hooks are allowed and reset the comparison baseline.

describe('foo', () => {
beforeEach(() => {});
beforeAll(() => {});
});
code-block.js:3:3 lint/nursery/useTestHooksInOrder ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

beforeAll is out of order compared to beforeEach.

1 │ describe(‘foo’, () => {
2 │ beforeEach(() => {});
> 3 │ beforeAll(() => {});
^^^^^^^^^^^^^^^^^^^
4 │ });
5 │

beforeEach is declared here but executes after beforeAll.

1 │ describe(‘foo’, () => {
> 2 │ beforeEach(() => {});
^^^^^^^^^^^^^^^^^^^^
3 │ beforeAll(() => {});
4 │ });

Reorder the lifecycle hooks to appear in the order they execute: beforeAll/before, beforeEach, afterEach, afterAll/after.

This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

describe('foo', () => {
afterEach(() => {});
afterAll(() => {});
beforeAll(() => {});
});
code-block.js:4:3 lint/nursery/useTestHooksInOrder ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

beforeAll is out of order compared to afterAll.

2 │ afterEach(() => {});
3 │ afterAll(() => {});
> 4 │ beforeAll(() => {});
^^^^^^^^^^^^^^^^^^^
5 │ });
6 │

afterAll is declared here but executes after beforeAll.

1 │ describe(‘foo’, () => {
2 │ afterEach(() => {});
> 3 │ afterAll(() => {});
^^^^^^^^^^^^^^^^^^
4 │ beforeAll(() => {});
5 │ });

Reorder the lifecycle hooks to appear in the order they execute: beforeAll/before, beforeEach, afterEach, afterAll/after.

This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

describe('foo', () => {
beforeAll(() => {});
beforeEach(() => {});
afterEach(() => {});
afterAll(() => {});
});
// Hooks separated by test cases are treated independently.
describe('foo', () => {
beforeEach(() => {});
it('a test', () => {});
afterAll(() => {});
});

See useTestHooksOnTop if you want to group all the hooks at the top of the block, before any test cases.