一键导入
testing
Expert at Playwright E2E tests, Vitest unit tests, Storybook interaction tests. Use when writing tests, debugging test failures, or improving test coverage.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Expert at Playwright E2E tests, Vitest unit tests, Storybook interaction tests. Use when writing tests, debugging test failures, or improving test coverage.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Expert at TypeScript strict mode, linting, formatting, code review standards. Use when checking code quality, fixing type errors, or enforcing standards.
Expert at TSDoc comments, Storybook stories, VitePress docs, TypeDoc API generation. Use when documenting code, adding comments, creating stories, or generating API docs.
| name | testing |
| description | Expert at Playwright E2E tests, Vitest unit tests, Storybook interaction tests. Use when writing tests, debugging test failures, or improving test coverage. |
| allowed-tools | Read, Write, Edit, Bash, Grep, Glob |
You are an expert at testing TypeScript/React applications using Playwright, Vitest, and Storybook.
Claude should automatically use this skill when:
| Tool | Purpose | Location |
|---|---|---|
| Playwright | E2E browser tests | e2e/*.spec.ts |
| Vitest | Unit/integration tests | src/**/*.test.ts |
| Storybook | Component visual tests | src/**/*.stories.tsx |
Before writing ANY E2E test, you MUST:
Toolbar.tsx, Editor.tsx)data-testid attributes (explicit testing contract)title attributes (accessibility, stable)aria-label attributes (accessibility)| Priority | Method | Example | Stability |
|---|---|---|---|
| 1 | data-testid | page.getByTestId('save-btn') | Most stable |
| 2 | role + name | page.getByRole('button', { name: 'Save' }) | Stable |
| 3 | title | page.locator('[title="Save"]') | Stable |
| 4 | text | page.getByText('Save') | Fragile |
NEVER use: CSS classes, XPath, or auto-generated IDs
// ❌ WRONG - Guessing without reading source
await editor.clickToolbarButton('B'); // Assumes button text is "B"
// ✅ CORRECT - After reading Toolbar.tsx:54 shows title="Bold (Cmd+B)"
await editor.clickToolbarButton('Bold (Cmd+B)');
When adding test IDs to components, use format: {scope}-{element}-{type}
data-testid="toolbar-bold-button"
data-testid="editor-content-area"
data-testid="sidebar-note-list"
e2e/
├── fixtures/
│ └── editor-helpers.ts # Shared test utilities
├── editor.spec.ts # Editor functionality
├── formatting.spec.ts # Text formatting
├── headings.spec.ts # Heading toggles
├── lists.spec.ts # List operations
├── blocks.spec.ts # Block elements
├── keyboard-shortcuts.spec.ts
├── toolbar.spec.ts
└── history.spec.ts
import { test, expect } from '@playwright/test';
import { EditorHelper } from './fixtures/editor-helpers';
test.describe('Feature Name', () => {
let editor: EditorHelper;
test.beforeEach(async ({ page }) => {
editor = new EditorHelper(page);
await editor.goto();
});
test('descriptive test name', async () => {
await editor.type('test content');
await editor.selectAll();
// Use title from Toolbar.tsx - NOT guessed text
await editor.clickToolbarButton('Bold (Cmd+B)');
await editor.expectElement('strong');
});
});
editor.goto() // Navigate to app
editor.clear() // Clear editor content
editor.type(text) // Type text
editor.selectAll() // Select all (Cmd+A)
editor.clickToolbarButton(title) // Click toolbar button by title attribute
editor.isToolbarButtonActive(title) // Check button state by title
editor.expectText(text) // Assert text exists
editor.expectElement(selector) // Assert element exists
editor.pressShortcut(key) // Press keyboard shortcut
| Button | Title Attribute |
|---|---|
| Bold | Bold (Cmd+B) |
| Italic | Italic (Cmd+I) |
| Underline | Underline (Cmd+U) |
| Strike | Strikethrough |
| H1 | Heading 1 |
| H2 | Heading 2 |
| H3 | Heading 3 |
| Bullet List | Bullet List |
| Numbered List | Numbered List |
| Task List | Task List |
| Quote | Quote |
| Code | Code Block |
| Undo | Undo (Cmd+Z) |
| Redo | Redo (Cmd+Shift+Z) |
| New | New Document |
| Open | Open Document |
| Save | Save Document |
pnpm test:e2e # Run all E2E tests
pnpm test:e2e:ui # Open Playwright UI
pnpm test:e2e:headed # Run with browser visible
pnpm test:e2e:chromium # Chrome only
pnpm test:e2e:webkit # Safari only
ComponentName.test.tsxuseHookName.test.tsutilName.test.tsimport { describe, it, expect, vi } from 'vitest';
import { functionName } from './module';
describe('functionName', () => {
it('should do something', () => {
const result = functionName(input);
expect(result).toBe(expected);
});
it('should handle edge case', () => {
expect(() => functionName(null)).toThrow();
});
});
import { renderHook, act } from '@testing-library/react';
import { useHookName } from './useHookName';
describe('useHookName', () => {
it('should return initial state', () => {
const { result } = renderHook(() => useHookName());
expect(result.current.value).toBe(initial);
});
it('should update on action', async () => {
const { result } = renderHook(() => useHookName());
await act(async () => {
await result.current.doAction();
});
expect(result.current.value).toBe(updated);
});
});
import { within, userEvent, expect } from '@storybook/test';
export const WithInteraction: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
// Find and interact with elements
const button = canvas.getByRole('button', { name: 'Submit' });
await userEvent.click(button);
// Assert results
await expect(canvas.getByText('Success')).toBeInTheDocument();
},
};
When writing tests:
| Type | Target |
|---|---|
| E2E | Critical user flows |
| Unit | Business logic, utilities |
| Component | Visual states, interactions |