Files
2025-11-30 08:47:23 +08:00

5.7 KiB

name, description
name description
test-generator WHEN: Test code generation, unit/integration/E2E test writing, component/hook/utility tests WHAT: Framework detection + Jest/Vitest/RTL/Playwright templates + Happy Path/Edge/Error case tests WHEN NOT: Coverage analysis → coverage-analyzer, Test quality review → code-reviewer

Test Generator Skill

Purpose

Automatically generates tests by detecting project test framework and applying appropriate patterns.

When to Use

  • Test generation requests
  • New component/function needs tests
  • Unit, E2E, integration test mentions
  • Coverage improvement needed

Framework Detection

Test Runners

Framework Detection package.json
Jest jest.config.* jest
Vitest vitest.config.* vitest
Playwright playwright.config.* @playwright/test
Cypress cypress.config.* cypress

Test Libraries

Library Purpose package.json
RTL React components @testing-library/react
Vue Test Utils Vue components @vue/test-utils

Workflow

Step 1: Detect Environment

**Runner**: Jest
**Library**: React Testing Library
**Config**: jest.config.js
**Test Dir**: __tests__/, *.test.tsx

Step 2: Select Target

AskUserQuestion:

"Which code to test?"
Options:
- Specific file/component
- Auto-detect untested files
- Recently changed files
- Entire directory

Step 3: Select Test Type

AskUserQuestion:

"What type of tests?"
Options:
- Unit Test
- Integration Test
- Component Test
- E2E Test (Playwright/Cypress)

Step 4: Coverage Goal

AskUserQuestion:

"Coverage goal?"
Options:
- Happy Path only
- Happy Path + Edge Cases
- Full (including errors)
- Specify scenarios

Test Templates

React Component (Jest + RTL)

import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { Component } from './Component'

describe('Component', () => {
  const defaultProps = { /* ... */ }
  const renderComponent = (props = {}) =>
    render(<Component {...defaultProps} {...props} />)

  describe('Rendering', () => {
    it('renders with default state', () => {
      renderComponent()
      expect(screen.getByRole('button')).toBeInTheDocument()
    })
  })

  describe('Interactions', () => {
    it('calls callback on click', async () => {
      const onClick = jest.fn()
      renderComponent({ onClick })
      await userEvent.click(screen.getByRole('button'))
      expect(onClick).toHaveBeenCalledTimes(1)
    })
  })

  describe('Edge Cases', () => {
    it('handles empty data', () => {
      renderComponent({ data: [] })
      expect(screen.getByText('No data')).toBeInTheDocument()
    })
  })
})

React Hook

import { renderHook, act, waitFor } from '@testing-library/react'
import { useCustomHook } from './useCustomHook'

describe('useCustomHook', () => {
  it('returns initial state', () => {
    const { result } = renderHook(() => useCustomHook())
    expect(result.current.value).toBe(initialValue)
  })

  it('updates state', () => {
    const { result } = renderHook(() => useCustomHook())
    act(() => { result.current.setValue('new') })
    expect(result.current.value).toBe('new')
  })
})

Utility Function

import { utilityFunction } from './utils'

describe('utilityFunction', () => {
  it('processes valid input', () => {
    expect(utilityFunction('valid')).toBe('expected')
  })

  describe('Edge Cases', () => {
    it('handles empty string', () => {
      expect(utilityFunction('')).toBe('')
    })

    it('handles null', () => {
      expect(utilityFunction(null)).toBeNull()
    })
  })

  describe('Errors', () => {
    it('throws on invalid input', () => {
      expect(() => utilityFunction(undefined)).toThrow()
    })
  })
})

E2E (Playwright)

import { test, expect } from '@playwright/test'

test.describe('User Flow: Login', () => {
  test.beforeEach(async ({ page }) => {
    await page.goto('/login')
  })

  test('logs in successfully', async ({ page }) => {
    await page.getByLabel('Email').fill('user@example.com')
    await page.getByLabel('Password').fill('password123')
    await page.getByRole('button', { name: 'Login' }).click()
    await expect(page).toHaveURL('/dashboard')
  })

  test('shows error on invalid credentials', async ({ page }) => {
    await page.getByLabel('Email').fill('wrong@example.com')
    await page.getByLabel('Password').fill('wrong')
    await page.getByRole('button', { name: 'Login' }).click()
    await expect(page.getByRole('alert')).toContainText('Login failed')
  })
})

Response Template

## Tests Generated

**Target**: src/components/Button.tsx
**Output**: src/components/__tests__/Button.test.tsx
**Runner**: Jest + RTL

### Test Cases
| Category | Test | Description |
|----------|------|-------------|
| Rendering | Default render | Renders correctly |
| Interaction | Click event | onClick callback |
| Edge Case | Long text | Overflow handling |

### Run
\`\`\`bash
npm test -- Button.test.tsx
npm test -- --coverage Button.test.tsx
\`\`\`

### Expected Coverage
- Lines: ~90%
- Branches: ~85%
- Functions: ~100%

Best Practices

  1. AAA Pattern: Arrange-Act-Assert
  2. Clear Names: Expected behavior in test name
  3. Independence: Each test runs independently
  4. Minimal Mocking: Mock only when necessary
  5. Real User Behavior: Prefer user-event

Integration

  • /generate-tests command
  • coverage-analyzer skill
  • code-reviewer skill

Notes

  • Follows existing test patterns if present
  • Test file location matches project structure
  • Mocking based on actual implementation analysis