Test Automation Expert Comprehensive testing guidance from unit to E2E. Designs test strategies, implements automation, and optimizes coverage for sustainable quality. When to Use Use for: - Designing test strategy for new projects - Setting up testing frameworks (Jest, Vitest, Playwright, Cypress, pytest) - Writing effective unit, integration, and E2E tests - Optimizing test coverage and eliminating gaps - Debugging flaky tests - CI/CD test pipeline configuration - Test-Driven Development (TDD) guidance - Mocking strategies and test fixtures Do NOT use for: - Manual QA test case writing - th…

: '\u003crootDir>/src/$1',\n '\\\\.(css|less|scss)

Test Automation Expert Comprehensive testing guidance from unit to E2E. Designs test strategies, implements automation, and optimizes coverage for sustainable quality. When to Use Use for: - Designing test strategy for new projects - Setting up testing frameworks (Jest, Vitest, Playwright, Cypress, pytest) - Writing effective unit, integration, and E2E tests - Optimizing test coverage and eliminating gaps - Debugging flaky tests - CI/CD test pipeline configuration - Test-Driven Development (TDD) guidance - Mocking strategies and test fixtures Do NOT use for: - Manual QA test case writing - th…

: 'identity-obj-proxy'\n },\n collectCoverageFrom: [\n 'src/**/*.{ts,tsx}',\n '!src/**/*.d.ts'\n ],\n coverageThreshold: {\n global: {\n branches: 75,\n functions: 80,\n lines: 80\n }\n }\n};\n```\n\n**Vitest (vitest.config.ts):**\n```typescript\nimport { defineConfig } from 'vitest/config';\nimport react from '@vitejs/plugin-react';\n\nexport default defineConfig({\n plugins: [react()],\n test: {\n environment: 'jsdom',\n setupFiles: ['./vitest.setup.ts'],\n globals: true,\n coverage: {\n provider: 'v8',\n reporter: ['text', 'json', 'html'],\n exclude: ['node_modules/', 'test/']\n }\n },\n resolve: {\n alias: {\n '@': '/src'\n }\n }\n});\n```\n\n## E2E Testing Frameworks\n\n### Comparison Matrix\n\n| Feature | Playwright | Cypress | Selenium |\n|---------|------------|---------|----------|\n| **Browsers** | All major | Chrome, FF, Edge | All major |\n| **Speed** | Fast | Fast | Slow |\n| **Parallel** | Native | Paid feature | External |\n| **Mobile** | Emulation | Limited | Appium |\n| **Network Mock** | Built-in | Built-in | Manual |\n| **Auto-wait** | Excellent | Good | Manual |\n| **Debugging** | Inspector, trace | Time travel | Limited |\n| **Language** | JS/TS/Python/C#/.NET | JS/TS only | Many |\n| **CI/CD** | Excellent | Good | Complex |\n| **Learning Curve** | Low | Low | High |\n| **Open Source** | Yes | Yes (core) | Yes |\n\n### When to Choose Each\n\n**Choose Playwright when:**\n- Cross-browser testing is critical\n- Need WebKit/Safari testing\n- API testing alongside E2E\n- Multiple language support needed\n- Complex scenarios (multiple tabs, auth)\n\n**Choose Cypress when:**\n- Developer experience is priority\n- React/Vue/Angular component testing\n- Team new to E2E testing\n- Single browser is acceptable\n- Real-time debugging needed\n\n**Choose Selenium when:**\n- Legacy infrastructure exists\n- Need language flexibility\n- Complex enterprise requirements\n- Grid-based parallel execution\n\n### Configuration Examples\n\n**Playwright (playwright.config.ts):**\n```typescript\nimport { defineConfig, devices } from '@playwright/test';\n\nexport default defineConfig({\n testDir: './e2e',\n fullyParallel: true,\n forbidOnly: !!process.env.CI,\n retries: process.env.CI ? 2 : 0,\n workers: process.env.CI ? 2 : undefined,\n reporter: [\n ['html'],\n ['junit', { outputFile: 'results.xml' }]\n ],\n use: {\n baseURL: 'http://localhost:3000',\n trace: 'on-first-retry',\n screenshot: 'only-on-failure'\n },\n projects: [\n {\n name: 'chromium',\n use: { ...devices['Desktop Chrome'] }\n },\n {\n name: 'firefox',\n use: { ...devices['Desktop Firefox'] }\n },\n {\n name: 'webkit',\n use: { ...devices['Desktop Safari'] }\n },\n {\n name: 'mobile-chrome',\n use: { ...devices['Pixel 5'] }\n }\n ],\n webServer: {\n command: 'npm run dev',\n url: 'http://localhost:3000',\n reuseExistingServer: !process.env.CI\n }\n});\n```\n\n**Cypress (cypress.config.ts):**\n```typescript\nimport { defineConfig } from 'cypress';\n\nexport default defineConfig({\n e2e: {\n baseUrl: 'http://localhost:3000',\n viewportWidth: 1280,\n viewportHeight: 720,\n video: false,\n screenshotOnRunFailure: true,\n retries: {\n runMode: 2,\n openMode: 0\n },\n setupNodeEvents(on, config) {\n // Task plugins\n on('task', {\n seedDatabase(data) {\n return db.seed(data);\n }\n });\n }\n },\n component: {\n devServer: {\n framework: 'react',\n bundler: 'vite'\n }\n }\n});\n```\n\n## Python Testing Frameworks\n\n### Comparison\n\n| Feature | pytest | unittest | nose2 |\n|---------|--------|----------|-------|\n| **Syntax** | Simple | Verbose | Simple |\n| **Fixtures** | Powerful | setUp/tearDown | Basic |\n| **Plugins** | 800+ | Limited | Some |\n| **Parametrize** | Built-in | SubTest | Plugin |\n| **Assertions** | Plain assert | self.assertEqual | Plain |\n| **Discovery** | Automatic | Manual | Automatic |\n| **Markers** | Flexible | Limited | Limited |\n| **Parallel** | pytest-xdist | No | Limited |\n\n### pytest Configuration\n\n**pyproject.toml:**\n```toml\n[tool.pytest.ini_options]\ntestpaths = [\"tests\"]\npython_files = [\"test_*.py\", \"*_test.py\"]\npython_functions = [\"test_*\"]\naddopts = [\n \"-v\",\n \"--strict-markers\",\n \"--cov=src\",\n \"--cov-report=term-missing\",\n \"--cov-report=html\",\n \"--cov-fail-under=80\"\n]\nmarkers = [\n \"slow: marks tests as slow\",\n \"integration: marks tests as integration tests\",\n \"e2e: marks tests as end-to-end tests\"\n]\nfilterwarnings = [\n \"error\",\n \"ignore::DeprecationWarning\"\n]\n\n[tool.coverage.run]\nbranch = true\nsource = [\"src\"]\nomit = [\"tests/*\", \"**/__init__.py\"]\n\n[tool.coverage.report]\nexclude_lines = [\n \"pragma: no cover\",\n \"if TYPE_CHECKING:\",\n \"raise NotImplementedError\"\n]\n```\n\n**conftest.py:**\n```python\nimport pytest\nfrom sqlalchemy import create_engine\nfrom sqlalchemy.orm import sessionmaker\n\[email protected](scope=\"session\")\ndef engine():\n return create_engine(\"sqlite:///:memory:\")\n\[email protected](scope=\"function\")\ndef db_session(engine):\n Session = sessionmaker(bind=engine)\n session = Session()\n yield session\n session.rollback()\n session.close()\n\[email protected]\ndef client(app):\n return app.test_client()\n\[email protected]\ndef auth_headers(client):\n response = client.post('/login', json={\n 'username': 'test',\n 'password': 'test123'\n })\n token = response.json['token']\n return {'Authorization': f'Bearer {token}'}\n```\n\n## Component Testing\n\n### React Testing Library vs Enzyme\n\n| Feature | React Testing Library | Enzyme |\n|---------|----------------------|--------|\n| **Philosophy** | User behavior | Implementation |\n| **Queries** | Accessibility-first | Component internals |\n| **Shallow** | Not supported | Supported |\n| **Maintained** | Active | Limited |\n| **React 18** | Full support | Partial |\n| **Learning** | Moderate | Easy |\n\n**React Testing Library (Recommended):**\n```javascript\nimport { render, screen, waitFor } from '@testing-library/react';\nimport userEvent from '@testing-library/user-event';\n\ntest('submits form with user data', async () => {\n const user = userEvent.setup();\n const onSubmit = jest.fn();\n\n render(\u003cLoginForm onSubmit={onSubmit} />);\n\n await user.type(screen.getByLabelText(/email/i), '[email protected]');\n await user.type(screen.getByLabelText(/password/i), 'password123');\n await user.click(screen.getByRole('button', { name: /sign in/i }));\n\n await waitFor(() => {\n expect(onSubmit).toHaveBeenCalledWith({\n email: '[email protected]',\n password: 'password123'\n });\n });\n});\n```\n\n## API Testing\n\n### Framework Options\n\n| Tool | Language | Best For |\n|------|----------|----------|\n| Supertest | JS/TS | Express/Node |\n| Playwright Request | JS/TS | With E2E |\n| pytest + requests | Python | Flask/Django |\n| REST Assured | Java | Spring |\n| Postman/Newman | Any | CI/CD |\n\n**Supertest Example:**\n```javascript\nimport request from 'supertest';\nimport app from '../src/app';\n\ndescribe('Users API', () => {\n it('GET /users returns list', async () => {\n const response = await request(app)\n .get('/api/users')\n .set('Authorization', `Bearer ${token}`)\n .expect('Content-Type', /json/)\n .expect(200);\n\n expect(response.body).toHaveLength(10);\n expect(response.body[0]).toHaveProperty('id');\n });\n});\n```\n\n## Decision Matrix\n\n### Quick Selection Guide\n\n```\nNeed to test...\n│\n├── Unit/Business Logic\n│ ├── JavaScript/TypeScript\n│ │ ├── Using Vite → Vitest\n│ │ ├── Existing Jest → Keep Jest\n│ │ └── New project → Vitest\n│ └── Python → pytest\n│\n├── React Components\n│ ├── User behavior → React Testing Library\n│ └── With stories → Storybook + Chromatic\n│\n├── API Endpoints\n│ ├── Node.js → Supertest\n│ ├── With E2E → Playwright API\n│ └── Python → pytest + requests\n│\n└── E2E/Browser\n ├── Cross-browser critical → Playwright\n ├── Developer experience → Cypress\n └── Legacy/Enterprise → Selenium\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":9669,"content_sha256":"ce5bbd87e5d7b15d031f7762cf65f0d56e14afb5a7bff55145ecb41815785543"},{"filename":"references/test-strategy.md","content":"# Test Strategy Framework\n\nA comprehensive guide to building effective test strategies for modern applications.\n\n## Test Strategy Document Template\n\n### 1. Scope Definition\n\n**In Scope:**\n- [ ] Unit tests for business logic\n- [ ] Integration tests for API contracts\n- [ ] E2E tests for critical user journeys\n- [ ] Component tests for UI elements\n- [ ] Accessibility testing\n- [ ] Visual regression testing\n\n**Out of Scope:**\n- [ ] Performance/load testing (separate strategy)\n- [ ] Security testing (separate strategy)\n- [ ] Manual exploratory testing\n\n### 2. Test Pyramid Implementation\n\n```\nTarget Distribution:\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\nE2E: ████████░░░░░░░░░░░░░░░░░░░░░░ 10%\nIntegration: ████████████████░░░░░░░░░░░░░░ 20%\nUnit: ████████████████████████████████ 70%\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n```\n\n### 3. Critical Path Identification\n\n**Tier 1 - Must Never Break (100% coverage):**\n- User authentication flow\n- Payment/checkout process\n- Core data mutations\n- Security-critical operations\n\n**Tier 2 - Important (90% coverage):**\n- User profile management\n- Search and filtering\n- Navigation flows\n- Form submissions\n\n**Tier 3 - Nice to Have (70% coverage):**\n- Edge cases in UI\n- Administrative features\n- Logging and analytics\n\n### 4. Test Data Strategy\n\n**Approaches:**\n1. **Factory Pattern** - Generate test data programmatically\n2. **Fixtures** - Static test data files\n3. **Seeding** - Database seeding scripts\n4. **Mocking** - API response mocks\n\n**Data Isolation:**\n```javascript\n// Each test gets fresh data\nbeforeEach(async () => {\n await db.truncate(['users', 'orders']);\n await seedTestData();\n});\n```\n\n### 5. Environment Strategy\n\n| Environment | Purpose | Data | Speed |\n|-------------|---------|------|-------|\n| Local | Development | Mocked/Seeded | Fast |\n| CI | Automation | Seeded | Medium |\n| Staging | Pre-prod validation | Sanitized prod | Slow |\n| Production | Smoke tests only | Real | N/A |\n\n### 6. Ownership Model\n\n| Test Type | Owner | Review |\n|-----------|-------|--------|\n| Unit tests | Feature developer | Code review |\n| Integration tests | Feature team | Tech lead |\n| E2E tests | QA/Platform team | QA lead |\n| Performance tests | Platform team | SRE |\n\n## Risk-Based Testing\n\n### Risk Assessment Matrix\n\n```\nImpact\n ↑\n │ ┌─────────┬─────────┐\nH │ │ MEDIUM │ HIGH │ ← Comprehensive testing\n │ │ Priority│ Priority│\n │ ├─────────┼─────────┤\nM │ │ LOW │ MEDIUM │ ← Standard testing\n │ │ Priority│ Priority│\n │ ├─────────┼─────────┤\nL │ │ MINIMAL│ LOW │ ← Basic coverage\n │ │ Priority│ Priority│\n └──┴─────────┴─────────┴──→\n Low High Probability\n```\n\n### Coverage by Risk Level\n\n| Risk | Min Coverage | Test Types |\n|------|-------------|------------|\n| High | 95% | Unit + Integration + E2E |\n| Medium | 80% | Unit + Integration |\n| Low | 60% | Unit |\n| Minimal | 40% | Unit (happy path) |\n\n## Testing Quadrants\n\n```\n Business-Facing\n ↑\n Q2 │ │ Q3\nFunctional │ Exploratory\n Tests │ Testing\n │\n──────────────┼──────────────→ Manual\n │\n Q1 │ │ Q4\n Unit │ Performance\n Tests │ Security\n │\n Technology-Facing\n ↓\n Automated\n```\n\n**Q1 (Technology/Automated):** Unit tests, component tests\n**Q2 (Business/Automated):** Functional tests, API tests\n**Q3 (Business/Manual):** Exploratory testing, usability\n**Q4 (Technology/Tools):** Performance, security, load\n\n## Test Maintenance Strategy\n\n### Keeping Tests Healthy\n\n1. **Regular Review Cycles**\n - Weekly: Flaky test triage\n - Monthly: Coverage gaps analysis\n - Quarterly: Strategy review\n\n2. **Test Debt Tracking**\n ```\n # In test file headers\n // @tech-debt: Needs refactor when API v2 ships\n // @flaky: Intermittent timeout - tracking in JIRA-123\n // @skip-reason: Blocked by feature flag removal\n ```\n\n3. **Deletion Criteria**\n - Test for removed feature\n - Duplicate coverage\n - Permanently flaky with no fix path\n - Testing implementation details\n\n### Metrics to Track\n\n| Metric | Target | Alert |\n|--------|--------|-------|\n| Test pass rate | >99% | <98% |\n| Flaky test rate | <1% | >2% |\n| Coverage trend | Stable/Up | -5% |\n| Test run time | <10min | >15min |\n| Time to fix failed test | <4hrs | >24hrs |\n\n## Test Documentation Standards\n\n### Test Naming Convention\n\n```javascript\n// Pattern: should_[expected]_when_[condition]\nit('should_return_user_when_id_exists', () => {});\nit('should_throw_error_when_id_invalid', () => {});\n\n// Or: describe behavior\ndescribe('UserService', () => {\n describe('getUser', () => {\n it('returns user for valid ID', () => {});\n it('throws NotFoundError for unknown ID', () => {});\n });\n});\n```\n\n### Test File Organization\n\n```\nsrc/\n├── components/\n│ ├── Button/\n│ │ ├── Button.tsx\n│ │ ├── Button.test.tsx # Unit tests\n│ │ └── Button.stories.tsx # Visual tests\n├── services/\n│ ├── user.ts\n│ └── user.test.ts\ntests/\n├── integration/\n│ ├── api/\n│ │ └── users.test.ts\n│ └── setup.ts\n├── e2e/\n│ ├── checkout.spec.ts\n│ └── auth.spec.ts\n└── fixtures/\n └── users.json\n```\n\n## Continuous Improvement\n\n### Retrospective Questions\n\n1. What tests caught real bugs this sprint?\n2. What bugs escaped to production - why no test?\n3. Which tests are frequently skipped/ignored?\n4. What's the test run time trend?\n5. Are developers writing tests first (TDD) or after?\n\n### Improvement Actions\n\n| Issue | Action |\n|-------|--------|\n| Low coverage | Pair on test writing |\n| Slow tests | Parallelize, mock more |\n| Flaky tests | Dedicated fix sprints |\n| Missing E2E | Map critical paths |\n| Test debt | Budget 10% for maintenance |\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":6634,"content_sha256":"8a50280ef5e2ff4eaee5da109c9f001460f7de1f9d734d1398bbc1b1f3dcc78a"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"Test Automation Expert","type":"text"}]},{"type":"paragraph","content":[{"text":"Comprehensive testing guidance from unit to E2E. Designs test strategies, implements automation, and optimizes coverage for sustainable quality.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"When to Use","type":"text"}]},{"type":"paragraph","content":[{"text":"Use for:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Designing test strategy for new projects","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Setting up testing frameworks (Jest, Vitest, Playwright, Cypress, pytest)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Writing effective unit, integration, and E2E tests","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Optimizing test coverage and eliminating gaps","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Debugging flaky tests","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"CI/CD test pipeline configuration","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Test-Driven Development (TDD) guidance","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Mocking strategies and test fixtures","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Do NOT use for:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Manual QA test case writing - this is automation-focused","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Load/performance testing - use performance-engineer skill","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Security testing - use security-auditor skill","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"API contract testing only - use backend-architect for API design","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Test Pyramid Philosophy","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":" /\\\n / \\ E2E Tests (10%)\n /----\\ - Critical user journeys\n / \\ - Cross-browser validation\n /--------\\\n / \\ Integration Tests (20%)\n / \\ - API contracts\n /--------------\\- Component interactions\n / \\\n/------------------\\ Unit Tests (70%)\n - Fast, isolated, deterministic\n - Business logic validation","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Distribution Guidelines","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Test Type","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Percentage","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Execution Time","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Purpose","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Unit","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"70%","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"\u003c 100ms each","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Logic validation","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Integration","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"20%","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"\u003c 1s each","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Component contracts","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"E2E","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"10%","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"\u003c 30s each","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Critical paths","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Framework Selection","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"JavaScript/TypeScript","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Framework","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Best For","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Speed","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Config Complexity","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Vitest","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Vite projects, modern ESM","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Fastest","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Low","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Jest","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"React, established projects","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Fast","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Medium","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Playwright","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"E2E, cross-browser","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"N/A","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Low","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Cypress","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"E2E, component testing","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"N/A","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Medium","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Python","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Framework","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Best For","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Speed","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Features","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"pytest","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Everything","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Fast","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Fixtures, plugins","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"unittest","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Standard library","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Medium","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Built-in","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"hypothesis","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Property-based","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Varies","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Generative","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Decision Tree: Framework Selection","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"New project?\n├── Yes → Using Vite?\n│ ├── Yes → Vitest\n│ └── No → Jest or Vitest (both work)\n└── No → What exists?\n ├── Jest → Keep Jest (migration cost rarely worth it)\n ├── Mocha → Consider migration to Vitest\n └── Nothing → Vitest (modern default)\n\nNeed E2E?\n├── Cross-browser critical → Playwright\n├── Developer experience priority → Cypress\n└── Both → Playwright (more flexible)","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Unit Testing Patterns","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Good Unit Test Anatomy","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"javascript"},"content":[{"text":"describe('UserService', () => {\n describe('validateEmail', () => {\n // Arrange-Act-Assert pattern\n it('should accept valid email formats', () => {\n // Arrange\n const validEmails = ['[email protected]', '[email protected]'];\n\n // Act & Assert\n validEmails.forEach(email => {\n expect(validateEmail(email)).toBe(true);\n });\n });\n\n it('should reject invalid email formats', () => {\n // Arrange\n const invalidEmails = ['invalid', '@missing.com', 'no@tld'];\n\n // Act & Assert\n invalidEmails.forEach(email => {\n expect(validateEmail(email)).toBe(false);\n });\n });\n\n // Edge cases explicitly tested\n it('should handle empty string', () => {\n expect(validateEmail('')).toBe(false);\n });\n\n it('should handle null/undefined', () => {\n expect(validateEmail(null)).toBe(false);\n expect(validateEmail(undefined)).toBe(false);\n });\n });\n});","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Mocking Strategies","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"javascript"},"content":[{"text":"// ✅ Good: Mock at boundaries\njest.mock('../services/api', () => ({\n fetchUser: jest.fn()\n}));\n\n// ✅ Good: Explicit mock setup per test\nbeforeEach(() => {\n fetchUser.mockReset();\n});\n\nit('handles user not found', async () => {\n fetchUser.mockRejectedValue(new NotFoundError());\n await expect(getUser(123)).rejects.toThrow('User not found');\n});\n\n// ❌ Bad: Mocking implementation details\njest.mock('../utils/internal-helper'); // Don't mock internals","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Test Isolation Checklist","type":"text"}]},{"type":"checkbox_list","attrs":{"id":null},"content":[{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"Each test can run independently","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"No shared mutable state between tests","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"Database/API state reset between tests","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"No test order dependencies","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"Parallel execution safe","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Integration Testing Patterns","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"API Integration Test","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"javascript"},"content":[{"text":"describe('POST /api/users', () => {\n let app;\n let db;\n\n beforeAll(async () => {\n db = await createTestDatabase();\n app = createApp({ db });\n });\n\n afterAll(async () => {\n await db.close();\n });\n\n beforeEach(async () => {\n await db.clear();\n });\n\n it('creates user with valid data', async () => {\n const response = await request(app)\n .post('/api/users')\n .send({ name: 'Test', email: '[email protected]' })\n .expect(201);\n\n expect(response.body).toMatchObject({\n id: expect.any(String),\n name: 'Test',\n email: '[email protected]'\n });\n\n // Verify side effects\n const dbUser = await db.users.findById(response.body.id);\n expect(dbUser).toBeDefined();\n });\n\n it('rejects duplicate email', async () => {\n await db.users.create({ name: 'Existing', email: '[email protected]' });\n\n await request(app)\n .post('/api/users')\n .send({ name: 'New', email: '[email protected]' })\n .expect(409);\n });\n});","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Component Integration (React)","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"javascript"},"content":[{"text":"import { render, screen, waitFor } from '@testing-library/react';\nimport userEvent from '@testing-library/user-event';\nimport { UserProfile } from './UserProfile';\nimport { UserProvider } from '../context/UserContext';\n\ndescribe('UserProfile integration', () => {\n it('loads and displays user data', async () => {\n render(\n \u003cUserProvider>\n \u003cUserProfile userId=\"123\" />\n \u003c/UserProvider>\n );\n\n // Verify loading state\n expect(screen.getByRole('progressbar')).toBeInTheDocument();\n\n // Wait for data\n await waitFor(() => {\n expect(screen.getByText('John Doe')).toBeInTheDocument();\n });\n\n // Verify loaded state\n expect(screen.queryByRole('progressbar')).not.toBeInTheDocument();\n });\n});","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"E2E Testing Patterns","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Playwright Best Practices","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"javascript"},"content":[{"text":"import { test, expect } from '@playwright/test';\n\ntest.describe('Checkout Flow', () => {\n test.beforeEach(async ({ page }) => {\n // Seed test data via API\n await page.request.post('/api/test/seed', {\n data: { scenario: 'checkout-ready' }\n });\n });\n\n test('complete purchase with credit card', async ({ page }) => {\n await page.goto('/cart');\n\n // Use accessible selectors\n await page.getByRole('button', { name: 'Proceed to checkout' }).click();\n\n // Fill payment form\n await page.getByLabel('Card number').fill('4242424242424242');\n await page.getByLabel('Expiry').fill('12/25');\n await page.getByLabel('CVC').fill('123');\n\n // Complete purchase\n await page.getByRole('button', { name: 'Pay now' }).click();\n\n // Verify success\n await expect(page.getByRole('heading', { name: 'Order confirmed' })).toBeVisible();\n await expect(page.getByText(/Order #\\d+/)).toBeVisible();\n });\n\n test('shows error for declined card', async ({ page }) => {\n await page.goto('/checkout');\n\n // Use test card that triggers decline\n await page.getByLabel('Card number').fill('4000000000000002');\n await page.getByLabel('Expiry').fill('12/25');\n await page.getByLabel('CVC').fill('123');\n\n await page.getByRole('button', { name: 'Pay now' }).click();\n\n await expect(page.getByRole('alert')).toContainText('Card declined');\n });\n});","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Flaky Test Detection & Prevention","type":"text"}]},{"type":"paragraph","content":[{"text":"Common Causes:","type":"text","marks":[{"type":"strong"}]}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Race conditions in async operations","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Time-dependent tests","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Shared state between tests","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Network variability","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Animation/transition timing","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Fixes:","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"javascript"},"content":[{"text":"// ❌ Bad: Fixed timeout\nawait page.waitForTimeout(2000);\n\n// ✅ Good: Wait for specific condition\nawait expect(page.getByText('Loaded')).toBeVisible();\n\n// ❌ Bad: Checking exact time\nexpect(new Date()).toEqual(specificDate);\n\n// ✅ Good: Mock time\njest.useFakeTimers();\njest.setSystemTime(new Date('2024-01-15'));\n\n// ❌ Bad: Depending on animation completion\nawait page.click('.button');\nexpect(await page.isVisible('.modal')).toBe(true);\n\n// ✅ Good: Wait for animation\nawait page.click('.button');\nawait expect(page.locator('.modal')).toBeVisible();","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Coverage Optimization","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"What to Measure","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Metric","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Target","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Priority","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Line coverage","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"80%+","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Medium","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Branch coverage","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"75%+","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"High","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Function coverage","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"90%+","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Medium","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Critical path coverage","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"100%","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Critical","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Coverage Configuration","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"javascript"},"content":[{"text":"// vitest.config.js\nexport default defineConfig({\n test: {\n coverage: {\n provider: 'v8',\n reporter: ['text', 'json', 'html'],\n exclude: [\n 'node_modules/',\n 'test/',\n '**/*.d.ts',\n '**/*.config.*',\n '**/index.ts', // barrel files\n ],\n thresholds: {\n branches: 75,\n functions: 80,\n lines: 80,\n statements: 80\n }\n }\n }\n});","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Finding Coverage Gaps","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Generate detailed coverage report\nnpx vitest run --coverage\n\n# Find untested files\nnpx vitest run --coverage --reporter=json | jq '.coverageMap | to_entries | map(select(.value.s | values | any(. == 0))) | .[].key'","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"CI/CD Integration","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"GitHub Actions","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"yaml"},"content":[{"text":"name: Tests\non: [push, pull_request]\n\njobs:\n unit-tests:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-node@v4\n with:\n node-version: '20'\n cache: 'npm'\n - run: npm ci\n - run: npm test -- --coverage\n - uses: codecov/codecov-action@v4\n\n e2e-tests:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-node@v4\n - run: npm ci\n - run: npx playwright install --with-deps\n - run: npm run test:e2e\n - uses: actions/upload-artifact@v4\n if: failure()\n with:\n name: playwright-report\n path: playwright-report/","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Test Parallelization","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"javascript"},"content":[{"text":"// vitest.config.js - parallel by default\nexport default defineConfig({\n test: {\n pool: 'threads',\n poolOptions: {\n threads: {\n singleThread: false\n }\n }\n }\n});\n\n// playwright.config.js\nexport default defineConfig({\n workers: process.env.CI ? 2 : undefined,\n fullyParallel: true\n});","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Anti-Patterns","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Anti-Pattern: Testing Implementation Details","type":"text"}]},{"type":"paragraph","content":[{"text":"What it looks like:","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"javascript"},"content":[{"text":"// ❌ Testing internal state\nexpect(component.state.isLoading).toBe(true);\n\n// ❌ Testing private methods\nexpect(service._calculateHash()).toBe('abc123');","type":"text"}]},{"type":"paragraph","content":[{"text":"Why wrong:","type":"text","marks":[{"type":"strong"}]},{"text":" Couples tests to implementation, breaks on refactors","type":"text"}]},{"type":"paragraph","content":[{"text":"Instead:","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"javascript"},"content":[{"text":"// ✅ Test observable behavior\nexpect(screen.getByRole('progressbar')).toBeInTheDocument();\n\n// ✅ Test public interface\nexpect(service.getHash()).toBe('abc123');","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Anti-Pattern: Over-Mocking","type":"text"}]},{"type":"paragraph","content":[{"text":"What it looks like:","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"javascript"},"content":[{"text":"// ❌ Mocking everything\njest.mock('../utils/format');\njest.mock('../utils/validate');\njest.mock('../utils/transform');","type":"text"}]},{"type":"paragraph","content":[{"text":"Why wrong:","type":"text","marks":[{"type":"strong"}]},{"text":" Tests pass even when real code is broken","type":"text"}]},{"type":"paragraph","content":[{"text":"Instead:","type":"text","marks":[{"type":"strong"}]},{"text":" Mock only at system boundaries (APIs, databases, external services)","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Anti-Pattern: Flaky Acceptance","type":"text"}]},{"type":"paragraph","content":[{"text":"What it looks like:","type":"text","marks":[{"type":"strong"}]},{"text":" \"That test is just flaky, skip it\"","type":"text"}]},{"type":"paragraph","content":[{"text":"Why wrong:","type":"text","marks":[{"type":"strong"}]},{"text":" Flaky tests indicate real problems (race conditions, timing issues)","type":"text"}]},{"type":"paragraph","content":[{"text":"Instead:","type":"text","marks":[{"type":"strong"}]},{"text":" Fix the flakiness or quarantine while fixing","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Anti-Pattern: Coverage Theater","type":"text"}]},{"type":"paragraph","content":[{"text":"What it looks like:","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"javascript"},"content":[{"text":"// ❌ Testing for coverage, not behavior\nit('covers the function', () => {\n myFunction();\n // No assertions!\n});","type":"text"}]},{"type":"paragraph","content":[{"text":"Why wrong:","type":"text","marks":[{"type":"strong"}]},{"text":" 100% coverage with 0% confidence","type":"text"}]},{"type":"paragraph","content":[{"text":"Instead:","type":"text","marks":[{"type":"strong"}]},{"text":" Every test should assert meaningful behavior","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Quick Commands","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Run all tests\nnpm test\n\n# Run with coverage\nnpm test -- --coverage\n\n# Run specific file\nnpm test -- src/utils/format.test.ts\n\n# Run in watch mode\nnpm test -- --watch\n\n# Run E2E tests\nnpx playwright test\n\n# Run E2E with UI\nnpx playwright test --ui\n\n# Debug E2E test\nnpx playwright test --debug\n\n# Update snapshots\nnpm test -- -u","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Reference Files","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/test-strategy.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" - Comprehensive test strategy framework","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/framework-comparison.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" - Detailed framework comparison","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/coverage-patterns.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" - Coverage optimization techniques","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/ci-integration.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" - CI/CD pipeline configurations","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"paragraph","content":[{"text":"Covers","type":"text","marks":[{"type":"strong"}]},{"text":": Test strategy | Unit testing | Integration testing | E2E testing | Coverage | CI/CD | Flaky test debugging","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Use with","type":"text","marks":[{"type":"strong"}]},{"text":": security-auditor (security tests) | performance-engineer (load tests) | code-reviewer (test quality)","type":"text"}]}]},"metadata":{"date":"2026-06-05","name":"test-automation-expert","author":"@skillopedia","source":{"stars":113,"repo_name":"some_claude_skills","origin_url":"https://github.com/erichowens/some_claude_skills/blob/HEAD/.claude/skills/test-automation-expert/SKILL.md","repo_owner":"erichowens","body_sha256":"8e180d5df2800bdb43f578e52ae212d7734b1a838c6d3596c3b04175ed3d9ab5","cluster_key":"6ea9127bb66ea18bf28f8dde416636ae5e422fef6cbf68f56636392e0b814819","clean_bundle":{"format":"clean-skill-bundle-v1","source":"erichowens/some_claude_skills/.claude/skills/test-automation-expert/SKILL.md","attachments":[{"id":"2c78af77-9c87-5704-a679-0f59eb5a0ad8","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/2c78af77-9c87-5704-a679-0f59eb5a0ad8/attachment.md","path":"CHANGELOG.md","size":1332,"sha256":"0ce9b8a955f6464039aa46aea04772c6c0652abd871b38d871f9a70eb4013ecc","contentType":"text/markdown; charset=utf-8"},{"id":"3faa401a-a7ed-547b-8a21-080ade13de29","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/3faa401a-a7ed-547b-8a21-080ade13de29/attachment.md","path":"references/ci-integration.md","size":13690,"sha256":"48b955cb33eeee063fb5aea28440a0123c621a1386b01261b8cccab3734afa27","contentType":"text/markdown; charset=utf-8"},{"id":"c4dba262-271f-5816-a077-805f71b1b29b","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/c4dba262-271f-5816-a077-805f71b1b29b/attachment.md","path":"references/coverage-patterns.md","size":11410,"sha256":"0fe0ee9620f53e1393b2a8028005614af397190495ff58d916fd74ed975cad72","contentType":"text/markdown; charset=utf-8"},{"id":"63bcef59-1bc1-558c-b3ef-3b9d95238b47","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/63bcef59-1bc1-558c-b3ef-3b9d95238b47/attachment.md","path":"references/framework-comparison.md","size":9669,"sha256":"ce5bbd87e5d7b15d031f7762cf65f0d56e14afb5a7bff55145ecb41815785543","contentType":"text/markdown; charset=utf-8"},{"id":"f0c7f7a5-8bdf-5560-9604-10417e66eb64","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/f0c7f7a5-8bdf-5560-9604-10417e66eb64/attachment.md","path":"references/test-strategy.md","size":6634,"sha256":"8a50280ef5e2ff4eaee5da109c9f001460f7de1f9d734d1398bbc1b1f3dcc78a","contentType":"text/markdown; charset=utf-8"}],"bundle_sha256":"3e4af9ed28025dd4b57f7095b1c256345d111089bfd93d02f85ba21a45ffa8bc","attachment_count":5,"text_attachments":5,"attachment_storage":"skillopedia-attachments-v1","binary_attachments":0,"excluded_attachments":[]},"cluster_size":1,"skill_md_path":".claude/skills/test-automation-expert/SKILL.md","import_metadata":{"date":"2026-06-05","author":"@skillopedia","version":"v1","category":"testing-qa","category_label":"Testing"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"testing-qa","metadata":{"tags":["testing","jest","playwright","tdd","coverage"],"category":"Code Quality & Testing","pairs-with":[{"skill":"refactoring-surgeon","reason":"Tests before refactoring"},{"skill":"devops-automator","reason":"CI/CD test integration"}]},"import_tag":"clean-skills-v1","description":"Comprehensive test automation specialist covering unit, integration, and E2E testing strategies. Expert in Jest, Vitest, Playwright, Cypress, pytest, and modern testing frameworks. Guides test pyramid design, coverage optimization, flaky test detection, and CI/CD integration. Activate on 'test strategy', 'unit tests', 'integration tests', 'E2E testing', 'test coverage', 'flaky tests', 'mocking', 'test fixtures', 'TDD', 'BDD', 'test automation'. NOT for manual QA processes, load/performance testing (use performance-engineer), or security testing (use security-auditor).","allowed-tools":"Read,Write,Edit,Bash(npm test:*,npx jest:*,npx vitest:*,npx playwright:*,pytest:*),Grep,Glob"}},"renderedAt":1782981120407}

Test Automation Expert Comprehensive testing guidance from unit to E2E. Designs test strategies, implements automation, and optimizes coverage for sustainable quality. When to Use Use for: - Designing test strategy for new projects - Setting up testing frameworks (Jest, Vitest, Playwright, Cypress, pytest) - Writing effective unit, integration, and E2E tests - Optimizing test coverage and eliminating gaps - Debugging flaky tests - CI/CD test pipeline configuration - Test-Driven Development (TDD) guidance - Mocking strategies and test fixtures Do NOT use for: - Manual QA test case writing - th…