OneApp Docs
PackagesCore

@repo/qa

Testing utilities, fixtures, mocks, and custom matchers for Vitest and Testing Library. Deterministic test data, API mocks, database mocks. Install as dev dependency only.

Quick Start

Add testing utilities in 2 minutes:

pnpm add -D @repo/qa

Fixtures, mocks, custom matchers included. Dev dependency only. Skip to Quick Start →

Why @repo/qa?

Every test file creates its own fixtures. Test data inconsistent across specs. Mocking requires boilerplate. API mocks duplicated. Database mocks need setup. Custom matchers written multiple times. Test utilities scattered.

@repo/qa solves this with shared testing utilities, fixtures, and mocks for the entire monorepo.

Production-ready with Vitest integration, Testing Library support, deterministic fixtures, and custom matchers.

Use cases

  • Test fixtures — Consistent user, post, product data across all tests
  • API mocks — Mock fetch calls with response history
  • Database mocks — Mock Prisma client for unit tests
  • Custom matcherstoMatchStructure, toBeWithinRange for better assertions
  • Test helpers — Render with providers, fake timers, mock storage

How it works

@repo/qa exports fixtures, mocks, and utilities:

import { fixtures, mockPrisma, renderWithProviders } from "@repo/qa";

// Fixtures - consistent test data
const user = fixtures.user();
const admin = fixtures.user({ role: "admin" });

// Mocks - database operations
const prisma = mockPrisma();
prisma.user.findMany.mockResolvedValue([user]);

// Utilities - render with context
const { getByText } = renderWithProviders(<MyComponent />, {
  user,
  theme: "dark",
});

Uses Vitest mocks, Testing Library, and custom utilities for testing.

Key features

Test fixtures — Deterministic data with override support

API/Service mocks — Mock fetch, services, databases

Custom matchers — Better assertions for structure, ranges

Render utilities — Testing Library with providers

Test helpers — Fake timers, mock date, mock storage

Vitest setup — Auto-configures testing environment

Quick Start

1. Install the package

pnpm add -D @repo/qa

2. Use fixtures for consistent test data

__tests__/user.test.ts
import { fixtures } from "@repo/qa/fixtures";
import { describe, it, expect } from "vitest";

describe("User", () => {
  it("creates a user with default values", () => {
    const user = fixtures.user();

    expect(user).toMatchObject({
      id: expect.any(String),
      email: expect.stringContaining("@"),
      name: expect.any(String)
    });
  });

  it("creates an admin user", () => {
    const admin = fixtures.user({ role: "admin" });

    expect(admin.role).toBe("admin");
  });
});

3. Mock database operations

__tests__/service.test.ts
import { mockPrisma } from "@repo/qa/mocks";
import { fixtures } from "@repo/qa/fixtures";
import { UserService } from "#/services/user";
import { describe, it, expect } from "vitest";

describe("UserService", () => {
  it("fetches users from database", async () => {
    const prisma = mockPrisma();
    const users = [fixtures.user(), fixtures.user()];

    prisma.user.findMany.mockResolvedValue(users);

    const service = new UserService(prisma);
    const result = await service.getAllUsers();

    expect(result).toHaveLength(2);
    expect(prisma.user.findMany).toHaveBeenCalled();
  });
});

4. Add Vitest setup

vitest.setup.ts
import "@repo/qa/setup";

// Automatically sets up:
// - Testing Library
// - Custom matchers
// - Browser API mocks
vitest.config.ts
import { defineConfig } from "vitest/config";

export default defineConfig({
  test: {
    setupFiles: ["./vitest.setup.ts"]
  }
});

That's it! You now have fixtures, mocks, and utilities for consistent testing across your app.

Use custom matchers

Better assertions with custom matchers:

import "@repo/qa/matchers";

expect(object).toMatchStructure({
  id: String,
  count: Number,
  items: Array
});

Technical Details

For Developers: Technical implementation details

Overview

PropertyValue
Locationpackages/qa
PurposeTesting utilities, fixtures, mocks
FrameworksVitest, Testing Library

Export Paths

PathDescription
@repo/qaMain exports
@repo/qa/fixturesTest fixtures
@repo/qa/mocksMock utilities
@repo/qa/matchersCustom matchers

Test Fixtures

Deterministic Testing

Fixtures provide consistent test data. Override specific fields while keeping sensible defaults.

User Fixtures

import { fixtures } from "@repo/qa/fixtures";

// highlight-next-line
const user = fixtures.user();
// { id: "user_xxx", name: "Test User", email: "test@example.com", ... }

// highlight-start
const admin = fixtures.user({ role: "admin" });
const users = fixtures.users(5); // Array of 5 users
// highlight-end

Post Fixtures

import { fixtures } from "@repo/qa/fixtures";

const post = fixtures.post();
const postWithAuthor = fixtures.post({ author: fixtures.user() });
const posts = fixtures.posts(10);

Custom Fixtures

import { createFixture } from "@repo/qa/fixtures";

const productFixture = createFixture({
  id: () => `prod_${Math.random().toString(36).slice(2)}`,
  name: "Test Product",
  price: 99.99,
  inStock: true
});

const product = productFixture();
const customProduct = productFixture({ price: 149.99 });

Mocks

API Mocks

import { mockApi } from "@repo/qa/mocks";

const api = mockApi();

api.get("/users").reply(200, [{ id: "1", name: "John" }]);
api.post("/users").reply(201, { id: "2", name: "Jane" });

// Use in tests
await fetch("/users");
expect(api.history.get).toHaveLength(1);

Service Mocks

import { mockService } from "@repo/qa/mocks";

const emailService = mockService({
  send: vi.fn().mockResolvedValue({ success: true }),
  verify: vi.fn().mockResolvedValue(true)
});

// Use and verify
await emailService.send({ to: "test@example.com" });
expect(emailService.send).toHaveBeenCalled();

Database Mocks

Isolation

Mock the database in unit tests. Use a real test database for integration tests.

import { mockPrisma } from "@repo/qa/mocks";

// highlight-next-line
const prisma = mockPrisma();

prisma.user.findMany.mockResolvedValue([fixtures.user()]);

// Use in tests
const users = await prisma.user.findMany();
expect(users).toHaveLength(1);

Test Utilities

Render with Providers

import { renderWithProviders } from "@repo/qa";

const { getByText, getByRole } = renderWithProviders(<MyComponent />, {
  user: fixtures.user(),
  theme: "dark",
});

Wait For

import { waitForElement, waitForText } from "@repo/qa";

await waitForElement("[data-testid='result']");
await waitForText("Success!");

Act Async

import { actAsync } from "@repo/qa";

await actAsync(async () => {
  fireEvent.click(button);
  await waitFor(() => expect(result).toBeVisible());
});

Custom Matchers

toHaveBeenCalledWithMatch

import "@repo/qa/matchers";

expect(mockFn).toHaveBeenCalledWithMatch({
  id: expect.any(String),
  name: "John"
});

toBeWithinRange

expect(value).toBeWithinRange(1, 10);

toMatchStructure

expect(object).toMatchStructure({
  id: String,
  count: Number,
  items: Array
});

Test Helpers

Fake Timers

import { fakeTimers } from "@repo/qa";

fakeTimers.install();
// ... test code
fakeTimers.tick(1000);
fakeTimers.uninstall();

Mock Date

import { mockDate } from "@repo/qa";

mockDate.set("2024-01-15");
// Date.now() returns timestamp for 2024-01-15
mockDate.reset();

Mock Storage

import { mockLocalStorage, mockSessionStorage } from "@repo/qa";

const localStorage = mockLocalStorage();
localStorage.setItem("key", "value");
expect(localStorage.getItem("key")).toBe("value");

Setup Files

Vitest Setup

// vitest.setup.ts
import "@repo/qa/setup";

// Automatically:
// - Sets up testing-library
// - Adds custom matchers
// - Mocks common browser APIs

Environment

import { testEnv } from "@repo/qa";

testEnv.set({
  DATABASE_URL: "test://localhost",
  API_KEY: "test-key"
});

// Clean up
testEnv.reset();

On this page