Skip to content

Jest Test Structure

Well-structured tests are easier to read, debug, and maintain. This lesson introduces the Arrange-Act-Assert pattern and other conventions for organizing Jest test files as your suite grows.

The Arrange-Act-Assert Pattern

Arrange-Act-Assert (AAA) is a simple, widely used structure for individual tests. "Arrange" sets up any data or mocks needed. "Act" calls the function or triggers the behavior being tested. "Assert" checks the result with expect(). Keeping these three phases visually separated makes tests easy to scan.

You don't need comments labeling each phase in every test, but keeping the underlying structure consistent — setup, then action, then assertion — makes even unfamiliar tests quick to understand.

test('applies a 10% discount to orders over $100', () => {
  // Arrange
  const order = { total: 150 };

  // Act
  const result = applyDiscount(order);

  // Assert
  expect(result.total).toBe(135);
});

Even without the comments, the three phases are visually distinct: build data, call the function, check the result.

One Focused Assertion Concept Per Test

describe('applyDiscount', () => {
  it('applies a 10% discount over $100', () => { /* ... */ });
  it('applies no discount at exactly $100', () => { /* ... */ });
  it('throws for a negative total', () => { /* ... */ });
});
  • Each it() should test one behavior, not several unrelated behaviors bundled together.
  • Multiple expect() calls in one test are fine if they check the same behavior from different angles.
  • Splitting behaviors into separate tests makes failures pinpoint the exact broken case.
  • Shared setup across tests belongs in beforeEach(), not repeated inline in every test.

Test Structure Cheat Sheet

Quick guidelines for organizing any Jest test file.

Guideline Why It Matters
Arrange-Act-Assert Keeps each test easy to scan
One behavior per test Failures point to a specific case
Descriptive test names Failure reports are self-explanatory
Shared setup in beforeEach() Avoids duplicated arrange code
Group related tests with describe() Improves readability of output
Avoid logic/branches in tests Keeps tests predictable and simple

Avoid Conditional Logic Inside Tests

A test with if statements or loops that change what gets asserted is a sign the test is trying to do too much. Tests should be simple and linear — if a condition is genuinely important, split it into its own dedicated test case instead of branching inside one.

// Avoid: conditional logic inside a test
test('validates user', () => {
  const user = getUser();
  if (user.role === 'admin') {
    expect(user.permissions.length).toBeGreaterThan(0);
  } else {
    expect(user.permissions.length).toBe(0);
  }
});

// Prefer: two focused tests
test('admin users have permissions', () => {
  expect(getUser('admin').permissions.length).toBeGreaterThan(0);
});

test('regular users have no permissions', () => {
  expect(getUser('member').permissions.length).toBe(0);
});

Organizing Larger Test Files

As a module grows, group its tests by method or feature using nested describe() blocks, and keep the file ordered the same way the source file is ordered. This makes it trivial to find the tests for any given function.

  • One top-level describe() per module or class.
  • One nested describe() per method or exported function.
  • Shared fixtures/mocks declared once near the top of the file.
  • Edge cases and error paths grouped together, clearly labeled.

Common Mistakes

  • Cramming multiple unrelated behaviors into a single test() block.
  • Adding if/else branches inside a test instead of splitting into separate cases.
  • Duplicating the same setup code in every test instead of using beforeEach().
  • Naming tests after implementation details instead of observable behavior.

Key Takeaways

  • Arrange-Act-Assert keeps individual tests easy to read at a glance.
  • Each test should focus on one behavior so failures are easy to diagnose.
  • Avoid conditional logic inside tests; split branches into separate test cases.
  • Nested describe() blocks that mirror the source file structure keep large suites navigable.

Pro Tip

If you find yourself writing a comment to explain what a test is really checking, that's usually a sign the test name itself should be more specific instead.