qa-skills 3.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (262) hide show
  1. package/README.md +20 -149
  2. package/bin/cli.js +1 -40
  3. package/package.json +23 -26
  4. package/dist/agents/registry.d.ts +0 -5
  5. package/dist/agents/registry.d.ts.map +0 -1
  6. package/dist/agents/registry.js +0 -101
  7. package/dist/agents/registry.js.map +0 -1
  8. package/dist/agents/types.d.ts +0 -9
  9. package/dist/agents/types.d.ts.map +0 -1
  10. package/dist/agents/types.js +0 -2
  11. package/dist/agents/types.js.map +0 -1
  12. package/dist/dependencies.d.ts +0 -21
  13. package/dist/dependencies.d.ts.map +0 -1
  14. package/dist/dependencies.js +0 -125
  15. package/dist/dependencies.js.map +0 -1
  16. package/dist/installer.d.ts +0 -25
  17. package/dist/installer.d.ts.map +0 -1
  18. package/dist/installer.js +0 -437
  19. package/dist/installer.js.map +0 -1
  20. package/dist/scaffold.d.ts +0 -27
  21. package/dist/scaffold.d.ts.map +0 -1
  22. package/dist/scaffold.js +0 -182
  23. package/dist/scaffold.js.map +0 -1
  24. package/skills/qa-accessibility-test-writer/SKILL.md +0 -127
  25. package/skills/qa-accessibility-test-writer/references/axe-core-patterns.md +0 -349
  26. package/skills/qa-accessibility-test-writer/references/best-practices.md +0 -184
  27. package/skills/qa-accessibility-test-writer/references/wcag-tests.md +0 -331
  28. package/skills/qa-api-contract-curator/SKILL.md +0 -104
  29. package/skills/qa-api-contract-curator/references/breaking-changes.md +0 -363
  30. package/skills/qa-api-contract-curator/references/openapi-structure.md +0 -404
  31. package/skills/qa-browser-data-collector/SKILL.md +0 -132
  32. package/skills/qa-browser-data-collector/references/data-collection-checklist.md +0 -91
  33. package/skills/qa-browser-data-collector/references/playwright-mcp-patterns.md +0 -113
  34. package/skills/qa-bug-ticket-creator/SKILL.md +0 -148
  35. package/skills/qa-bug-ticket-creator/references/bug-report-format.md +0 -149
  36. package/skills/qa-bug-ticket-creator/references/severity-guide.md +0 -81
  37. package/skills/qa-bug-ticket-creator/templates/bug-ticket-template.md +0 -39
  38. package/skills/qa-changelog-analyzer/SKILL.md +0 -134
  39. package/skills/qa-changelog-analyzer/references/git-analysis-patterns.md +0 -138
  40. package/skills/qa-changelog-analyzer/references/impact-mapping.md +0 -120
  41. package/skills/qa-clickup-integration/SKILL.md +0 -166
  42. package/skills/qa-clickup-integration/references/api-patterns.md +0 -102
  43. package/skills/qa-clickup-integration/references/field-mapping.md +0 -71
  44. package/skills/qa-codeceptjs-writer/SKILL.md +0 -136
  45. package/skills/qa-codeceptjs-writer/references/best-practices.md +0 -207
  46. package/skills/qa-codeceptjs-writer/references/config.md +0 -255
  47. package/skills/qa-codeceptjs-writer/references/patterns.md +0 -285
  48. package/skills/qa-coverage-analyzer/SKILL.md +0 -166
  49. package/skills/qa-coverage-analyzer/references/best-practices.md +0 -142
  50. package/skills/qa-coverage-analyzer/references/coverage-dimensions.md +0 -155
  51. package/skills/qa-coverage-analyzer/references/tools.md +0 -204
  52. package/skills/qa-cypress-writer/SKILL.md +0 -134
  53. package/skills/qa-cypress-writer/references/assertions.md +0 -121
  54. package/skills/qa-cypress-writer/references/best-practices.md +0 -82
  55. package/skills/qa-cypress-writer/references/config.md +0 -121
  56. package/skills/qa-cypress-writer/references/patterns.md +0 -170
  57. package/skills/qa-data-factory/SKILL.md +0 -126
  58. package/skills/qa-data-factory/references/factory-patterns.md +0 -164
  59. package/skills/qa-data-factory/references/faker-guide.md +0 -131
  60. package/skills/qa-diagram-generator/SKILL.md +0 -125
  61. package/skills/qa-diagram-generator/references/c4-model.md +0 -53
  62. package/skills/qa-diagram-generator/references/charts.md +0 -58
  63. package/skills/qa-diagram-generator/references/class-diagram.md +0 -85
  64. package/skills/qa-diagram-generator/references/er-diagram.md +0 -69
  65. package/skills/qa-diagram-generator/references/flowchart.md +0 -92
  66. package/skills/qa-diagram-generator/references/from-screenshot.md +0 -45
  67. package/skills/qa-diagram-generator/references/gantt.md +0 -49
  68. package/skills/qa-diagram-generator/references/journey.md +0 -50
  69. package/skills/qa-diagram-generator/references/mindmap.md +0 -75
  70. package/skills/qa-diagram-generator/references/sequence.md +0 -69
  71. package/skills/qa-diagram-generator/references/state-diagram.md +0 -56
  72. package/skills/qa-discovery-interview/SKILL.md +0 -182
  73. package/skills/qa-discovery-interview/references/completeness-checklist.md +0 -53
  74. package/skills/qa-discovery-interview/references/conflict-patterns.md +0 -101
  75. package/skills/qa-discovery-interview/references/qa-categories.md +0 -147
  76. package/skills/qa-discovery-interview/templates/qa-brief-template.md +0 -168
  77. package/skills/qa-environment-checker/SKILL.md +0 -142
  78. package/skills/qa-environment-checker/references/dependency-matrix.md +0 -101
  79. package/skills/qa-environment-checker/references/health-checks.md +0 -209
  80. package/skills/qa-environment-checker/templates/env-readiness-template.md +0 -64
  81. package/skills/qa-flaky-detector/SKILL.md +0 -153
  82. package/skills/qa-flaky-detector/references/ci-analysis.md +0 -140
  83. package/skills/qa-flaky-detector/references/flaky-patterns.md +0 -247
  84. package/skills/qa-github-issues-enhanced/SKILL.md +0 -175
  85. package/skills/qa-github-issues-enhanced/references/issue-templates.md +0 -425
  86. package/skills/qa-github-issues-enhanced/references/label-taxonomy.md +0 -130
  87. package/skills/qa-github-issues-enhanced/references/workflow-patterns.md +0 -188
  88. package/skills/qa-httpx-writer/SKILL.md +0 -138
  89. package/skills/qa-httpx-writer/references/assertions.md +0 -195
  90. package/skills/qa-httpx-writer/references/best-practices.md +0 -140
  91. package/skills/qa-httpx-writer/references/config.md +0 -212
  92. package/skills/qa-httpx-writer/references/patterns.md +0 -262
  93. package/skills/qa-jest-writer/SKILL.md +0 -131
  94. package/skills/qa-jest-writer/references/assertions.md +0 -125
  95. package/skills/qa-jest-writer/references/best-practices.md +0 -136
  96. package/skills/qa-jest-writer/references/config.md +0 -134
  97. package/skills/qa-jest-writer/references/patterns.md +0 -172
  98. package/skills/qa-jira-integration/SKILL.md +0 -135
  99. package/skills/qa-jira-integration/references/api-patterns.md +0 -143
  100. package/skills/qa-jira-integration/references/field-mapping.md +0 -79
  101. package/skills/qa-jira-integration/references/xray-integration.md +0 -85
  102. package/skills/qa-jmeter-writer/SKILL.md +0 -171
  103. package/skills/qa-jmeter-writer/references/best-practices.md +0 -157
  104. package/skills/qa-jmeter-writer/references/config.md +0 -204
  105. package/skills/qa-jmeter-writer/references/patterns.md +0 -242
  106. package/skills/qa-junit5-writer/SKILL.md +0 -157
  107. package/skills/qa-junit5-writer/references/assertions.md +0 -118
  108. package/skills/qa-junit5-writer/references/config.md +0 -97
  109. package/skills/qa-junit5-writer/references/patterns.md +0 -162
  110. package/skills/qa-k6-writer/SKILL.md +0 -155
  111. package/skills/qa-k6-writer/references/best-practices.md +0 -236
  112. package/skills/qa-k6-writer/references/config.md +0 -219
  113. package/skills/qa-k6-writer/references/patterns.md +0 -304
  114. package/skills/qa-linear-integration/SKILL.md +0 -137
  115. package/skills/qa-linear-integration/references/api-patterns.md +0 -249
  116. package/skills/qa-linear-integration/references/field-mapping.md +0 -121
  117. package/skills/qa-locust-writer/SKILL.md +0 -151
  118. package/skills/qa-locust-writer/references/best-practices.md +0 -126
  119. package/skills/qa-locust-writer/references/config.md +0 -170
  120. package/skills/qa-locust-writer/references/patterns.md +0 -235
  121. package/skills/qa-manual-test-designer/SKILL.md +0 -145
  122. package/skills/qa-manual-test-designer/references/exploratory-charters.md +0 -138
  123. package/skills/qa-manual-test-designer/references/personas.md +0 -146
  124. package/skills/qa-manual-test-designer/templates/exploratory-charter-template.md +0 -47
  125. package/skills/qa-manual-test-designer/templates/test-case-template.md +0 -31
  126. package/skills/qa-mobile-test-writer/SKILL.md +0 -144
  127. package/skills/qa-mobile-test-writer/references/best-practices.md +0 -214
  128. package/skills/qa-mobile-test-writer/references/config.md +0 -309
  129. package/skills/qa-mobile-test-writer/references/patterns.md +0 -304
  130. package/skills/qa-nfr-analyst/SKILL.md +0 -177
  131. package/skills/qa-nfr-analyst/references/iso-25010-model.md +0 -159
  132. package/skills/qa-nfr-analyst/references/owasp-wstg-baseline.md +0 -202
  133. package/skills/qa-nfr-analyst/references/wcag-checklist.md +0 -184
  134. package/skills/qa-nfr-analyst/templates/owasp-checklist-template.md +0 -89
  135. package/skills/qa-nfr-analyst/templates/wcag-checklist-template.md +0 -48
  136. package/skills/qa-orchestrator/SKILL.md +0 -132
  137. package/skills/qa-orchestrator/references/handoff-chains.md +0 -105
  138. package/skills/qa-orchestrator/references/pipeline-modes.md +0 -115
  139. package/skills/qa-orchestrator/references/scheduler-rules.md +0 -84
  140. package/skills/qa-pact-writer/SKILL.md +0 -133
  141. package/skills/qa-pact-writer/references/best-practices.md +0 -100
  142. package/skills/qa-pact-writer/references/config.md +0 -135
  143. package/skills/qa-pact-writer/references/patterns.md +0 -161
  144. package/skills/qa-plan-creator/SKILL.md +0 -139
  145. package/skills/qa-plan-creator/references/introduction-plan.md +0 -43
  146. package/skills/qa-plan-creator/references/migration-plan.md +0 -44
  147. package/skills/qa-plan-creator/references/onboarding-plan.md +0 -46
  148. package/skills/qa-plan-creator/references/performance-plan.md +0 -44
  149. package/skills/qa-plan-creator/references/regression-plan.md +0 -45
  150. package/skills/qa-plan-creator/references/release-plan.md +0 -45
  151. package/skills/qa-plan-creator/references/sprint-plan.md +0 -44
  152. package/skills/qa-plan-creator/references/test-plan.md +0 -59
  153. package/skills/qa-plan-creator/references/uat-plan.md +0 -43
  154. package/skills/qa-plan-creator/templates/checklist-template.md +0 -36
  155. package/skills/qa-plan-creator/templates/regression-checklist-template.md +0 -49
  156. package/skills/qa-plan-creator/templates/release-checklist-template.md +0 -46
  157. package/skills/qa-plan-creator/templates/test-plan-template.md +0 -74
  158. package/skills/qa-playwright-py-writer/SKILL.md +0 -156
  159. package/skills/qa-playwright-py-writer/references/best-practices.md +0 -194
  160. package/skills/qa-playwright-py-writer/references/config.md +0 -195
  161. package/skills/qa-playwright-py-writer/references/patterns.md +0 -212
  162. package/skills/qa-playwright-ts-writer/SKILL.md +0 -151
  163. package/skills/qa-playwright-ts-writer/references/assertions.md +0 -109
  164. package/skills/qa-playwright-ts-writer/references/best-practices.md +0 -191
  165. package/skills/qa-playwright-ts-writer/references/config.md +0 -144
  166. package/skills/qa-playwright-ts-writer/references/patterns.md +0 -171
  167. package/skills/qa-pytest-writer/SKILL.md +0 -145
  168. package/skills/qa-pytest-writer/references/assertions.md +0 -149
  169. package/skills/qa-pytest-writer/references/best-practices.md +0 -97
  170. package/skills/qa-pytest-writer/references/config.md +0 -176
  171. package/skills/qa-pytest-writer/references/patterns.md +0 -251
  172. package/skills/qa-qase-integration/SKILL.md +0 -149
  173. package/skills/qa-qase-integration/references/api-reference.md +0 -354
  174. package/skills/qa-qase-integration/references/ci-integration.md +0 -196
  175. package/skills/qa-qase-integration/references/field-mapping.md +0 -157
  176. package/skills/qa-requirements-generator/SKILL.md +0 -152
  177. package/skills/qa-requirements-generator/references/iso-29148-structure.md +0 -153
  178. package/skills/qa-requirements-generator/references/requirement-patterns.md +0 -278
  179. package/skills/qa-rest-assured-writer/SKILL.md +0 -137
  180. package/skills/qa-rest-assured-writer/references/best-practices.md +0 -50
  181. package/skills/qa-rest-assured-writer/references/config.md +0 -124
  182. package/skills/qa-rest-assured-writer/references/patterns.md +0 -192
  183. package/skills/qa-risk-analyzer/SKILL.md +0 -158
  184. package/skills/qa-risk-analyzer/references/impact-analysis.md +0 -133
  185. package/skills/qa-risk-analyzer/references/risk-factors.md +0 -123
  186. package/skills/qa-robot-framework-writer/SKILL.md +0 -147
  187. package/skills/qa-robot-framework-writer/references/best-practices.md +0 -249
  188. package/skills/qa-robot-framework-writer/references/config.md +0 -204
  189. package/skills/qa-robot-framework-writer/references/libraries.md +0 -273
  190. package/skills/qa-robot-framework-writer/references/patterns.md +0 -216
  191. package/skills/qa-security-test-writer/SKILL.md +0 -123
  192. package/skills/qa-security-test-writer/references/best-practices.md +0 -155
  193. package/skills/qa-security-test-writer/references/owasp-top10.md +0 -331
  194. package/skills/qa-security-test-writer/references/zap-config.md +0 -258
  195. package/skills/qa-selenium-java-writer/SKILL.md +0 -143
  196. package/skills/qa-selenium-java-writer/references/best-practices.md +0 -59
  197. package/skills/qa-selenium-java-writer/references/config.md +0 -143
  198. package/skills/qa-selenium-java-writer/references/patterns.md +0 -170
  199. package/skills/qa-selenium-py-writer/SKILL.md +0 -150
  200. package/skills/qa-selenium-py-writer/references/best-practices.md +0 -175
  201. package/skills/qa-selenium-py-writer/references/config.md +0 -224
  202. package/skills/qa-selenium-py-writer/references/patterns.md +0 -255
  203. package/skills/qa-shortcut-integration/SKILL.md +0 -143
  204. package/skills/qa-shortcut-integration/references/api-patterns.md +0 -126
  205. package/skills/qa-shortcut-integration/references/field-mapping.md +0 -66
  206. package/skills/qa-spec-auditor/SKILL.md +0 -162
  207. package/skills/qa-spec-auditor/references/audit-checklist.md +0 -144
  208. package/skills/qa-spec-auditor/references/drift-patterns.md +0 -207
  209. package/skills/qa-spec-writer/SKILL.md +0 -143
  210. package/skills/qa-spec-writer/references/gherkin-guide.md +0 -253
  211. package/skills/qa-spec-writer/references/specification-patterns.md +0 -274
  212. package/skills/qa-spring-test-writer/SKILL.md +0 -170
  213. package/skills/qa-spring-test-writer/references/best-practices.md +0 -57
  214. package/skills/qa-spring-test-writer/references/config.md +0 -179
  215. package/skills/qa-spring-test-writer/references/patterns.md +0 -235
  216. package/skills/qa-supertest-writer/SKILL.md +0 -150
  217. package/skills/qa-supertest-writer/references/assertions.md +0 -192
  218. package/skills/qa-supertest-writer/references/best-practices.md +0 -102
  219. package/skills/qa-supertest-writer/references/config.md +0 -166
  220. package/skills/qa-supertest-writer/references/patterns.md +0 -242
  221. package/skills/qa-task-creator/SKILL.md +0 -142
  222. package/skills/qa-task-creator/references/linking-patterns.md +0 -127
  223. package/skills/qa-task-creator/references/task-types.md +0 -169
  224. package/skills/qa-task-creator/templates/task-template.md +0 -24
  225. package/skills/qa-test-doc-compiler/SKILL.md +0 -114
  226. package/skills/qa-test-doc-compiler/references/agile-tailoring.md +0 -220
  227. package/skills/qa-test-doc-compiler/references/iso-29119-3-documents.md +0 -302
  228. package/skills/qa-test-healer/SKILL.md +0 -101
  229. package/skills/qa-test-healer/references/diagnosis-patterns.md +0 -142
  230. package/skills/qa-test-healer/references/fix-strategies.md +0 -177
  231. package/skills/qa-test-reporter/SKILL.md +0 -130
  232. package/skills/qa-test-reporter/references/best-practices.md +0 -162
  233. package/skills/qa-test-reporter/references/iso-29119-reports.md +0 -236
  234. package/skills/qa-test-reporter/references/report-formats.md +0 -287
  235. package/skills/qa-test-reviewer/SKILL.md +0 -142
  236. package/skills/qa-test-reviewer/references/anti-patterns.md +0 -268
  237. package/skills/qa-test-reviewer/references/review-checklist.md +0 -93
  238. package/skills/qa-test-strategy/SKILL.md +0 -133
  239. package/skills/qa-test-strategy/references/entry-exit-criteria.md +0 -176
  240. package/skills/qa-test-strategy/references/risk-matrix.md +0 -102
  241. package/skills/qa-test-strategy/references/testing-types.md +0 -143
  242. package/skills/qa-testcase-from-docs/SKILL.md +0 -161
  243. package/skills/qa-testcase-from-docs/references/test-case-format.md +0 -196
  244. package/skills/qa-testcase-from-docs/references/test-design-techniques.md +0 -126
  245. package/skills/qa-testcase-from-docs/templates/test-case-template.md +0 -31
  246. package/skills/qa-testcase-from-ui/SKILL.md +0 -109
  247. package/skills/qa-testcase-from-ui/references/ui-element-patterns.md +0 -126
  248. package/skills/qa-testcase-from-ui/references/visual-analysis-guide.md +0 -146
  249. package/skills/qa-testcase-from-ui/templates/test-case-template.md +0 -31
  250. package/skills/qa-visual-regression-writer/SKILL.md +0 -175
  251. package/skills/qa-visual-regression-writer/references/best-practices.md +0 -154
  252. package/skills/qa-visual-regression-writer/references/config.md +0 -220
  253. package/skills/qa-visual-regression-writer/references/patterns.md +0 -213
  254. package/skills/qa-vitest-writer/SKILL.md +0 -141
  255. package/skills/qa-vitest-writer/references/assertions.md +0 -105
  256. package/skills/qa-vitest-writer/references/best-practices.md +0 -62
  257. package/skills/qa-vitest-writer/references/config.md +0 -127
  258. package/skills/qa-vitest-writer/references/patterns.md +0 -141
  259. package/skills/qa-webdriverio-writer/SKILL.md +0 -145
  260. package/skills/qa-webdriverio-writer/references/best-practices.md +0 -176
  261. package/skills/qa-webdriverio-writer/references/config.md +0 -240
  262. package/skills/qa-webdriverio-writer/references/patterns.md +0 -269
@@ -1,140 +0,0 @@
1
- # Python API Testing Best Practices
2
-
3
- ## Async vs Sync
4
-
5
- | Use Case | Recommendation |
6
- | -------- | -------------- |
7
- | **Most API tests** | Sync `httpx.Client` — simpler, sufficient for typical CRUD |
8
- | **High concurrency** | Async `httpx.AsyncClient` — when testing many parallel requests |
9
- | **Async app under test** | Async client — matches async handlers |
10
- | **Mixed codebase** | Prefer sync unless async is required |
11
-
12
- ### When to Use Async
13
-
14
- - Testing endpoints that benefit from concurrent requests
15
- - Matching async application architecture
16
- - Performance benchmarks with many simultaneous calls
17
-
18
- ### Sync Simplicity
19
-
20
- ```python
21
- # Prefer sync for straightforward tests
22
- def test_get_users(client, base_url):
23
- response = client.get(f"{base_url}/users")
24
- assert response.status_code == 200
25
- ```
26
-
27
- ## Session Reuse
28
-
29
- | Scope | Pros | Cons |
30
- | ----- | ---- | ---- |
31
- | **Function** | Isolated; no shared state | New connection per test |
32
- | **Module** | Fewer connections | Shared state across tests in module |
33
- | **Session** | Fastest; single connection pool | Must avoid mutating shared state |
34
-
35
- **Recommendation:** Use function-scoped client by default. Use session scope only when tests are read-only and do not mutate server state.
36
-
37
- ## Schema Validation
38
-
39
- 1. **Use Pydantic when** — OpenAPI contract exists; response shape is well-defined
40
- 2. **Use JSON Schema when** — Contract is in JSON Schema format; no Pydantic in project
41
- 3. **Use manual assertions when** — Only a few fields matter; full schema is overkill
42
-
43
- ### Contract-Driven
44
-
45
- ```python
46
- # From qa-api-contract-curator OpenAPI spec
47
- class UserResponse(BaseModel):
48
- id: int
49
- email: EmailStr
50
- name: str | None = None
51
-
52
- def test_user_matches_contract(client, base_url, auth_headers):
53
- response = client.get(f"{base_url}/users/1", headers=auth_headers)
54
- UserResponse.model_validate(response.json()) # Fails if contract violated
55
- ```
56
-
57
- ## Test Isolation
58
-
59
- 1. **Independent tests** — Each test passes regardless of order
60
- 2. **No shared mutable state** — Avoid global variables; use fixtures
61
- 3. **Clean data** — Create/delete test data per test or use unique identifiers
62
- 4. **Idempotent when possible** — GET requests are safe; POST may create duplicates — use unique emails, UUIDs
63
-
64
- ### Unique Test Data
65
-
66
- ```python
67
- import uuid
68
-
69
- def test_create_user_unique(client, base_url, auth_headers):
70
- email = f"test-{uuid.uuid4().hex}@example.com"
71
- response = client.post(
72
- f"{base_url}/users",
73
- json={"email": email, "name": "Test"},
74
- headers=auth_headers
75
- )
76
- assert response.status_code == 201
77
- ```
78
-
79
- ## Error Scenarios
80
-
81
- Cover at least:
82
-
83
- | Scenario | Status | Assertion |
84
- | -------- | ------ | --------- |
85
- | Success | 200/201/204 | Per contract |
86
- | Validation error | 400 | Error payload structure |
87
- | Unauthorized | 401 | When missing/invalid auth |
88
- | Forbidden | 403 | Insufficient permissions |
89
- | Not found | 404 | Missing resource |
90
- | Conflict | 409 | Duplicate, constraint violation |
91
-
92
- ## Avoid
93
-
94
- 1. **Hardcoded secrets** — Use `os.environ` or pytest fixtures
95
- 2. **Fragile assertions** — Prefer partial match for dynamic fields (id, createdAt)
96
- 3. **Sleep/timeout for flakiness** — Use retries or deterministic data instead
97
- 4. **Testing implementation** — Test behavior and contract, not internal routes
98
- 5. **Large fixtures** — Minimize payload size; use factories for scale
99
- 6. **External services in unit tests** — Mock third-party APIs; use real API only in integration tests
100
-
101
- ## File Organization
102
-
103
- ```
104
- tests/
105
- conftest.py # base_url, client, auth
106
- api/
107
- conftest.py # auth_headers, token
108
- test_users_api.py
109
- test_products_api.py
110
- unit/ # Mocked API calls
111
- test_services.py
112
- ```
113
-
114
- ## Parallel Execution
115
-
116
- When using `pytest-xdist`:
117
-
118
- - Use unique data (UUIDs, timestamps) to avoid collisions
119
- - Or run API tests sequentially: `pytest -m api --forked` or single worker
120
- - Consider separate DB/schema per worker for integration tests
121
-
122
- ## Dependencies
123
-
124
- ```toml
125
- # pyproject.toml
126
- [project.optional-dependencies]
127
- test = [
128
- "httpx>=0.24.0",
129
- "pytest>=7.0",
130
- "pytest-asyncio>=0.21.0",
131
- "pydantic>=2.0",
132
- ]
133
- ```
134
-
135
- ## Contract-Driven Workflow
136
-
137
- 1. **Get OpenAPI** — From qa-api-contract-curator
138
- 2. **Generate Pydantic models** — From `components.schemas` (or use datamodel-code-generator)
139
- 3. **Generate tests** — One test per operation × status code
140
- 4. **Validate responses** — `Model.model_validate(response.json())`
@@ -1,212 +0,0 @@
1
- # httpx Test Configuration
2
-
3
- ## conftest.py Structure
4
-
5
- ```python
6
- # tests/conftest.py
7
- import os
8
- import pytest
9
- import httpx
10
-
11
-
12
- @pytest.fixture
13
- def base_url():
14
- return os.environ.get("API_BASE_URL", "http://localhost:8000")
15
-
16
-
17
- @pytest.fixture
18
- def client(base_url):
19
- """Sync client; use for non-async tests."""
20
- with httpx.Client(
21
- base_url=base_url,
22
- timeout=30.0,
23
- follow_redirects=True,
24
- ) as c:
25
- yield c
26
-
27
-
28
- @pytest.fixture
29
- async def async_client(base_url):
30
- """Async client; use with @pytest.mark.asyncio."""
31
- async with httpx.AsyncClient(
32
- base_url=base_url,
33
- timeout=30.0,
34
- follow_redirects=True,
35
- ) as c:
36
- yield c
37
- ```
38
-
39
- ## Base URL Management
40
-
41
- ### Environment Variable
42
-
43
- ```python
44
- # .env.test or pytest.ini
45
- # API_BASE_URL=https://api.staging.example.com
46
-
47
- @pytest.fixture
48
- def base_url():
49
- url = os.environ.get("API_BASE_URL")
50
- if not url:
51
- pytest.skip("API_BASE_URL not set")
52
- return url
53
- ```
54
-
55
- ### Per-Environment
56
-
57
- ```python
58
- @pytest.fixture
59
- def base_url():
60
- env = os.environ.get("TEST_ENV", "local")
61
- urls = {
62
- "local": "http://localhost:8000",
63
- "staging": "https://api.staging.example.com",
64
- "integration": "https://api.integration.example.com",
65
- }
66
- return urls.get(env, urls["local"])
67
- ```
68
-
69
- ## Client Fixtures
70
-
71
- ### Function-Scoped (Default)
72
-
73
- ```python
74
- @pytest.fixture
75
- def client(base_url):
76
- with httpx.Client(base_url=base_url) as c:
77
- yield c
78
- # New client per test; no shared state
79
- ```
80
-
81
- ### Session-Scoped (Connection Reuse)
82
-
83
- ```python
84
- @pytest.fixture(scope="session")
85
- def client(base_url):
86
- with httpx.Client(base_url=base_url) as c:
87
- yield c
88
- # Reuse connection across tests; faster but shared state
89
- ```
90
-
91
- ### With Custom Headers
92
-
93
- ```python
94
- @pytest.fixture
95
- def client(base_url, default_headers):
96
- with httpx.Client(
97
- base_url=base_url,
98
- headers=default_headers,
99
- ) as c:
100
- yield c
101
-
102
- @pytest.fixture
103
- def default_headers():
104
- return {
105
- "Accept": "application/json",
106
- "Content-Type": "application/json",
107
- "User-Agent": "qa-httpx-tests/1.0",
108
- }
109
- ```
110
-
111
- ## Auth Fixtures
112
-
113
- ```python
114
- @pytest.fixture
115
- def token(client, base_url):
116
- response = client.post(
117
- f"{base_url}/auth/login",
118
- json={
119
- "email": os.environ.get("TEST_USER_EMAIL", "test@example.com"),
120
- "password": os.environ.get("TEST_USER_PASSWORD", "test"),
121
- },
122
- )
123
- assert response.status_code == 200
124
- return response.json()["token"]
125
-
126
-
127
- @pytest.fixture
128
- def auth_headers(token):
129
- return {"Authorization": f"Bearer {token}"}
130
-
131
-
132
- @pytest.fixture
133
- def auth_client(client, auth_headers):
134
- client.headers.update(auth_headers)
135
- return client
136
- ```
137
-
138
- ## pytest-asyncio Configuration
139
-
140
- ### pyproject.toml
141
-
142
- ```toml
143
- [tool.pytest.ini_options]
144
- asyncio_mode = "auto"
145
- asyncio_default_fixture_loop_scope = "function"
146
- testpaths = ["tests"]
147
- ```
148
-
149
- ### pytest.ini
150
-
151
- ```ini
152
- [pytest]
153
- asyncio_mode = auto
154
- asyncio_default_fixture_loop_scope = function
155
- ```
156
-
157
- ## Timeout and Retry
158
-
159
- ```python
160
- from httpx import Timeout, Limits
161
-
162
- @pytest.fixture
163
- def client(base_url):
164
- with httpx.Client(
165
- base_url=base_url,
166
- timeout=Timeout(60.0),
167
- limits=Limits(max_keepalive_connections=5, max_connections=10),
168
- ) as c:
169
- yield c
170
- ```
171
-
172
- ## Markers for API Tests
173
-
174
- ```toml
175
- # pyproject.toml
176
- [tool.pytest.ini_options]
177
- markers = [
178
- "api: marks tests as API integration tests",
179
- "slow: marks tests as slow (network-dependent)",
180
- ]
181
- ```
182
-
183
- ```python
184
- @pytest.mark.api
185
- def test_users_endpoint(client, base_url):
186
- response = client.get(f"{base_url}/users")
187
- assert response.status_code == 200
188
- ```
189
-
190
- ## Directory Layout
191
-
192
- ```
193
- tests/
194
- conftest.py # Shared fixtures
195
- api/
196
- conftest.py # API-specific fixtures (auth, etc.)
197
- test_users_api.py
198
- test_products_api.py
199
- test_auth_api.py
200
- fixtures/
201
- sample_users.json
202
- ```
203
-
204
- ## Environment Config
205
-
206
- ```python
207
- # tests/conftest.py
208
- def pytest_configure(config):
209
- os.environ.setdefault("TESTING", "1")
210
- if "API_BASE_URL" not in os.environ:
211
- os.environ["API_BASE_URL"] = "http://localhost:8000"
212
- ```
@@ -1,262 +0,0 @@
1
- # httpx API Test Patterns
2
-
3
- ## Sync Client (httpx.Client)
4
-
5
- ```python
6
- import httpx
7
-
8
- def test_get_users():
9
- with httpx.Client(base_url="https://api.example.com") as client:
10
- response = client.get("/users")
11
- assert response.status_code == 200
12
- data = response.json()
13
- assert "users" in data
14
- assert isinstance(data["users"], list)
15
- ```
16
-
17
- ## Async Client (httpx.AsyncClient)
18
-
19
- ```python
20
- import httpx
21
- import pytest
22
-
23
- @pytest.mark.asyncio
24
- async def test_get_users_async():
25
- async with httpx.AsyncClient(base_url="https://api.example.com") as client:
26
- response = await client.get("/users")
27
- assert response.status_code == 200
28
- data = response.json()
29
- assert "users" in data
30
- ```
31
-
32
- ## CRUD Endpoints
33
-
34
- ### GET (List)
35
-
36
- ```python
37
- def test_get_users_list(client, base_url):
38
- response = client.get(f"{base_url}/users")
39
- assert response.status_code == 200
40
- assert "application/json" in response.headers.get("content-type", "")
41
- data = response.json()
42
- assert isinstance(data.get("users"), list)
43
-
44
- def test_get_users_unauthorized(client, base_url):
45
- response = client.get(f"{base_url}/users") # No auth
46
- assert response.status_code == 401
47
- ```
48
-
49
- ### GET (Single)
50
-
51
- ```python
52
- def test_get_user_by_id(client, base_url, auth_headers):
53
- response = client.get(f"{base_url}/users/1", headers=auth_headers)
54
- assert response.status_code == 200
55
- user = response.json()
56
- assert user["id"] == 1
57
- assert "email" in user
58
-
59
- def test_get_user_not_found(client, base_url, auth_headers):
60
- response = client.get(f"{base_url}/users/99999", headers=auth_headers)
61
- assert response.status_code == 404
62
- ```
63
-
64
- ### POST (Create)
65
-
66
- ```python
67
- def test_create_user(client, base_url, auth_headers):
68
- payload = {"email": "test@example.com", "name": "Test User"}
69
- response = client.post(f"{base_url}/users", json=payload, headers=auth_headers)
70
- assert response.status_code == 201
71
- user = response.json()
72
- assert "id" in user
73
- assert user["email"] == "test@example.com"
74
-
75
- def test_create_user_validation_error(client, base_url, auth_headers):
76
- response = client.post(
77
- f"{base_url}/users",
78
- json={"email": "invalid"},
79
- headers=auth_headers
80
- )
81
- assert response.status_code == 400
82
- errors = response.json()
83
- assert "errors" in errors or "message" in errors
84
- ```
85
-
86
- ### PUT/PATCH (Update)
87
-
88
- ```python
89
- def test_update_user(client, base_url, auth_headers):
90
- response = client.put(
91
- f"{base_url}/users/1",
92
- json={"name": "Updated Name"},
93
- headers=auth_headers
94
- )
95
- assert response.status_code == 200
96
- user = response.json()
97
- assert user["name"] == "Updated Name"
98
- ```
99
-
100
- ### DELETE
101
-
102
- ```python
103
- def test_delete_user(client, base_url, auth_headers):
104
- response = client.delete(f"{base_url}/users/1", headers=auth_headers)
105
- assert response.status_code == 204
106
- assert response.content == b""
107
-
108
- def test_delete_user_not_found(client, base_url, auth_headers):
109
- response = client.delete(f"{base_url}/users/99999", headers=auth_headers)
110
- assert response.status_code == 404
111
- ```
112
-
113
- ## Authentication
114
-
115
- ### Bearer Token
116
-
117
- ```python
118
- @pytest.fixture
119
- def auth_headers(token):
120
- return {"Authorization": f"Bearer {token}"}
121
-
122
- @pytest.fixture
123
- def token(client, base_url):
124
- response = client.post(
125
- f"{base_url}/auth/login",
126
- json={"email": "test@example.com", "password": "secret"}
127
- )
128
- assert response.status_code == 200
129
- return response.json()["token"]
130
-
131
- def test_protected_route(client, base_url, auth_headers):
132
- response = client.get(f"{base_url}/users", headers=auth_headers)
133
- assert response.status_code == 200
134
- ```
135
-
136
- ### API Key
137
-
138
- ```python
139
- @pytest.fixture
140
- def api_key_headers():
141
- return {"X-API-Key": os.environ.get("TEST_API_KEY", "test-key")}
142
-
143
- def test_with_api_key(client, base_url, api_key_headers):
144
- response = client.get(f"{base_url}/api/data", headers=api_key_headers)
145
- assert response.status_code == 200
146
- ```
147
-
148
- ### Basic Auth
149
-
150
- ```python
151
- def test_basic_auth(client, base_url):
152
- auth = httpx.BasicAuth("user", "password")
153
- response = client.get(f"{base_url}/admin", auth=auth)
154
- assert response.status_code == 200
155
- ```
156
-
157
- ### OAuth2
158
-
159
- ```python
160
- # Manual token flow
161
- def test_oauth2_protected(client, base_url, oauth_token):
162
- response = client.get(
163
- f"{base_url}/protected",
164
- headers={"Authorization": f"Bearer {oauth_token}"}
165
- )
166
- assert response.status_code == 200
167
- ```
168
-
169
- ### Cookies (Session)
170
-
171
- ```python
172
- def test_session_cookies(client, base_url):
173
- # Login to set cookies
174
- client.post(
175
- f"{base_url}/auth/login",
176
- json={"email": "test@example.com", "password": "secret"}
177
- )
178
- # Subsequent request uses session cookies
179
- response = client.get(f"{base_url}/users")
180
- assert response.status_code == 200
181
- ```
182
-
183
- ## File Upload
184
-
185
- ```python
186
- def test_file_upload(client, base_url, auth_headers, tmp_path):
187
- file_path = tmp_path / "sample.pdf"
188
- file_path.write_bytes(b"%PDF-1.4 fake content")
189
-
190
- with open(file_path, "rb") as f:
191
- files = {"file": ("sample.pdf", f, "application/pdf")}
192
- response = client.post(
193
- f"{base_url}/upload",
194
- files=files,
195
- headers=auth_headers
196
- )
197
-
198
- assert response.status_code == 201
199
- data = response.json()
200
- assert "url" in data or "id" in data
201
- ```
202
-
203
- ## Streaming
204
-
205
- ```python
206
- def test_streaming_response(client, base_url):
207
- with client.stream("GET", f"{base_url}/stream") as response:
208
- assert response.status_code == 200
209
- chunks = []
210
- for chunk in response.iter_bytes():
211
- chunks.append(chunk)
212
- assert len(chunks) > 0
213
- ```
214
-
215
- ## Query Parameters
216
-
217
- ```python
218
- def test_query_params(client, base_url):
219
- response = client.get(
220
- f"{base_url}/search",
221
- params={"q": "test", "limit": 5}
222
- )
223
- assert response.status_code == 200
224
- # URL: /search?q=test&limit=5
225
- ```
226
-
227
- ## Retry Logic
228
-
229
- ```python
230
- from httpx import Limits, Timeout
231
-
232
- @pytest.fixture
233
- def client_with_retry(base_url):
234
- transport = httpx.HTTPTransport(retries=3)
235
- with httpx.Client(
236
- base_url=base_url,
237
- transport=transport,
238
- timeout=Timeout(30.0)
239
- ) as client:
240
- yield client
241
- ```
242
-
243
- ## requests Fallback
244
-
245
- When httpx is not available, use requests with similar patterns:
246
-
247
- ```python
248
- import requests
249
-
250
- def test_with_requests(base_url):
251
- response = requests.get(f"{base_url}/users")
252
- assert response.status_code == 200
253
- data = response.json()
254
- assert "users" in data
255
-
256
- # Session for connection reuse
257
- def test_with_session(base_url):
258
- with requests.Session() as session:
259
- session.headers.update({"Authorization": f"Bearer {token}"})
260
- response = session.get(f"{base_url}/users")
261
- assert response.status_code == 200
262
- ```