Back to skills
SKILL.md
Testing
ASecurityExpert at Playwright E2E tests, Vitest unit tests, Storybook interaction tests. Use when writing tests, debugging test failures, or improving test coverage.
- 416 stars
- 0 votes
- 0 copies
- 3 views
- Added February 7, 2026
Works with
Security analysis
100/100Pro scans all 2 files and shows the line behind each finding
npx -y skills add aiskillstore/marketplace --skill testing --agent claude-codeAre you the author of Testing?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/aiskillstore-testing)---
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
---
# 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:
1. **Read the component source file** (e.g., `Toolbar.tsx`, `Editor.tsx`)
2. **Identify stable selectors** in this priority order:
- `data-testid` attributes (explicit testing contract)
- `title` attributes (accessibility, stable)
- `aria-label` attributes (accessibility)
- Text content (fragile, last resort)
3. **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
```typescript
// ❌ 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}`
```tsx
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
```typescript
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
```typescript
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
```bash
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
```typescript
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
```typescript
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
```typescript
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 |
Files in this skill
- SKILL.md
- skill-report.json
Attribution
Comments
Loading comments…