qa-skills 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +168 -0
- package/bin/cli.js +42 -0
- package/dist/agents/registry.d.ts +5 -0
- package/dist/agents/registry.d.ts.map +1 -0
- package/dist/agents/registry.js +101 -0
- package/dist/agents/registry.js.map +1 -0
- package/dist/agents/types.d.ts +9 -0
- package/dist/agents/types.d.ts.map +1 -0
- package/dist/agents/types.js +2 -0
- package/dist/agents/types.js.map +1 -0
- package/dist/dependencies.d.ts +21 -0
- package/dist/dependencies.d.ts.map +1 -0
- package/dist/dependencies.js +125 -0
- package/dist/dependencies.js.map +1 -0
- package/dist/installer.d.ts +25 -0
- package/dist/installer.d.ts.map +1 -0
- package/dist/installer.js +437 -0
- package/dist/installer.js.map +1 -0
- package/dist/scaffold.d.ts +27 -0
- package/dist/scaffold.d.ts.map +1 -0
- package/dist/scaffold.js +182 -0
- package/dist/scaffold.js.map +1 -0
- package/package.json +40 -0
- package/skills/qa-accessibility-test-writer/SKILL.md +127 -0
- package/skills/qa-accessibility-test-writer/references/axe-core-patterns.md +349 -0
- package/skills/qa-accessibility-test-writer/references/best-practices.md +184 -0
- package/skills/qa-accessibility-test-writer/references/wcag-tests.md +331 -0
- package/skills/qa-api-contract-curator/SKILL.md +104 -0
- package/skills/qa-api-contract-curator/references/breaking-changes.md +363 -0
- package/skills/qa-api-contract-curator/references/openapi-structure.md +404 -0
- package/skills/qa-browser-data-collector/SKILL.md +132 -0
- package/skills/qa-browser-data-collector/references/data-collection-checklist.md +91 -0
- package/skills/qa-browser-data-collector/references/playwright-mcp-patterns.md +113 -0
- package/skills/qa-bug-ticket-creator/SKILL.md +148 -0
- package/skills/qa-bug-ticket-creator/references/bug-report-format.md +149 -0
- package/skills/qa-bug-ticket-creator/references/severity-guide.md +81 -0
- package/skills/qa-bug-ticket-creator/templates/bug-ticket-template.md +39 -0
- package/skills/qa-changelog-analyzer/SKILL.md +134 -0
- package/skills/qa-changelog-analyzer/references/git-analysis-patterns.md +138 -0
- package/skills/qa-changelog-analyzer/references/impact-mapping.md +120 -0
- package/skills/qa-clickup-integration/SKILL.md +166 -0
- package/skills/qa-clickup-integration/references/api-patterns.md +102 -0
- package/skills/qa-clickup-integration/references/field-mapping.md +71 -0
- package/skills/qa-codeceptjs-writer/SKILL.md +136 -0
- package/skills/qa-codeceptjs-writer/references/best-practices.md +207 -0
- package/skills/qa-codeceptjs-writer/references/config.md +255 -0
- package/skills/qa-codeceptjs-writer/references/patterns.md +285 -0
- package/skills/qa-coverage-analyzer/SKILL.md +166 -0
- package/skills/qa-coverage-analyzer/references/best-practices.md +142 -0
- package/skills/qa-coverage-analyzer/references/coverage-dimensions.md +155 -0
- package/skills/qa-coverage-analyzer/references/tools.md +204 -0
- package/skills/qa-cypress-writer/SKILL.md +134 -0
- package/skills/qa-cypress-writer/references/assertions.md +121 -0
- package/skills/qa-cypress-writer/references/best-practices.md +82 -0
- package/skills/qa-cypress-writer/references/config.md +121 -0
- package/skills/qa-cypress-writer/references/patterns.md +170 -0
- package/skills/qa-data-factory/SKILL.md +126 -0
- package/skills/qa-data-factory/references/factory-patterns.md +164 -0
- package/skills/qa-data-factory/references/faker-guide.md +131 -0
- package/skills/qa-diagram-generator/SKILL.md +125 -0
- package/skills/qa-diagram-generator/references/c4-model.md +53 -0
- package/skills/qa-diagram-generator/references/charts.md +58 -0
- package/skills/qa-diagram-generator/references/class-diagram.md +85 -0
- package/skills/qa-diagram-generator/references/er-diagram.md +69 -0
- package/skills/qa-diagram-generator/references/flowchart.md +92 -0
- package/skills/qa-diagram-generator/references/from-screenshot.md +45 -0
- package/skills/qa-diagram-generator/references/gantt.md +49 -0
- package/skills/qa-diagram-generator/references/journey.md +50 -0
- package/skills/qa-diagram-generator/references/mindmap.md +75 -0
- package/skills/qa-diagram-generator/references/sequence.md +69 -0
- package/skills/qa-diagram-generator/references/state-diagram.md +56 -0
- package/skills/qa-discovery-interview/SKILL.md +182 -0
- package/skills/qa-discovery-interview/references/completeness-checklist.md +53 -0
- package/skills/qa-discovery-interview/references/conflict-patterns.md +101 -0
- package/skills/qa-discovery-interview/references/qa-categories.md +147 -0
- package/skills/qa-discovery-interview/templates/qa-brief-template.md +168 -0
- package/skills/qa-environment-checker/SKILL.md +142 -0
- package/skills/qa-environment-checker/references/dependency-matrix.md +101 -0
- package/skills/qa-environment-checker/references/health-checks.md +209 -0
- package/skills/qa-environment-checker/templates/env-readiness-template.md +64 -0
- package/skills/qa-flaky-detector/SKILL.md +153 -0
- package/skills/qa-flaky-detector/references/ci-analysis.md +140 -0
- package/skills/qa-flaky-detector/references/flaky-patterns.md +247 -0
- package/skills/qa-github-issues-enhanced/SKILL.md +175 -0
- package/skills/qa-github-issues-enhanced/references/issue-templates.md +425 -0
- package/skills/qa-github-issues-enhanced/references/label-taxonomy.md +130 -0
- package/skills/qa-github-issues-enhanced/references/workflow-patterns.md +188 -0
- package/skills/qa-httpx-writer/SKILL.md +138 -0
- package/skills/qa-httpx-writer/references/assertions.md +195 -0
- package/skills/qa-httpx-writer/references/best-practices.md +140 -0
- package/skills/qa-httpx-writer/references/config.md +212 -0
- package/skills/qa-httpx-writer/references/patterns.md +262 -0
- package/skills/qa-jest-writer/SKILL.md +131 -0
- package/skills/qa-jest-writer/references/assertions.md +125 -0
- package/skills/qa-jest-writer/references/best-practices.md +136 -0
- package/skills/qa-jest-writer/references/config.md +134 -0
- package/skills/qa-jest-writer/references/patterns.md +172 -0
- package/skills/qa-jira-integration/SKILL.md +135 -0
- package/skills/qa-jira-integration/references/api-patterns.md +143 -0
- package/skills/qa-jira-integration/references/field-mapping.md +79 -0
- package/skills/qa-jira-integration/references/xray-integration.md +85 -0
- package/skills/qa-jmeter-writer/SKILL.md +171 -0
- package/skills/qa-jmeter-writer/references/best-practices.md +157 -0
- package/skills/qa-jmeter-writer/references/config.md +204 -0
- package/skills/qa-jmeter-writer/references/patterns.md +242 -0
- package/skills/qa-junit5-writer/SKILL.md +157 -0
- package/skills/qa-junit5-writer/references/assertions.md +118 -0
- package/skills/qa-junit5-writer/references/config.md +97 -0
- package/skills/qa-junit5-writer/references/patterns.md +162 -0
- package/skills/qa-k6-writer/SKILL.md +155 -0
- package/skills/qa-k6-writer/references/best-practices.md +236 -0
- package/skills/qa-k6-writer/references/config.md +219 -0
- package/skills/qa-k6-writer/references/patterns.md +304 -0
- package/skills/qa-linear-integration/SKILL.md +137 -0
- package/skills/qa-linear-integration/references/api-patterns.md +249 -0
- package/skills/qa-linear-integration/references/field-mapping.md +121 -0
- package/skills/qa-locust-writer/SKILL.md +151 -0
- package/skills/qa-locust-writer/references/best-practices.md +126 -0
- package/skills/qa-locust-writer/references/config.md +170 -0
- package/skills/qa-locust-writer/references/patterns.md +235 -0
- package/skills/qa-manual-test-designer/SKILL.md +145 -0
- package/skills/qa-manual-test-designer/references/exploratory-charters.md +138 -0
- package/skills/qa-manual-test-designer/references/personas.md +146 -0
- package/skills/qa-manual-test-designer/templates/exploratory-charter-template.md +47 -0
- package/skills/qa-manual-test-designer/templates/test-case-template.md +31 -0
- package/skills/qa-mobile-test-writer/SKILL.md +144 -0
- package/skills/qa-mobile-test-writer/references/best-practices.md +214 -0
- package/skills/qa-mobile-test-writer/references/config.md +309 -0
- package/skills/qa-mobile-test-writer/references/patterns.md +304 -0
- package/skills/qa-nfr-analyst/SKILL.md +177 -0
- package/skills/qa-nfr-analyst/references/iso-25010-model.md +159 -0
- package/skills/qa-nfr-analyst/references/owasp-wstg-baseline.md +202 -0
- package/skills/qa-nfr-analyst/references/wcag-checklist.md +184 -0
- package/skills/qa-nfr-analyst/templates/owasp-checklist-template.md +89 -0
- package/skills/qa-nfr-analyst/templates/wcag-checklist-template.md +48 -0
- package/skills/qa-orchestrator/SKILL.md +132 -0
- package/skills/qa-orchestrator/references/handoff-chains.md +105 -0
- package/skills/qa-orchestrator/references/pipeline-modes.md +115 -0
- package/skills/qa-orchestrator/references/scheduler-rules.md +84 -0
- package/skills/qa-pact-writer/SKILL.md +133 -0
- package/skills/qa-pact-writer/references/best-practices.md +100 -0
- package/skills/qa-pact-writer/references/config.md +135 -0
- package/skills/qa-pact-writer/references/patterns.md +161 -0
- package/skills/qa-plan-creator/SKILL.md +139 -0
- package/skills/qa-plan-creator/references/introduction-plan.md +43 -0
- package/skills/qa-plan-creator/references/migration-plan.md +44 -0
- package/skills/qa-plan-creator/references/onboarding-plan.md +46 -0
- package/skills/qa-plan-creator/references/performance-plan.md +44 -0
- package/skills/qa-plan-creator/references/regression-plan.md +45 -0
- package/skills/qa-plan-creator/references/release-plan.md +45 -0
- package/skills/qa-plan-creator/references/sprint-plan.md +44 -0
- package/skills/qa-plan-creator/references/test-plan.md +59 -0
- package/skills/qa-plan-creator/references/uat-plan.md +43 -0
- package/skills/qa-plan-creator/templates/checklist-template.md +36 -0
- package/skills/qa-plan-creator/templates/regression-checklist-template.md +49 -0
- package/skills/qa-plan-creator/templates/release-checklist-template.md +46 -0
- package/skills/qa-plan-creator/templates/test-plan-template.md +74 -0
- package/skills/qa-playwright-py-writer/SKILL.md +156 -0
- package/skills/qa-playwright-py-writer/references/best-practices.md +194 -0
- package/skills/qa-playwright-py-writer/references/config.md +195 -0
- package/skills/qa-playwright-py-writer/references/patterns.md +212 -0
- package/skills/qa-playwright-ts-writer/SKILL.md +151 -0
- package/skills/qa-playwright-ts-writer/references/assertions.md +109 -0
- package/skills/qa-playwright-ts-writer/references/best-practices.md +191 -0
- package/skills/qa-playwright-ts-writer/references/config.md +144 -0
- package/skills/qa-playwright-ts-writer/references/patterns.md +171 -0
- package/skills/qa-pytest-writer/SKILL.md +145 -0
- package/skills/qa-pytest-writer/references/assertions.md +149 -0
- package/skills/qa-pytest-writer/references/best-practices.md +97 -0
- package/skills/qa-pytest-writer/references/config.md +176 -0
- package/skills/qa-pytest-writer/references/patterns.md +251 -0
- package/skills/qa-qase-integration/SKILL.md +149 -0
- package/skills/qa-qase-integration/references/api-reference.md +354 -0
- package/skills/qa-qase-integration/references/ci-integration.md +196 -0
- package/skills/qa-qase-integration/references/field-mapping.md +157 -0
- package/skills/qa-requirements-generator/SKILL.md +152 -0
- package/skills/qa-requirements-generator/references/iso-29148-structure.md +153 -0
- package/skills/qa-requirements-generator/references/requirement-patterns.md +278 -0
- package/skills/qa-rest-assured-writer/SKILL.md +137 -0
- package/skills/qa-rest-assured-writer/references/best-practices.md +50 -0
- package/skills/qa-rest-assured-writer/references/config.md +124 -0
- package/skills/qa-rest-assured-writer/references/patterns.md +192 -0
- package/skills/qa-risk-analyzer/SKILL.md +158 -0
- package/skills/qa-risk-analyzer/references/impact-analysis.md +133 -0
- package/skills/qa-risk-analyzer/references/risk-factors.md +123 -0
- package/skills/qa-robot-framework-writer/SKILL.md +147 -0
- package/skills/qa-robot-framework-writer/references/best-practices.md +249 -0
- package/skills/qa-robot-framework-writer/references/config.md +204 -0
- package/skills/qa-robot-framework-writer/references/libraries.md +273 -0
- package/skills/qa-robot-framework-writer/references/patterns.md +216 -0
- package/skills/qa-security-test-writer/SKILL.md +123 -0
- package/skills/qa-security-test-writer/references/best-practices.md +155 -0
- package/skills/qa-security-test-writer/references/owasp-top10.md +331 -0
- package/skills/qa-security-test-writer/references/zap-config.md +258 -0
- package/skills/qa-selenium-java-writer/SKILL.md +143 -0
- package/skills/qa-selenium-java-writer/references/best-practices.md +59 -0
- package/skills/qa-selenium-java-writer/references/config.md +143 -0
- package/skills/qa-selenium-java-writer/references/patterns.md +170 -0
- package/skills/qa-selenium-py-writer/SKILL.md +150 -0
- package/skills/qa-selenium-py-writer/references/best-practices.md +175 -0
- package/skills/qa-selenium-py-writer/references/config.md +224 -0
- package/skills/qa-selenium-py-writer/references/patterns.md +255 -0
- package/skills/qa-shortcut-integration/SKILL.md +143 -0
- package/skills/qa-shortcut-integration/references/api-patterns.md +126 -0
- package/skills/qa-shortcut-integration/references/field-mapping.md +66 -0
- package/skills/qa-spec-auditor/SKILL.md +162 -0
- package/skills/qa-spec-auditor/references/audit-checklist.md +144 -0
- package/skills/qa-spec-auditor/references/drift-patterns.md +207 -0
- package/skills/qa-spec-writer/SKILL.md +143 -0
- package/skills/qa-spec-writer/references/gherkin-guide.md +253 -0
- package/skills/qa-spec-writer/references/specification-patterns.md +274 -0
- package/skills/qa-spring-test-writer/SKILL.md +170 -0
- package/skills/qa-spring-test-writer/references/best-practices.md +57 -0
- package/skills/qa-spring-test-writer/references/config.md +179 -0
- package/skills/qa-spring-test-writer/references/patterns.md +235 -0
- package/skills/qa-supertest-writer/SKILL.md +150 -0
- package/skills/qa-supertest-writer/references/assertions.md +192 -0
- package/skills/qa-supertest-writer/references/best-practices.md +102 -0
- package/skills/qa-supertest-writer/references/config.md +166 -0
- package/skills/qa-supertest-writer/references/patterns.md +242 -0
- package/skills/qa-task-creator/SKILL.md +142 -0
- package/skills/qa-task-creator/references/linking-patterns.md +127 -0
- package/skills/qa-task-creator/references/task-types.md +169 -0
- package/skills/qa-task-creator/templates/task-template.md +24 -0
- package/skills/qa-test-doc-compiler/SKILL.md +114 -0
- package/skills/qa-test-doc-compiler/references/agile-tailoring.md +220 -0
- package/skills/qa-test-doc-compiler/references/iso-29119-3-documents.md +302 -0
- package/skills/qa-test-healer/SKILL.md +101 -0
- package/skills/qa-test-healer/references/diagnosis-patterns.md +142 -0
- package/skills/qa-test-healer/references/fix-strategies.md +177 -0
- package/skills/qa-test-reporter/SKILL.md +130 -0
- package/skills/qa-test-reporter/references/best-practices.md +162 -0
- package/skills/qa-test-reporter/references/iso-29119-reports.md +236 -0
- package/skills/qa-test-reporter/references/report-formats.md +287 -0
- package/skills/qa-test-reviewer/SKILL.md +142 -0
- package/skills/qa-test-reviewer/references/anti-patterns.md +268 -0
- package/skills/qa-test-reviewer/references/review-checklist.md +93 -0
- package/skills/qa-test-strategy/SKILL.md +133 -0
- package/skills/qa-test-strategy/references/entry-exit-criteria.md +176 -0
- package/skills/qa-test-strategy/references/risk-matrix.md +102 -0
- package/skills/qa-test-strategy/references/testing-types.md +143 -0
- package/skills/qa-testcase-from-docs/SKILL.md +161 -0
- package/skills/qa-testcase-from-docs/references/test-case-format.md +196 -0
- package/skills/qa-testcase-from-docs/references/test-design-techniques.md +126 -0
- package/skills/qa-testcase-from-docs/templates/test-case-template.md +31 -0
- package/skills/qa-testcase-from-ui/SKILL.md +109 -0
- package/skills/qa-testcase-from-ui/references/ui-element-patterns.md +126 -0
- package/skills/qa-testcase-from-ui/references/visual-analysis-guide.md +146 -0
- package/skills/qa-testcase-from-ui/templates/test-case-template.md +31 -0
- package/skills/qa-visual-regression-writer/SKILL.md +175 -0
- package/skills/qa-visual-regression-writer/references/best-practices.md +154 -0
- package/skills/qa-visual-regression-writer/references/config.md +220 -0
- package/skills/qa-visual-regression-writer/references/patterns.md +213 -0
- package/skills/qa-vitest-writer/SKILL.md +141 -0
- package/skills/qa-vitest-writer/references/assertions.md +105 -0
- package/skills/qa-vitest-writer/references/best-practices.md +62 -0
- package/skills/qa-vitest-writer/references/config.md +127 -0
- package/skills/qa-vitest-writer/references/patterns.md +141 -0
- package/skills/qa-webdriverio-writer/SKILL.md +145 -0
- package/skills/qa-webdriverio-writer/references/best-practices.md +176 -0
- package/skills/qa-webdriverio-writer/references/config.md +240 -0
- package/skills/qa-webdriverio-writer/references/patterns.md +269 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: qa-jest-writer
|
|
3
|
+
description: Generate Jest unit and integration tests for TypeScript/JavaScript projects with jest.mock, snapshots, code coverage, and describe/it patterns.
|
|
4
|
+
output_dir: tests/unit
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# QA Jest Writer
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
Write Jest unit and integration tests from test case specifications (Phase 2 output). Transform structured test cases into executable TypeScript/JavaScript tests using Jest's describe/it patterns, mocking, snapshots, and coverage tooling.
|
|
12
|
+
|
|
13
|
+
## Trigger Phrases
|
|
14
|
+
|
|
15
|
+
- "Write Jest tests for [module/function]"
|
|
16
|
+
- "Generate Jest unit tests from test cases"
|
|
17
|
+
- "Create Jest integration tests for [service]"
|
|
18
|
+
- "Add Jest tests with mocks for [dependency]"
|
|
19
|
+
- "Jest snapshot tests for [component]"
|
|
20
|
+
- "Jest test coverage for [file]"
|
|
21
|
+
- "Parameterized Jest tests for [function]"
|
|
22
|
+
- "Jest async tests for [API handler]"
|
|
23
|
+
|
|
24
|
+
## Test Types
|
|
25
|
+
|
|
26
|
+
| Type | Scope | Focus |
|
|
27
|
+
| ---- | ----- | ----- |
|
|
28
|
+
| **Unit** | Isolated function/class testing | Single unit, mocked dependencies |
|
|
29
|
+
| **Integration** | Module interaction, service layer | Real or partial integration, fewer mocks |
|
|
30
|
+
|
|
31
|
+
## Workflow
|
|
32
|
+
|
|
33
|
+
1. **Read test cases** — From Phase 2 (qa-testcase-from-docs, qa-testcase-from-ui, qa-manual-test-designer)
|
|
34
|
+
2. **Analyze target code** — Identify module under test, dependencies, exports
|
|
35
|
+
3. **Generate test files** — Create `{module}.test.ts` or `{module}.spec.ts`
|
|
36
|
+
4. **Add mocks/fixtures** — jest.mock, jest.spyOn, factory functions, test data
|
|
37
|
+
5. **Verify coverage** — Ensure assertions match test case steps, run coverage report
|
|
38
|
+
|
|
39
|
+
## Context7 MCP
|
|
40
|
+
|
|
41
|
+
Uses **Context7 MCP** to fetch current Jest documentation when needed. Query for Jest API, matchers, or configuration to ensure generated tests align with latest Jest behavior.
|
|
42
|
+
|
|
43
|
+
## Key Patterns
|
|
44
|
+
|
|
45
|
+
| Pattern | Use Case |
|
|
46
|
+
| ------- | -------- |
|
|
47
|
+
| `describe` / `it` / `test` | Group and define test cases |
|
|
48
|
+
| `beforeEach` / `afterEach` | Setup and teardown per test |
|
|
49
|
+
| `jest.mock()` | Mock entire modules (hoisted) |
|
|
50
|
+
| `jest.spyOn()` | Spy on object methods |
|
|
51
|
+
| Snapshot testing | UI components, serializable output |
|
|
52
|
+
| `test.each` | Parameterized / table-driven tests |
|
|
53
|
+
| `async`/`await`, `done` | Async testing |
|
|
54
|
+
| Custom matchers | Domain-specific assertions |
|
|
55
|
+
|
|
56
|
+
## Assertion Patterns
|
|
57
|
+
|
|
58
|
+
| Assertion | Use |
|
|
59
|
+
| --------- | --- |
|
|
60
|
+
| `toBe` | Strict equality (===) |
|
|
61
|
+
| `toEqual` | Deep equality |
|
|
62
|
+
| `toMatchObject` | Partial object match |
|
|
63
|
+
| `toThrow` | Error thrown |
|
|
64
|
+
| `toHaveBeenCalledWith` | Mock call arguments |
|
|
65
|
+
| `resolves` / `rejects` | Promise outcomes |
|
|
66
|
+
|
|
67
|
+
See `references/assertions.md` for full reference.
|
|
68
|
+
|
|
69
|
+
## Configuration
|
|
70
|
+
|
|
71
|
+
- **jest.config.ts** — TypeScript config with `moduleNameMapper`, `transform`, `coverage`
|
|
72
|
+
- **tsconfig paths** — Map aliases (e.g., `@/` → `src/`)
|
|
73
|
+
- **setupFiles** — Global setup (e.g., env vars, polyfills)
|
|
74
|
+
|
|
75
|
+
See `references/config.md` for configuration guide.
|
|
76
|
+
|
|
77
|
+
## File Naming
|
|
78
|
+
|
|
79
|
+
- `{module}.test.ts` — Preferred (aligns with Jest default)
|
|
80
|
+
- `{module}.spec.ts` — Alternative (common in Angular/Vue)
|
|
81
|
+
|
|
82
|
+
Place tests next to source (`__tests__/` or colocated) or in `tests/` per project convention.
|
|
83
|
+
|
|
84
|
+
## Scope
|
|
85
|
+
|
|
86
|
+
**Can do (autonomous):**
|
|
87
|
+
- Generate Jest unit and integration tests from test case specs
|
|
88
|
+
- Add jest.mock, jest.spyOn, manual mocks
|
|
89
|
+
- Create snapshot tests for components/output
|
|
90
|
+
- Write parameterized tests (test.each)
|
|
91
|
+
- Handle async tests (async/await, resolves/rejects)
|
|
92
|
+
- Configure jest.config.ts patterns (moduleNameMapper, coverage)
|
|
93
|
+
- Use Context7 MCP for current Jest docs
|
|
94
|
+
|
|
95
|
+
**Cannot do (requires confirmation):**
|
|
96
|
+
- Change production code to make it testable
|
|
97
|
+
- Add tests for modules not in test case scope
|
|
98
|
+
- Override project Jest configuration without approval
|
|
99
|
+
|
|
100
|
+
**Will not do (out of scope):**
|
|
101
|
+
- E2E tests (use Playwright/Cypress skills)
|
|
102
|
+
- Run tests or interpret coverage reports
|
|
103
|
+
- Modify CI/CD pipelines
|
|
104
|
+
|
|
105
|
+
## References
|
|
106
|
+
|
|
107
|
+
- `references/patterns.md` — Unit structure, mocking strategies, async, snapshots, error testing
|
|
108
|
+
- `references/assertions.md` — Complete Jest assertion reference by category
|
|
109
|
+
- `references/config.md` — jest.config, tsconfig paths, coverage, setupFiles
|
|
110
|
+
- `references/best-practices.md` — Anti-patterns, AAA, isolation, descriptive names
|
|
111
|
+
|
|
112
|
+
## Quality Checklist
|
|
113
|
+
|
|
114
|
+
- [ ] No hardcoded sensitive data (use fixtures/env)
|
|
115
|
+
- [ ] Proper mocking (dependencies isolated, no real I/O)
|
|
116
|
+
- [ ] Assertions specific (no vague toBeTruthy for complex objects)
|
|
117
|
+
- [ ] Tests independent (order-independent, no shared mutable state)
|
|
118
|
+
- [ ] Descriptive test names (behavior/outcome, not implementation)
|
|
119
|
+
- [ ] Each test case step has corresponding assertion(s)
|
|
120
|
+
- [ ] Async tests use async/await or proper done/resolves
|
|
121
|
+
|
|
122
|
+
## Troubleshooting
|
|
123
|
+
|
|
124
|
+
| Symptom | Likely Cause | Fix |
|
|
125
|
+
| ------- | ------------ | --- |
|
|
126
|
+
| Module not found | Path/alias mismatch | Check `moduleNameMapper` in jest.config, tsconfig paths |
|
|
127
|
+
| Mock not working | Hoisting / import order | Use `jest.mock()` at top of file, before imports |
|
|
128
|
+
| Timeout | Async not resolved | Increase `jest.setTimeout()`, ensure promises resolve |
|
|
129
|
+
| Snapshot drift | Intentional change | Run `jest -u` to update; verify change is correct |
|
|
130
|
+
| Coverage gaps | Missing branches | Add tests for error paths, edge cases |
|
|
131
|
+
| Spy not called | Wrong target or timing | Verify spy on correct object, call after setup |
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Jest Assertion Reference
|
|
2
|
+
|
|
3
|
+
Organized by category. Use the most specific matcher for clear intent.
|
|
4
|
+
|
|
5
|
+
## Equality
|
|
6
|
+
|
|
7
|
+
| Matcher | Description | Example |
|
|
8
|
+
| ------- | ----------- | ------- |
|
|
9
|
+
| `toBe` | Strict equality (===) | `expect(1).toBe(1)` |
|
|
10
|
+
| `toEqual` | Deep equality | `expect({ a: 1 }).toEqual({ a: 1 })` |
|
|
11
|
+
| `toStrictEqual` | Deep + type check | `expect({ a: 1 }).toStrictEqual({ a: 1 })` |
|
|
12
|
+
| `toMatchObject` | Partial object match | `expect(obj).toMatchObject({ a: 1 })` |
|
|
13
|
+
| `toBeNull` | Exactly null | `expect(x).toBeNull()` |
|
|
14
|
+
| `toBeUndefined` | Exactly undefined | `expect(x).toBeUndefined()` |
|
|
15
|
+
| `toBeDefined` | Not undefined | `expect(x).toBeDefined()` |
|
|
16
|
+
|
|
17
|
+
## Truthiness
|
|
18
|
+
|
|
19
|
+
| Matcher | Description | Example |
|
|
20
|
+
| ------- | ----------- | ------- |
|
|
21
|
+
| `toBeTruthy` | Truthy value | `expect(1).toBeTruthy()` |
|
|
22
|
+
| `toBeFalsy` | Falsy value | `expect(0).toBeFalsy()` |
|
|
23
|
+
| `toBeTrue` | Exactly true | `expect(flag).toBe(true)` |
|
|
24
|
+
| `toBeFalse` | Exactly false | `expect(flag).toBe(false)` |
|
|
25
|
+
|
|
26
|
+
## Numbers
|
|
27
|
+
|
|
28
|
+
| Matcher | Description | Example |
|
|
29
|
+
| ------- | ----------- | ------- |
|
|
30
|
+
| `toBeGreaterThan` | > | `expect(5).toBeGreaterThan(3)` |
|
|
31
|
+
| `toBeGreaterThanOrEqual` | >= | `expect(5).toBeGreaterThanOrEqual(5)` |
|
|
32
|
+
| `toBeLessThan` | < | `expect(2).toBeLessThan(5)` |
|
|
33
|
+
| `toBeLessThanOrEqual` | <= | `expect(2).toBeLessThanOrEqual(2)` |
|
|
34
|
+
| `toBeCloseTo` | Float approx | `expect(0.1 + 0.2).toBeCloseTo(0.3)` |
|
|
35
|
+
|
|
36
|
+
## Strings
|
|
37
|
+
|
|
38
|
+
| Matcher | Description | Example |
|
|
39
|
+
| ------- | ----------- | ------- |
|
|
40
|
+
| `toMatch` | Regex or substring | `expect('hello').toMatch(/hel/)` |
|
|
41
|
+
| `toContain` | Substring | `expect('hello').toContain('ell')` |
|
|
42
|
+
| `toHaveLength` | Length | `expect('hi').toHaveLength(2)` |
|
|
43
|
+
|
|
44
|
+
## Arrays
|
|
45
|
+
|
|
46
|
+
| Matcher | Description | Example |
|
|
47
|
+
| ------- | ----------- | ------- |
|
|
48
|
+
| `toContain` | Item in array | `expect([1,2]).toContain(2)` |
|
|
49
|
+
| `toContainEqual` | Deep item match | `expect([{a:1}]).toContainEqual({a:1})` |
|
|
50
|
+
| `toHaveLength` | Array length | `expect([1,2]).toHaveLength(2)` |
|
|
51
|
+
| `toEqual` | Full array match | `expect(arr).toEqual([1,2,3])` |
|
|
52
|
+
|
|
53
|
+
## Objects
|
|
54
|
+
|
|
55
|
+
| Matcher | Description | Example |
|
|
56
|
+
| ------- | ----------- | ------- |
|
|
57
|
+
| `toMatchObject` | Partial match | `expect(obj).toMatchObject({ key: 1 })` |
|
|
58
|
+
| `toHaveProperty` | Has key | `expect(obj).toHaveProperty('key')` |
|
|
59
|
+
| `toHaveProperty('key', value)` | Key + value | `expect(obj).toHaveProperty('key', 1)` |
|
|
60
|
+
| `toEqual` | Deep equality | `expect(obj).toEqual(expected)` |
|
|
61
|
+
|
|
62
|
+
## Functions
|
|
63
|
+
|
|
64
|
+
| Matcher | Description | Example |
|
|
65
|
+
| ------- | ----------- | ------- |
|
|
66
|
+
| `toThrow` | Throws | `expect(() => fn()).toThrow()` |
|
|
67
|
+
| `toThrow('msg')` | Throws with message | `expect(() => fn()).toThrow('msg')` |
|
|
68
|
+
| `toThrow(/regex/)` | Throws matching regex | `expect(() => fn()).toThrow(/error/)` |
|
|
69
|
+
| `toThrow(ErrorType)` | Throws instance | `expect(() => fn()).toThrow(ValidationError)` |
|
|
70
|
+
|
|
71
|
+
## Mocks / Spies
|
|
72
|
+
|
|
73
|
+
| Matcher | Description | Example |
|
|
74
|
+
| ------- | ----------- | ------- |
|
|
75
|
+
| `toHaveBeenCalled` | Called at least once | `expect(mock).toHaveBeenCalled()` |
|
|
76
|
+
| `toHaveBeenCalledTimes(n)` | Called n times | `expect(mock).toHaveBeenCalledTimes(2)` |
|
|
77
|
+
| `toHaveBeenCalledWith(...args)` | Called with args | `expect(mock).toHaveBeenCalledWith(1, 2)` |
|
|
78
|
+
| `toHaveBeenLastCalledWith(...args)` | Last call args | `expect(mock).toHaveBeenLastCalledWith(1)` |
|
|
79
|
+
| `toHaveBeenNthCalledWith(n, ...args)` | Nth call args | `expect(mock).toHaveBeenNthCalledWith(2, 1, 2)` |
|
|
80
|
+
| `toHaveReturnedWith(value)` | Returned value | `expect(mock).toHaveReturnedWith(42)` |
|
|
81
|
+
| `not.toHaveBeenCalled` | Never called | `expect(mock).not.toHaveBeenCalled()` |
|
|
82
|
+
|
|
83
|
+
## Promises
|
|
84
|
+
|
|
85
|
+
| Matcher | Description | Example |
|
|
86
|
+
| ------- | ----------- | ------- |
|
|
87
|
+
| `resolves` | Awaits and asserts | `await expect(promise).resolves.toBe(1)` |
|
|
88
|
+
| `rejects` | Awaits rejection | `await expect(promise).rejects.toThrow()` |
|
|
89
|
+
| `resolves.toEqual` | Resolved value | `await expect(promise).resolves.toEqual(obj)` |
|
|
90
|
+
| `rejects.toThrow` | Rejected error | `await expect(promise).rejects.toThrow('err')` |
|
|
91
|
+
|
|
92
|
+
## Errors
|
|
93
|
+
|
|
94
|
+
| Matcher | Description | Example |
|
|
95
|
+
| ------- | ----------- | ------- |
|
|
96
|
+
| `toThrow` | Throws any | `expect(() => fn()).toThrow()` |
|
|
97
|
+
| `toThrow(Error)` | Throws Error type | `expect(() => fn()).toThrow(TypeError)` |
|
|
98
|
+
| `toThrow('message')` | Message match | `expect(() => fn()).toThrow('invalid')` |
|
|
99
|
+
| `toThrow(/pattern/)` | Message regex | `expect(() => fn()).toThrow(/invalid/)` |
|
|
100
|
+
|
|
101
|
+
## Negation
|
|
102
|
+
|
|
103
|
+
Use `.not` before any matcher:
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
expect(1).not.toBe(2);
|
|
107
|
+
expect(mock).not.toHaveBeenCalled();
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Custom Matchers
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
expect.extend({
|
|
114
|
+
toBeWithinRange(received, floor, ceiling) {
|
|
115
|
+
const pass = received >= floor && received <= ceiling;
|
|
116
|
+
return {
|
|
117
|
+
pass,
|
|
118
|
+
message: () =>
|
|
119
|
+
pass
|
|
120
|
+
? `expected ${received} not to be within ${floor} - ${ceiling}`
|
|
121
|
+
: `expected ${received} to be within ${floor} - ${ceiling}`,
|
|
122
|
+
};
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
```
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# Jest Best Practices and Anti-Patterns
|
|
2
|
+
|
|
3
|
+
## AAA Pattern
|
|
4
|
+
|
|
5
|
+
Structure each test as **Arrange, Act, Assert**:
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
it('calculates total with tax', () => {
|
|
9
|
+
// Arrange
|
|
10
|
+
const items = [{ price: 10 }, { price: 20 }];
|
|
11
|
+
const taxRate = 0.1;
|
|
12
|
+
|
|
13
|
+
// Act
|
|
14
|
+
const total = calculateTotal(items, taxRate);
|
|
15
|
+
|
|
16
|
+
// Assert
|
|
17
|
+
expect(total).toBe(33);
|
|
18
|
+
});
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Test Isolation
|
|
22
|
+
|
|
23
|
+
- Each test must run independently
|
|
24
|
+
- No shared mutable state between tests
|
|
25
|
+
- Use `beforeEach` for fresh setup
|
|
26
|
+
- Reset mocks with `jest.clearAllMocks()` or `jest.resetAllMocks()` when needed
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
beforeEach(() => {
|
|
30
|
+
jest.clearAllMocks();
|
|
31
|
+
});
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Descriptive Test Names
|
|
35
|
+
|
|
36
|
+
| Avoid | Prefer |
|
|
37
|
+
| ----- | ------ |
|
|
38
|
+
| `it('works')` | `it('returns user when id is valid')` |
|
|
39
|
+
| `it('test 1')` | `it('throws when input is null')` |
|
|
40
|
+
| `it('handles error')` | `it('returns 400 when email is invalid')` |
|
|
41
|
+
|
|
42
|
+
Use: **"should [expected behavior] when [condition]"**
|
|
43
|
+
|
|
44
|
+
## Test Behavior, Not Implementation
|
|
45
|
+
|
|
46
|
+
- Assert outcomes, not internal steps
|
|
47
|
+
- Avoid testing private methods directly
|
|
48
|
+
- Prefer testing through public API
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
// Avoid: testing implementation
|
|
52
|
+
expect(component.state.count).toBe(1);
|
|
53
|
+
|
|
54
|
+
// Prefer: testing behavior
|
|
55
|
+
expect(screen.getByText('Count: 1')).toBeInTheDocument();
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Mock Cleanup
|
|
59
|
+
|
|
60
|
+
- Restore spies: `spy.mockRestore()` in `afterEach`
|
|
61
|
+
- Clear mocks when reusing: `mockFn.mockClear()`
|
|
62
|
+
- Reset modules when needed: `jest.resetModules()`
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
afterEach(() => {
|
|
66
|
+
jest.restoreAllMocks();
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Anti-Patterns to Avoid
|
|
71
|
+
|
|
72
|
+
| Anti-Pattern | Problem | Fix |
|
|
73
|
+
| ------------ | ------- | --- |
|
|
74
|
+
| Multiple assertions for unrelated behaviors | Hard to pinpoint failure | One behavior per test |
|
|
75
|
+
| Testing implementation details | Brittle, breaks on refactor | Test observable behavior |
|
|
76
|
+
| Shared mutable state | Flaky, order-dependent | Fresh setup per test |
|
|
77
|
+
| `expect(x).toBeTruthy()` for objects | Vague, hides bugs | Use `toEqual`, `toMatchObject` |
|
|
78
|
+
| Hardcoded secrets | Security risk | Use env, fixtures, faker |
|
|
79
|
+
| Real I/O (DB, HTTP) in unit tests | Slow, flaky | Mock dependencies |
|
|
80
|
+
| Empty catch blocks | Swallows errors | Let tests fail or assert on error |
|
|
81
|
+
| Giant test files | Hard to maintain | Split by module/feature |
|
|
82
|
+
| `any` in test types | Weak typing | Use proper types |
|
|
83
|
+
|
|
84
|
+
## One Assertion Per Test (Guideline)
|
|
85
|
+
|
|
86
|
+
Prefer one logical assertion per test. Multiple related assertions for the same outcome are fine:
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
it('returns valid user object', () => {
|
|
90
|
+
const user = getUser(1);
|
|
91
|
+
expect(user).toHaveProperty('id', 1);
|
|
92
|
+
expect(user).toHaveProperty('name');
|
|
93
|
+
expect(user.email).toMatch(/^[\w.+-]+@[\w.-]+\.\w+$/);
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Fixtures Over Hardcoded Data
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
// fixtures/users.ts
|
|
101
|
+
export const mockUser = {
|
|
102
|
+
id: 1,
|
|
103
|
+
name: 'Test User',
|
|
104
|
+
email: 'test@example.com',
|
|
105
|
+
};
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
import { mockUser } from '../fixtures/users';
|
|
110
|
+
jest.mocked(api.fetchUser).mockResolvedValue(mockUser);
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Async: Prefer async/await
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
// Prefer
|
|
117
|
+
it('fetches data', async () => {
|
|
118
|
+
const data = await fetchData();
|
|
119
|
+
expect(data).toBeDefined();
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// Avoid when possible
|
|
123
|
+
it('fetches data', (done) => {
|
|
124
|
+
fetchData().then((data) => {
|
|
125
|
+
expect(data).toBeDefined();
|
|
126
|
+
done();
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Snapshot Discipline
|
|
132
|
+
|
|
133
|
+
- Use for stable, structured output
|
|
134
|
+
- Keep snapshots small and focused
|
|
135
|
+
- Review diffs before `jest -u`
|
|
136
|
+
- Prefer explicit assertions when behavior is more important than structure
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Jest Configuration Guide
|
|
2
|
+
|
|
3
|
+
## jest.config.ts (TypeScript)
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
import type { Config } from 'jest';
|
|
7
|
+
|
|
8
|
+
const config: Config = {
|
|
9
|
+
preset: 'ts-jest',
|
|
10
|
+
testEnvironment: 'node',
|
|
11
|
+
roots: ['<rootDir>/src'],
|
|
12
|
+
testMatch: ['**/*.test.ts', '**/*.spec.ts'],
|
|
13
|
+
moduleNameMapper: {
|
|
14
|
+
'^@/(.*)$': '<rootDir>/src/$1',
|
|
15
|
+
},
|
|
16
|
+
transform: {
|
|
17
|
+
'^.+\\.tsx?$': ['ts-jest', { useESM: true }],
|
|
18
|
+
},
|
|
19
|
+
collectCoverageFrom: [
|
|
20
|
+
'src/**/*.{ts,tsx}',
|
|
21
|
+
'!src/**/*.d.ts',
|
|
22
|
+
'!src/**/index.ts',
|
|
23
|
+
],
|
|
24
|
+
coverageDirectory: 'coverage',
|
|
25
|
+
coverageReporters: ['text', 'lcov', 'html'],
|
|
26
|
+
setupFiles: ['<rootDir>/jest.setup.ts'],
|
|
27
|
+
testTimeout: 10000,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export default config;
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## tsconfig Paths → moduleNameMapper
|
|
34
|
+
|
|
35
|
+
When using path aliases in tsconfig:
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"compilerOptions": {
|
|
40
|
+
"baseUrl": ".",
|
|
41
|
+
"paths": {
|
|
42
|
+
"@/*": ["src/*"],
|
|
43
|
+
"@utils/*": ["src/utils/*"]
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Map them in Jest:
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
moduleNameMapper: {
|
|
53
|
+
'^@/(.*)$': '<rootDir>/src/$1',
|
|
54
|
+
'^@utils/(.*)$': '<rootDir>/src/utils/$1',
|
|
55
|
+
},
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Coverage Setup
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
collectCoverageFrom: [
|
|
62
|
+
'src/**/*.{ts,tsx}',
|
|
63
|
+
'!src/**/*.d.ts',
|
|
64
|
+
'!src/**/index.ts',
|
|
65
|
+
'!src/**/__tests__/**',
|
|
66
|
+
],
|
|
67
|
+
coverageDirectory: 'coverage',
|
|
68
|
+
coverageReporters: ['text', 'lcov', 'html'],
|
|
69
|
+
coverageThreshold: {
|
|
70
|
+
global: {
|
|
71
|
+
branches: 80,
|
|
72
|
+
functions: 80,
|
|
73
|
+
lines: 80,
|
|
74
|
+
statements: 80,
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## transform
|
|
80
|
+
|
|
81
|
+
| Preset | Use Case |
|
|
82
|
+
| ------ | -------- |
|
|
83
|
+
| `ts-jest` | TypeScript |
|
|
84
|
+
| `babel-jest` | Babel + TS/JS |
|
|
85
|
+
| `@swc/jest` | Fast TS/JS via SWC |
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
transform: {
|
|
89
|
+
'^.+\\.tsx?$': ['ts-jest', { useESM: true }],
|
|
90
|
+
'^.+\\.(js|jsx)$': 'babel-jest',
|
|
91
|
+
},
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## testMatch
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
testMatch: [
|
|
98
|
+
'**/__tests__/**/*.[jt]s?(x)',
|
|
99
|
+
'**/?(*.)+(spec|test).[jt]s?(x)',
|
|
100
|
+
],
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## setupFiles
|
|
104
|
+
|
|
105
|
+
Global setup (runs before each test file):
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
setupFiles: ['<rootDir>/jest.setup.ts'],
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
// jest.setup.ts
|
|
113
|
+
process.env.NODE_ENV = 'test';
|
|
114
|
+
jest.setTimeout(10000);
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## testEnvironment
|
|
118
|
+
|
|
119
|
+
| Value | Use Case |
|
|
120
|
+
| ----- | -------- |
|
|
121
|
+
| `node` | Node.js (APIs, utils) |
|
|
122
|
+
| `jsdom` | DOM (React, Vue) |
|
|
123
|
+
| `jest-environment-jsdom` | Same as jsdom (Jest 28+) |
|
|
124
|
+
|
|
125
|
+
## Common Options
|
|
126
|
+
|
|
127
|
+
| Option | Description |
|
|
128
|
+
| ------ | ----------- |
|
|
129
|
+
| `clearMocks` | Clear mock calls between tests |
|
|
130
|
+
| `restoreMocks` | Restore original implementations |
|
|
131
|
+
| `testTimeout` | Default timeout (ms) |
|
|
132
|
+
| `verbose` | Individual test results |
|
|
133
|
+
| `roots` | Root directories for tests |
|
|
134
|
+
| `moduleFileExtensions` | Resolve order (e.g. `['ts','tsx','js','json']`) |
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# Jest Test Patterns
|
|
2
|
+
|
|
3
|
+
## Unit Test Structure
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
describe('ModuleName', () => {
|
|
7
|
+
describe('functionName', () => {
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
// Reset state, create fresh instances
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('should do X when Y', () => {
|
|
13
|
+
// Arrange
|
|
14
|
+
const input = { ... };
|
|
15
|
+
// Act
|
|
16
|
+
const result = functionName(input);
|
|
17
|
+
// Assert
|
|
18
|
+
expect(result).toEqual(expected);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
- **describe** — Groups by module, then by function or scenario
|
|
25
|
+
- **it** / **test** — One behavior per test
|
|
26
|
+
- **beforeEach** — Fresh setup; avoid shared mutable state
|
|
27
|
+
|
|
28
|
+
## Mocking Strategies
|
|
29
|
+
|
|
30
|
+
### Manual Mocks
|
|
31
|
+
|
|
32
|
+
Place in `__mocks__/` next to the module:
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
src/
|
|
36
|
+
services/
|
|
37
|
+
api.ts
|
|
38
|
+
__mocks__/
|
|
39
|
+
api.ts
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
// __mocks__/api.ts
|
|
44
|
+
export const fetchUser = jest.fn();
|
|
45
|
+
export const fetchPosts = jest.fn();
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Auto Mocks
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
jest.mock('./api');
|
|
52
|
+
// All exports become jest.fn()
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Factory Functions
|
|
56
|
+
|
|
57
|
+
For configurable mocks:
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
jest.mock('./api', () => ({
|
|
61
|
+
fetchUser: jest.fn(),
|
|
62
|
+
fetchPosts: jest.fn(),
|
|
63
|
+
}));
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### jest.spyOn
|
|
67
|
+
|
|
68
|
+
Spy on existing methods without replacing the module:
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
const spy = jest.spyOn(console, 'log').mockImplementation(() => {});
|
|
72
|
+
// ... test
|
|
73
|
+
spy.mockRestore();
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Mock Return Values
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
jest.mocked(api.fetchUser).mockResolvedValue({ id: 1, name: 'Alice' });
|
|
80
|
+
jest.mocked(api.fetchUser).mockRejectedValue(new Error('Network error'));
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Async Patterns
|
|
84
|
+
|
|
85
|
+
### async/await
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
it('fetches user', async () => {
|
|
89
|
+
const user = await fetchUser(1);
|
|
90
|
+
expect(user.name).toBe('Alice');
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### resolves / rejects
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
await expect(fetchUser(1)).resolves.toMatchObject({ id: 1 });
|
|
98
|
+
await expect(fetchUser(-1)).rejects.toThrow('Invalid id');
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### done Callback (legacy)
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
it('calls callback', (done) => {
|
|
105
|
+
someAsyncFn((err, result) => {
|
|
106
|
+
expect(err).toBeNull();
|
|
107
|
+
expect(result).toBeDefined();
|
|
108
|
+
done();
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Snapshot Patterns
|
|
114
|
+
|
|
115
|
+
### Basic Snapshot
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
it('renders correctly', () => {
|
|
119
|
+
const { container } = render(<MyComponent />);
|
|
120
|
+
expect(container).toMatchSnapshot();
|
|
121
|
+
});
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Inline Snapshot
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
expect(result).toMatchInlineSnapshot(`
|
|
128
|
+
Object {
|
|
129
|
+
"status": "ok",
|
|
130
|
+
"count": 1,
|
|
131
|
+
}
|
|
132
|
+
`);
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Snapshot Best Practices
|
|
136
|
+
|
|
137
|
+
- Use for stable, serializable output (UI, JSON)
|
|
138
|
+
- Avoid large snapshots; prefer focused assertions when possible
|
|
139
|
+
- Review snapshot diffs before updating
|
|
140
|
+
|
|
141
|
+
## Error Testing
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
it('throws when input is invalid', () => {
|
|
145
|
+
expect(() => validateInput(null)).toThrow('Input is required');
|
|
146
|
+
expect(() => validateInput(null)).toThrow(/required/);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('rejects with error', async () => {
|
|
150
|
+
await expect(asyncFn()).rejects.toThrow('Expected error');
|
|
151
|
+
});
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Parameterized Tests (test.each)
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
test.each([
|
|
158
|
+
[1, 1, 2],
|
|
159
|
+
[2, 3, 5],
|
|
160
|
+
[-1, 1, 0],
|
|
161
|
+
])('adds %i + %i = %i', (a, b, expected) => {
|
|
162
|
+
expect(add(a, b)).toBe(expected);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
test.each`
|
|
166
|
+
input | expected
|
|
167
|
+
${'a'} | ${'A'}
|
|
168
|
+
${'ab'} | ${'AB'}
|
|
169
|
+
`('uppercases $input to $expected', ({ input, expected }) => {
|
|
170
|
+
expect(input.toUpperCase()).toBe(expected);
|
|
171
|
+
});
|
|
172
|
+
```
|