# describe, it and Arrange-Act-Assert — Jest, Vitest & Testing Library

Source: https://www.skillbyai.com/en/javascript-testing/w-structure

> 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.

![Three ideas: structure, matchers, isolation with hooks.](assets/figures/javascript-testing/section-2-map.svg) — 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.

```typescript
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.

**Quiz:** What does arrange-act-assert describe?

- [ ] Write the assertion first and the code never
- [x] 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.
