Testing
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.
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.
# Run all unit tests
bun test:unit
Tests use standard Vitest patterns with vi.mock() for mocking dependencies:
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:
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.
# 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:
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
# Unit + E2E
bun test
This runs Playwright first, then Vitest.