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