---
name: describe-api
description: describe/suite for grouping tests into logical blocks
---

# Describe API

Group related tests into suites for organization and shared setup.

## Basic Usage

```ts
import { describe, expect, test } from 'vitest';

describe('Math', () => {
  test('adds numbers', () => {
    expect(1 + 1).toBe(2);
  });

  test('subtracts numbers', () => {
    expect(3 - 1).toBe(2);
  });
});

// Alias: suite
import { suite } from 'vitest';
suite('equivalent to describe', () => {});
```

## Nested Suites

```ts
describe('User', () => {
  describe('when logged in', () => {
    test('shows dashboard', () => {});
    test('can update profile', () => {});
  });

  describe('when logged out', () => {
    test('shows login page', () => {});
  });
});
```

## Suite Options

```ts
// All tests inherit options
describe('slow tests', { timeout: 30_000 }, () => {
  test('test 1', () => {}); // 30s timeout
  test('test 2', () => {}); // 30s timeout
});
```

## Suite Modifiers

### Skip Suites

```ts
describe.skip('skipped suite', () => {
  test('wont run', () => {});
});

// Conditional
describe.skipIf(process.env.CI)('not in CI', () => {});
describe.runIf(!process.env.CI)('only local', () => {});
```

### Focus Suites

```ts
describe.only('only this suite runs', () => {
  test('runs', () => {});
});
```

### Todo Suites

```ts
describe.todo('implement later');
```

### Concurrent Suites

```ts
// All tests run in parallel
describe.concurrent('parallel tests', () => {
  test('test 1', async ({ expect }) => {});
  test('test 2', async ({ expect }) => {});
});
```

### Sequential in Concurrent

```ts
describe.concurrent('parallel', () => {
  test('concurrent 1', async () => {});

  describe.sequential('must be sequential', () => {
    test('step 1', async () => {});
    test('step 2', async () => {});
  });
});
```

### Shuffle Tests

```ts
describe.shuffle('random order', () => {
  test('test 1', () => {});
  test('test 2', () => {});
  test('test 3', () => {});
});

// Or with option
describe('random', { shuffle: true }, () => {});
```

## Parameterized Suites

### describe.each

```ts
describe.each([
  { name: 'Chrome', version: 100 },
  { name: 'Firefox', version: 90 },
])('$name browser', ({ name, version }) => {
  test('has version', () => {
    expect(version).toBeGreaterThan(0);
  });
});
```

### describe.for

```ts
describe.for([
  ['Chrome', 100],
  ['Firefox', 90],
])('%s browser', ([name, version]) => {
  test('has version', () => {
    expect(version).toBeGreaterThan(0);
  });
});
```

## Hooks in Suites

```ts
describe('Database', () => {
  let db;

  beforeAll(async () => {
    db = await createDb();
  });

  afterAll(async () => {
    await db.close();
  });

  beforeEach(async () => {
    await db.clear();
  });

  test('insert works', async () => {
    await db.insert({ name: 'test' });
    expect(await db.count()).toBe(1);
  });
});
```

## Modifier Combinations

All modifiers can be chained:

```ts
describe.skip.concurrent('skipped concurrent', () => {});
describe.only.shuffle('only and shuffled', () => {});
describe.concurrent.skip('equivalent', () => {});
```

## Key Points

- Top-level tests belong to an implicit file suite
- Nested suites inherit parent's options (timeout, retry, etc.)
- Hooks are scoped to their suite and nested suites
- Use `describe.concurrent` with context's `expect` for snapshots
- Shuffle order depends on `sequence.seed` config

<!--
Source references:
- https://vitest.dev/api/describe.html
-->
