一键导入
testing
Vitest + Testing Library patterns for unit tests, Playwright for integration/e2e tests. Use when writing tests or adding test coverage.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Vitest + Testing Library patterns for unit tests, Playwright for integration/e2e tests. Use when writing tests or adding test coverage.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Design-token and theming conventions for the Starter — semantic CSS variables in theme.css, Tailwind v4 @theme registration in globals.css, dark mode, and the Figma token-sync flow. Use when extracting repeated design values, adding/editing tokens, theming, or syncing tokens from Figma.
API service layer with ky/apiClient and Next.js API routes with Zod validation. Use when creating services, API endpoints, or HTTP calls.
Project file organization, naming conventions, and import patterns. Use when creating new files, organizing code, or deciding where to place modules.
Conventions when no auth provider is bundled. Use when adding authentication or guarding routes.
React component patterns — server vs client components, styling with cn(), props interfaces. Use when creating UI or shared components.
Use before writing or referencing any stack library — fetches version-accurate docs via the context7 MCP server so call signatures, hooks, and APIs match what is installed. Invoke on first usage of any non-none slot library, on any non-trivial Next.js API, or when uncertain whether an API is current.
| name | testing |
| description | Vitest + Testing Library patterns for unit tests, Playwright for integration/e2e tests. Use when writing tests or adding test coverage. |
| paths | ["src/**/__tests__/**","e2e/**"] |
Framework: Vitest + React Testing Library
Location: Co-located __tests__/ directories next to the code they test
import { describe, it, expect } from 'vitest'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { Button } from '../Button'
describe('Button', () => {
it('renders with text', () => {
render(<Button>Click me</Button>)
expect(screen.getByRole('button', { name: /click me/i })).toBeInTheDocument()
})
it('handles click events', async () => {
const user = userEvent.setup()
let clicked = false
render(
<Button
onClick={() => {
clicked = true
}}
>
Click
</Button>
)
await user.click(screen.getByRole('button'))
expect(clicked).toBe(true)
})
})
import { describe, it, expect, beforeEach } from 'vitest'
import { useMyStore } from '../my.store'
describe('useMyStore', () => {
beforeEach(() => {
useMyStore.setState({ items: [] })
})
it('adds an item', () => {
useMyStore.getState().addItem({ id: '1', name: 'Test' })
expect(useMyStore.getState().items).toHaveLength(1)
})
})
import { describe, it, expect } from 'vitest'
import { loginSchema } from '../auth'
describe('loginSchema', () => {
it('accepts valid data', () => {
const result = loginSchema.safeParse({ email: 'a@b.com', password: 'pass' })
expect(result.success).toBe(true)
})
it('rejects invalid email', () => {
const result = loginSchema.safeParse({ email: 'bad', password: 'pass' })
expect(result.success).toBe(false)
})
})
When a component internally calls useQuery or useMutation, wrap it with a fresh QueryClient per test to avoid cache bleed between tests:
import { describe, it, expect } from 'vitest'
import { render, screen } from '@testing-library/react'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { UserCard } from '../UserCard'
function renderWithQuery(ui: React.ReactElement) {
const queryClient = new QueryClient({
defaultOptions: { queries: { retry: false } },
})
return render(<QueryClientProvider client={queryClient}>{ui}</QueryClientProvider>)
}
describe('UserCard', () => {
it('renders loading state', () => {
renderWithQuery(<UserCard userId="1" />)
expect(screen.getByRole('status')).toBeInTheDocument()
})
})
src/**/__tests__/*.test.{ts,tsx}describe blocks to group related testsit (not test) for test casesscreen.getByRole() queries for accessibilityuserEvent over fireEvent for user interactionsuserEvent.setup() before interactingQueryClient per test with retry: falsenpm run test (watch) or npm run test:run (CI)console.log in tests — ESLint rule is relaxed for test filesFramework: Playwright
Location: e2e/ directory at project root
import { test, expect } from '@playwright/test'
// API route — use request fixture (no browser needed)
test('GET /api/health returns 200', async ({ request }) => {
const res = await request.get('/api/health')
expect(res.status()).toBe(200)
expect(await res.json()).toMatchObject({ status: 'ok', environment: expect.any(String) })
})
// Page smoke test — use page fixture
test('home page loads', async ({ page }) => {
await page.goto('/')
await expect(page).toHaveTitle(/Starter/)
})
e2e/**/*.spec.tstest (not it) — Playwright conventionrequest fixture for API route tests (no browser needed)page fixture for page-level E2E testsnpm run test:e2e or npm run test:e2e:ui (visual mode)playwright.config.ts at project rootwebServer configplaywright.config.ts if needed