aigroup-workflow 2.2.0 → 2.2.2

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.
Files changed (645) hide show
  1. package/.claude/commands/fix-build.md +10 -5
  2. package/.claude/commands/init-project.md +13 -8
  3. package/.claude/commands/plan.md +15 -8
  4. package/.claude/commands/review.md +12 -6
  5. package/.claude/commands/tdd.md +11 -5
  6. package/.claude/commands/workflow-start.md +20 -11
  7. package/.claude/settings.json +28 -0
  8. package/.codex/agents/architect.toml +207 -0
  9. package/.codex/agents/build-error-resolver.toml +110 -0
  10. package/.codex/agents/code-reviewer.toml +233 -0
  11. package/.codex/agents/doc-updater.toml +103 -0
  12. package/.codex/agents/e2e-runner.toml +103 -0
  13. package/.codex/agents/get-current-datetime.toml +23 -0
  14. package/.codex/agents/init-architect.toml +181 -0
  15. package/.codex/agents/planner.toml +208 -0
  16. package/.codex/agents/refactor-cleaner.toml +81 -0
  17. package/.codex/agents/rust-reviewer.toml +90 -0
  18. package/.codex/agents/security-reviewer.toml +104 -0
  19. package/.codex/agents/tdd-guide.toml +87 -0
  20. package/AGENTS.md +2 -2
  21. package/CLAUDE.md +23 -1
  22. package/LICENSE +20 -20
  23. package/README.md +333 -333
  24. package/agents/a11y-architect.md +141 -141
  25. package/agents/architect.md +211 -211
  26. package/agents/build-error-resolver.md +114 -114
  27. package/agents/chief-of-staff.md +151 -151
  28. package/agents/code-architect.md +71 -71
  29. package/agents/code-explorer.md +69 -69
  30. package/agents/code-reviewer.md +237 -237
  31. package/agents/code-simplifier.md +47 -47
  32. package/agents/comment-analyzer.md +45 -45
  33. package/agents/conversation-analyzer.md +52 -52
  34. package/agents/cpp-build-resolver.md +90 -90
  35. package/agents/cpp-reviewer.md +72 -72
  36. package/agents/csharp-reviewer.md +101 -101
  37. package/agents/dart-build-resolver.md +201 -201
  38. package/agents/database-reviewer.md +91 -91
  39. package/agents/doc-updater.md +107 -107
  40. package/agents/docs-lookup.md +68 -68
  41. package/agents/e2e-runner.md +107 -107
  42. package/agents/flutter-reviewer.md +243 -243
  43. package/agents/gan-evaluator.md +209 -209
  44. package/agents/gan-generator.md +131 -131
  45. package/agents/gan-planner.md +99 -99
  46. package/agents/get-current-datetime.md +26 -26
  47. package/agents/go-build-resolver.md +94 -94
  48. package/agents/go-reviewer.md +76 -76
  49. package/agents/harness-optimizer.md +35 -35
  50. package/agents/healthcare-reviewer.md +83 -83
  51. package/agents/java-build-resolver.md +153 -153
  52. package/agents/java-reviewer.md +92 -92
  53. package/agents/kotlin-build-resolver.md +118 -118
  54. package/agents/kotlin-reviewer.md +159 -159
  55. package/agents/loop-operator.md +36 -36
  56. package/agents/opensource-forker.md +198 -198
  57. package/agents/opensource-packager.md +249 -249
  58. package/agents/opensource-sanitizer.md +188 -188
  59. package/agents/performance-optimizer.md +446 -446
  60. package/agents/planner.md +212 -212
  61. package/agents/pr-test-analyzer.md +45 -45
  62. package/agents/python-reviewer.md +98 -98
  63. package/agents/pytorch-build-resolver.md +120 -120
  64. package/agents/refactor-cleaner.md +85 -85
  65. package/agents/rust-build-resolver.md +148 -148
  66. package/agents/rust-reviewer.md +94 -94
  67. package/agents/security-reviewer.md +108 -108
  68. package/agents/seo-specialist.md +59 -59
  69. package/agents/silent-failure-hunter.md +50 -50
  70. package/agents/tdd-guide.md +91 -91
  71. package/agents/type-design-analyzer.md +41 -41
  72. package/agents/typescript-reviewer.md +112 -112
  73. package/cli/commands/update.mjs +1 -1
  74. package/cli/utils/scaffold.mjs +53 -0
  75. package/docs/rules/agents.md +166 -50
  76. package/docs/rules/cpp/coding-style.md +44 -44
  77. package/docs/rules/cpp/hooks.md +39 -39
  78. package/docs/rules/cpp/patterns.md +51 -51
  79. package/docs/rules/cpp/security.md +51 -51
  80. package/docs/rules/cpp/testing.md +44 -44
  81. package/docs/rules/csharp/coding-style.md +72 -72
  82. package/docs/rules/csharp/hooks.md +25 -25
  83. package/docs/rules/csharp/patterns.md +50 -50
  84. package/docs/rules/csharp/security.md +58 -58
  85. package/docs/rules/csharp/testing.md +46 -46
  86. package/docs/rules/dart/coding-style.md +159 -159
  87. package/docs/rules/dart/hooks.md +66 -66
  88. package/docs/rules/dart/patterns.md +261 -261
  89. package/docs/rules/dart/security.md +135 -135
  90. package/docs/rules/dart/testing.md +215 -215
  91. package/docs/rules/golang/coding-style.md +32 -32
  92. package/docs/rules/golang/hooks.md +17 -17
  93. package/docs/rules/golang/patterns.md +45 -45
  94. package/docs/rules/golang/security.md +34 -34
  95. package/docs/rules/golang/testing.md +31 -31
  96. package/docs/rules/java/coding-style.md +114 -114
  97. package/docs/rules/java/hooks.md +18 -18
  98. package/docs/rules/java/patterns.md +146 -146
  99. package/docs/rules/java/security.md +100 -100
  100. package/docs/rules/java/testing.md +131 -131
  101. package/docs/rules/kotlin/coding-style.md +86 -86
  102. package/docs/rules/kotlin/hooks.md +17 -17
  103. package/docs/rules/kotlin/patterns.md +146 -146
  104. package/docs/rules/kotlin/security.md +82 -82
  105. package/docs/rules/kotlin/testing.md +128 -128
  106. package/docs/rules/perl/coding-style.md +46 -46
  107. package/docs/rules/perl/hooks.md +22 -22
  108. package/docs/rules/perl/patterns.md +76 -76
  109. package/docs/rules/perl/security.md +69 -69
  110. package/docs/rules/perl/testing.md +54 -54
  111. package/docs/rules/php/coding-style.md +40 -40
  112. package/docs/rules/php/hooks.md +24 -24
  113. package/docs/rules/php/patterns.md +33 -33
  114. package/docs/rules/php/security.md +37 -37
  115. package/docs/rules/php/testing.md +39 -39
  116. package/docs/rules/python/coding-style.md +42 -42
  117. package/docs/rules/python/hooks.md +19 -19
  118. package/docs/rules/python/patterns.md +39 -39
  119. package/docs/rules/python/security.md +30 -30
  120. package/docs/rules/python/testing.md +38 -38
  121. package/docs/rules/rust/coding-style.md +151 -151
  122. package/docs/rules/rust/hooks.md +16 -16
  123. package/docs/rules/rust/patterns.md +168 -168
  124. package/docs/rules/rust/security.md +141 -141
  125. package/docs/rules/rust/testing.md +154 -154
  126. package/docs/rules/swift/coding-style.md +47 -47
  127. package/docs/rules/swift/hooks.md +20 -20
  128. package/docs/rules/swift/patterns.md +66 -66
  129. package/docs/rules/swift/security.md +33 -33
  130. package/docs/rules/swift/testing.md +45 -45
  131. package/docs/rules/typescript/coding-style.md +199 -199
  132. package/docs/rules/typescript/hooks.md +22 -22
  133. package/docs/rules/typescript/patterns.md +52 -52
  134. package/docs/rules/typescript/security.md +28 -28
  135. package/docs/rules/typescript/testing.md +18 -18
  136. package/docs/rules/web/coding-style.md +96 -96
  137. package/docs/rules/web/design-quality.md +62 -62
  138. package/docs/rules/web/hooks.md +120 -120
  139. package/docs/rules/web/patterns.md +79 -79
  140. package/docs/rules/web/performance.md +64 -64
  141. package/docs/rules/web/security.md +57 -57
  142. package/docs/rules/web/testing.md +55 -55
  143. package/docs/templates/README.md +36 -36
  144. package/docs/templates/ai-project-final.md +124 -124
  145. package/docs/templates/ai-project.md +105 -105
  146. package/docs/templates/api.md +157 -157
  147. package/docs/templates/bug.md +62 -62
  148. package/docs/templates/code-review.md +87 -87
  149. package/docs/templates/generic.md +116 -116
  150. package/docs/templates/implementation-plan.md +1 -1
  151. package/docs/templates/meeting.md +68 -68
  152. package/docs/templates/prd.md +98 -98
  153. package/docs/templates/ui.md +134 -134
  154. package/docs/workflow-pipeline.md +11 -10
  155. package/package.json +40 -39
  156. package/scripts/hooks/checks/orchestration-artifacts.cjs +28 -23
  157. package/scripts/hooks/checks/workflow-state.cjs +4 -5
  158. package/scripts/orchestration/lib/orchestrator.cjs +344 -117
  159. package/scripts/orchestration/lib/validate.cjs +145 -0
  160. package/scripts/orchestration/session.cjs +88 -44
  161. package/skills/SUPERPOWERS-LICENSE +21 -21
  162. package/skills/ai-ml/fine-tuning-expert/SKILL.md +162 -162
  163. package/skills/ai-ml/fine-tuning-expert/references/dataset-preparation.md +540 -540
  164. package/skills/ai-ml/fine-tuning-expert/references/deployment-optimization.md +673 -673
  165. package/skills/ai-ml/fine-tuning-expert/references/evaluation-metrics.md +597 -597
  166. package/skills/ai-ml/fine-tuning-expert/references/hyperparameter-tuning.md +565 -565
  167. package/skills/ai-ml/fine-tuning-expert/references/lora-peft.md +347 -347
  168. package/skills/ai-ml/ml-pipeline/SKILL.md +159 -159
  169. package/skills/ai-ml/ml-pipeline/references/experiment-tracking.md +833 -833
  170. package/skills/ai-ml/ml-pipeline/references/feature-engineering.md +631 -631
  171. package/skills/ai-ml/ml-pipeline/references/model-validation.md +978 -978
  172. package/skills/ai-ml/ml-pipeline/references/pipeline-orchestration.md +907 -907
  173. package/skills/ai-ml/ml-pipeline/references/training-pipelines.md +782 -782
  174. package/skills/ai-ml/rag-architect/SKILL.md +194 -194
  175. package/skills/ai-ml/rag-architect/references/chunking-strategies.md +878 -878
  176. package/skills/ai-ml/rag-architect/references/embedding-models.md +561 -561
  177. package/skills/ai-ml/rag-architect/references/rag-evaluation.md +833 -833
  178. package/skills/ai-ml/rag-architect/references/retrieval-optimization.md +795 -795
  179. package/skills/ai-ml/rag-architect/references/vector-databases.md +589 -589
  180. package/skills/ai-ml/spark-engineer/SKILL.md +148 -148
  181. package/skills/ai-ml/spark-engineer/references/partitioning-caching.md +543 -543
  182. package/skills/ai-ml/spark-engineer/references/performance-tuning.md +544 -544
  183. package/skills/ai-ml/spark-engineer/references/rdd-operations.md +599 -599
  184. package/skills/ai-ml/spark-engineer/references/spark-sql-dataframes.md +474 -474
  185. package/skills/ai-ml/spark-engineer/references/streaming-patterns.md +786 -786
  186. package/skills/backend/api-designer/SKILL.md +217 -217
  187. package/skills/backend/api-designer/references/error-handling.md +541 -541
  188. package/skills/backend/api-designer/references/openapi.md +824 -824
  189. package/skills/backend/api-designer/references/pagination.md +494 -494
  190. package/skills/backend/api-designer/references/rest-patterns.md +335 -335
  191. package/skills/backend/api-designer/references/versioning.md +391 -391
  192. package/skills/backend/architecture-designer/SKILL.md +117 -117
  193. package/skills/backend/architecture-designer/references/adr-template.md +116 -116
  194. package/skills/backend/architecture-designer/references/architecture-patterns.md +111 -111
  195. package/skills/backend/architecture-designer/references/database-selection.md +102 -102
  196. package/skills/backend/architecture-designer/references/nfr-checklist.md +112 -112
  197. package/skills/backend/architecture-designer/references/system-design.md +100 -100
  198. package/skills/backend/code-documenter/SKILL.md +147 -147
  199. package/skills/backend/code-documenter/references/api-docs-fastapi-django.md +166 -166
  200. package/skills/backend/code-documenter/references/api-docs-nestjs-express.md +220 -220
  201. package/skills/backend/code-documenter/references/coverage-reports.md +125 -125
  202. package/skills/backend/code-documenter/references/documentation-systems.md +333 -333
  203. package/skills/backend/code-documenter/references/interactive-api-docs.md +531 -531
  204. package/skills/backend/code-documenter/references/python-docstrings.md +121 -121
  205. package/skills/backend/code-documenter/references/typescript-jsdoc.md +145 -145
  206. package/skills/backend/code-documenter/references/user-guides-tutorials.md +530 -530
  207. package/skills/backend/debugging-wizard/SKILL.md +105 -105
  208. package/skills/backend/debugging-wizard/references/common-patterns.md +132 -132
  209. package/skills/backend/debugging-wizard/references/debugging-tools.md +140 -140
  210. package/skills/backend/debugging-wizard/references/quick-fixes.md +177 -177
  211. package/skills/backend/debugging-wizard/references/strategies.md +142 -142
  212. package/skills/backend/debugging-wizard/references/systematic-debugging.md +367 -367
  213. package/skills/backend/feature-forge/SKILL.md +98 -98
  214. package/skills/backend/feature-forge/references/acceptance-criteria.md +104 -104
  215. package/skills/backend/feature-forge/references/ears-syntax.md +99 -99
  216. package/skills/backend/feature-forge/references/interview-questions.md +150 -150
  217. package/skills/backend/feature-forge/references/pre-discovery-subagents.md +54 -54
  218. package/skills/backend/feature-forge/references/specification-template.md +103 -103
  219. package/skills/backend/fullstack-guardian/SKILL.md +105 -105
  220. package/skills/backend/fullstack-guardian/references/api-design-standards.md +307 -307
  221. package/skills/backend/fullstack-guardian/references/architecture-decisions.md +350 -350
  222. package/skills/backend/fullstack-guardian/references/backend-patterns.md +237 -237
  223. package/skills/backend/fullstack-guardian/references/common-patterns.md +134 -134
  224. package/skills/backend/fullstack-guardian/references/deliverables-checklist.md +354 -354
  225. package/skills/backend/fullstack-guardian/references/design-template.md +91 -91
  226. package/skills/backend/fullstack-guardian/references/error-handling.md +135 -135
  227. package/skills/backend/fullstack-guardian/references/frontend-patterns.md +340 -340
  228. package/skills/backend/fullstack-guardian/references/integration-patterns.md +333 -333
  229. package/skills/backend/fullstack-guardian/references/security-checklist.md +106 -106
  230. package/skills/backend/graphql-architect/SKILL.md +146 -146
  231. package/skills/backend/graphql-architect/references/federation.md +418 -418
  232. package/skills/backend/graphql-architect/references/migration-from-rest.md +1141 -1141
  233. package/skills/backend/graphql-architect/references/resolvers.md +425 -425
  234. package/skills/backend/graphql-architect/references/schema-design.md +393 -393
  235. package/skills/backend/graphql-architect/references/security.md +569 -569
  236. package/skills/backend/graphql-architect/references/subscriptions.md +510 -510
  237. package/skills/backend/legacy-modernizer/SKILL.md +137 -137
  238. package/skills/backend/legacy-modernizer/references/legacy-testing.md +381 -381
  239. package/skills/backend/legacy-modernizer/references/migration-strategies.md +423 -423
  240. package/skills/backend/legacy-modernizer/references/refactoring-patterns.md +395 -395
  241. package/skills/backend/legacy-modernizer/references/strangler-fig-pattern.md +281 -281
  242. package/skills/backend/legacy-modernizer/references/system-assessment.md +487 -487
  243. package/skills/backend/microservices-architect/SKILL.md +164 -164
  244. package/skills/backend/microservices-architect/references/communication.md +499 -499
  245. package/skills/backend/microservices-architect/references/data.md +721 -721
  246. package/skills/backend/microservices-architect/references/decomposition.md +344 -344
  247. package/skills/backend/microservices-architect/references/observability.md +805 -805
  248. package/skills/backend/microservices-architect/references/patterns.md +603 -603
  249. package/skills/database/database-optimizer/SKILL.md +147 -147
  250. package/skills/database/database-optimizer/references/index-strategies.md +331 -331
  251. package/skills/database/database-optimizer/references/monitoring-analysis.md +501 -501
  252. package/skills/database/database-optimizer/references/mysql-tuning.md +452 -452
  253. package/skills/database/database-optimizer/references/postgresql-tuning.md +413 -413
  254. package/skills/database/database-optimizer/references/query-optimization.md +251 -251
  255. package/skills/database/postgres-pro/SKILL.md +152 -152
  256. package/skills/database/postgres-pro/references/extensions.md +404 -404
  257. package/skills/database/postgres-pro/references/jsonb.md +321 -321
  258. package/skills/database/postgres-pro/references/maintenance.md +481 -481
  259. package/skills/database/postgres-pro/references/performance.md +265 -265
  260. package/skills/database/postgres-pro/references/replication.md +446 -446
  261. package/skills/database/sql-pro/SKILL.md +129 -129
  262. package/skills/database/sql-pro/references/database-design.md +402 -402
  263. package/skills/database/sql-pro/references/dialect-differences.md +419 -419
  264. package/skills/database/sql-pro/references/optimization.md +384 -384
  265. package/skills/database/sql-pro/references/query-patterns.md +285 -285
  266. package/skills/database/sql-pro/references/window-functions.md +328 -328
  267. package/skills/dotnet/csharp-developer/SKILL.md +125 -125
  268. package/skills/dotnet/csharp-developer/references/aspnet-core.md +394 -394
  269. package/skills/dotnet/csharp-developer/references/blazor.md +553 -553
  270. package/skills/dotnet/csharp-developer/references/entity-framework.md +409 -409
  271. package/skills/dotnet/csharp-developer/references/modern-csharp.md +248 -248
  272. package/skills/dotnet/csharp-developer/references/performance.md +498 -498
  273. package/skills/dotnet/dotnet-core-expert/SKILL.md +138 -138
  274. package/skills/dotnet/dotnet-core-expert/references/authentication.md +546 -546
  275. package/skills/dotnet/dotnet-core-expert/references/clean-architecture.md +455 -455
  276. package/skills/dotnet/dotnet-core-expert/references/cloud-native.md +548 -548
  277. package/skills/dotnet/dotnet-core-expert/references/entity-framework.md +440 -440
  278. package/skills/dotnet/dotnet-core-expert/references/minimal-apis.md +319 -319
  279. package/skills/frontend/angular-architect/SKILL.md +152 -152
  280. package/skills/frontend/angular-architect/references/components.md +297 -297
  281. package/skills/frontend/angular-architect/references/ngrx.md +401 -401
  282. package/skills/frontend/angular-architect/references/routing.md +361 -361
  283. package/skills/frontend/angular-architect/references/rxjs.md +319 -319
  284. package/skills/frontend/angular-architect/references/testing.md +405 -405
  285. package/skills/frontend/design-commands/design.md +91 -91
  286. package/skills/frontend/design-commands/handoff.md +97 -97
  287. package/skills/frontend/design-commands/prototype.md +120 -120
  288. package/skills/frontend/design-commands/spec.md +160 -160
  289. package/skills/frontend/design-commands/style.md +78 -78
  290. package/skills/frontend/flutter-expert/SKILL.md +138 -138
  291. package/skills/frontend/flutter-expert/references/bloc-state.md +259 -259
  292. package/skills/frontend/flutter-expert/references/gorouter-navigation.md +119 -119
  293. package/skills/frontend/flutter-expert/references/performance.md +99 -99
  294. package/skills/frontend/flutter-expert/references/project-structure.md +118 -118
  295. package/skills/frontend/flutter-expert/references/riverpod-state.md +130 -130
  296. package/skills/frontend/flutter-expert/references/widget-patterns.md +123 -123
  297. package/skills/frontend/nextjs-developer/SKILL.md +143 -143
  298. package/skills/frontend/nextjs-developer/references/app-router.md +311 -311
  299. package/skills/frontend/nextjs-developer/references/data-fetching.md +482 -482
  300. package/skills/frontend/nextjs-developer/references/deployment.md +545 -545
  301. package/skills/frontend/nextjs-developer/references/server-actions.md +462 -462
  302. package/skills/frontend/nextjs-developer/references/server-components.md +384 -384
  303. package/skills/frontend/react-expert/SKILL.md +149 -149
  304. package/skills/frontend/react-expert/references/hooks-patterns.md +162 -162
  305. package/skills/frontend/react-expert/references/migration-class-to-modern.md +1119 -1119
  306. package/skills/frontend/react-expert/references/performance.md +168 -168
  307. package/skills/frontend/react-expert/references/react-19-features.md +174 -174
  308. package/skills/frontend/react-expert/references/server-components.md +143 -143
  309. package/skills/frontend/react-expert/references/state-management.md +171 -171
  310. package/skills/frontend/react-expert/references/testing-react.md +174 -174
  311. package/skills/frontend/react-native-expert/SKILL.md +185 -185
  312. package/skills/frontend/react-native-expert/references/expo-router.md +187 -187
  313. package/skills/frontend/react-native-expert/references/list-optimization.md +204 -204
  314. package/skills/frontend/react-native-expert/references/platform-handling.md +188 -188
  315. package/skills/frontend/react-native-expert/references/project-structure.md +171 -171
  316. package/skills/frontend/react-native-expert/references/storage-hooks.md +173 -173
  317. package/skills/frontend/senior-frontend/SKILL.md +477 -477
  318. package/skills/frontend/senior-frontend/references/frontend_best_practices.md +806 -806
  319. package/skills/frontend/senior-frontend/references/nextjs_optimization_guide.md +724 -724
  320. package/skills/frontend/senior-frontend/references/react_patterns.md +746 -746
  321. package/skills/frontend/senior-frontend/scripts/bundle_analyzer.py +407 -407
  322. package/skills/frontend/senior-frontend/scripts/component_generator.py +329 -329
  323. package/skills/frontend/senior-frontend/scripts/frontend_scaffolder.py +1005 -1005
  324. package/skills/frontend/ui-ux-pro-max/SKILL.md +386 -386
  325. package/skills/frontend/ui-ux-pro-max/data/charts.csv +26 -26
  326. package/skills/frontend/ui-ux-pro-max/data/colors.csv +97 -97
  327. package/skills/frontend/ui-ux-pro-max/data/icons.csv +101 -101
  328. package/skills/frontend/ui-ux-pro-max/data/landing.csv +31 -31
  329. package/skills/frontend/ui-ux-pro-max/data/products.csv +96 -96
  330. package/skills/frontend/ui-ux-pro-max/data/react-performance.csv +45 -45
  331. package/skills/frontend/ui-ux-pro-max/data/stacks/astro.csv +54 -54
  332. package/skills/frontend/ui-ux-pro-max/data/stacks/flutter.csv +53 -53
  333. package/skills/frontend/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -56
  334. package/skills/frontend/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -53
  335. package/skills/frontend/ui-ux-pro-max/data/stacks/nextjs.csv +53 -53
  336. package/skills/frontend/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -51
  337. package/skills/frontend/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -59
  338. package/skills/frontend/ui-ux-pro-max/data/stacks/react-native.csv +52 -52
  339. package/skills/frontend/ui-ux-pro-max/data/stacks/react.csv +54 -54
  340. package/skills/frontend/ui-ux-pro-max/data/stacks/shadcn.csv +61 -61
  341. package/skills/frontend/ui-ux-pro-max/data/stacks/svelte.csv +54 -54
  342. package/skills/frontend/ui-ux-pro-max/data/stacks/swiftui.csv +51 -51
  343. package/skills/frontend/ui-ux-pro-max/data/stacks/vue.csv +50 -50
  344. package/skills/frontend/ui-ux-pro-max/data/styles.csv +68 -68
  345. package/skills/frontend/ui-ux-pro-max/data/typography.csv +57 -57
  346. package/skills/frontend/ui-ux-pro-max/data/ui-reasoning.csv +101 -101
  347. package/skills/frontend/ui-ux-pro-max/data/ux-guidelines.csv +99 -99
  348. package/skills/frontend/ui-ux-pro-max/data/web-interface.csv +31 -31
  349. package/skills/frontend/ui-ux-pro-max/scripts/core.py +253 -253
  350. package/skills/frontend/ui-ux-pro-max/scripts/design_system.py +1067 -1067
  351. package/skills/frontend/ui-ux-pro-max/scripts/search.py +114 -114
  352. package/skills/frontend/vue-expert/SKILL.md +98 -98
  353. package/skills/frontend/vue-expert/references/build-tooling.md +480 -480
  354. package/skills/frontend/vue-expert/references/components.md +448 -448
  355. package/skills/frontend/vue-expert/references/composition-api.md +299 -299
  356. package/skills/frontend/vue-expert/references/mobile-hybrid.md +636 -636
  357. package/skills/frontend/vue-expert/references/nuxt.md +669 -669
  358. package/skills/frontend/vue-expert/references/state-management.md +449 -449
  359. package/skills/frontend/vue-expert/references/typescript.md +584 -584
  360. package/skills/frontend/vue-expert-js/SKILL.md +167 -167
  361. package/skills/frontend/vue-expert-js/references/component-architecture.md +219 -219
  362. package/skills/frontend/vue-expert-js/references/composables-patterns.md +183 -183
  363. package/skills/frontend/vue-expert-js/references/jsdoc-typing.md +535 -535
  364. package/skills/frontend/vue-expert-js/references/state-management.md +249 -249
  365. package/skills/frontend/vue-expert-js/references/testing-patterns.md +237 -237
  366. package/skills/go-rust-cpp/cpp-pro/SKILL.md +115 -115
  367. package/skills/go-rust-cpp/cpp-pro/references/build-tooling.md +440 -440
  368. package/skills/go-rust-cpp/cpp-pro/references/concurrency.md +437 -437
  369. package/skills/go-rust-cpp/cpp-pro/references/memory-performance.md +397 -397
  370. package/skills/go-rust-cpp/cpp-pro/references/modern-cpp.md +304 -304
  371. package/skills/go-rust-cpp/cpp-pro/references/templates.md +357 -357
  372. package/skills/go-rust-cpp/golang-pro/SKILL.md +122 -122
  373. package/skills/go-rust-cpp/golang-pro/references/concurrency.md +329 -329
  374. package/skills/go-rust-cpp/golang-pro/references/generics.md +442 -442
  375. package/skills/go-rust-cpp/golang-pro/references/interfaces.md +432 -432
  376. package/skills/go-rust-cpp/golang-pro/references/project-structure.md +477 -477
  377. package/skills/go-rust-cpp/golang-pro/references/testing.md +451 -451
  378. package/skills/go-rust-cpp/rust-engineer/SKILL.md +167 -167
  379. package/skills/go-rust-cpp/rust-engineer/references/async.md +458 -458
  380. package/skills/go-rust-cpp/rust-engineer/references/error-handling.md +334 -334
  381. package/skills/go-rust-cpp/rust-engineer/references/ownership.md +278 -278
  382. package/skills/go-rust-cpp/rust-engineer/references/testing.md +470 -470
  383. package/skills/go-rust-cpp/rust-engineer/references/traits.md +413 -413
  384. package/skills/infra/cli-developer/SKILL.md +113 -113
  385. package/skills/infra/cli-developer/references/design-patterns.md +221 -221
  386. package/skills/infra/cli-developer/references/go-cli.md +540 -540
  387. package/skills/infra/cli-developer/references/node-cli.md +383 -383
  388. package/skills/infra/cli-developer/references/python-cli.md +422 -422
  389. package/skills/infra/cli-developer/references/ux-patterns.md +448 -448
  390. package/skills/infra/cloud-architect/SKILL.md +216 -216
  391. package/skills/infra/cloud-architect/references/aws.md +394 -394
  392. package/skills/infra/cloud-architect/references/azure.md +562 -562
  393. package/skills/infra/cloud-architect/references/cost.md +582 -582
  394. package/skills/infra/cloud-architect/references/gcp.md +633 -633
  395. package/skills/infra/cloud-architect/references/multi-cloud.md +483 -483
  396. package/skills/infra/devops-engineer/SKILL.md +144 -144
  397. package/skills/infra/devops-engineer/references/deployment-strategies.md +241 -241
  398. package/skills/infra/devops-engineer/references/docker-patterns.md +113 -113
  399. package/skills/infra/devops-engineer/references/github-actions.md +139 -139
  400. package/skills/infra/devops-engineer/references/incident-response.md +331 -331
  401. package/skills/infra/devops-engineer/references/kubernetes.md +154 -154
  402. package/skills/infra/devops-engineer/references/platform-engineering.md +417 -417
  403. package/skills/infra/devops-engineer/references/release-automation.md +527 -527
  404. package/skills/infra/devops-engineer/references/terraform-iac.md +141 -141
  405. package/skills/infra/kubernetes-specialist/SKILL.md +241 -241
  406. package/skills/infra/kubernetes-specialist/references/configuration.md +452 -452
  407. package/skills/infra/kubernetes-specialist/references/cost-optimization.md +458 -458
  408. package/skills/infra/kubernetes-specialist/references/custom-operators.md +563 -563
  409. package/skills/infra/kubernetes-specialist/references/gitops.md +530 -530
  410. package/skills/infra/kubernetes-specialist/references/helm-charts.md +912 -912
  411. package/skills/infra/kubernetes-specialist/references/multi-cluster.md +507 -507
  412. package/skills/infra/kubernetes-specialist/references/networking.md +447 -447
  413. package/skills/infra/kubernetes-specialist/references/service-mesh.md +459 -459
  414. package/skills/infra/kubernetes-specialist/references/storage.md +535 -535
  415. package/skills/infra/kubernetes-specialist/references/troubleshooting.md +414 -414
  416. package/skills/infra/kubernetes-specialist/references/workloads.md +377 -377
  417. package/skills/infra/mcp-developer/SKILL.md +143 -143
  418. package/skills/infra/mcp-developer/references/protocol.md +244 -244
  419. package/skills/infra/mcp-developer/references/python-sdk.md +367 -367
  420. package/skills/infra/mcp-developer/references/resources.md +554 -554
  421. package/skills/infra/mcp-developer/references/tools.md +480 -480
  422. package/skills/infra/mcp-developer/references/typescript-sdk.md +350 -350
  423. package/skills/infra/monitoring-expert/SKILL.md +176 -176
  424. package/skills/infra/monitoring-expert/references/alerting-rules.md +141 -141
  425. package/skills/infra/monitoring-expert/references/application-profiling.md +331 -331
  426. package/skills/infra/monitoring-expert/references/capacity-planning.md +344 -344
  427. package/skills/infra/monitoring-expert/references/dashboards.md +126 -126
  428. package/skills/infra/monitoring-expert/references/opentelemetry.md +123 -123
  429. package/skills/infra/monitoring-expert/references/performance-testing.md +269 -269
  430. package/skills/infra/monitoring-expert/references/prometheus-metrics.md +136 -136
  431. package/skills/infra/monitoring-expert/references/structured-logging.md +142 -142
  432. package/skills/infra/sre-engineer/SKILL.md +181 -181
  433. package/skills/infra/sre-engineer/references/automation-toil.md +492 -492
  434. package/skills/infra/sre-engineer/references/error-budget-policy.md +334 -334
  435. package/skills/infra/sre-engineer/references/incident-chaos.md +576 -576
  436. package/skills/infra/sre-engineer/references/monitoring-alerting.md +424 -424
  437. package/skills/infra/sre-engineer/references/slo-sli-management.md +238 -238
  438. package/skills/infra/terraform-engineer/SKILL.md +143 -143
  439. package/skills/infra/terraform-engineer/references/best-practices.md +583 -583
  440. package/skills/infra/terraform-engineer/references/module-patterns.md +297 -297
  441. package/skills/infra/terraform-engineer/references/providers.md +452 -452
  442. package/skills/infra/terraform-engineer/references/state-management.md +371 -371
  443. package/skills/infra/terraform-engineer/references/testing.md +486 -486
  444. package/skills/infra/websocket-engineer/SKILL.md +168 -168
  445. package/skills/infra/websocket-engineer/references/alternatives.md +391 -391
  446. package/skills/infra/websocket-engineer/references/patterns.md +400 -400
  447. package/skills/infra/websocket-engineer/references/protocol.md +195 -195
  448. package/skills/infra/websocket-engineer/references/scaling.md +333 -333
  449. package/skills/infra/websocket-engineer/references/security.md +474 -474
  450. package/skills/java/java-architect/SKILL.md +132 -132
  451. package/skills/java/java-architect/references/jpa-optimization.md +393 -393
  452. package/skills/java/java-architect/references/reactive-webflux.md +356 -356
  453. package/skills/java/java-architect/references/spring-boot-setup.md +269 -269
  454. package/skills/java/java-architect/references/spring-security.md +445 -445
  455. package/skills/java/java-architect/references/testing-patterns.md +500 -500
  456. package/skills/java/kotlin-specialist/SKILL.md +147 -147
  457. package/skills/java/kotlin-specialist/references/android-compose.md +419 -419
  458. package/skills/java/kotlin-specialist/references/coroutines-flow.md +276 -276
  459. package/skills/java/kotlin-specialist/references/dsl-idioms.md +421 -421
  460. package/skills/java/kotlin-specialist/references/ktor-server.md +426 -426
  461. package/skills/java/kotlin-specialist/references/multiplatform-kmp.md +380 -380
  462. package/skills/java/spring-boot-engineer/SKILL.md +195 -195
  463. package/skills/java/spring-boot-engineer/references/cloud.md +498 -498
  464. package/skills/java/spring-boot-engineer/references/data.md +381 -381
  465. package/skills/java/spring-boot-engineer/references/security.md +459 -459
  466. package/skills/java/spring-boot-engineer/references/testing.md +545 -545
  467. package/skills/java/spring-boot-engineer/references/web.md +295 -295
  468. package/skills/javascript/javascript-pro/SKILL.md +132 -132
  469. package/skills/javascript/javascript-pro/references/async-patterns.md +334 -334
  470. package/skills/javascript/javascript-pro/references/browser-apis.md +398 -398
  471. package/skills/javascript/javascript-pro/references/modern-syntax.md +272 -272
  472. package/skills/javascript/javascript-pro/references/modules.md +357 -357
  473. package/skills/javascript/javascript-pro/references/node-essentials.md +471 -471
  474. package/skills/javascript/nestjs-expert/SKILL.md +206 -206
  475. package/skills/javascript/nestjs-expert/references/authentication.md +166 -166
  476. package/skills/javascript/nestjs-expert/references/controllers-routing.md +111 -111
  477. package/skills/javascript/nestjs-expert/references/dtos-validation.md +153 -153
  478. package/skills/javascript/nestjs-expert/references/migration-from-express.md +1237 -1237
  479. package/skills/javascript/nestjs-expert/references/services-di.md +140 -140
  480. package/skills/javascript/nestjs-expert/references/testing-patterns.md +186 -186
  481. package/skills/javascript/typescript-pro/SKILL.md +145 -145
  482. package/skills/javascript/typescript-pro/references/advanced-types.md +259 -259
  483. package/skills/javascript/typescript-pro/references/configuration.md +445 -445
  484. package/skills/javascript/typescript-pro/references/patterns.md +484 -484
  485. package/skills/javascript/typescript-pro/references/type-guards.md +352 -352
  486. package/skills/javascript/typescript-pro/references/utility-types.md +329 -329
  487. package/skills/php/laravel-specialist/SKILL.md +262 -262
  488. package/skills/php/laravel-specialist/references/eloquent.md +351 -351
  489. package/skills/php/laravel-specialist/references/livewire.md +512 -512
  490. package/skills/php/laravel-specialist/references/queues.md +423 -423
  491. package/skills/php/laravel-specialist/references/routing.md +362 -362
  492. package/skills/php/laravel-specialist/references/testing.md +522 -522
  493. package/skills/php/php-pro/SKILL.md +206 -206
  494. package/skills/php/php-pro/references/async-patterns.md +412 -412
  495. package/skills/php/php-pro/references/laravel-patterns.md +377 -377
  496. package/skills/php/php-pro/references/modern-php-features.md +323 -323
  497. package/skills/php/php-pro/references/symfony-patterns.md +466 -466
  498. package/skills/php/php-pro/references/testing-quality.md +466 -466
  499. package/skills/product/competitive-analysis/SKILL.md +257 -257
  500. package/skills/product/meeting-notes/SKILL.md +266 -266
  501. package/skills/product/prd-template/SKILL.md +150 -150
  502. package/skills/product/stakeholder-update/SKILL.md +225 -225
  503. package/skills/product/user-research-synthesis/SKILL.md +235 -235
  504. package/skills/python/django-expert/SKILL.md +162 -162
  505. package/skills/python/django-expert/references/authentication.md +145 -145
  506. package/skills/python/django-expert/references/drf-serializers.md +148 -148
  507. package/skills/python/django-expert/references/models-orm.md +151 -151
  508. package/skills/python/django-expert/references/testing-django.md +204 -204
  509. package/skills/python/django-expert/references/viewsets-views.md +153 -153
  510. package/skills/python/fastapi-expert/SKILL.md +185 -185
  511. package/skills/python/fastapi-expert/references/async-sqlalchemy.md +146 -146
  512. package/skills/python/fastapi-expert/references/authentication.md +159 -159
  513. package/skills/python/fastapi-expert/references/endpoints-routing.md +142 -142
  514. package/skills/python/fastapi-expert/references/migration-from-django.md +996 -996
  515. package/skills/python/fastapi-expert/references/pydantic-v2.md +135 -135
  516. package/skills/python/fastapi-expert/references/testing-async.md +159 -159
  517. package/skills/python/pandas-pro/SKILL.md +178 -178
  518. package/skills/python/pandas-pro/references/aggregation-groupby.md +545 -545
  519. package/skills/python/pandas-pro/references/data-cleaning.md +500 -500
  520. package/skills/python/pandas-pro/references/dataframe-operations.md +420 -420
  521. package/skills/python/pandas-pro/references/merging-joining.md +596 -596
  522. package/skills/python/pandas-pro/references/performance-optimization.md +597 -597
  523. package/skills/python/python-pro/SKILL.md +177 -177
  524. package/skills/python/python-pro/references/async-patterns.md +356 -356
  525. package/skills/python/python-pro/references/packaging.md +460 -460
  526. package/skills/python/python-pro/references/standard-library.md +378 -378
  527. package/skills/python/python-pro/references/testing.md +404 -404
  528. package/skills/python/python-pro/references/type-system.md +290 -290
  529. package/skills/quality/chaos-engineer/SKILL.md +182 -182
  530. package/skills/quality/chaos-engineer/references/chaos-tools.md +511 -511
  531. package/skills/quality/chaos-engineer/references/experiment-design.md +229 -229
  532. package/skills/quality/chaos-engineer/references/game-days.md +434 -434
  533. package/skills/quality/chaos-engineer/references/infrastructure-chaos.md +348 -348
  534. package/skills/quality/chaos-engineer/references/kubernetes-chaos.md +432 -432
  535. package/skills/quality/code-reviewer/SKILL.md +119 -119
  536. package/skills/quality/code-reviewer/references/common-issues.md +142 -142
  537. package/skills/quality/code-reviewer/references/feedback-examples.md +144 -144
  538. package/skills/quality/code-reviewer/references/receiving-feedback.md +238 -238
  539. package/skills/quality/code-reviewer/references/report-template.md +109 -109
  540. package/skills/quality/code-reviewer/references/review-checklist.md +88 -88
  541. package/skills/quality/code-reviewer/references/spec-compliance-review.md +258 -258
  542. package/skills/quality/playwright-expert/SKILL.md +169 -169
  543. package/skills/quality/playwright-expert/references/api-mocking.md +140 -140
  544. package/skills/quality/playwright-expert/references/configuration.md +155 -155
  545. package/skills/quality/playwright-expert/references/debugging-flaky.md +150 -150
  546. package/skills/quality/playwright-expert/references/page-object-model.md +152 -152
  547. package/skills/quality/playwright-expert/references/selectors-locators.md +119 -119
  548. package/skills/quality/secure-code-guardian/SKILL.md +191 -191
  549. package/skills/quality/secure-code-guardian/references/authentication.md +136 -136
  550. package/skills/quality/secure-code-guardian/references/input-validation.md +146 -146
  551. package/skills/quality/secure-code-guardian/references/owasp-prevention.md +135 -135
  552. package/skills/quality/secure-code-guardian/references/security-headers.md +133 -133
  553. package/skills/quality/secure-code-guardian/references/xss-csrf.md +157 -157
  554. package/skills/quality/security-reviewer/SKILL.md +103 -103
  555. package/skills/quality/security-reviewer/references/infrastructure-security.md +268 -268
  556. package/skills/quality/security-reviewer/references/penetration-testing.md +268 -268
  557. package/skills/quality/security-reviewer/references/report-template.md +170 -170
  558. package/skills/quality/security-reviewer/references/sast-tools.md +117 -117
  559. package/skills/quality/security-reviewer/references/secret-scanning.md +125 -125
  560. package/skills/quality/security-reviewer/references/vulnerability-patterns.md +152 -152
  561. package/skills/quality/senior-qa/README.md +196 -196
  562. package/skills/quality/senior-qa/SKILL.md +399 -399
  563. package/skills/quality/senior-qa/references/qa_best_practices.md +964 -964
  564. package/skills/quality/senior-qa/references/test_automation_patterns.md +1009 -1009
  565. package/skills/quality/senior-qa/references/testing_strategies.md +649 -649
  566. package/skills/quality/senior-qa/scripts/coverage_analyzer.py +836 -836
  567. package/skills/quality/senior-qa/scripts/e2e_test_scaffolder.py +820 -820
  568. package/skills/quality/senior-qa/scripts/test_suite_generator.py +605 -605
  569. package/skills/quality/tdd-guide/HOW_TO_USE.md +313 -313
  570. package/skills/quality/tdd-guide/README.md +680 -680
  571. package/skills/quality/tdd-guide/SKILL.md +122 -122
  572. package/skills/quality/tdd-guide/assets/expected_output.json +77 -77
  573. package/skills/quality/tdd-guide/assets/sample_input_python.json +39 -39
  574. package/skills/quality/tdd-guide/assets/sample_input_typescript.json +36 -36
  575. package/skills/quality/tdd-guide/references/ci-integration.md +195 -195
  576. package/skills/quality/tdd-guide/references/framework-guide.md +206 -206
  577. package/skills/quality/tdd-guide/references/tdd-best-practices.md +128 -128
  578. package/skills/quality/tdd-guide/scripts/coverage_analyzer.py +434 -434
  579. package/skills/quality/tdd-guide/scripts/fixture_generator.py +440 -440
  580. package/skills/quality/tdd-guide/scripts/format_detector.py +384 -384
  581. package/skills/quality/tdd-guide/scripts/framework_adapter.py +428 -428
  582. package/skills/quality/tdd-guide/scripts/metrics_calculator.py +456 -456
  583. package/skills/quality/tdd-guide/scripts/output_formatter.py +354 -354
  584. package/skills/quality/tdd-guide/scripts/tdd_workflow.py +474 -474
  585. package/skills/quality/tdd-guide/scripts/test_generator.py +438 -438
  586. package/skills/quality/test-master/SKILL.md +94 -94
  587. package/skills/quality/test-master/references/automation-frameworks.md +294 -294
  588. package/skills/quality/test-master/references/e2e-testing.md +128 -128
  589. package/skills/quality/test-master/references/integration-testing.md +120 -120
  590. package/skills/quality/test-master/references/performance-testing.md +118 -118
  591. package/skills/quality/test-master/references/qa-methodology.md +247 -247
  592. package/skills/quality/test-master/references/security-testing.md +127 -127
  593. package/skills/quality/test-master/references/tdd-iron-laws.md +174 -174
  594. package/skills/quality/test-master/references/test-reports.md +104 -104
  595. package/skills/quality/test-master/references/testing-anti-patterns.md +231 -231
  596. package/skills/quality/test-master/references/unit-testing.md +113 -113
  597. package/skills/ruby/rails-expert/SKILL.md +154 -154
  598. package/skills/ruby/rails-expert/references/active-record.md +244 -244
  599. package/skills/ruby/rails-expert/references/api-development.md +401 -401
  600. package/skills/ruby/rails-expert/references/background-jobs.md +272 -272
  601. package/skills/ruby/rails-expert/references/hotwire-turbo.md +228 -228
  602. package/skills/ruby/rails-expert/references/rspec-testing.md +367 -367
  603. package/skills/swift/swift-expert/SKILL.md +163 -163
  604. package/skills/swift/swift-expert/references/async-concurrency.md +360 -360
  605. package/skills/swift/swift-expert/references/memory-performance.md +377 -377
  606. package/skills/swift/swift-expert/references/protocol-oriented.md +354 -354
  607. package/skills/swift/swift-expert/references/swiftui-patterns.md +291 -291
  608. package/skills/swift/swift-expert/references/testing-patterns.md +399 -399
  609. package/skills/workflow/brainstorming/SKILL.md +164 -164
  610. package/skills/workflow/brainstorming/scripts/frame-template.html +214 -214
  611. package/skills/workflow/brainstorming/scripts/helper.js +88 -88
  612. package/skills/workflow/brainstorming/scripts/server.cjs +354 -354
  613. package/skills/workflow/brainstorming/scripts/start-server.sh +148 -148
  614. package/skills/workflow/brainstorming/scripts/stop-server.sh +56 -56
  615. package/skills/workflow/brainstorming/spec-document-reviewer-prompt.md +49 -49
  616. package/skills/workflow/brainstorming/visual-companion.md +287 -287
  617. package/skills/workflow/documentation/SKILL.md +45 -45
  618. package/skills/workflow/entropy-management/SKILL.md +115 -115
  619. package/skills/workflow/executing-plans/SKILL.md +70 -70
  620. package/skills/workflow/finishing-a-development-branch/SKILL.md +200 -200
  621. package/skills/workflow/receiving-code-review/SKILL.md +213 -213
  622. package/skills/workflow/requesting-code-review/SKILL.md +105 -105
  623. package/skills/workflow/requesting-code-review/code-reviewer.md +146 -146
  624. package/skills/workflow/requirement-engineering/SKILL.md +111 -111
  625. package/skills/workflow/systematic-debugging/CREATION-LOG.md +119 -119
  626. package/skills/workflow/systematic-debugging/SKILL.md +296 -296
  627. package/skills/workflow/systematic-debugging/condition-based-waiting-example.ts +158 -158
  628. package/skills/workflow/systematic-debugging/condition-based-waiting.md +115 -115
  629. package/skills/workflow/systematic-debugging/defense-in-depth.md +122 -122
  630. package/skills/workflow/systematic-debugging/find-polluter.sh +63 -63
  631. package/skills/workflow/systematic-debugging/root-cause-tracing.md +169 -169
  632. package/skills/workflow/systematic-debugging/test-academic.md +14 -14
  633. package/skills/workflow/systematic-debugging/test-pressure-1.md +58 -58
  634. package/skills/workflow/systematic-debugging/test-pressure-2.md +68 -68
  635. package/skills/workflow/systematic-debugging/test-pressure-3.md +69 -69
  636. package/skills/workflow/using-git-worktrees/SKILL.md +218 -218
  637. package/skills/workflow/verification-before-completion/SKILL.md +139 -139
  638. package/skills/workflow/writing-plans/SKILL.md +151 -151
  639. package/skills/workflow/writing-plans/plan-document-reviewer-prompt.md +49 -49
  640. package/skills/workflow/writing-skills/SKILL.md +655 -655
  641. package/skills/workflow/writing-skills/anthropic-best-practices.md +1150 -1150
  642. package/skills/workflow/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -189
  643. package/skills/workflow/writing-skills/persuasion-principles.md +187 -187
  644. package/skills/workflow/writing-skills/render-graphs.js +168 -168
  645. package/skills/workflow/writing-skills/testing-skills-with-subagents.md +384 -384
@@ -1,964 +1,964 @@
1
- # QA Best Practices for React and Next.js
2
-
3
- Guidelines for writing maintainable tests, debugging failures, and measuring test quality.
4
-
5
- ---
6
-
7
- ## Table of Contents
8
-
9
- - [Writing Testable Code](#writing-testable-code)
10
- - [Test Naming Conventions](#test-naming-conventions)
11
- - [Arrange-Act-Assert Pattern](#arrange-act-assert-pattern)
12
- - [Test Isolation Principles](#test-isolation-principles)
13
- - [Handling Flaky Tests](#handling-flaky-tests)
14
- - [Code Review for Testability](#code-review-for-testability)
15
- - [Test Maintenance Strategies](#test-maintenance-strategies)
16
- - [Debugging Failed Tests](#debugging-failed-tests)
17
- - [Quality Metrics and KPIs](#quality-metrics-and-kpis)
18
-
19
- ---
20
-
21
- ## Writing Testable Code
22
-
23
- Testable code is easy to understand, has clear boundaries, and minimizes dependencies.
24
-
25
- ### Dependency Injection
26
-
27
- Instead of creating dependencies inside functions, pass them as parameters.
28
-
29
- **Hard to Test:**
30
-
31
- ```typescript
32
- // src/services/userService.ts
33
- import { prisma } from '../lib/prisma';
34
- import { sendEmail } from '../lib/email';
35
-
36
- export async function createUser(data: UserInput) {
37
- const user = await prisma.user.create({ data });
38
- await sendEmail(user.email, 'Welcome!');
39
- return user;
40
- }
41
- ```
42
-
43
- **Easy to Test:**
44
-
45
- ```typescript
46
- // src/services/userService.ts
47
- export function createUserService(
48
- db: PrismaClient,
49
- emailService: EmailService
50
- ) {
51
- return {
52
- async createUser(data: UserInput) {
53
- const user = await db.user.create({ data });
54
- await emailService.send(user.email, 'Welcome!');
55
- return user;
56
- },
57
- };
58
- }
59
-
60
- // Usage in app
61
- const userService = createUserService(prisma, emailService);
62
-
63
- // Usage in tests
64
- const mockDb = { user: { create: jest.fn() } };
65
- const mockEmail = { send: jest.fn() };
66
- const testService = createUserService(mockDb, mockEmail);
67
- ```
68
-
69
- ### Pure Functions
70
-
71
- Pure functions are deterministic and have no side effects, making them trivial to test.
72
-
73
- **Impure (Hard to Test):**
74
-
75
- ```typescript
76
- function formatTimestamp() {
77
- const now = new Date();
78
- return `${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()}`;
79
- }
80
- ```
81
-
82
- **Pure (Easy to Test):**
83
-
84
- ```typescript
85
- function formatTimestamp(date: Date): string {
86
- return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
87
- }
88
-
89
- // Test
90
- expect(formatTimestamp(new Date('2024-03-15'))).toBe('2024-3-15');
91
- ```
92
-
93
- ### Separation of Concerns
94
-
95
- Separate business logic from UI and I/O operations.
96
-
97
- **Mixed Concerns (Hard to Test):**
98
-
99
- ```typescript
100
- // Component with embedded business logic
101
- function CheckoutForm() {
102
- const [total, setTotal] = useState(0);
103
-
104
- const handleSubmit = async (items: CartItem[]) => {
105
- // Business logic mixed with UI
106
- let sum = 0;
107
- for (const item of items) {
108
- sum += item.price * item.quantity;
109
- if (item.category === 'electronics') {
110
- sum *= 0.9; // 10% discount
111
- }
112
- }
113
- const tax = sum * 0.08;
114
- const finalTotal = sum + tax;
115
-
116
- // API call
117
- await fetch('/api/orders', {
118
- method: 'POST',
119
- body: JSON.stringify({ items, total: finalTotal }),
120
- });
121
-
122
- setTotal(finalTotal);
123
- };
124
-
125
- return <form onSubmit={handleSubmit}>...</form>;
126
- }
127
- ```
128
-
129
- **Separated Concerns (Easy to Test):**
130
-
131
- ```typescript
132
- // Pure business logic (easy to unit test)
133
- export function calculateOrderTotal(items: CartItem[]): number {
134
- return items.reduce((sum, item) => {
135
- const subtotal = item.price * item.quantity;
136
- const discount = item.category === 'electronics' ? 0.9 : 1;
137
- return sum + subtotal * discount;
138
- }, 0);
139
- }
140
-
141
- export function calculateTax(subtotal: number, rate = 0.08): number {
142
- return subtotal * rate;
143
- }
144
-
145
- // Custom hook for order logic (testable with renderHook)
146
- export function useCheckout() {
147
- const [total, setTotal] = useState(0);
148
- const mutation = useMutation(createOrder);
149
-
150
- const checkout = async (items: CartItem[]) => {
151
- const subtotal = calculateOrderTotal(items);
152
- const tax = calculateTax(subtotal);
153
- const finalTotal = subtotal + tax;
154
-
155
- await mutation.mutateAsync({ items, total: finalTotal });
156
- setTotal(finalTotal);
157
- };
158
-
159
- return { checkout, total, isLoading: mutation.isLoading };
160
- }
161
-
162
- // Component (integration testable)
163
- function CheckoutForm() {
164
- const { checkout, total, isLoading } = useCheckout();
165
- return <form onSubmit={() => checkout(items)}>...</form>;
166
- }
167
- ```
168
-
169
- ### Component Design for Testability
170
-
171
- | Pattern | Testability | Example |
172
- |---------|-------------|---------|
173
- | Props over context | High | `<Button disabled={!valid}>` |
174
- | Callbacks over side effects | High | `onSubmit={handleSubmit}` |
175
- | Controlled components | High | `<Input value={value} onChange={...}>` |
176
- | Render props | Medium | `<DataProvider render={data => ...}>` |
177
- | Internal state | Low | `const [x, setX] = useState()` |
178
- | Global state | Low | `useGlobalStore()` |
179
-
180
- ---
181
-
182
- ## Test Naming Conventions
183
-
184
- Good test names document expected behavior and help diagnose failures.
185
-
186
- ### Naming Patterns
187
-
188
- **Pattern 1: should [expected behavior] when [condition]**
189
-
190
- ```typescript
191
- describe('LoginForm', () => {
192
- it('should display error message when credentials are invalid', () => {});
193
- it('should redirect to dashboard when login succeeds', () => {});
194
- it('should disable submit button when form is submitting', () => {});
195
- });
196
- ```
197
-
198
- **Pattern 2: [method/action] [expected result]**
199
-
200
- ```typescript
201
- describe('calculateDiscount', () => {
202
- it('returns 0 for orders under $50', () => {});
203
- it('returns 10% for orders $50-$99', () => {});
204
- it('returns 20% for orders $100+', () => {});
205
- });
206
- ```
207
-
208
- **Pattern 3: given [context], when [action], then [result]**
209
-
210
- ```typescript
211
- describe('ShoppingCart', () => {
212
- it('given an empty cart, when adding an item, then cart count is 1', () => {});
213
- it('given items in cart, when removing all, then cart is empty', () => {});
214
- });
215
- ```
216
-
217
- ### Describe Block Organization
218
-
219
- ```typescript
220
- describe('UserService', () => {
221
- describe('createUser', () => {
222
- describe('with valid input', () => {
223
- it('creates user in database', () => {});
224
- it('sends welcome email', () => {});
225
- it('returns user with id', () => {});
226
- });
227
-
228
- describe('with invalid input', () => {
229
- it('throws ValidationError for missing email', () => {});
230
- it('throws ValidationError for invalid email format', () => {});
231
- it('throws ConflictError for duplicate email', () => {});
232
- });
233
- });
234
-
235
- describe('deleteUser', () => {
236
- it('removes user from database', () => {});
237
- it('throws NotFoundError for non-existent user', () => {});
238
- });
239
- });
240
- ```
241
-
242
- ### Anti-patterns to Avoid
243
-
244
- | Bad | Good | Why |
245
- |-----|------|-----|
246
- | `it('works')` | `it('returns sum of two numbers')` | Describes behavior |
247
- | `it('test 1')` | `it('handles empty array')` | Specific scenario |
248
- | `it('should do stuff')` | `it('should validate email format')` | Clear expectation |
249
- | Duplicating code in name | Describing behavior | Readable output |
250
-
251
- ---
252
-
253
- ## Arrange-Act-Assert Pattern
254
-
255
- The AAA pattern structures tests into three clear phases.
256
-
257
- ### Structure
258
-
259
- ```typescript
260
- it('calculates total with discount', () => {
261
- // Arrange - Set up test data and conditions
262
- const items = [
263
- { name: 'Widget', price: 100, quantity: 2 },
264
- { name: 'Gadget', price: 50, quantity: 1 },
265
- ];
266
- const discountRate = 0.1;
267
-
268
- // Act - Execute the code being tested
269
- const result = calculateTotal(items, discountRate);
270
-
271
- // Assert - Verify the outcome
272
- expect(result).toBe(225); // (200 + 50) * 0.9
273
- });
274
- ```
275
-
276
- ### Async Example
277
-
278
- ```typescript
279
- it('fetches user profile', async () => {
280
- // Arrange
281
- const userId = '123';
282
- server.use(
283
- rest.get('/api/users/:id', (req, res, ctx) =>
284
- res(ctx.json({ id: userId, name: 'John' }))
285
- )
286
- );
287
-
288
- // Act
289
- render(<UserProfile userId={userId} />);
290
-
291
- // Assert
292
- await expect(screen.findByText('John')).resolves.toBeInTheDocument();
293
- });
294
- ```
295
-
296
- ### Component Testing Example
297
-
298
- ```typescript
299
- it('submits form with user input', async () => {
300
- // Arrange
301
- const user = userEvent.setup();
302
- const onSubmit = jest.fn();
303
- render(<ContactForm onSubmit={onSubmit} />);
304
-
305
- // Act
306
- await user.type(screen.getByLabelText('Name'), 'John Doe');
307
- await user.type(screen.getByLabelText('Email'), 'john@example.com');
308
- await user.type(screen.getByLabelText('Message'), 'Hello!');
309
- await user.click(screen.getByRole('button', { name: 'Send' }));
310
-
311
- // Assert
312
- expect(onSubmit).toHaveBeenCalledWith({
313
- name: 'John Doe',
314
- email: 'john@example.com',
315
- message: 'Hello!',
316
- });
317
- });
318
- ```
319
-
320
- ### Guidelines
321
-
322
- 1. **One Act per test** - Test one behavior at a time
323
- 2. **Multiple assertions OK** - If they verify the same behavior
324
- 3. **Avoid logic in tests** - No if/else, loops in test code
325
- 4. **Setup in Arrange, not beforeEach** - Unless truly shared
326
-
327
- ---
328
-
329
- ## Test Isolation Principles
330
-
331
- Isolated tests are independent, repeatable, and can run in any order.
332
-
333
- ### State Isolation
334
-
335
- ```typescript
336
- describe('CartService', () => {
337
- let cartService: CartService;
338
-
339
- // Fresh instance for each test
340
- beforeEach(() => {
341
- cartService = new CartService();
342
- });
343
-
344
- it('adds item to empty cart', () => {
345
- cartService.addItem({ id: '1', quantity: 1 });
346
- expect(cartService.getItems()).toHaveLength(1);
347
- });
348
-
349
- it('starts with empty cart', () => {
350
- // Not affected by previous test
351
- expect(cartService.getItems()).toHaveLength(0);
352
- });
353
- });
354
- ```
355
-
356
- ### Database Isolation
357
-
358
- ```typescript
359
- describe('UserRepository', () => {
360
- beforeAll(async () => {
361
- // Connect to test database
362
- await db.connect(process.env.TEST_DATABASE_URL);
363
- });
364
-
365
- beforeEach(async () => {
366
- // Clean database before each test
367
- await db.query('TRUNCATE users CASCADE');
368
- });
369
-
370
- afterAll(async () => {
371
- await db.disconnect();
372
- });
373
-
374
- it('creates user', async () => {
375
- const user = await userRepo.create({ email: 'test@example.com' });
376
- expect(user.id).toBeDefined();
377
- });
378
- });
379
- ```
380
-
381
- ### API Mocking Isolation
382
-
383
- ```typescript
384
- describe('ProductList', () => {
385
- // Reset handlers after each test
386
- afterEach(() => server.resetHandlers());
387
-
388
- it('shows products from API', async () => {
389
- // Default handler returns products
390
- render(<ProductList />);
391
- await expect(screen.findByText('Widget')).resolves.toBeInTheDocument();
392
- });
393
-
394
- it('shows error on API failure', async () => {
395
- // Override handler for this test only
396
- server.use(
397
- rest.get('/api/products', (req, res, ctx) =>
398
- res(ctx.status(500))
399
- )
400
- );
401
-
402
- render(<ProductList />);
403
- await expect(screen.findByText('Error')).resolves.toBeInTheDocument();
404
- });
405
-
406
- it('shows products again', async () => {
407
- // Back to default handler (server.resetHandlers ran)
408
- render(<ProductList />);
409
- await expect(screen.findByText('Widget')).resolves.toBeInTheDocument();
410
- });
411
- });
412
- ```
413
-
414
- ### Isolation Checklist
415
-
416
- | Aspect | Solution |
417
- |--------|----------|
418
- | Global state | Reset in beforeEach |
419
- | Timers | jest.useFakeTimers() + jest.useRealTimers() |
420
- | DOM | RTL's cleanup (automatic) |
421
- | Database | Truncate tables or use transactions |
422
- | API mocks | server.resetHandlers() |
423
- | File system | Use temp directories, clean up in afterEach |
424
- | Environment vars | Restore in afterEach |
425
-
426
- ---
427
-
428
- ## Handling Flaky Tests
429
-
430
- Flaky tests pass and fail intermittently without code changes.
431
-
432
- ### Common Causes and Fixes
433
-
434
- **1. Timing Issues**
435
-
436
- ```typescript
437
- // Flaky - race condition
438
- it('shows loading then data', () => {
439
- render(<UserProfile />);
440
- expect(screen.getByText('Loading')).toBeInTheDocument();
441
- expect(screen.getByText('John')).toBeInTheDocument(); // May fail
442
- });
443
-
444
- // Fixed - proper async handling
445
- it('shows loading then data', async () => {
446
- render(<UserProfile />);
447
- expect(screen.getByText('Loading')).toBeInTheDocument();
448
- await waitFor(() => {
449
- expect(screen.getByText('John')).toBeInTheDocument();
450
- });
451
- });
452
- ```
453
-
454
- **2. Non-deterministic Data**
455
-
456
- ```typescript
457
- // Flaky - random data
458
- it('sorts users alphabetically', () => {
459
- const users = [createUser(), createUser(), createUser()];
460
- // Names are random, order unpredictable
461
- });
462
-
463
- // Fixed - deterministic data
464
- it('sorts users alphabetically', () => {
465
- const users = [
466
- createUser({ name: 'Charlie' }),
467
- createUser({ name: 'Alice' }),
468
- createUser({ name: 'Bob' }),
469
- ];
470
- const sorted = sortUsers(users);
471
- expect(sorted.map(u => u.name)).toEqual(['Alice', 'Bob', 'Charlie']);
472
- });
473
- ```
474
-
475
- **3. Test Order Dependencies**
476
-
477
- ```typescript
478
- // Flaky - relies on previous test
479
- describe('Counter', () => {
480
- const counter = new Counter(); // Shared instance!
481
-
482
- it('increments', () => {
483
- counter.increment();
484
- expect(counter.value).toBe(1);
485
- });
486
-
487
- it('starts at zero', () => {
488
- expect(counter.value).toBe(0); // Fails! Value is 1
489
- });
490
- });
491
-
492
- // Fixed - fresh instance per test
493
- describe('Counter', () => {
494
- let counter: Counter;
495
-
496
- beforeEach(() => {
497
- counter = new Counter();
498
- });
499
-
500
- it('increments', () => {
501
- counter.increment();
502
- expect(counter.value).toBe(1);
503
- });
504
-
505
- it('starts at zero', () => {
506
- expect(counter.value).toBe(0); // Passes
507
- });
508
- });
509
- ```
510
-
511
- **4. Network/External Dependencies**
512
-
513
- ```typescript
514
- // Flaky - real network call
515
- it('fetches data', async () => {
516
- const data = await fetch('https://api.example.com/data');
517
- expect(data).toBeDefined();
518
- });
519
-
520
- // Fixed - mock the network
521
- it('fetches data', async () => {
522
- server.use(
523
- rest.get('https://api.example.com/data', (req, res, ctx) =>
524
- res(ctx.json({ value: 42 }))
525
- )
526
- );
527
-
528
- const data = await fetchData();
529
- expect(data.value).toBe(42);
530
- });
531
- ```
532
-
533
- ### Flaky Test Detection
534
-
535
- ```javascript
536
- // jest.config.js
537
- module.exports = {
538
- // Run each test multiple times to detect flakiness
539
- testEnvironment: 'jsdom',
540
-
541
- // Add reporters to track flaky tests
542
- reporters: [
543
- 'default',
544
- ['jest-junit', { outputDirectory: './reports' }],
545
- ],
546
- };
547
-
548
- // Run tests multiple times
549
- // npx jest --runInBand --testTimeout=10000 --repeat=5
550
- ```
551
-
552
- ### Quarantine Strategy
553
-
554
- 1. **Identify** - Track tests that fail randomly
555
- 2. **Quarantine** - Move to separate suite, run separately
556
- 3. **Fix** - Investigate and fix root cause
557
- 4. **Restore** - Move back to main suite
558
-
559
- ```typescript
560
- // Temporarily skip flaky test
561
- it.skip('flaky test to fix', () => {
562
- // TODO: Fix timing issue in #123
563
- });
564
-
565
- // Or run only when investigating
566
- it.todo('investigate flaky behavior');
567
- ```
568
-
569
- ---
570
-
571
- ## Code Review for Testability
572
-
573
- Questions to ask during code review to ensure testable code.
574
-
575
- ### Testability Checklist
576
-
577
- **Functions and Methods:**
578
- - [ ] Does it have a single responsibility?
579
- - [ ] Are dependencies injected?
580
- - [ ] Can it be tested without mocking internals?
581
- - [ ] Does it return a value or have observable side effects?
582
-
583
- **Components:**
584
- - [ ] Are props descriptive and minimal?
585
- - [ ] Can behavior be triggered via user events?
586
- - [ ] Are loading/error states exposed?
587
- - [ ] Can it be rendered without a full app context?
588
-
589
- **State Management:**
590
- - [ ] Is state minimal and derived where possible?
591
- - [ ] Can state changes be triggered and observed?
592
- - [ ] Are side effects separated from reducers?
593
-
594
- ### Review Comments
595
-
596
- **Before:**
597
- ```typescript
598
- // Hard to test - embedded dependency
599
- function processPayment(order: Order) {
600
- const stripe = new Stripe(process.env.STRIPE_KEY);
601
- return stripe.charges.create({
602
- amount: order.total,
603
- currency: 'usd',
604
- });
605
- }
606
- ```
607
-
608
- **Review Comment:**
609
- > Consider injecting the payment processor to improve testability:
610
- > ```typescript
611
- > function processPayment(order: Order, processor: PaymentProcessor) {
612
- > return processor.charge(order.total, 'usd');
613
- > }
614
- > ```
615
- > This allows testing with a mock processor without hitting Stripe's API.
616
-
617
- ---
618
-
619
- ## Test Maintenance Strategies
620
-
621
- Keep tests maintainable as the codebase evolves.
622
-
623
- ### Reducing Duplication
624
-
625
- **Use helpers for common assertions:**
626
-
627
- ```typescript
628
- // __tests__/helpers/assertions.ts
629
- export function expectLoadingState(container: HTMLElement) {
630
- expect(within(container).getByRole('progressbar')).toBeInTheDocument();
631
- }
632
-
633
- export function expectErrorState(container: HTMLElement, message: string) {
634
- expect(within(container).getByRole('alert')).toHaveTextContent(message);
635
- }
636
-
637
- // Usage
638
- it('shows loading state', () => {
639
- render(<DataList />);
640
- expectLoadingState(screen.getByTestId('data-list'));
641
- });
642
- ```
643
-
644
- **Use factory functions:**
645
-
646
- ```typescript
647
- // Instead of repeating setup
648
- function renderWithUser(ui: ReactElement, user = createUser()) {
649
- return {
650
- user,
651
- ...render(<AuthProvider user={user}>{ui}</AuthProvider>),
652
- };
653
- }
654
- ```
655
-
656
- ### Updating Tests When Code Changes
657
-
658
- **Scenario: Renaming a prop**
659
-
660
- ```typescript
661
- // Old component
662
- <Button onClick={handleClick} />
663
-
664
- // New component
665
- <Button onPress={handleClick} />
666
-
667
- // Find and update all tests
668
- // grep -r "onClick" __tests__/ --include="*.test.tsx"
669
- ```
670
-
671
- **Scenario: Changing API response shape**
672
-
673
- ```typescript
674
- // Update factory first
675
- export function createUserResponse(overrides = {}) {
676
- return {
677
- user: { // New nested structure
678
- id: '1',
679
- name: 'Test User',
680
- ...overrides,
681
- },
682
- };
683
- }
684
-
685
- // Tests automatically get new shape
686
- ```
687
-
688
- ### When to Delete Tests
689
-
690
- - **Redundant coverage** - Multiple tests testing the same thing
691
- - **Testing implementation** - Tests that break on refactor
692
- - **Obsolete features** - Tests for removed functionality
693
- - **Flaky beyond repair** - Tests that can't be stabilized
694
-
695
- ### Test Documentation
696
-
697
- ```typescript
698
- /**
699
- * @group integration
700
- * @requires database
701
- *
702
- * Tests for the order processing workflow.
703
- * These tests require a running PostgreSQL instance.
704
- *
705
- * Setup: docker-compose up -d postgres
706
- */
707
- describe('OrderProcessor', () => {
708
- /**
709
- * Verifies that orders with backordered items
710
- * are split into separate fulfillment batches.
711
- *
712
- * Related: JIRA-1234
713
- */
714
- it('splits orders with backordered items', () => {});
715
- });
716
- ```
717
-
718
- ---
719
-
720
- ## Debugging Failed Tests
721
-
722
- Techniques for investigating test failures.
723
-
724
- ### Jest Debugging
725
-
726
- **Run single test:**
727
- ```bash
728
- # By name pattern
729
- npx jest -t "should validate email"
730
-
731
- # By file
732
- npx jest src/utils/__tests__/validation.test.ts
733
-
734
- # Watch mode for iteration
735
- npx jest --watch
736
- ```
737
-
738
- **Debug with Node inspector:**
739
- ```bash
740
- node --inspect-brk node_modules/.bin/jest --runInBand
741
- # Open chrome://inspect in Chrome
742
- ```
743
-
744
- **Verbose output:**
745
- ```bash
746
- npx jest --verbose --no-coverage
747
- ```
748
-
749
- ### React Testing Library Debugging
750
-
751
- ```typescript
752
- it('renders user profile', async () => {
753
- render(<UserProfile userId="123" />);
754
-
755
- // Print current DOM
756
- screen.debug();
757
-
758
- // Print specific element
759
- screen.debug(screen.getByRole('heading'));
760
-
761
- // Log accessible roles
762
- screen.logTestingPlaygroundURL(); // Opens interactive playground
763
-
764
- // Check what queries would match
765
- const element = screen.getByRole('button');
766
- console.log(prettyDOM(element));
767
- });
768
- ```
769
-
770
- ### Playwright Debugging
771
-
772
- ```bash
773
- # Debug mode - opens browser with inspector
774
- npx playwright test --debug
775
-
776
- # UI mode - visual test runner
777
- npx playwright test --ui
778
-
779
- # Headed mode - see browser
780
- npx playwright test --headed
781
-
782
- # Trace viewer after failure
783
- npx playwright show-trace trace.zip
784
- ```
785
-
786
- **Pause in test:**
787
- ```typescript
788
- test('debug this', async ({ page }) => {
789
- await page.goto('/');
790
- await page.pause(); // Opens inspector
791
- await page.click('button');
792
- });
793
- ```
794
-
795
- ### Common Failure Patterns
796
-
797
- | Symptom | Likely Cause | Debug Approach |
798
- |---------|--------------|----------------|
799
- | "Unable to find element" | Wrong query or element not rendered | `screen.debug()`, check async |
800
- | "Expected X, received Y" | Logic error or stale mock | Log intermediate values |
801
- | "Timeout exceeded" | Slow async or missing await | Increase timeout, check promises |
802
- | "Cannot read property of undefined" | Missing mock or setup | Check beforeEach, mock returns |
803
- | Passes locally, fails in CI | Environment difference | Check env vars, timing |
804
-
805
- ### Investigating Flaky Failures
806
-
807
- ```typescript
808
- // Add logging for intermittent failures
809
- it('processes order', async () => {
810
- console.log('Test started at', Date.now());
811
-
812
- const order = await createOrder();
813
- console.log('Order created:', order.id);
814
-
815
- const result = await processOrder(order);
816
- console.log('Process result:', result);
817
-
818
- expect(result.status).toBe('completed');
819
- });
820
- ```
821
-
822
- ---
823
-
824
- ## Quality Metrics and KPIs
825
-
826
- Measure test suite effectiveness and track quality improvements.
827
-
828
- ### Key Metrics
829
-
830
- **Coverage Metrics:**
831
-
832
- | Metric | Target | Measurement |
833
- |--------|--------|-------------|
834
- | Line coverage | 80% | `jest --coverage` |
835
- | Branch coverage | 75% | `jest --coverage` |
836
- | Function coverage | 80% | `jest --coverage` |
837
- | Critical path coverage | 95% | Custom tracking |
838
-
839
- **Test Suite Health:**
840
-
841
- | Metric | Target | Measurement |
842
- |--------|--------|-------------|
843
- | Test pass rate | 100% | CI reports |
844
- | Flaky test rate | <1% | Track retries |
845
- | Test execution time | <5 min | CI timing |
846
- | Tests per component | ≥3 | Test count / components |
847
-
848
- **Defect Metrics:**
849
-
850
- | Metric | Target | Measurement |
851
- |--------|--------|-------------|
852
- | Defects found in testing | >70% | Bug tracking |
853
- | Defects escaped to prod | <10% | Production bugs |
854
- | Regression rate | <5% | Bugs reintroduced |
855
- | Mean time to detect | <1 day | Bug timestamps |
856
-
857
- ### Dashboard Example
858
-
859
- ```typescript
860
- // scripts/test-metrics.ts
861
- import { readCoverageReport } from './utils';
862
-
863
- const coverage = readCoverageReport('./coverage/coverage-summary.json');
864
- const testResults = readTestReport('./reports/jest-results.json');
865
-
866
- const metrics = {
867
- coverage: {
868
- lines: coverage.total.lines.pct,
869
- branches: coverage.total.branches.pct,
870
- functions: coverage.total.functions.pct,
871
- },
872
- tests: {
873
- total: testResults.numTotalTests,
874
- passed: testResults.numPassedTests,
875
- failed: testResults.numFailedTests,
876
- passRate: (testResults.numPassedTests / testResults.numTotalTests) * 100,
877
- },
878
- execution: {
879
- duration: testResults.testResults.reduce((sum, r) => sum + r.duration, 0),
880
- },
881
- };
882
-
883
- console.log('Test Metrics:', JSON.stringify(metrics, null, 2));
884
- ```
885
-
886
- ### CI Quality Gates
887
-
888
- ```yaml
889
- # .github/workflows/quality.yml
890
- name: Quality Gates
891
-
892
- on: [push, pull_request]
893
-
894
- jobs:
895
- test:
896
- runs-on: ubuntu-latest
897
- steps:
898
- - uses: actions/checkout@v4
899
- - uses: actions/setup-node@v4
900
-
901
- - run: npm ci
902
- - run: npm test -- --coverage
903
-
904
- # Coverage gate
905
- - name: Check coverage
906
- run: |
907
- coverage=$(jq '.total.lines.pct' coverage/coverage-summary.json)
908
- if (( $(echo "$coverage < 80" | bc -l) )); then
909
- echo "Coverage $coverage% is below 80% threshold"
910
- exit 1
911
- fi
912
-
913
- # Test count gate
914
- - name: Check test count
915
- run: |
916
- tests=$(jq '.numTotalTests' reports/test-results.json)
917
- if [ "$tests" -lt 100 ]; then
918
- echo "Test count $tests is below minimum of 100"
919
- exit 1
920
- fi
921
- ```
922
-
923
- ### Trend Tracking
924
-
925
- Track metrics over time to identify trends:
926
-
927
- ```typescript
928
- // Weekly metrics collection
929
- {
930
- "week": "2024-W03",
931
- "coverage": {
932
- "lines": 82.4,
933
- "branches": 76.1,
934
- "trend": "+1.2%" // vs previous week
935
- },
936
- "tests": {
937
- "total": 487,
938
- "new": 23,
939
- "removed": 5
940
- },
941
- "execution": {
942
- "avgDuration": 245, // seconds
943
- "trend": "-12s"
944
- },
945
- "flaky": {
946
- "count": 3,
947
- "rate": 0.6
948
- }
949
- }
950
- ```
951
-
952
- ---
953
-
954
- ## Summary
955
-
956
- 1. **Write testable code** - Inject dependencies, use pure functions, separate concerns
957
- 2. **Name tests clearly** - Describe behavior, not implementation
958
- 3. **Follow AAA pattern** - Arrange, Act, Assert for clear structure
959
- 4. **Isolate tests** - Fresh state, reset mocks, no dependencies between tests
960
- 5. **Fix flaky tests** - Handle timing, use deterministic data, mock externals
961
- 6. **Review for testability** - Check during code review, not after
962
- 7. **Maintain tests** - Reduce duplication, update with code changes
963
- 8. **Debug systematically** - Use debug tools, log strategically
964
- 9. **Measure quality** - Track coverage, pass rate, execution time
1
+ # QA Best Practices for React and Next.js
2
+
3
+ Guidelines for writing maintainable tests, debugging failures, and measuring test quality.
4
+
5
+ ---
6
+
7
+ ## Table of Contents
8
+
9
+ - [Writing Testable Code](#writing-testable-code)
10
+ - [Test Naming Conventions](#test-naming-conventions)
11
+ - [Arrange-Act-Assert Pattern](#arrange-act-assert-pattern)
12
+ - [Test Isolation Principles](#test-isolation-principles)
13
+ - [Handling Flaky Tests](#handling-flaky-tests)
14
+ - [Code Review for Testability](#code-review-for-testability)
15
+ - [Test Maintenance Strategies](#test-maintenance-strategies)
16
+ - [Debugging Failed Tests](#debugging-failed-tests)
17
+ - [Quality Metrics and KPIs](#quality-metrics-and-kpis)
18
+
19
+ ---
20
+
21
+ ## Writing Testable Code
22
+
23
+ Testable code is easy to understand, has clear boundaries, and minimizes dependencies.
24
+
25
+ ### Dependency Injection
26
+
27
+ Instead of creating dependencies inside functions, pass them as parameters.
28
+
29
+ **Hard to Test:**
30
+
31
+ ```typescript
32
+ // src/services/userService.ts
33
+ import { prisma } from '../lib/prisma';
34
+ import { sendEmail } from '../lib/email';
35
+
36
+ export async function createUser(data: UserInput) {
37
+ const user = await prisma.user.create({ data });
38
+ await sendEmail(user.email, 'Welcome!');
39
+ return user;
40
+ }
41
+ ```
42
+
43
+ **Easy to Test:**
44
+
45
+ ```typescript
46
+ // src/services/userService.ts
47
+ export function createUserService(
48
+ db: PrismaClient,
49
+ emailService: EmailService
50
+ ) {
51
+ return {
52
+ async createUser(data: UserInput) {
53
+ const user = await db.user.create({ data });
54
+ await emailService.send(user.email, 'Welcome!');
55
+ return user;
56
+ },
57
+ };
58
+ }
59
+
60
+ // Usage in app
61
+ const userService = createUserService(prisma, emailService);
62
+
63
+ // Usage in tests
64
+ const mockDb = { user: { create: jest.fn() } };
65
+ const mockEmail = { send: jest.fn() };
66
+ const testService = createUserService(mockDb, mockEmail);
67
+ ```
68
+
69
+ ### Pure Functions
70
+
71
+ Pure functions are deterministic and have no side effects, making them trivial to test.
72
+
73
+ **Impure (Hard to Test):**
74
+
75
+ ```typescript
76
+ function formatTimestamp() {
77
+ const now = new Date();
78
+ return `${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()}`;
79
+ }
80
+ ```
81
+
82
+ **Pure (Easy to Test):**
83
+
84
+ ```typescript
85
+ function formatTimestamp(date: Date): string {
86
+ return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
87
+ }
88
+
89
+ // Test
90
+ expect(formatTimestamp(new Date('2024-03-15'))).toBe('2024-3-15');
91
+ ```
92
+
93
+ ### Separation of Concerns
94
+
95
+ Separate business logic from UI and I/O operations.
96
+
97
+ **Mixed Concerns (Hard to Test):**
98
+
99
+ ```typescript
100
+ // Component with embedded business logic
101
+ function CheckoutForm() {
102
+ const [total, setTotal] = useState(0);
103
+
104
+ const handleSubmit = async (items: CartItem[]) => {
105
+ // Business logic mixed with UI
106
+ let sum = 0;
107
+ for (const item of items) {
108
+ sum += item.price * item.quantity;
109
+ if (item.category === 'electronics') {
110
+ sum *= 0.9; // 10% discount
111
+ }
112
+ }
113
+ const tax = sum * 0.08;
114
+ const finalTotal = sum + tax;
115
+
116
+ // API call
117
+ await fetch('/api/orders', {
118
+ method: 'POST',
119
+ body: JSON.stringify({ items, total: finalTotal }),
120
+ });
121
+
122
+ setTotal(finalTotal);
123
+ };
124
+
125
+ return <form onSubmit={handleSubmit}>...</form>;
126
+ }
127
+ ```
128
+
129
+ **Separated Concerns (Easy to Test):**
130
+
131
+ ```typescript
132
+ // Pure business logic (easy to unit test)
133
+ export function calculateOrderTotal(items: CartItem[]): number {
134
+ return items.reduce((sum, item) => {
135
+ const subtotal = item.price * item.quantity;
136
+ const discount = item.category === 'electronics' ? 0.9 : 1;
137
+ return sum + subtotal * discount;
138
+ }, 0);
139
+ }
140
+
141
+ export function calculateTax(subtotal: number, rate = 0.08): number {
142
+ return subtotal * rate;
143
+ }
144
+
145
+ // Custom hook for order logic (testable with renderHook)
146
+ export function useCheckout() {
147
+ const [total, setTotal] = useState(0);
148
+ const mutation = useMutation(createOrder);
149
+
150
+ const checkout = async (items: CartItem[]) => {
151
+ const subtotal = calculateOrderTotal(items);
152
+ const tax = calculateTax(subtotal);
153
+ const finalTotal = subtotal + tax;
154
+
155
+ await mutation.mutateAsync({ items, total: finalTotal });
156
+ setTotal(finalTotal);
157
+ };
158
+
159
+ return { checkout, total, isLoading: mutation.isLoading };
160
+ }
161
+
162
+ // Component (integration testable)
163
+ function CheckoutForm() {
164
+ const { checkout, total, isLoading } = useCheckout();
165
+ return <form onSubmit={() => checkout(items)}>...</form>;
166
+ }
167
+ ```
168
+
169
+ ### Component Design for Testability
170
+
171
+ | Pattern | Testability | Example |
172
+ |---------|-------------|---------|
173
+ | Props over context | High | `<Button disabled={!valid}>` |
174
+ | Callbacks over side effects | High | `onSubmit={handleSubmit}` |
175
+ | Controlled components | High | `<Input value={value} onChange={...}>` |
176
+ | Render props | Medium | `<DataProvider render={data => ...}>` |
177
+ | Internal state | Low | `const [x, setX] = useState()` |
178
+ | Global state | Low | `useGlobalStore()` |
179
+
180
+ ---
181
+
182
+ ## Test Naming Conventions
183
+
184
+ Good test names document expected behavior and help diagnose failures.
185
+
186
+ ### Naming Patterns
187
+
188
+ **Pattern 1: should [expected behavior] when [condition]**
189
+
190
+ ```typescript
191
+ describe('LoginForm', () => {
192
+ it('should display error message when credentials are invalid', () => {});
193
+ it('should redirect to dashboard when login succeeds', () => {});
194
+ it('should disable submit button when form is submitting', () => {});
195
+ });
196
+ ```
197
+
198
+ **Pattern 2: [method/action] [expected result]**
199
+
200
+ ```typescript
201
+ describe('calculateDiscount', () => {
202
+ it('returns 0 for orders under $50', () => {});
203
+ it('returns 10% for orders $50-$99', () => {});
204
+ it('returns 20% for orders $100+', () => {});
205
+ });
206
+ ```
207
+
208
+ **Pattern 3: given [context], when [action], then [result]**
209
+
210
+ ```typescript
211
+ describe('ShoppingCart', () => {
212
+ it('given an empty cart, when adding an item, then cart count is 1', () => {});
213
+ it('given items in cart, when removing all, then cart is empty', () => {});
214
+ });
215
+ ```
216
+
217
+ ### Describe Block Organization
218
+
219
+ ```typescript
220
+ describe('UserService', () => {
221
+ describe('createUser', () => {
222
+ describe('with valid input', () => {
223
+ it('creates user in database', () => {});
224
+ it('sends welcome email', () => {});
225
+ it('returns user with id', () => {});
226
+ });
227
+
228
+ describe('with invalid input', () => {
229
+ it('throws ValidationError for missing email', () => {});
230
+ it('throws ValidationError for invalid email format', () => {});
231
+ it('throws ConflictError for duplicate email', () => {});
232
+ });
233
+ });
234
+
235
+ describe('deleteUser', () => {
236
+ it('removes user from database', () => {});
237
+ it('throws NotFoundError for non-existent user', () => {});
238
+ });
239
+ });
240
+ ```
241
+
242
+ ### Anti-patterns to Avoid
243
+
244
+ | Bad | Good | Why |
245
+ |-----|------|-----|
246
+ | `it('works')` | `it('returns sum of two numbers')` | Describes behavior |
247
+ | `it('test 1')` | `it('handles empty array')` | Specific scenario |
248
+ | `it('should do stuff')` | `it('should validate email format')` | Clear expectation |
249
+ | Duplicating code in name | Describing behavior | Readable output |
250
+
251
+ ---
252
+
253
+ ## Arrange-Act-Assert Pattern
254
+
255
+ The AAA pattern structures tests into three clear phases.
256
+
257
+ ### Structure
258
+
259
+ ```typescript
260
+ it('calculates total with discount', () => {
261
+ // Arrange - Set up test data and conditions
262
+ const items = [
263
+ { name: 'Widget', price: 100, quantity: 2 },
264
+ { name: 'Gadget', price: 50, quantity: 1 },
265
+ ];
266
+ const discountRate = 0.1;
267
+
268
+ // Act - Execute the code being tested
269
+ const result = calculateTotal(items, discountRate);
270
+
271
+ // Assert - Verify the outcome
272
+ expect(result).toBe(225); // (200 + 50) * 0.9
273
+ });
274
+ ```
275
+
276
+ ### Async Example
277
+
278
+ ```typescript
279
+ it('fetches user profile', async () => {
280
+ // Arrange
281
+ const userId = '123';
282
+ server.use(
283
+ rest.get('/api/users/:id', (req, res, ctx) =>
284
+ res(ctx.json({ id: userId, name: 'John' }))
285
+ )
286
+ );
287
+
288
+ // Act
289
+ render(<UserProfile userId={userId} />);
290
+
291
+ // Assert
292
+ await expect(screen.findByText('John')).resolves.toBeInTheDocument();
293
+ });
294
+ ```
295
+
296
+ ### Component Testing Example
297
+
298
+ ```typescript
299
+ it('submits form with user input', async () => {
300
+ // Arrange
301
+ const user = userEvent.setup();
302
+ const onSubmit = jest.fn();
303
+ render(<ContactForm onSubmit={onSubmit} />);
304
+
305
+ // Act
306
+ await user.type(screen.getByLabelText('Name'), 'John Doe');
307
+ await user.type(screen.getByLabelText('Email'), 'john@example.com');
308
+ await user.type(screen.getByLabelText('Message'), 'Hello!');
309
+ await user.click(screen.getByRole('button', { name: 'Send' }));
310
+
311
+ // Assert
312
+ expect(onSubmit).toHaveBeenCalledWith({
313
+ name: 'John Doe',
314
+ email: 'john@example.com',
315
+ message: 'Hello!',
316
+ });
317
+ });
318
+ ```
319
+
320
+ ### Guidelines
321
+
322
+ 1. **One Act per test** - Test one behavior at a time
323
+ 2. **Multiple assertions OK** - If they verify the same behavior
324
+ 3. **Avoid logic in tests** - No if/else, loops in test code
325
+ 4. **Setup in Arrange, not beforeEach** - Unless truly shared
326
+
327
+ ---
328
+
329
+ ## Test Isolation Principles
330
+
331
+ Isolated tests are independent, repeatable, and can run in any order.
332
+
333
+ ### State Isolation
334
+
335
+ ```typescript
336
+ describe('CartService', () => {
337
+ let cartService: CartService;
338
+
339
+ // Fresh instance for each test
340
+ beforeEach(() => {
341
+ cartService = new CartService();
342
+ });
343
+
344
+ it('adds item to empty cart', () => {
345
+ cartService.addItem({ id: '1', quantity: 1 });
346
+ expect(cartService.getItems()).toHaveLength(1);
347
+ });
348
+
349
+ it('starts with empty cart', () => {
350
+ // Not affected by previous test
351
+ expect(cartService.getItems()).toHaveLength(0);
352
+ });
353
+ });
354
+ ```
355
+
356
+ ### Database Isolation
357
+
358
+ ```typescript
359
+ describe('UserRepository', () => {
360
+ beforeAll(async () => {
361
+ // Connect to test database
362
+ await db.connect(process.env.TEST_DATABASE_URL);
363
+ });
364
+
365
+ beforeEach(async () => {
366
+ // Clean database before each test
367
+ await db.query('TRUNCATE users CASCADE');
368
+ });
369
+
370
+ afterAll(async () => {
371
+ await db.disconnect();
372
+ });
373
+
374
+ it('creates user', async () => {
375
+ const user = await userRepo.create({ email: 'test@example.com' });
376
+ expect(user.id).toBeDefined();
377
+ });
378
+ });
379
+ ```
380
+
381
+ ### API Mocking Isolation
382
+
383
+ ```typescript
384
+ describe('ProductList', () => {
385
+ // Reset handlers after each test
386
+ afterEach(() => server.resetHandlers());
387
+
388
+ it('shows products from API', async () => {
389
+ // Default handler returns products
390
+ render(<ProductList />);
391
+ await expect(screen.findByText('Widget')).resolves.toBeInTheDocument();
392
+ });
393
+
394
+ it('shows error on API failure', async () => {
395
+ // Override handler for this test only
396
+ server.use(
397
+ rest.get('/api/products', (req, res, ctx) =>
398
+ res(ctx.status(500))
399
+ )
400
+ );
401
+
402
+ render(<ProductList />);
403
+ await expect(screen.findByText('Error')).resolves.toBeInTheDocument();
404
+ });
405
+
406
+ it('shows products again', async () => {
407
+ // Back to default handler (server.resetHandlers ran)
408
+ render(<ProductList />);
409
+ await expect(screen.findByText('Widget')).resolves.toBeInTheDocument();
410
+ });
411
+ });
412
+ ```
413
+
414
+ ### Isolation Checklist
415
+
416
+ | Aspect | Solution |
417
+ |--------|----------|
418
+ | Global state | Reset in beforeEach |
419
+ | Timers | jest.useFakeTimers() + jest.useRealTimers() |
420
+ | DOM | RTL's cleanup (automatic) |
421
+ | Database | Truncate tables or use transactions |
422
+ | API mocks | server.resetHandlers() |
423
+ | File system | Use temp directories, clean up in afterEach |
424
+ | Environment vars | Restore in afterEach |
425
+
426
+ ---
427
+
428
+ ## Handling Flaky Tests
429
+
430
+ Flaky tests pass and fail intermittently without code changes.
431
+
432
+ ### Common Causes and Fixes
433
+
434
+ **1. Timing Issues**
435
+
436
+ ```typescript
437
+ // Flaky - race condition
438
+ it('shows loading then data', () => {
439
+ render(<UserProfile />);
440
+ expect(screen.getByText('Loading')).toBeInTheDocument();
441
+ expect(screen.getByText('John')).toBeInTheDocument(); // May fail
442
+ });
443
+
444
+ // Fixed - proper async handling
445
+ it('shows loading then data', async () => {
446
+ render(<UserProfile />);
447
+ expect(screen.getByText('Loading')).toBeInTheDocument();
448
+ await waitFor(() => {
449
+ expect(screen.getByText('John')).toBeInTheDocument();
450
+ });
451
+ });
452
+ ```
453
+
454
+ **2. Non-deterministic Data**
455
+
456
+ ```typescript
457
+ // Flaky - random data
458
+ it('sorts users alphabetically', () => {
459
+ const users = [createUser(), createUser(), createUser()];
460
+ // Names are random, order unpredictable
461
+ });
462
+
463
+ // Fixed - deterministic data
464
+ it('sorts users alphabetically', () => {
465
+ const users = [
466
+ createUser({ name: 'Charlie' }),
467
+ createUser({ name: 'Alice' }),
468
+ createUser({ name: 'Bob' }),
469
+ ];
470
+ const sorted = sortUsers(users);
471
+ expect(sorted.map(u => u.name)).toEqual(['Alice', 'Bob', 'Charlie']);
472
+ });
473
+ ```
474
+
475
+ **3. Test Order Dependencies**
476
+
477
+ ```typescript
478
+ // Flaky - relies on previous test
479
+ describe('Counter', () => {
480
+ const counter = new Counter(); // Shared instance!
481
+
482
+ it('increments', () => {
483
+ counter.increment();
484
+ expect(counter.value).toBe(1);
485
+ });
486
+
487
+ it('starts at zero', () => {
488
+ expect(counter.value).toBe(0); // Fails! Value is 1
489
+ });
490
+ });
491
+
492
+ // Fixed - fresh instance per test
493
+ describe('Counter', () => {
494
+ let counter: Counter;
495
+
496
+ beforeEach(() => {
497
+ counter = new Counter();
498
+ });
499
+
500
+ it('increments', () => {
501
+ counter.increment();
502
+ expect(counter.value).toBe(1);
503
+ });
504
+
505
+ it('starts at zero', () => {
506
+ expect(counter.value).toBe(0); // Passes
507
+ });
508
+ });
509
+ ```
510
+
511
+ **4. Network/External Dependencies**
512
+
513
+ ```typescript
514
+ // Flaky - real network call
515
+ it('fetches data', async () => {
516
+ const data = await fetch('https://api.example.com/data');
517
+ expect(data).toBeDefined();
518
+ });
519
+
520
+ // Fixed - mock the network
521
+ it('fetches data', async () => {
522
+ server.use(
523
+ rest.get('https://api.example.com/data', (req, res, ctx) =>
524
+ res(ctx.json({ value: 42 }))
525
+ )
526
+ );
527
+
528
+ const data = await fetchData();
529
+ expect(data.value).toBe(42);
530
+ });
531
+ ```
532
+
533
+ ### Flaky Test Detection
534
+
535
+ ```javascript
536
+ // jest.config.js
537
+ module.exports = {
538
+ // Run each test multiple times to detect flakiness
539
+ testEnvironment: 'jsdom',
540
+
541
+ // Add reporters to track flaky tests
542
+ reporters: [
543
+ 'default',
544
+ ['jest-junit', { outputDirectory: './reports' }],
545
+ ],
546
+ };
547
+
548
+ // Run tests multiple times
549
+ // npx jest --runInBand --testTimeout=10000 --repeat=5
550
+ ```
551
+
552
+ ### Quarantine Strategy
553
+
554
+ 1. **Identify** - Track tests that fail randomly
555
+ 2. **Quarantine** - Move to separate suite, run separately
556
+ 3. **Fix** - Investigate and fix root cause
557
+ 4. **Restore** - Move back to main suite
558
+
559
+ ```typescript
560
+ // Temporarily skip flaky test
561
+ it.skip('flaky test to fix', () => {
562
+ // TODO: Fix timing issue in #123
563
+ });
564
+
565
+ // Or run only when investigating
566
+ it.todo('investigate flaky behavior');
567
+ ```
568
+
569
+ ---
570
+
571
+ ## Code Review for Testability
572
+
573
+ Questions to ask during code review to ensure testable code.
574
+
575
+ ### Testability Checklist
576
+
577
+ **Functions and Methods:**
578
+ - [ ] Does it have a single responsibility?
579
+ - [ ] Are dependencies injected?
580
+ - [ ] Can it be tested without mocking internals?
581
+ - [ ] Does it return a value or have observable side effects?
582
+
583
+ **Components:**
584
+ - [ ] Are props descriptive and minimal?
585
+ - [ ] Can behavior be triggered via user events?
586
+ - [ ] Are loading/error states exposed?
587
+ - [ ] Can it be rendered without a full app context?
588
+
589
+ **State Management:**
590
+ - [ ] Is state minimal and derived where possible?
591
+ - [ ] Can state changes be triggered and observed?
592
+ - [ ] Are side effects separated from reducers?
593
+
594
+ ### Review Comments
595
+
596
+ **Before:**
597
+ ```typescript
598
+ // Hard to test - embedded dependency
599
+ function processPayment(order: Order) {
600
+ const stripe = new Stripe(process.env.STRIPE_KEY);
601
+ return stripe.charges.create({
602
+ amount: order.total,
603
+ currency: 'usd',
604
+ });
605
+ }
606
+ ```
607
+
608
+ **Review Comment:**
609
+ > Consider injecting the payment processor to improve testability:
610
+ > ```typescript
611
+ > function processPayment(order: Order, processor: PaymentProcessor) {
612
+ > return processor.charge(order.total, 'usd');
613
+ > }
614
+ > ```
615
+ > This allows testing with a mock processor without hitting Stripe's API.
616
+
617
+ ---
618
+
619
+ ## Test Maintenance Strategies
620
+
621
+ Keep tests maintainable as the codebase evolves.
622
+
623
+ ### Reducing Duplication
624
+
625
+ **Use helpers for common assertions:**
626
+
627
+ ```typescript
628
+ // __tests__/helpers/assertions.ts
629
+ export function expectLoadingState(container: HTMLElement) {
630
+ expect(within(container).getByRole('progressbar')).toBeInTheDocument();
631
+ }
632
+
633
+ export function expectErrorState(container: HTMLElement, message: string) {
634
+ expect(within(container).getByRole('alert')).toHaveTextContent(message);
635
+ }
636
+
637
+ // Usage
638
+ it('shows loading state', () => {
639
+ render(<DataList />);
640
+ expectLoadingState(screen.getByTestId('data-list'));
641
+ });
642
+ ```
643
+
644
+ **Use factory functions:**
645
+
646
+ ```typescript
647
+ // Instead of repeating setup
648
+ function renderWithUser(ui: ReactElement, user = createUser()) {
649
+ return {
650
+ user,
651
+ ...render(<AuthProvider user={user}>{ui}</AuthProvider>),
652
+ };
653
+ }
654
+ ```
655
+
656
+ ### Updating Tests When Code Changes
657
+
658
+ **Scenario: Renaming a prop**
659
+
660
+ ```typescript
661
+ // Old component
662
+ <Button onClick={handleClick} />
663
+
664
+ // New component
665
+ <Button onPress={handleClick} />
666
+
667
+ // Find and update all tests
668
+ // grep -r "onClick" __tests__/ --include="*.test.tsx"
669
+ ```
670
+
671
+ **Scenario: Changing API response shape**
672
+
673
+ ```typescript
674
+ // Update factory first
675
+ export function createUserResponse(overrides = {}) {
676
+ return {
677
+ user: { // New nested structure
678
+ id: '1',
679
+ name: 'Test User',
680
+ ...overrides,
681
+ },
682
+ };
683
+ }
684
+
685
+ // Tests automatically get new shape
686
+ ```
687
+
688
+ ### When to Delete Tests
689
+
690
+ - **Redundant coverage** - Multiple tests testing the same thing
691
+ - **Testing implementation** - Tests that break on refactor
692
+ - **Obsolete features** - Tests for removed functionality
693
+ - **Flaky beyond repair** - Tests that can't be stabilized
694
+
695
+ ### Test Documentation
696
+
697
+ ```typescript
698
+ /**
699
+ * @group integration
700
+ * @requires database
701
+ *
702
+ * Tests for the order processing workflow.
703
+ * These tests require a running PostgreSQL instance.
704
+ *
705
+ * Setup: docker-compose up -d postgres
706
+ */
707
+ describe('OrderProcessor', () => {
708
+ /**
709
+ * Verifies that orders with backordered items
710
+ * are split into separate fulfillment batches.
711
+ *
712
+ * Related: JIRA-1234
713
+ */
714
+ it('splits orders with backordered items', () => {});
715
+ });
716
+ ```
717
+
718
+ ---
719
+
720
+ ## Debugging Failed Tests
721
+
722
+ Techniques for investigating test failures.
723
+
724
+ ### Jest Debugging
725
+
726
+ **Run single test:**
727
+ ```bash
728
+ # By name pattern
729
+ npx jest -t "should validate email"
730
+
731
+ # By file
732
+ npx jest src/utils/__tests__/validation.test.ts
733
+
734
+ # Watch mode for iteration
735
+ npx jest --watch
736
+ ```
737
+
738
+ **Debug with Node inspector:**
739
+ ```bash
740
+ node --inspect-brk node_modules/.bin/jest --runInBand
741
+ # Open chrome://inspect in Chrome
742
+ ```
743
+
744
+ **Verbose output:**
745
+ ```bash
746
+ npx jest --verbose --no-coverage
747
+ ```
748
+
749
+ ### React Testing Library Debugging
750
+
751
+ ```typescript
752
+ it('renders user profile', async () => {
753
+ render(<UserProfile userId="123" />);
754
+
755
+ // Print current DOM
756
+ screen.debug();
757
+
758
+ // Print specific element
759
+ screen.debug(screen.getByRole('heading'));
760
+
761
+ // Log accessible roles
762
+ screen.logTestingPlaygroundURL(); // Opens interactive playground
763
+
764
+ // Check what queries would match
765
+ const element = screen.getByRole('button');
766
+ console.log(prettyDOM(element));
767
+ });
768
+ ```
769
+
770
+ ### Playwright Debugging
771
+
772
+ ```bash
773
+ # Debug mode - opens browser with inspector
774
+ npx playwright test --debug
775
+
776
+ # UI mode - visual test runner
777
+ npx playwright test --ui
778
+
779
+ # Headed mode - see browser
780
+ npx playwright test --headed
781
+
782
+ # Trace viewer after failure
783
+ npx playwright show-trace trace.zip
784
+ ```
785
+
786
+ **Pause in test:**
787
+ ```typescript
788
+ test('debug this', async ({ page }) => {
789
+ await page.goto('/');
790
+ await page.pause(); // Opens inspector
791
+ await page.click('button');
792
+ });
793
+ ```
794
+
795
+ ### Common Failure Patterns
796
+
797
+ | Symptom | Likely Cause | Debug Approach |
798
+ |---------|--------------|----------------|
799
+ | "Unable to find element" | Wrong query or element not rendered | `screen.debug()`, check async |
800
+ | "Expected X, received Y" | Logic error or stale mock | Log intermediate values |
801
+ | "Timeout exceeded" | Slow async or missing await | Increase timeout, check promises |
802
+ | "Cannot read property of undefined" | Missing mock or setup | Check beforeEach, mock returns |
803
+ | Passes locally, fails in CI | Environment difference | Check env vars, timing |
804
+
805
+ ### Investigating Flaky Failures
806
+
807
+ ```typescript
808
+ // Add logging for intermittent failures
809
+ it('processes order', async () => {
810
+ console.log('Test started at', Date.now());
811
+
812
+ const order = await createOrder();
813
+ console.log('Order created:', order.id);
814
+
815
+ const result = await processOrder(order);
816
+ console.log('Process result:', result);
817
+
818
+ expect(result.status).toBe('completed');
819
+ });
820
+ ```
821
+
822
+ ---
823
+
824
+ ## Quality Metrics and KPIs
825
+
826
+ Measure test suite effectiveness and track quality improvements.
827
+
828
+ ### Key Metrics
829
+
830
+ **Coverage Metrics:**
831
+
832
+ | Metric | Target | Measurement |
833
+ |--------|--------|-------------|
834
+ | Line coverage | 80% | `jest --coverage` |
835
+ | Branch coverage | 75% | `jest --coverage` |
836
+ | Function coverage | 80% | `jest --coverage` |
837
+ | Critical path coverage | 95% | Custom tracking |
838
+
839
+ **Test Suite Health:**
840
+
841
+ | Metric | Target | Measurement |
842
+ |--------|--------|-------------|
843
+ | Test pass rate | 100% | CI reports |
844
+ | Flaky test rate | <1% | Track retries |
845
+ | Test execution time | <5 min | CI timing |
846
+ | Tests per component | ≥3 | Test count / components |
847
+
848
+ **Defect Metrics:**
849
+
850
+ | Metric | Target | Measurement |
851
+ |--------|--------|-------------|
852
+ | Defects found in testing | >70% | Bug tracking |
853
+ | Defects escaped to prod | <10% | Production bugs |
854
+ | Regression rate | <5% | Bugs reintroduced |
855
+ | Mean time to detect | <1 day | Bug timestamps |
856
+
857
+ ### Dashboard Example
858
+
859
+ ```typescript
860
+ // scripts/test-metrics.ts
861
+ import { readCoverageReport } from './utils';
862
+
863
+ const coverage = readCoverageReport('./coverage/coverage-summary.json');
864
+ const testResults = readTestReport('./reports/jest-results.json');
865
+
866
+ const metrics = {
867
+ coverage: {
868
+ lines: coverage.total.lines.pct,
869
+ branches: coverage.total.branches.pct,
870
+ functions: coverage.total.functions.pct,
871
+ },
872
+ tests: {
873
+ total: testResults.numTotalTests,
874
+ passed: testResults.numPassedTests,
875
+ failed: testResults.numFailedTests,
876
+ passRate: (testResults.numPassedTests / testResults.numTotalTests) * 100,
877
+ },
878
+ execution: {
879
+ duration: testResults.testResults.reduce((sum, r) => sum + r.duration, 0),
880
+ },
881
+ };
882
+
883
+ console.log('Test Metrics:', JSON.stringify(metrics, null, 2));
884
+ ```
885
+
886
+ ### CI Quality Gates
887
+
888
+ ```yaml
889
+ # .github/workflows/quality.yml
890
+ name: Quality Gates
891
+
892
+ on: [push, pull_request]
893
+
894
+ jobs:
895
+ test:
896
+ runs-on: ubuntu-latest
897
+ steps:
898
+ - uses: actions/checkout@v4
899
+ - uses: actions/setup-node@v4
900
+
901
+ - run: npm ci
902
+ - run: npm test -- --coverage
903
+
904
+ # Coverage gate
905
+ - name: Check coverage
906
+ run: |
907
+ coverage=$(jq '.total.lines.pct' coverage/coverage-summary.json)
908
+ if (( $(echo "$coverage < 80" | bc -l) )); then
909
+ echo "Coverage $coverage% is below 80% threshold"
910
+ exit 1
911
+ fi
912
+
913
+ # Test count gate
914
+ - name: Check test count
915
+ run: |
916
+ tests=$(jq '.numTotalTests' reports/test-results.json)
917
+ if [ "$tests" -lt 100 ]; then
918
+ echo "Test count $tests is below minimum of 100"
919
+ exit 1
920
+ fi
921
+ ```
922
+
923
+ ### Trend Tracking
924
+
925
+ Track metrics over time to identify trends:
926
+
927
+ ```typescript
928
+ // Weekly metrics collection
929
+ {
930
+ "week": "2024-W03",
931
+ "coverage": {
932
+ "lines": 82.4,
933
+ "branches": 76.1,
934
+ "trend": "+1.2%" // vs previous week
935
+ },
936
+ "tests": {
937
+ "total": 487,
938
+ "new": 23,
939
+ "removed": 5
940
+ },
941
+ "execution": {
942
+ "avgDuration": 245, // seconds
943
+ "trend": "-12s"
944
+ },
945
+ "flaky": {
946
+ "count": 3,
947
+ "rate": 0.6
948
+ }
949
+ }
950
+ ```
951
+
952
+ ---
953
+
954
+ ## Summary
955
+
956
+ 1. **Write testable code** - Inject dependencies, use pure functions, separate concerns
957
+ 2. **Name tests clearly** - Describe behavior, not implementation
958
+ 3. **Follow AAA pattern** - Arrange, Act, Assert for clear structure
959
+ 4. **Isolate tests** - Fresh state, reset mocks, no dependencies between tests
960
+ 5. **Fix flaky tests** - Handle timing, use deterministic data, mock externals
961
+ 6. **Review for testability** - Check during code review, not after
962
+ 7. **Maintain tests** - Reduce duplication, update with code changes
963
+ 8. **Debug systematically** - Use debug tools, log strategically
964
+ 9. **Measure quality** - Track coverage, pass rate, execution time