---
title: Testing
description: Unit tests and end-to-end testing with Vitest and Playwright
---

ChatJS includes two testing layers: **Vitest** for unit tests and **Playwright** for end-to-end browser tests. For AI-specific quality evaluation, see [Evaluations](/reference/evaluations).

## Unit Tests (Vitest)

Unit tests cover individual functions and modules. They live alongside the source code as `*.test.ts` files. Vitest is configured in `vitest.config.ts` to exclude `*.e2e.ts` files so E2E tests never run as unit tests.

```bash
# Run all unit tests
bun test:unit
```

Tests use standard Vitest patterns with `vi.mock()` for mocking dependencies:

```typescript
import { describe, it, expect, vi } from "vitest";

describe("myFunction", () => {
  it("returns expected result", () => {
    expect(myFunction("input")).toBe("output");
  });
});
```

### Mocking AI models

For tests that interact with AI models, mock the model resolution layer rather than the AI SDK directly:

```typescript
vi.mock("../ai/app-models", () => ({
  getAppModelDefinition: vi.fn().mockImplementation((modelId: string) => {
    const models: Record<
      string,
      { pricing?: { input: string; output: string } }
    > = {
      "test-model": { pricing: { input: "0.00001", output: "0.00003" } },
    };
    return Promise.resolve(models[modelId] || {});
  }),
}));
```

## End-to-End Tests (Playwright)

Playwright tests simulate real user interactions in a browser. Configuration is in `playwright.config.ts`.

```bash
# Run E2E tests
bun test:e2e
```

### Test projects

The Playwright config defines five test projects that run in dependency order:

| Project | File | Depends On | Purpose |
| --- | --- | --- | --- |
| `setup:auth` | `auth.setup.e2e.ts` | - | Authenticate and save session |
| `setup:reasoning` | `reasoning.setup.e2e.ts` | `setup:auth` | Prepare reasoning model state |
| `chat` | `chat.e2e.ts` | `setup:auth` | Core chat interactions |
| `reasoning` | `reasoning.e2e.ts` | `setup:reasoning` | Reasoning model tests |
| `artifacts` | `artifacts.e2e.ts` | `setup:auth` | Canvas and document tests |

### CI behavior

| Setting | Local                    | CI             |
| ------- | ------------------------ | -------------- |
| Workers | Unlimited                | 1              |
| Retries | 1                        | 2              |
| Server  | Reuse running dev server | Start fresh    |
| Traces  | On first retry           | On first retry |

### Writing E2E tests

Create test files in the `tests/` directory using the `*.e2e.ts` naming convention. Tests have access to authenticated sessions via Playwright's [storage state](https://playwright.dev/docs/auth):

```typescript
import { test, expect } from "@playwright/test";

test("send a message and get a response", async ({ page }) => {
  await page.goto("/");
  await page.fill('[data-testid="chat-input"]', "Hello");
  await page.click('[data-testid="send-button"]');
  await expect(page.locator('[data-testid="assistant-message"]')).toBeVisible();
});
```

## Running All Tests

```bash
# Unit + E2E
bun test
```

This runs Playwright first, then Vitest.
