SkillByAIOpen interactive version →

Lesson 4 / 25

describe, it and Arrange-Act-Assert

Shape every test the same way.

One behaviour per test

describe groups related tests; it and test are aliases that declare a single test. Write names as sentences about behaviour (it('rejects an expired coupon')), not about implementation. Inside, follow arrange-act-assert: arrange the inputs and collaborators, act by calling the code once, assert on the observable result. Blank lines between the three parts make tests scannable. it.each / test.each runs the same test over a table of cases, and test.todo records a test you plan to write. Prefer several small tests over one test that checks ten things: when it fails, the name tells you what broke.

Small, readable, independent

A good test names one behaviour, sets up only what it needs, and checks the outcome with a precise matcher.

Figure 2.1 — Structure a test, assert precisely, keep tests isolated.

A table-driven test with clear AAA

Works the same in Jest and Vitest.

import { describe, it, expect } from 'vitest';
import { applyCoupon } from './cart';

describe('applyCoupon', () => {
  it('takes 10% off with SAVE10', () => {
    // arrange
    const cart = { subtotal: 200, coupon: null };

    // act
    const result = applyCoupon(cart, 'SAVE10');

    // assert
    expect(result.total).toBe(180);
  });

  it.each([
    ['', 'empty code'],
    ['save10', 'wrong case'],
    ['EXPIRED5', 'expired code'],
  ])('rejects %s (%s)', (code) => {
    expect(() => applyCoupon({ subtotal: 200, coupon: null }, code)).toThrow(/invalid coupon/i);
  });

  it.todo('stacks with a loyalty discount');
});

Read the failure message first

Before trusting a new test, make it fail on purpose (break the code or the expectation) and check the failure message explains the problem. A test you have never seen fail may not be testing anything.

Quick check: What does arrange-act-assert describe?

  • Write the assertion first and the code never
  • Set up inputs, perform one action, then check the observable result
  • Run the test three times to confirm
  • Mock every dependency before writing code
Answer

Set up inputs, perform one action, then check the observable result — A consistent shape makes tests easy to read.