Skip to content
Development
Skill

/testing-patterns

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.

From plugin
safe-agentic-workflow
42920 skills11 agents24 commands

Claude Code

$ npx -y skills add bybren-llc/safe-agentic-workflow --skill testing-patterns --agent claude-code

SKILL.md

testing-patterns.SKILL.md
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.
allowed-tools: Read, Bash, Grep, Glob

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

// FORBIDDEN: Direct Prisma calls in tests (bypass RLS)
const user = await prisma.user.findUnique({ where: { user_id } });

// FORBIDDEN: Shared test state (causes flaky tests)
let sharedUser: User;
beforeAll(() => { sharedUser = createUser(); });

// FORBIDDEN: Hard-coded IDs (test pollution)
const userId = "user-123";

// FORBIDDEN: Missing cleanup (leaky tests)
it("creates user", async () => {
  await prisma.user.create({ data: userData });
  // No cleanup!
});

✅ CORRECT Patterns

// CORRECT: Use RLS context helpers
const user = await withSystemContext(prisma, "test", async (client) => {
  return client.user.findUnique({ where: { user_id } });
});

// CORRECT: Isolated test state per test
beforeEach(() => {
  const testUser = createTestUser();
});

// CORRECT: Unique identifiers
const userId = `user-${crypto.randomUUID()}`;
const email = `test-${Date.now()}@example.com`;

// CORRECT: Proper cleanup
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 () => {
    // Create test user with RLS context
    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();
      },
    );
    // RLS ensures only this user's payments returned
    expect(payments.every((p) => p.user_id === testUserId)).toBe(true);
  });
});

Test Isolation

Use unique identifiers to prevent test pollution:

const uniqueEmail = `test-${Date.now()}@example.com`;
const uniqueUserId = `user-${crypto.randomUUID()}`;

Test Commands

# Run all unit tests
yarn test:unit

# Run integration tests
yarn test:integration

# Run specific test file
yarn jest __tests__/unit/components/my-component.test.tsx

# Run tests matching pattern
yarn jest --testNamePattern="should handle"

# Run with coverage
yarn test:unit --coverage

# Run E2E tests
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 C
Read more
@bybren-llc
Ships withsafe-agentic-workflow

SAW — SAFe Agentic Workflow AI Agent Harness for Multi-Agent Team Workflows Built on SAFe methodology (Scaled Agile Framework), adapted for AI agent teams (Now With AI-DLC!) Works for any team with repeatable processes: Software, Marketing, Research, Legal, Operations.

42920 skills11 agents
Get the whole plugin

Stars on GitHub

Momentum

stars in total
429
Star history of bybren-llc/safe-agentic-workflow on GitHub, a chart by star-history.com

Other skills on safe-agentic-workflow.

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills13d309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc2w293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react4d252k
@facebook@facebookInstall Skill

Questions about testing-patterns.

Which coding agents can use testing-patterns?
testing-patterns installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.