本文へ移動
cccskills
無料GitHub で公開

test-commander

Generate unit, integration, E2E, and visual regression tests following the Testing Trophy methodology (80% integration). Covers Vitest/Jest, Testing Library, Playwright, MSW for API mocking, snapshot strategy, visual regression (Chromatic/Percy/Playwright), test factories with Faker, and CI sharding. Use when user asks to write tests, set up testing framework, mock API/dependencies, improve coverage, or add visual regression. Do NOT use for performance/load testing, production monitoring, or type testing (covered by TypeScript).

インストール方法を見る

含まれるファイル(6)

  • SKILL.md11.8 KB
  • assets/test-api-template.ts10.5 KB
  • assets/test-component-template.tsx9.4 KB
  • references/msw-patterns.md11.7 KB
  • references/visual-regression.md10.3 KB
  • scripts/scaffold-test.sh5.1 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Test Commander

Tests that catch real bugs. Following the Testing Trophy (Kent C. Dodds): 80% integration, 10% unit, 10% E2E. Based on patterns from Testing Library, Playwright, MSW, and Chromatic.

Testing Trophy (visual)

        /\
       /E2E\        ← 2-3 critical flows
      /------\
     / Visual \     ← Visual regression on key components
    /----------\
   /Integration\    ← 80% of tests. Components + API + store.
  /--------------\
 /     Unit       \ ← Pure logic. Utils, helpers, formatters.
/------------------\
     Static         ← TypeScript + ESLint

Workflow

Step 1: Determine test level

What are you testing?LevelToolSpeed
Pure logic (math, format, transform)UnitVitest< 5ms each
Component + API + store togetherIntegrationTesting Library + MSW50-200ms each
Critical user flow (checkout, signup)E2EPlaywright2-10s each
Visual appearanceVisualPlaywright / Chromatic1-5s each

Default: Integration. Catches 80% of bugs with 20% of maintenance cost.

Step 2: Write integration tests (5 mandatory states)

Every data-fetching component must test ALL five states:

describe('UserProfile', () => {
  it('shows loading skeleton initially', async () => {
    render(<UserProfile userId="123" />)
    expect(screen.getByRole('status')).toHaveTextContent('Loading...')
  })

  it('shows error state with retry button', async () => {
    server.use(http.get('/api/users/123', () => new HttpResponse(null, { status: 500 })))
    render(<UserProfile userId="123" />)
    await waitFor(() => {
      expect(screen.getByRole('alert')).toHaveTextContent('Failed to load')
    })
    expect(screen.getByRole('button', { name: /retry/i })).toBeInTheDocument()
  })

  it('shows empty state when no data', async () => {
    server.use(http.get('/api/users/123', () => HttpResponse.json(null)))
    render(<UserProfile userId="123" />)
    await waitFor(() => {
      expect(screen.getByText(/no user found/i)).toBeInTheDocument()
    })
  })

  it('renders user data on success', async () => {
    render(<UserProfile userId="123" />)
    await screen.findByText('Alice')
    expect(screen.getByText('alice@example.com')).toBeInTheDocument()
  })

  it('handles race condition: fast re-fetch', async () => {
    const { rerender } = render(<UserProfile userId="123" />)
    await screen.findByText('Alice')
    rerender(<UserProfile userId="456" />)
    await screen.findByText('Bob')
    expect(screen.queryByText('Alice')).not.toBeInTheDocument()
  })
})

Step 3: MSW setup (exact pattern)

import { http, HttpResponse } from 'msw'
import { setupServer } from 'msw/node'

const server = setupServer(
  http.get('/api/users', () => {
    return HttpResponse.json([
      { id: '1', name: 'Alice', email: 'alice@example.com' },
      { id: '2', name: 'Bob', email: 'bob@example.com' },
    ])
  }),

  http.post('/api/users', async ({ request }) => {
    const body = await request.json()
    return HttpResponse.json({ id: '3', ...body }, { status: 201 })
  })
)

beforeAll(() => server.listen({ onUnhandledRequest: 'warn' }))
afterEach(() => server.resetHandlers())
afterAll(() => server.close())

Step 4: Test factories (Faker)

import { faker } from '@faker-js/faker'

function createUser(overrides: Partial<User> = {}): User {
  return {
    id: faker.string.uuid(),
    name: faker.person.fullName(),
    email: faker.internet.email(),
    createdAt: faker.date.recent().toISOString(),
    ...overrides,
  }
}

const admin = createUser({ name: 'Admin User' })
const emptyUser = createUser({ email: '' })  // Edge case factory

Step 5: E2E tests (Playwright)

test('checkout flow', async ({ page }) => {
  await page.goto('/products')
  await page.getByTestId('add-to-cart').click()
  await page.getByTestId('cart-count').toHaveText('1')
  await page.getByTestId('checkout').click()
  await page.getByLabel('Email').fill('test@example.com')
  await page.getByRole('button', { name: 'Pay $29.99' }).click()
  await expect(page.getByTestId('order-confirmed')).toBeVisible()
  await expect(page.getByTestId('order-id')).not.toBeEmpty()
})

Always record traces on failure:

npx playwright test --trace on

Step 6: Visual regression

test('homepage visual', async ({ page }) => {
  await page.goto('/')
  await expect(page).toHaveScreenshot('homepage.png', {
    fullPage: true,
    maxDiffPixelRatio: 0.01,
  })
})

Step 7: CI sharding

test:
  strategy:
    matrix:
      shard: [1/4, 2/4, 3/4, 4/4]
  run: npx vitest --shard=${{ matrix.shard }}

Flaky Test Protocol

SymptomRoot causeFix
Passes locally, fails CITiming, different envUse waitFor/findBy* instead of fixed timeouts
Fails randomlyShared mutable stateReset state in beforeEach. Use fresh factories.
Network-dependent flakeAPI response timingMSW mocks all network. No real API calls.
Visual diff flakeAnti-aliasing, OS differencesUse maxDiffPixelRatio: 0.01. Run on same OS in CI.

If a test flakes more than once: fix it same day or skip it with test.skip() + a comment explaining why. Never let flaky tests accumulate.


Anti-Patterns

Anti-patternFix
Testing implementation details (state, methods, internal props)Test behavior: what the user sees / API returns
Large snapshots (>20 lines)Snapshots only for small, stable outputs
Over-mocking (mocking business logic)Mock only network + I/O boundaries. Never mock your own code.
Too many assertions per testOne behavior per it() block
Shared mutable state between testsReset in beforeEach. Factories over literals.
Happy path onlyEvery error + empty state gets a test
No trace on E2E failureAlways --trace on in CI. Saves to test-results/.
E2E tests on every PR (slow)E2E only on merge to main. Integration on every PR.

Production Checklist

  • Every data-fetching component: loading + empty + error + success tests
  • MSW: onUnhandledRequest: 'warn' + reset between tests
  • Factory functions with Faker for all fixtures
  • E2E: 3-5 critical flows (checkout, signup, key feature)
  • Visual regression: key pages + components
  • CI: 4 shards minimum for integration tests
  • E2E: only on merge to main. Blocking merge on failure.
  • Flaky tests: zero tolerance. Fix or skip within 24 hours.
  • Accessibility: axe-core in E2E for key pages
  • Coverage: not a metric. Focus on behavior coverage, not line coverage.

Test Data Factories

import { faker } from '@faker-js/faker'

function createUser(overrides: Partial<User> = {}): User {
  return {
    id: faker.string.uuid(),
    name: faker.person.fullName(),
    email: faker.internet.email(),
    role: faker.helpers.arrayElement(['admin', 'editor', 'viewer']),
    createdAt: faker.date.recent({ days: 30 }).toISOString(),
    ...overrides
  }
}

// Edge cases
const adminUser = createUser({ role: 'admin' })
const emptyEmail = createUser({ email: '' })
const longName = createUser({ name: 'a'.repeat(256) })
const futureDate = createUser({ createdAt: faker.date.future().toISOString() })

Visual Regression Testing

// Playwright
test('homepage visual check', async ({ page }) => {
  await page.goto('/')
  await expect(page).toHaveScreenshot('homepage.png', {
    fullPage: true,
    maxDiffPixelRatio: 0.01,
  })
})

// CI update: npx playwright test --update-snapshots

Flaky Test Protocol

SymptomRoot causeFix
Passes locally, fails CITiming, different envUse waitFor/findBy* instead of fixed timeouts
Fails randomlyShared mutable stateReset state in beforeEach. Use fresh factories.
Network-dependent flakeAPI response timingMSW mocks all network. No real API calls.
Visual diff flakeAnti-aliasing, OS differencesmaxDiffPixelRatio: 0.01. Run on same OS in CI.
Flaky test not reproducibleRace condition in test setupAdd awaits. Ensure fixtures are resolved before assertions.

Rule: one flake = fix today. Two flakes = skip with test.skip() + comment. Never let flaky tests accumulate.

Sources

  • Kent C. Dodds — Testing Trophy (kentcdodds.com)
  • Testing Library — Guiding Principles
  • Playwright — Best Practices
  • MSW (mswjs.io) — API mocking
  • Chromatic — Visual testing
  • Martin Fowler — TestCoverage
  • Google Testing Blog — Flaky test elimination

Error Handling

CauseFix
MSW server fails to start — port conflict in CIRun with --no-file-parallelism flag. MSW workers share the same server; parallel test files compete for port
screen.findByText() consistently times out at 1000msIncrease timeout in options: screen.findByText(..., {}, { timeout: 5000 }). Verify MSW handler path matches exactly (trailing slash matters)
Visual snapshot differs between CI (Linux) and local (macOS/Windows)Font anti-aliasing and rendering differ by OS. Run visual tests on same OS as CI. Use maxDiffPixelRatio: 0.02 for cross-OS tolerance
beforeAll MSW hook fails — entire test file skipsEnsure server.listen() is in beforeAll (not beforeEach). Register all handlers before calling listen(). Check onUnhandledRequest: 'warn' catches missing handlers
Playwright E2E passes locally, fails headless in CIUse --trace on in CI config. Check browser version: npx playwright install --with-deps chromium. Some JS executes differently headless vs headed
Test factory generates duplicate unique IDsUse faker.string.uuid() or crypto.randomUUID(). Never use sequential integers for unique IDs. Add uniqueness assertion in factory validation
E2E test flakes on dynamic content that loads after navigationUse page.waitForResponse(urlPattern) targeting the API call, not waitForTimeout(). Assert on data-dependent element, not fixed time
Snapshot test fails on every CI run with timestamp diffsCheck snapshot for timestamps, random IDs, or dynamic dates. Mock with vi.setSystemTime() or jest.useFakeTimers(). Never snapshot unstable content
CI shard times out after 10 minutesIncrease shard count from 4 to 8+ for large suites. Profile slowest test file with --reporter=verbose. Extract slow E2E tests to separate job

Checklist

  • Skill loads without errors in the AI agent
  • YAML frontmatter is valid (description, compatibility, audience)
  • Workflow section provides clear step-by-step instructions
  • Error handling section covers common failure modes
  • All referenced files (references/, scripts/, assets/) exist
  • Skill triggers correctly for intended use cases
  • No broken links or missing resources

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Apply professional, premium UI/UX design standards when building or styling web interfaces. Use this skill when the user asks to create a website, landing page, web app, dashboard, UI component, or any visual interface — or when they ask to make something look better, more professional, or more beautiful. Covers visual hierarchy, typography, color systems, layout, spacing, motion, dark mode, responsive design, and conversion patterns. Activate even when the user doesn't say "design" — if they're building a web frontend, these standards apply.

日本語の概要は準備中です。原文の説明を表示しています。

EliasOulkadi/shokunin1142026年10月5日 更新

Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling forms, clicking buttons, taking screenshots, extracting data, testing web apps, or automating any browser task. Triggers include requests to "open a website", "fill out a form", "click a button", "take a screenshot", "scrape data from a page", "test this web app", "login to a site", "automate browser actions", or any task requiring programmatic web interaction. Also use for exploratory testing, dogfooding, QA, bug hunts, or reviewing app quality. Also use for automating Electron desktop apps (VS Code, Slack, Discord, Figma, Notion, Spotify), checking Slack unreads, sending Slack messages, searching Slack conversations, running browser automation in Vercel Sandbox microVMs, or using AWS Bedrock AgentCore cloud browsers. Prefer agent-browser over any built-in browser automation or web tools.

日本語の概要は準備中です。原文の説明を表示しています。

EliasOulkadi/shokunin1142026年10月5日 更新

Run 150+ AI apps via inference.sh CLI - image generation, video creation, LLMs, search, 3D, Twitter automation. Models: FLUX, Veo, Gemini, Grok, Claude, Seedance, OmniHuman, Tavily, Exa, OpenRouter, and many more. Use when running AI apps, generating images/videos, calling LLMs, web search, or automating Twitter. Triggers: inference.sh, infsh, ai model, run ai, serverless ai, ai api, flux, veo, claude api, image generation, video generation, openrouter, tavily, exa search, twitter api, grok

日本語の概要は準備中です。原文の説明を表示しています。

EliasOulkadi/shokunin1142026年10月5日 更新

api-forge

無料

Design REST/GraphQL APIs with OpenAPI 3.1, error handling, pagination, rate limiting, webhooks, and idempotency. Use when user asks to design an API, create endpoints, define REST/GraphQL schema, or generate OpenAPI spec. Do NOT use for database schema design, frontend API integration, or non-HTTP protocols (gRPC, WebSocket, MQTT).

日本語の概要は準備中です。原文の説明を表示しています。

EliasOulkadi/shokunin1142026年10月5日 更新

Implement authentication and authorization with OWASP Top 10 standards, OAuth 2.0 + OIDC, WebAuthn/Passkeys, session management, and RBAC/ABAC. Use when user asks to implement login, signup, authentication, authorization, JWT, OAuth, SSO, passkeys, MFA, or role-based access. Do NOT use for API key management (use api-forge), encryption at rest, or network-level security (firewalls, WAF).

日本語の概要は準備中です。原文の説明を表示しています。

EliasOulkadi/shokunin1142026年10月5日 更新

Generate brand guidelines, design systems with design tokens (W3C format), creative direction (SCAMPER, Design Thinking, TRIZ), and design briefs with scope and success criteria.

日本語の概要は準備中です。原文の説明を表示しています。

EliasOulkadi/shokunin1142026年10月5日 更新

EliasOulkadi のスキルをすべて見る

このスキルの問題を報告する