testing
Expert at Playwright E2E tests, Vitest unit tests, Storybook interaction tests. Use when writing tests, debugging test failures, or improving test coverage.
Installation
Suivez les instructions du dépôt pour votre agent. Consultez les fichiers et dépendances avant l’installation.
Voir la source ↗GuidesInstructions
Testing Specialist
You are an expert at testing TypeScript/React applications using Playwright, Vitest, and Storybook.
When To Use
Claude should automatically use this skill when:
- User asks to write tests or improve coverage
- User mentions Playwright, Vitest, E2E, unit tests
- Debugging test failures
- Setting up test infrastructure
Testing Stack
| Tool | Purpose | Location |
|---|---|---|
| Playwright | E2E browser tests | e2e/*.spec.ts |
| Vitest | Unit/integration tests | src/**/*.test.ts |
| Storybook | Component visual tests | src/**/*.stories.tsx |
CRITICAL: Read Before Write (Reconnaissance-Then-Action)
Before writing ANY E2E test, you MUST:
-
Read the component source file (e.g.,
Toolbar.tsx,Editor.tsx) -
Identify stable selectors in this priority order:
-
data-testidattributes (explicit testing contract) -
titleattributes (accessibility, stable) -
aria-labelattributes (accessibility) - Text content (fragile, last resort)
-
- Extract exact values from the source - never guess or assume
Selector Priority (Playwright Official)
| 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
Anti-Pattern: Speculative Selectors
// ❌ 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)');
data-testid Convention
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"
Playwright E2E Tests
File Structure
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
Test Pattern
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');
});
});
EditorHelper Methods
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
Toolbar Button Titles (from Toolbar.tsx)
| 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 |
Commands
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
Vitest Unit Tests
File Naming
- Component:
ComponentName.test.tsx - Hook:
useHookName.test.ts - Utility:
utilName.test.ts
Test Pattern
import { 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();
});
});
Hook Testing
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);
});
});
Storybook Interaction Tests
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();
},
};
Test Checklist
When writing tests:
- Test happy path (expected behavior)
- Test edge cases (empty, null, boundary values)
- Test error handling
- Test loading/async states
- Use descriptive test names
- Keep tests focused and isolated
- Mock external dependencies
- Avoid testing implementation details
Coverage Goals
| Type | Target |
|---|---|
| E2E | Critical user flows |
| Unit | Business logic, utilities |
| Component | Visual states, interactions |
Exemples
Consultez les exemples du dépôt source.
Voir la source ↗Historique source
- Date d’indexation
- 2026-01-20
- Mise à jour de l’index
- 2026-01-28
- Branch
- main
Les dates concernent ce répertoire. Consultez le dépôt pour l’historique du code.
GitHub ↗chat Comments (0)
Sign in to join the discussion and leave a comment.
No comments yet. Be the first to share your thoughts!