skills/testing/SKILL.md
Comprehensive testing skill covering TDD, E2E, BDD, contract testing, mutation testing, and visual regression. Use when writing tests, designing test strategy, adding test coverage, fixing flaky tests, mocking services, setting up testing frameworks, or any testing task. Triggers on 'write tests', 'add test coverage', 'test strategy', 'fix flaky test', 'mock', 'E2E test', 'unit test', 'integration test'.
npx skillsauth add michelabboud/claude-code-helper skills/testingInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Comprehensive testing toolkit covering test generation, TDD workflows, E2E patterns, BDD frameworks, contract testing, mutation testing, and visual regression testing.
/testing src/utils/validation.ts unit # Generate unit tests
/testing src/services/user-service # Auto-detect test type
/testing "user registration flow" e2e # Generate E2E tests
/testing tdd # TDD Red-Green-Refactor workflow
/testing e2e # Advanced E2E patterns
/testing bdd # BDD with Cucumber/Gherkin
/testing contract # Contract testing with Pact
/testing mutation # Mutation testing guidance
/testing visual # Visual regression testing
Generate tests by specifying a target and optional type.
| Type | Description | Speed | Scope |
|------|-------------|-------|-------|
| unit | Single functions/methods | Fast (<100ms) | Isolated |
| integration | Module interactions | Moderate | Connected |
| e2e | Complete user flows | Slow | Full stack |
| api | API endpoint tests | Moderate | HTTP layer |
| component | React/Vue component tests | Fast | UI layer |
describe('Component/Function Name', () => {
it('should do something specific', () => {
// Arrange - Set up test data
const input = { foo: 'bar' }
// Act - Execute the code
const result = functionUnderTest(input)
// Assert - Verify results
expect(result).toEqual(expectedOutput)
})
})
| Framework | Language | Use Case | |-----------|----------|----------| | Jest | JavaScript/TypeScript | General testing | | Vitest | Vite projects | Fast ESM-native testing | | pytest | Python | Python testing | | RSpec | Ruby | Ruby testing | | JUnit | Java | Java testing |
it('should return 401 when token is expired')describe('UserService', () => {
describe('createUser', () => {
it('should create user with valid data', async () => {
const userData = { email: '[email protected]', name: 'Test' };
const user = await service.createUser(userData);
expect(user.id).toBeDefined();
expect(user.email).toBe('[email protected]');
});
it('should throw error for duplicate email', async () => {
await service.createUser({ email: '[email protected]', name: 'A' });
await expect(
service.createUser({ email: '[email protected]', name: 'B' })
).rejects.toThrow('Email already registered');
});
it('should hash password before saving', async () => {
const user = await service.createUser({
email: '[email protected]', password: 'plain123',
});
expect(user.password).not.toBe('plain123');
expect(user.password).toMatch(/^\$2[aby]\$/);
});
});
});
/testing tdd -- TDD Red-Green-RefactorFake It Till You Make It -- Start with hardcoded values, add tests to force generalization:
// Test 1 -> hardcode return 'Hello, Alice!'
// Test 2 (greet('Bob')) -> forced to implement `Hello, ${name}!`
Triangulation -- Use multiple test cases to force a general solution.
One to Many -- Start with a single item, then generalize to collections.
/testing e2e -- Advanced E2E with Playwright// tests/auth.setup.ts -- authenticate once, save state
setup('authenticate', async ({ page }) => {
await page.goto('/login')
await page.fill('[data-testid="email"]', '[email protected]')
await page.fill('[data-testid="password"]', 'Password123')
await page.click('[data-testid="login-button"]')
await page.waitForURL('**/dashboard')
await page.context().storageState({ path: 'playwright/.auth/user.json' })
})
Configure in playwright.config.ts with dependencies: ['setup'] and storageState.
test.describe('Admin Role', () => {
test.use({ storageState: 'playwright/.auth/admin.json' })
test('admin can access settings', async ({ page }) => { /* ... */ })
})
test.describe('User Role', () => {
test.use({ storageState: 'playwright/.auth/user.json' })
test('user cannot access admin settings', async ({ page }) => { /* ... */ })
})
await page.route('**/api/products', async (route) => {
await route.fulfill({ status: 200, body: JSON.stringify({ products: [...] }) })
})
Mock errors (500s), slow responses (setTimeout), and verify request payloads with page.waitForRequest.
Encapsulate page interactions in classes (LoginPage, DashboardPage) for reusability and maintainability.
setInputFiles(), page.waitForEvent('download')projects in playwright.config.ts for chromium/firefox/webkitperformance.getEntriesByType('navigation') metrics and assert thresholds@axe-core/playwright with new AxeBuilder({ page }).analyze()/testing bdd -- BDD with Cucumber/GherkinFeature: User Authentication
Scenario: Successful login
Given a user exists with email "[email protected]" and password "Pass123"
When I login with those credentials
Then I should be redirected to the dashboard
| Framework | Language | Install |
|-----------|----------|---------|
| Cucumber | JS/TS | npm i -D @cucumber/cucumber |
| Behave | Python | pip install behave |
| SpecFlow | C#/.NET | NuGet: SpecFlow |
Given('a user exists with email {string} and password {string}',
async function(email: string, password: string) {
this.currentUser = await this.userService.createUser({ email, password })
})
When('I login with those credentials', async function() {
await this.authPage.login(this.currentUser.email, this.currentUser.password)
})
Then('I should be redirected to the dashboard', async function() {
expect(await this.authPage.getCurrentUrl()).toContain('/dashboard')
})
When I login with valid credentials not When I click the Login button and type...@smoke, @regression, @slownpx cucumber-js --tags "@smoke" # Run tagged tests
npx cucumber-js --tags "@regression and not @slow" # Combine tags
/testing contract -- Contract Testing with PactConsumer defines expectations -> Generates contract file -> Provider verifies it
Both sides test independently, no need to run both services simultaneously.
const provider = new PactV3({ consumer: 'FrontendApp', provider: 'UserService' })
test('gets a user by ID', async () => {
await provider
.given('user with ID 123 exists')
.uponReceiving('a request for user 123')
.withRequest({ method: 'GET', path: '/users/123' })
.willRespondWith({
status: 200,
body: { id: like(123), name: like('John'), email: like('[email protected]') }
})
.executeTest(async (mockServer) => {
const user = await userService.getUser(123)
expect(user.name).toBe('John')
})
})
Use Verifier with stateHandlers to set up test data for each provider state. Publish results to Pact Broker for deployment safety (can-i-deploy).
like() (type), eachLike() (array), regex(), iso8601DateTime(), uuid(), integer(), decimal(), boolean()
GraphQLInteraction with queries/mutationsMessageConsumerPact for async event-driven architecturesoptional() for backward-compatible new fields/testing mutation -- Mutation TestingMutation testing introduces controlled bugs (mutants) into your code and checks if tests catch them. Surviving mutants reveal test gaps.
Mutation Score = (Killed Mutants / Total Mutants) x 100%
Target: 80-90% for critical code
| Tool | Language | Install |
|------|----------|---------|
| Stryker | JS/TS | npm i -D @stryker-mutator/core && npx stryker init |
| PITest | Java | Maven plugin pitest-maven |
| Mutmut | Python | pip install mutmut |
{
"testRunner": "jest",
"mutate": ["src/**/*.ts", "!src/**/*.spec.ts"],
"thresholds": { "high": 80, "low": 60, "break": 50 },
"coverageAnalysis": "perTest"
}
npx stryker run # Full run
npx stryker run --mutate "src/utils/calculator.ts" # Specific file
npx stryker run --incremental # Changed files only
+ to -, * to /> to >=, == to !=&& to ||, remove !true to false, 0 to 1When a mutant survives, add a test that asserts the specific behavior the mutation breaks. Example: if price * (1 - discount) mutates to price * (1 + discount) and survives, add expect(discounted).toBeLessThan(original).
/testing visual -- Visual Regression TestingCSS layout changes, font rendering differences, color/styling changes, responsive design breakage, cross-browser rendering issues.
| Tool | Type | Best For |
|------|------|----------|
| Percy | SaaS | Playwright/Cypress integration |
| Chromatic | SaaS | Storybook component testing |
| BackstopJS | Self-hosted | Free, CI-friendly |
| Playwright | Built-in | toHaveScreenshot() comparisons |
// Element snapshot
await expect(page.locator('[data-testid="button"]'))
.toHaveScreenshot('button.png', { threshold: 0.2, maxDiffPixels: 100 })
// Full page snapshot
await expect(page).toHaveScreenshot('homepage.png', {
fullPage: true, animations: 'disabled'
})
import percySnapshot from '@percy/playwright'
await percySnapshot(page, 'Homepage')
// Run: PERCY_TOKEN=xxx npx percy exec -- playwright test
Write stories with chromatic: { viewports: [320, 768, 1200] } parameter. Run npx chromatic --project-token=xxx.
networkidle, document.fonts.ready, image loadinghelloRespond with:
Hello! I'm Testing v2.0.0. Comprehensive testing skill covering test generation, TDD, E2E, BDD, contract testing, mutation testing, and visual regression. Use
/testing hello IDfor the full guide.
hello IDRespond with complete skill information:
/testing [target] [type] for test generation, or /testing tdd|e2e|bdd|contract|mutation|visual for specialized modes[target] [type] | tdd | e2e | bdd | contract | mutation | visual | hello | hello ID/testing skill with subcommandsAuthor: Michel Abboud License: Apache-2.0 Repository: claude-code-helper Issues & Discussions: GitHub Issues
development
Score a coding task by complexity (1-10) and recommend the right model (haiku/sonnet/opus) before invoking a language agent. Holds the per-language rubric for all language/framework experts.
tools
When the user asks about [TRIGGER WORDS], wants to [ACTION], or needs help with [TOPIC], use this skill to provide [CAPABILITY]
tools
Check if your claude-code-helper installation is up to date and apply updates. Reads the local manifest and compares against the latest component-versions index on GitHub. Supports checking all components, a single component by name, and applying updates with automatic backup.
testing
Refresh agent knowledge from official reference URLs. Fetches latest documentation, release notes, and changelogs to keep agents current. Supports refreshing a single agent, all agents, or checking refresh status.