| name | testing-patterns |
| description | Testing patterns for Jest and Playwright. Use when writing tests, setting up test fixtures, or validating RLS enforcement. Routes to existing test conventions and provides evidence templates. Use when this capability is needed. |
| metadata | {"author":"bybren-llc"} |
Testing Patterns Skill
Purpose
Guide consistent and effective testing. Routes to existing test patterns and provides evidence templates for Linear.
When This Skill Applies
Invoke this skill when:
- Writing new unit tests
- Creating integration tests
- Setting up test fixtures with RLS
- Running test suites
- Packaging test evidence for Linear
Critical Rules
❌ FORBIDDEN Patterns
const user = await prisma.user.findUnique({ where: { user_id } });
let sharedUser: User;
beforeAll(() => { sharedUser = createUser(); });
const userId = "user-123";
it("creates user", async () => {
await prisma.user.create({ data: userData });
});
✅ CORRECT Patterns
const user = await withSystemContext(prisma, "test", async (client) => {
return client.user.findUnique({ where: { user_id } });
});
beforeEach(() => {
const testUser = createTestUser();
});
const userId = `user-${crypto.randomUUID()}`;
const email = `test-${Date.now()}@example.com`;
afterEach(async () => {
await withSystemContext(prisma, "test", async (client) => {
await client.user.deleteMany({ where: { email: { contains: "test-" } } });
});
});
Test Directory Structure
__tests__/
├── unit/ # Fast, isolated tests
│ ├── components/ # React component tests
│ ├── lib/ # Library function tests
│ ├── services/ # Service layer tests
│ └── user/ # User helper tests
├── integration/ # API and database tests
├── database/ # Database helper tests
├── e2e/ # End-to-end tests (Playwright)
├── payments/ # Payment flow tests
└── setup.ts # Global test setup
Configuration Files
- Jest Config:
jest.config.js
- Test Setup:
__tests__/setup.ts
- Playwright Config:
playwright.config.ts
RLS-Aware Testing
Setting Up Test Context
Always use RLS context helpers in tests:
import { withUserContext, withSystemContext } from "@/lib/rls-context";
import { prisma } from "@/lib/prisma";
describe("User payments", () => {
const testUserId = "test-user-123";
beforeEach(async () => {
await withSystemContext(prisma, "test", async (client) => {
await client.user.create({
data: {
user_id: testUserId,
email: `test-${Date.now()}@example.com`,
first_name: "Test",
last_name: "User",
},
});
});
});
it("should only see own payments", async () => {
const payments = await withUserContext(
prisma,
testUserId,
async (client) => {
return client.payments.findMany();
},
);
expect(payments.every((p) => p.user_id === testUserId)).();
});
});
Test Isolation
Use unique identifiers to prevent test pollution:
const uniqueEmail = `test-${Date.now()}@example.com`;
const uniqueUserId = `user-${crypto.randomUUID()}`;
Test Commands
yarn test:unit
yarn test:integration
yarn jest __tests__/unit/components/my-component.test.tsx
yarn jest --testNamePattern="should handle"
yarn test:unit --coverage
yarn test:e2e
Common Patterns
Component Testing
import { render, screen, fireEvent } from "@testing-library/react";
import { MyComponent } from "@/components/my-component";
describe("MyComponent", () => {
it("renders correctly", () => {
render(<MyComponent />);
expect(screen.getByRole("button")).toBeInTheDocument();
});
it("handles click events", async () => {
const onClickMock = jest.fn();
render(<MyComponent onClick={onClickMock} />);
fireEvent.click(screen.getByRole("button"));
expect(onClickMock).toHaveBeenCalledTimes(1);
});
});
API Route Testing
import { GET } from "@/app/api/my-route/route";
import { NextRequest } from "next/server";
describe("GET /api/my-route", () => {
it("returns 200 with data", async () => {
const request = new NextRequest("http://localhost:3000/api/my-route");
const response = await GET(request);
expect(response.status).toBe(200);
const data = await response.json();
expect(data).toHaveProperty("success", true);
});
});
Mocking Prisma
jest.mock("@/lib/prisma", () => ({
prisma: {
user: {
findUnique: jest.fn(),
create: jest.fn(),
},
},
}));
Evidence Template for Linear
When completing test work, attach this evidence block:
**Test Execution Evidence**
**Test Suite**: [unit/integration/e2e]
**Files Changed**: [list files]
**Test Results:**
- Total Tests: [X]
- Passed: [X]
- Failed: [0]
- Skipped: [X]
**Coverage** (if applicable):
- Statements: X%
- Branches: X%
- Functions: X%
- Lines: X%
**Commands Run:**
\`\`\`bash
yarn test:unit --coverage
\`\`\`
**Output:**
[Paste relevant test output]
Pre-Push Validation
Always run before pushing:
yarn ci:validate
This runs:
- Type checking
- ESLint
- Unit tests
- Format check
Authoritative References
- Jest Config:
jest.config.js
- Test Setup:
__tests__/setup.ts
- RLS Context:
lib/rls-context.ts
- CI Validation:
package.json scripts
Source: bybren-llc/rendertrust — distributed by TomeVault.