qaa-agent 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/commands/create-test.md +40 -0
- package/.claude/commands/qa-analyze.md +60 -0
- package/.claude/commands/qa-audit.md +37 -0
- package/.claude/commands/qa-blueprint.md +54 -0
- package/.claude/commands/qa-fix.md +36 -0
- package/.claude/commands/qa-from-ticket.md +88 -0
- package/.claude/commands/qa-gap.md +54 -0
- package/.claude/commands/qa-pom.md +36 -0
- package/.claude/commands/qa-pyramid.md +37 -0
- package/.claude/commands/qa-report.md +38 -0
- package/.claude/commands/qa-start.md +33 -0
- package/.claude/commands/qa-testid.md +54 -0
- package/.claude/commands/qa-validate.md +54 -0
- package/.claude/commands/update-test.md +58 -0
- package/.claude/settings.json +19 -0
- package/.claude/skills/qa-bug-detective/SKILL.md +122 -0
- package/.claude/skills/qa-repo-analyzer/SKILL.md +88 -0
- package/.claude/skills/qa-self-validator/SKILL.md +109 -0
- package/.claude/skills/qa-template-engine/SKILL.md +113 -0
- package/.claude/skills/qa-testid-injector/SKILL.md +93 -0
- package/.claude/skills/qa-workflow-documenter/SKILL.md +87 -0
- package/CLAUDE.md +543 -0
- package/README.md +418 -0
- package/agents/qa-pipeline-orchestrator.md +1217 -0
- package/agents/qaa-analyzer.md +508 -0
- package/agents/qaa-bug-detective.md +444 -0
- package/agents/qaa-executor.md +618 -0
- package/agents/qaa-planner.md +374 -0
- package/agents/qaa-scanner.md +422 -0
- package/agents/qaa-testid-injector.md +583 -0
- package/agents/qaa-validator.md +450 -0
- package/bin/install.cjs +176 -0
- package/bin/lib/commands.cjs +709 -0
- package/bin/lib/config.cjs +307 -0
- package/bin/lib/core.cjs +497 -0
- package/bin/lib/frontmatter.cjs +299 -0
- package/bin/lib/init.cjs +989 -0
- package/bin/lib/milestone.cjs +241 -0
- package/bin/lib/model-profiles.cjs +60 -0
- package/bin/lib/phase.cjs +911 -0
- package/bin/lib/roadmap.cjs +306 -0
- package/bin/lib/state.cjs +748 -0
- package/bin/lib/template.cjs +222 -0
- package/bin/lib/verify.cjs +842 -0
- package/bin/qaa-tools.cjs +607 -0
- package/package.json +34 -0
- package/templates/failure-classification.md +391 -0
- package/templates/gap-analysis.md +409 -0
- package/templates/pr-template.md +48 -0
- package/templates/qa-analysis.md +381 -0
- package/templates/qa-audit-report.md +465 -0
- package/templates/qa-repo-blueprint.md +636 -0
- package/templates/scan-manifest.md +312 -0
- package/templates/test-inventory.md +582 -0
- package/templates/testid-audit-report.md +354 -0
- package/templates/validation-report.md +243 -0
|
@@ -0,0 +1,582 @@
|
|
|
1
|
+
---
|
|
2
|
+
template_name: test-inventory
|
|
3
|
+
version: "1.0"
|
|
4
|
+
artifact_type: inventory
|
|
5
|
+
produces: TEST_INVENTORY.md
|
|
6
|
+
producer_agent: qa-analyzer
|
|
7
|
+
consumer_agents:
|
|
8
|
+
- qa-planner
|
|
9
|
+
- qa-executor
|
|
10
|
+
required_sections:
|
|
11
|
+
- summary
|
|
12
|
+
- unit-tests
|
|
13
|
+
- integration-tests
|
|
14
|
+
- api-tests
|
|
15
|
+
- e2e-smoke-tests
|
|
16
|
+
example_domain: shopflow
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# TEST_INVENTORY.md Template
|
|
20
|
+
|
|
21
|
+
**Purpose:** Complete, pyramid-based test case inventory with every test specified to the level of detail needed for automated generation. Every test case has a unique ID, specific target, concrete inputs, and an explicit expected outcome. This inventory is the single source of truth for what tests will be generated.
|
|
22
|
+
|
|
23
|
+
**Producer:** `qa-analyzer` agent
|
|
24
|
+
**Consumers:** `qa-planner` (reads inventory to create generation plan with task breakdown and file assignments), `qa-executor` (reads individual test cases to write actual test code)
|
|
25
|
+
|
|
26
|
+
**Input required:** `QA_ANALYSIS.md` must exist before this artifact is produced. The analyzer uses the top 10 unit targets, API targets, risk assessment, and testing pyramid from the analysis to populate this inventory.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Required Sections
|
|
31
|
+
|
|
32
|
+
### Section 1: Summary
|
|
33
|
+
|
|
34
|
+
**Description:** High-level overview of the complete test inventory. Provides counts and distributions that downstream agents use to estimate effort and validate completeness.
|
|
35
|
+
|
|
36
|
+
**Fields:**
|
|
37
|
+
|
|
38
|
+
| Field | Type | Required | Description |
|
|
39
|
+
|-------|------|----------|-------------|
|
|
40
|
+
| total_tests | number | YES | Total number of test cases across all tiers |
|
|
41
|
+
| unit_count | number | YES | Number of unit tests |
|
|
42
|
+
| unit_percent | number | YES | Percentage of total (target: 60-70%) |
|
|
43
|
+
| integration_count | number | YES | Number of integration tests |
|
|
44
|
+
| integration_percent | number | YES | Percentage of total (target: 10-15%) |
|
|
45
|
+
| api_count | number | YES | Number of API tests |
|
|
46
|
+
| api_percent | number | YES | Percentage of total (target: 20-25%) |
|
|
47
|
+
| e2e_count | number | YES | Number of E2E smoke tests |
|
|
48
|
+
| e2e_percent | number | YES | Percentage of total (target: 3-5%) |
|
|
49
|
+
| p0_count | number | YES | Number of P0 (blocks release) tests |
|
|
50
|
+
| p1_count | number | YES | Number of P1 (should fix) tests |
|
|
51
|
+
| p2_count | number | YES | Number of P2 (nice to have) tests |
|
|
52
|
+
| coverage_narrative | string | YES | 2-3 sentence assessment of what this inventory covers and any known gaps |
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
### Section 2: Unit Tests (60-70%)
|
|
57
|
+
|
|
58
|
+
**Description:** Tests for individual functions, methods, and modules in isolation. Each test case targets a specific function with concrete inputs and an explicit expected outcome. This is the largest tier and covers all business logic, validation, and utility functions.
|
|
59
|
+
|
|
60
|
+
**Per test case -- ALL fields are MANDATORY:**
|
|
61
|
+
|
|
62
|
+
| Field | Type | Required | Description |
|
|
63
|
+
|-------|------|----------|-------------|
|
|
64
|
+
| test_id | string | YES | Format: `UT-MODULE-NNN` (e.g., `UT-PRICE-001`) |
|
|
65
|
+
| target | string | YES | Format: `file_path:function_name` (e.g., `src/utils/priceCalculator.ts:calculateOrderTotal`) |
|
|
66
|
+
| what_to_validate | string | YES | One-sentence description of the behavior being tested |
|
|
67
|
+
| concrete_inputs | string | YES | Actual values to pass -- NOT "valid data" or "correct input" |
|
|
68
|
+
| mocks_needed | string | YES | List of dependencies to mock, or "None (pure function)" |
|
|
69
|
+
| expected_outcome | string | YES | Exact return value, exact error message, or exact state change |
|
|
70
|
+
| priority | enum | YES | `P0` (blocks release), `P1` (should fix), `P2` (nice to have) |
|
|
71
|
+
|
|
72
|
+
**CRITICAL ANTI-PATTERN:**
|
|
73
|
+
|
|
74
|
+
> "Returns correct value" is **NOT** an expected outcome.
|
|
75
|
+
> "Returns 239.47" **IS** an expected outcome.
|
|
76
|
+
>
|
|
77
|
+
> "Handles error correctly" is **NOT** an expected outcome.
|
|
78
|
+
> "Throws InvalidTransitionError with message 'Cannot transition from delivered to pending'" **IS** an expected outcome.
|
|
79
|
+
>
|
|
80
|
+
> Every expected outcome must contain a **concrete value, specific error, or measurable state change**.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
### Section 3: Integration/Contract Tests (10-15%)
|
|
85
|
+
|
|
86
|
+
**Description:** Tests verifying that two or more modules interact correctly. These test the contracts between components -- not internal logic (that's unit tests) and not HTTP contracts (that's API tests). Focus on database interactions, service-to-service calls, and cross-module state flows.
|
|
87
|
+
|
|
88
|
+
**Per test case -- ALL fields are MANDATORY:**
|
|
89
|
+
|
|
90
|
+
| Field | Type | Required | Description |
|
|
91
|
+
|-------|------|----------|-------------|
|
|
92
|
+
| test_id | string | YES | Format: `INT-MODULE-NNN` (e.g., `INT-ORDER-001`) |
|
|
93
|
+
| components_involved | string | YES | Which modules interact (e.g., "orderService + inventoryService + Prisma") |
|
|
94
|
+
| what_to_validate | string | YES | The interaction contract being tested |
|
|
95
|
+
| setup_required | string | YES | Database state, mock services, or seed data needed before the test |
|
|
96
|
+
| expected_outcome | string | YES | Specific behavior when components interact correctly |
|
|
97
|
+
| priority | enum | YES | `P0`, `P1`, or `P2` |
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
### Section 4: API Tests (20-25%)
|
|
102
|
+
|
|
103
|
+
**Description:** HTTP-level tests verifying request/response contracts for each endpoint. These ensure the API surface area behaves as documented -- correct status codes, response shapes, error formats, and auth enforcement.
|
|
104
|
+
|
|
105
|
+
**Per test case -- ALL fields are MANDATORY:**
|
|
106
|
+
|
|
107
|
+
| Field | Type | Required | Description |
|
|
108
|
+
|-------|------|----------|-------------|
|
|
109
|
+
| test_id | string | YES | Format: `API-RESOURCE-NNN` (e.g., `API-AUTH-001`) |
|
|
110
|
+
| method_endpoint | string | YES | HTTP method + path (e.g., `POST /api/v1/auth/login`) |
|
|
111
|
+
| request_body | string | YES | Exact JSON payload or "N/A" for GET requests |
|
|
112
|
+
| headers | string | YES | Required headers (e.g., `Authorization: Bearer {token}`) or "None" |
|
|
113
|
+
| expected_status | number | YES | Exact HTTP status code (200, 201, 400, 401, 404, etc.) |
|
|
114
|
+
| expected_response | string | YES | Key fields in response body with types or exact values |
|
|
115
|
+
| priority | enum | YES | `P0`, `P1`, or `P2` |
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
### Section 5: E2E Smoke Tests (3-5%)
|
|
120
|
+
|
|
121
|
+
**Description:** End-to-end tests covering the most critical user journeys. These are the minimum set of tests that MUST pass before any release. Maximum 3-8 tests -- each one a multi-step user flow that exercises the full stack.
|
|
122
|
+
|
|
123
|
+
**Per test case -- ALL fields are MANDATORY:**
|
|
124
|
+
|
|
125
|
+
| Field | Type | Required | Description |
|
|
126
|
+
|-------|------|----------|-------------|
|
|
127
|
+
| test_id | string | YES | Format: `E2E-FLOW-NNN` (e.g., `E2E-FLOW-001`) |
|
|
128
|
+
| user_journey | string | YES | Step-by-step description of what the user does |
|
|
129
|
+
| pages_involved | string | YES | List of views/routes the user navigates through |
|
|
130
|
+
| expected_outcome | string | YES | Final state the user observes after completing the journey |
|
|
131
|
+
| priority | enum | YES | Always `P0` -- E2E tests are release-blocking by definition |
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Worked Example (ShopFlow E-Commerce API)
|
|
136
|
+
|
|
137
|
+
> The following is a complete, filled TEST_INVENTORY.md for the ShopFlow e-commerce application. This example demonstrates the expected depth, specificity, and concrete values required in every test case.
|
|
138
|
+
|
|
139
|
+
### Summary
|
|
140
|
+
|
|
141
|
+
| Metric | Value |
|
|
142
|
+
|--------|-------|
|
|
143
|
+
| **Total Tests** | 45 |
|
|
144
|
+
| **Unit Tests** | 28 (62%) |
|
|
145
|
+
| **Integration Tests** | 7 (16%) |
|
|
146
|
+
| **API Tests** | 8 (18%) |
|
|
147
|
+
| **E2E Smoke Tests** | 2 (4%) |
|
|
148
|
+
| **P0 (blocks release)** | 15 |
|
|
149
|
+
| **P1 (should fix)** | 20 |
|
|
150
|
+
| **P2 (nice to have)** | 10 |
|
|
151
|
+
|
|
152
|
+
**Coverage narrative:** This inventory covers all business-critical logic (price calculation, order state machine, payment processing, authentication), the complete API contract surface, key integration points (order-to-inventory, payment-to-order), and the two most critical user journeys (purchase flow and registration). Known gap: admin-only endpoints (product CRUD) are covered at P1 level only -- no E2E test for admin flows since admin UI is out of current scope.
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
### Unit Tests (28 tests -- 62%)
|
|
157
|
+
|
|
158
|
+
#### Price Calculation Module
|
|
159
|
+
|
|
160
|
+
##### UT-PRICE-001: Calculate Order Total with Multiple Items
|
|
161
|
+
- **Target:** `src/utils/priceCalculator.ts:calculateOrderTotal`
|
|
162
|
+
- **What to validate:** Correctly sums line items with quantity multiplication
|
|
163
|
+
- **Concrete inputs:** `[{sku: 'WIDGET-001', qty: 3, unitPrice: 29.99}, {sku: 'GADGET-002', qty: 1, unitPrice: 149.50}]`
|
|
164
|
+
- **Mocks needed:** None (pure function)
|
|
165
|
+
- **Expected outcome:** Returns `239.47` (29.99 * 3 + 149.50)
|
|
166
|
+
- **Priority:** P0
|
|
167
|
+
|
|
168
|
+
##### UT-PRICE-002: Apply Percentage Discount
|
|
169
|
+
- **Target:** `src/utils/priceCalculator.ts:applyDiscount`
|
|
170
|
+
- **What to validate:** Applies percentage discount correctly and rounds to 2 decimal places
|
|
171
|
+
- **Concrete inputs:** `{subtotal: 239.47, discountCode: 'SAVE10', discountPercent: 10}`
|
|
172
|
+
- **Mocks needed:** None (pure function)
|
|
173
|
+
- **Expected outcome:** Returns `215.52` (239.47 * 0.90, rounded to 2 decimals)
|
|
174
|
+
- **Priority:** P1
|
|
175
|
+
|
|
176
|
+
##### UT-PRICE-003: Calculate Tax
|
|
177
|
+
- **Target:** `src/utils/priceCalculator.ts:calculateTax`
|
|
178
|
+
- **What to validate:** Applies state tax rate correctly
|
|
179
|
+
- **Concrete inputs:** `{subtotal: 215.52, state: 'CA', taxRate: 0.0875}`
|
|
180
|
+
- **Mocks needed:** None (pure function)
|
|
181
|
+
- **Expected outcome:** Returns `18.86` (215.52 * 0.0875, rounded to 2 decimals)
|
|
182
|
+
- **Priority:** P1
|
|
183
|
+
|
|
184
|
+
##### UT-PRICE-004: Calculate Shipping by Weight
|
|
185
|
+
- **Target:** `src/utils/priceCalculator.ts:calculateShipping`
|
|
186
|
+
- **What to validate:** Returns correct shipping cost based on weight tiers
|
|
187
|
+
- **Concrete inputs:** `{totalWeight: 4.5, shippingMethod: 'standard'}`
|
|
188
|
+
- **Mocks needed:** None (pure function)
|
|
189
|
+
- **Expected outcome:** Returns `8.99` (standard rate for 2-5 kg tier)
|
|
190
|
+
- **Priority:** P2
|
|
191
|
+
|
|
192
|
+
##### UT-PRICE-005: Calculate Order Total with Zero Items
|
|
193
|
+
- **Target:** `src/utils/priceCalculator.ts:calculateOrderTotal`
|
|
194
|
+
- **What to validate:** Returns 0 for empty cart
|
|
195
|
+
- **Concrete inputs:** `[]`
|
|
196
|
+
- **Mocks needed:** None (pure function)
|
|
197
|
+
- **Expected outcome:** Returns `0.00`
|
|
198
|
+
- **Priority:** P1
|
|
199
|
+
|
|
200
|
+
#### Authentication Module
|
|
201
|
+
|
|
202
|
+
##### UT-AUTH-001: Hash Password with bcrypt
|
|
203
|
+
- **Target:** `src/services/authService.ts:hashPassword`
|
|
204
|
+
- **What to validate:** Produces a bcrypt hash that validates against the original password
|
|
205
|
+
- **Concrete inputs:** `'SecureP@ss123!'`
|
|
206
|
+
- **Mocks needed:** None
|
|
207
|
+
- **Expected outcome:** `bcrypt.compare('SecureP@ss123!', result)` returns `true`; result starts with `$2b$`
|
|
208
|
+
- **Priority:** P0
|
|
209
|
+
|
|
210
|
+
##### UT-AUTH-002: Verify Password -- Correct Password
|
|
211
|
+
- **Target:** `src/services/authService.ts:verifyPassword`
|
|
212
|
+
- **What to validate:** Returns true for correct password against stored hash
|
|
213
|
+
- **Concrete inputs:** `{password: 'SecureP@ss123!', hash: '$2b$10$...' (pre-computed valid hash)}`
|
|
214
|
+
- **Mocks needed:** None
|
|
215
|
+
- **Expected outcome:** Returns `true`
|
|
216
|
+
- **Priority:** P0
|
|
217
|
+
|
|
218
|
+
##### UT-AUTH-003: Verify Password -- Wrong Password
|
|
219
|
+
- **Target:** `src/services/authService.ts:verifyPassword`
|
|
220
|
+
- **What to validate:** Returns false for incorrect password
|
|
221
|
+
- **Concrete inputs:** `{password: 'WrongPassword!', hash: '$2b$10$...' (hash of 'SecureP@ss123!')}`
|
|
222
|
+
- **Mocks needed:** None
|
|
223
|
+
- **Expected outcome:** Returns `false`
|
|
224
|
+
- **Priority:** P0
|
|
225
|
+
|
|
226
|
+
##### UT-AUTH-004: Generate JWT Token with Correct Claims
|
|
227
|
+
- **Target:** `src/services/authService.ts:generateToken`
|
|
228
|
+
- **What to validate:** Generates a JWT with correct user ID, email, and expiration
|
|
229
|
+
- **Concrete inputs:** `{userId: 'usr_abc123', email: 'test@shopflow.com', role: 'customer'}`
|
|
230
|
+
- **Mocks needed:** Mock `jwt.sign` to capture payload
|
|
231
|
+
- **Expected outcome:** Token payload contains `{sub: 'usr_abc123', email: 'test@shopflow.com', role: 'customer', exp: <now + 15min>}`
|
|
232
|
+
- **Priority:** P0
|
|
233
|
+
|
|
234
|
+
##### UT-AUTH-005: Reject Expired Token
|
|
235
|
+
- **Target:** `src/services/authService.ts:verifyToken`
|
|
236
|
+
- **What to validate:** Throws error when token has expired
|
|
237
|
+
- **Concrete inputs:** JWT token with `exp` set to 1 hour ago
|
|
238
|
+
- **Mocks needed:** None (use real jwt.verify with expired token)
|
|
239
|
+
- **Expected outcome:** Throws `TokenExpiredError` with message "jwt expired"
|
|
240
|
+
- **Priority:** P0
|
|
241
|
+
|
|
242
|
+
#### Order Management Module
|
|
243
|
+
|
|
244
|
+
##### UT-ORDER-001: Transition Order Status -- Valid Transition (pending -> confirmed)
|
|
245
|
+
- **Target:** `src/services/orderService.ts:transitionOrderStatus`
|
|
246
|
+
- **What to validate:** Accepts valid state transition and returns new status
|
|
247
|
+
- **Concrete inputs:** `{orderId: 'ord_123', currentStatus: 'pending', newStatus: 'confirmed'}`
|
|
248
|
+
- **Mocks needed:** Mock Prisma `order.update` to return updated record
|
|
249
|
+
- **Expected outcome:** Returns `{orderId: 'ord_123', status: 'confirmed', updatedAt: <timestamp>}`
|
|
250
|
+
- **Priority:** P0
|
|
251
|
+
|
|
252
|
+
##### UT-ORDER-002: Transition Order Status -- Invalid Transition (delivered -> pending)
|
|
253
|
+
- **Target:** `src/services/orderService.ts:transitionOrderStatus`
|
|
254
|
+
- **What to validate:** Rejects invalid state transition with descriptive error
|
|
255
|
+
- **Concrete inputs:** `{orderId: 'ord_456', currentStatus: 'delivered', newStatus: 'pending'}`
|
|
256
|
+
- **Mocks needed:** Mock Prisma `order.findUnique` to return order with status 'delivered'
|
|
257
|
+
- **Expected outcome:** Throws `InvalidTransitionError` with message "Cannot transition from delivered to pending"
|
|
258
|
+
- **Priority:** P0
|
|
259
|
+
|
|
260
|
+
##### UT-ORDER-003: Transition Order Status -- Cancel from Pending
|
|
261
|
+
- **Target:** `src/services/orderService.ts:transitionOrderStatus`
|
|
262
|
+
- **What to validate:** Allows cancellation from pending status
|
|
263
|
+
- **Concrete inputs:** `{orderId: 'ord_789', currentStatus: 'pending', newStatus: 'cancelled'}`
|
|
264
|
+
- **Mocks needed:** Mock Prisma `order.update` to return updated record
|
|
265
|
+
- **Expected outcome:** Returns `{orderId: 'ord_789', status: 'cancelled', updatedAt: <timestamp>}`
|
|
266
|
+
- **Priority:** P0
|
|
267
|
+
|
|
268
|
+
##### UT-ORDER-004: Transition Order Status -- Cancel from Shipped (should fail)
|
|
269
|
+
- **Target:** `src/services/orderService.ts:transitionOrderStatus`
|
|
270
|
+
- **What to validate:** Rejects cancellation after shipment
|
|
271
|
+
- **Concrete inputs:** `{orderId: 'ord_012', currentStatus: 'shipped', newStatus: 'cancelled'}`
|
|
272
|
+
- **Mocks needed:** Mock Prisma `order.findUnique` to return order with status 'shipped'
|
|
273
|
+
- **Expected outcome:** Throws `InvalidTransitionError` with message "Cannot cancel an order that has been shipped"
|
|
274
|
+
- **Priority:** P1
|
|
275
|
+
|
|
276
|
+
#### Payment Module
|
|
277
|
+
|
|
278
|
+
##### UT-PAY-001: Charge Customer -- Success
|
|
279
|
+
- **Target:** `src/services/paymentService.ts:chargeCustomer`
|
|
280
|
+
- **What to validate:** Creates a Stripe charge and returns payment confirmation
|
|
281
|
+
- **Concrete inputs:** `{orderId: 'ord_123', amount: 25846, currency: 'usd', paymentMethodId: 'pm_test_visa'}`
|
|
282
|
+
- **Mocks needed:** Mock `stripe.paymentIntents.create` to return `{id: 'pi_abc', status: 'succeeded', amount: 25846}`
|
|
283
|
+
- **Expected outcome:** Returns `{paymentId: 'pi_abc', status: 'succeeded', amount: 258.46}`
|
|
284
|
+
- **Priority:** P0
|
|
285
|
+
|
|
286
|
+
##### UT-PAY-002: Charge Customer -- Card Declined
|
|
287
|
+
- **Target:** `src/services/paymentService.ts:chargeCustomer`
|
|
288
|
+
- **What to validate:** Handles Stripe card decline gracefully
|
|
289
|
+
- **Concrete inputs:** `{orderId: 'ord_456', amount: 15000, currency: 'usd', paymentMethodId: 'pm_test_declined'}`
|
|
290
|
+
- **Mocks needed:** Mock `stripe.paymentIntents.create` to throw `StripeCardError` with code 'card_declined'
|
|
291
|
+
- **Expected outcome:** Throws `PaymentFailedError` with message "Card was declined" and does NOT update order status
|
|
292
|
+
- **Priority:** P0
|
|
293
|
+
|
|
294
|
+
##### UT-PAY-003: Handle Webhook -- Valid Signature
|
|
295
|
+
- **Target:** `src/services/paymentService.ts:handleWebhook`
|
|
296
|
+
- **What to validate:** Processes webhook with valid Stripe signature
|
|
297
|
+
- **Concrete inputs:** `{rawBody: '{"type":"payment_intent.succeeded",...}', signature: 'valid_sig_hash'}`
|
|
298
|
+
- **Mocks needed:** Mock `stripe.webhooks.constructEvent` to return parsed event
|
|
299
|
+
- **Expected outcome:** Returns `{processed: true, eventType: 'payment_intent.succeeded'}`
|
|
300
|
+
- **Priority:** P0
|
|
301
|
+
|
|
302
|
+
##### UT-PAY-004: Handle Webhook -- Invalid Signature
|
|
303
|
+
- **Target:** `src/services/paymentService.ts:handleWebhook`
|
|
304
|
+
- **What to validate:** Rejects webhook with invalid or missing Stripe signature
|
|
305
|
+
- **Concrete inputs:** `{rawBody: '{"type":"payment_intent.succeeded",...}', signature: 'invalid_sig'}`
|
|
306
|
+
- **Mocks needed:** Mock `stripe.webhooks.constructEvent` to throw `SignatureVerificationError`
|
|
307
|
+
- **Expected outcome:** Throws `WebhookVerificationError` with message "Invalid webhook signature"
|
|
308
|
+
- **Priority:** P0
|
|
309
|
+
|
|
310
|
+
#### Inventory Module
|
|
311
|
+
|
|
312
|
+
##### UT-INV-001: Reserve Stock -- Sufficient Inventory
|
|
313
|
+
- **Target:** `src/services/inventoryService.ts:reserveStock`
|
|
314
|
+
- **What to validate:** Decrements available stock when sufficient inventory exists
|
|
315
|
+
- **Concrete inputs:** `{productId: 'prod_001', quantity: 3, currentStock: 10}`
|
|
316
|
+
- **Mocks needed:** Mock Prisma `product.update` to return updated stock
|
|
317
|
+
- **Expected outcome:** Returns `{productId: 'prod_001', reserved: 3, remainingStock: 7}`
|
|
318
|
+
- **Priority:** P0
|
|
319
|
+
|
|
320
|
+
##### UT-INV-002: Reserve Stock -- Insufficient Inventory
|
|
321
|
+
- **Target:** `src/services/inventoryService.ts:reserveStock`
|
|
322
|
+
- **What to validate:** Rejects reservation when insufficient stock
|
|
323
|
+
- **Concrete inputs:** `{productId: 'prod_002', quantity: 5, currentStock: 2}`
|
|
324
|
+
- **Mocks needed:** Mock Prisma `product.findUnique` to return product with stock 2
|
|
325
|
+
- **Expected outcome:** Throws `InsufficientStockError` with message "Only 2 units available for prod_002, requested 5"
|
|
326
|
+
- **Priority:** P0
|
|
327
|
+
|
|
328
|
+
##### UT-INV-003: Release Stock on Payment Failure
|
|
329
|
+
- **Target:** `src/services/inventoryService.ts:releaseStock`
|
|
330
|
+
- **What to validate:** Increments available stock when releasing a reservation
|
|
331
|
+
- **Concrete inputs:** `{productId: 'prod_001', quantity: 3, currentStock: 7}`
|
|
332
|
+
- **Mocks needed:** Mock Prisma `product.update` to return updated stock
|
|
333
|
+
- **Expected outcome:** Returns `{productId: 'prod_001', released: 3, availableStock: 10}`
|
|
334
|
+
- **Priority:** P1
|
|
335
|
+
|
|
336
|
+
#### Validation Module
|
|
337
|
+
|
|
338
|
+
##### UT-VAL-001: Validate Email -- Valid Format
|
|
339
|
+
- **Target:** `src/utils/validators.ts:validateEmail`
|
|
340
|
+
- **What to validate:** Accepts valid email format
|
|
341
|
+
- **Concrete inputs:** `'user@shopflow.com'`
|
|
342
|
+
- **Mocks needed:** None (pure function)
|
|
343
|
+
- **Expected outcome:** Returns `true`
|
|
344
|
+
- **Priority:** P1
|
|
345
|
+
|
|
346
|
+
##### UT-VAL-002: Validate Email -- Invalid Format
|
|
347
|
+
- **Target:** `src/utils/validators.ts:validateEmail`
|
|
348
|
+
- **What to validate:** Rejects invalid email format
|
|
349
|
+
- **Concrete inputs:** `'not-an-email'`
|
|
350
|
+
- **Mocks needed:** None (pure function)
|
|
351
|
+
- **Expected outcome:** Returns `false`
|
|
352
|
+
- **Priority:** P1
|
|
353
|
+
|
|
354
|
+
##### UT-VAL-003: Validate Password -- Meets Requirements
|
|
355
|
+
- **Target:** `src/utils/validators.ts:validatePassword`
|
|
356
|
+
- **What to validate:** Accepts password meeting minimum requirements (8+ chars, 1 uppercase, 1 number, 1 special)
|
|
357
|
+
- **Concrete inputs:** `'SecureP@ss123!'`
|
|
358
|
+
- **Mocks needed:** None (pure function)
|
|
359
|
+
- **Expected outcome:** Returns `{valid: true, errors: []}`
|
|
360
|
+
- **Priority:** P1
|
|
361
|
+
|
|
362
|
+
##### UT-VAL-004: Validate Password -- Too Short
|
|
363
|
+
- **Target:** `src/utils/validators.ts:validatePassword`
|
|
364
|
+
- **What to validate:** Rejects password under minimum length
|
|
365
|
+
- **Concrete inputs:** `'Ab1!'`
|
|
366
|
+
- **Mocks needed:** None (pure function)
|
|
367
|
+
- **Expected outcome:** Returns `{valid: false, errors: ['Password must be at least 8 characters']}`
|
|
368
|
+
- **Priority:** P1
|
|
369
|
+
|
|
370
|
+
#### Auth Middleware
|
|
371
|
+
|
|
372
|
+
##### UT-MID-001: Auth Middleware -- Valid Token
|
|
373
|
+
- **Target:** `src/middleware/authMiddleware.ts:verifyToken`
|
|
374
|
+
- **What to validate:** Attaches decoded user to request when valid token provided
|
|
375
|
+
- **Concrete inputs:** `{headers: {authorization: 'Bearer <valid-jwt>'}, decoded: {sub: 'usr_abc123', email: 'test@shopflow.com'}}`
|
|
376
|
+
- **Mocks needed:** Mock `jwt.verify` to return decoded payload
|
|
377
|
+
- **Expected outcome:** `req.user` is set to `{id: 'usr_abc123', email: 'test@shopflow.com'}`, `next()` is called
|
|
378
|
+
- **Priority:** P0
|
|
379
|
+
|
|
380
|
+
##### UT-MID-002: Auth Middleware -- Missing Token
|
|
381
|
+
- **Target:** `src/middleware/authMiddleware.ts:verifyToken`
|
|
382
|
+
- **What to validate:** Returns 401 when no Authorization header present
|
|
383
|
+
- **Concrete inputs:** `{headers: {}}`
|
|
384
|
+
- **Mocks needed:** None
|
|
385
|
+
- **Expected outcome:** Response status `401`, body `{error: 'Authentication required'}`
|
|
386
|
+
- **Priority:** P0
|
|
387
|
+
|
|
388
|
+
---
|
|
389
|
+
|
|
390
|
+
### Integration Tests (7 tests -- 16%)
|
|
391
|
+
|
|
392
|
+
##### INT-ORDER-001: Order Creation Reserves Inventory
|
|
393
|
+
- **Components involved:** orderService + inventoryService + Prisma (PostgreSQL)
|
|
394
|
+
- **What to validate:** Creating an order automatically reserves stock for each line item
|
|
395
|
+
- **Setup required:** Seed database with Product (id: 'prod_001', stock: 10) and authenticated User (id: 'usr_001')
|
|
396
|
+
- **Expected outcome:** After `orderService.createOrder({userId: 'usr_001', items: [{productId: 'prod_001', qty: 2}]})`, product stock is decremented to 8 in database, order status is 'pending'
|
|
397
|
+
- **Priority:** P0
|
|
398
|
+
|
|
399
|
+
##### INT-ORDER-002: Payment Success Updates Order Status
|
|
400
|
+
- **Components involved:** paymentService + orderService + Prisma (PostgreSQL)
|
|
401
|
+
- **What to validate:** Successful payment charge transitions order from pending to confirmed
|
|
402
|
+
- **Setup required:** Seed database with Order (id: 'ord_001', status: 'pending', total: 259.47). Mock Stripe to return successful charge.
|
|
403
|
+
- **Expected outcome:** After `paymentService.chargeCustomer({orderId: 'ord_001', ...})`, order status in database is 'confirmed', payment record exists with status 'succeeded'
|
|
404
|
+
- **Priority:** P0
|
|
405
|
+
|
|
406
|
+
##### INT-ORDER-003: Payment Failure Releases Inventory
|
|
407
|
+
- **Components involved:** paymentService + inventoryService + orderService + Prisma (PostgreSQL)
|
|
408
|
+
- **What to validate:** Failed payment releases reserved stock and keeps order in pending
|
|
409
|
+
- **Setup required:** Seed database with Order (id: 'ord_002', status: 'pending'), Product (id: 'prod_001', stock: 8, reserved: 2). Mock Stripe to throw card_declined.
|
|
410
|
+
- **Expected outcome:** After payment failure, product stock is restored to 10 in database, order status remains 'pending'
|
|
411
|
+
- **Priority:** P0
|
|
412
|
+
|
|
413
|
+
##### INT-ORDER-004: Webhook Updates Order After Async Payment
|
|
414
|
+
- **Components involved:** paymentController (webhook handler) + orderService + Prisma (PostgreSQL)
|
|
415
|
+
- **What to validate:** Stripe webhook event triggers order status update
|
|
416
|
+
- **Setup required:** Seed database with Order (id: 'ord_003', status: 'pending'). Construct valid webhook payload with Stripe test signing secret.
|
|
417
|
+
- **Expected outcome:** After webhook delivery with event type 'payment_intent.succeeded', order status in database is 'confirmed'
|
|
418
|
+
- **Priority:** P0
|
|
419
|
+
|
|
420
|
+
##### INT-AUTH-001: Auth Middleware Blocks Unauthorized Routes
|
|
421
|
+
- **Components involved:** authMiddleware + orderController + Express routing
|
|
422
|
+
- **What to validate:** Protected routes return 401 without valid JWT
|
|
423
|
+
- **Setup required:** Express app with routes mounted, no auth token in request
|
|
424
|
+
- **Expected outcome:** GET /api/v1/orders returns `401 {error: 'Authentication required'}`, POST /api/v1/orders returns `401 {error: 'Authentication required'}`
|
|
425
|
+
- **Priority:** P1
|
|
426
|
+
|
|
427
|
+
##### INT-AUTH-002: Refresh Token Rotation
|
|
428
|
+
- **Components involved:** authService + authController + Prisma (PostgreSQL)
|
|
429
|
+
- **What to validate:** Refreshing a token invalidates the old refresh token and issues a new pair
|
|
430
|
+
- **Setup required:** Seed database with User and valid refresh token record
|
|
431
|
+
- **Expected outcome:** After POST /api/v1/auth/refresh with old token, response contains new access token and new refresh token, old refresh token is marked invalid in database
|
|
432
|
+
- **Priority:** P1
|
|
433
|
+
|
|
434
|
+
##### INT-DB-001: Prisma Transaction Rollback on Error
|
|
435
|
+
- **Components involved:** orderService + Prisma (PostgreSQL) transaction
|
|
436
|
+
- **What to validate:** If any step in order creation fails, the entire transaction rolls back
|
|
437
|
+
- **Setup required:** Seed database with Product (stock: 1). Attempt to create order with qty: 2 (should fail on inventory check).
|
|
438
|
+
- **Expected outcome:** No order created in database, product stock unchanged at 1, `InsufficientStockError` thrown
|
|
439
|
+
- **Priority:** P1
|
|
440
|
+
|
|
441
|
+
---
|
|
442
|
+
|
|
443
|
+
### API Tests (8 tests -- 18%)
|
|
444
|
+
|
|
445
|
+
##### API-AUTH-001: Login with Valid Credentials
|
|
446
|
+
- **Method + Endpoint:** `POST /api/v1/auth/login`
|
|
447
|
+
- **Request body:** `{"email": "customer@shopflow.com", "password": "SecureP@ss123!"}`
|
|
448
|
+
- **Headers:** `Content-Type: application/json`
|
|
449
|
+
- **Expected status:** 200
|
|
450
|
+
- **Expected response:** `{token: string (JWT format), refreshToken: string (UUID format), user: {id: string, name: "Test Customer", email: "customer@shopflow.com"}}`
|
|
451
|
+
- **Priority:** P0
|
|
452
|
+
|
|
453
|
+
##### API-AUTH-002: Login with Invalid Password
|
|
454
|
+
- **Method + Endpoint:** `POST /api/v1/auth/login`
|
|
455
|
+
- **Request body:** `{"email": "customer@shopflow.com", "password": "WrongPassword"}`
|
|
456
|
+
- **Headers:** `Content-Type: application/json`
|
|
457
|
+
- **Expected status:** 401
|
|
458
|
+
- **Expected response:** `{error: "Invalid email or password"}`
|
|
459
|
+
- **Priority:** P0
|
|
460
|
+
|
|
461
|
+
##### API-AUTH-003: Register New User
|
|
462
|
+
- **Method + Endpoint:** `POST /api/v1/auth/register`
|
|
463
|
+
- **Request body:** `{"name": "New User", "email": "newuser@shopflow.com", "password": "SecureP@ss123!"}`
|
|
464
|
+
- **Headers:** `Content-Type: application/json`
|
|
465
|
+
- **Expected status:** 201
|
|
466
|
+
- **Expected response:** `{id: string (UUID), email: "newuser@shopflow.com", token: string (JWT format)}`
|
|
467
|
+
- **Priority:** P0
|
|
468
|
+
|
|
469
|
+
##### API-ORDER-001: Create Order with Valid Items
|
|
470
|
+
- **Method + Endpoint:** `POST /api/v1/orders`
|
|
471
|
+
- **Request body:** `{"items": [{"productId": "prod_001", "qty": 2}], "shippingAddress": {"street": "123 Main St", "city": "San Francisco", "state": "CA", "zip": "94102"}}`
|
|
472
|
+
- **Headers:** `Authorization: Bearer {valid_token}`, `Content-Type: application/json`
|
|
473
|
+
- **Expected status:** 201
|
|
474
|
+
- **Expected response:** `{orderId: string (UUID), status: "pending", total: number (> 0), items: [{productId: "prod_001", qty: 2, unitPrice: number}]}`
|
|
475
|
+
- **Priority:** P0
|
|
476
|
+
|
|
477
|
+
##### API-ORDER-002: Create Order Without Auth Token
|
|
478
|
+
- **Method + Endpoint:** `POST /api/v1/orders`
|
|
479
|
+
- **Request body:** `{"items": [{"productId": "prod_001", "qty": 1}], "shippingAddress": {...}}`
|
|
480
|
+
- **Headers:** None (no Authorization header)
|
|
481
|
+
- **Expected status:** 401
|
|
482
|
+
- **Expected response:** `{error: "Authentication required"}`
|
|
483
|
+
- **Priority:** P0
|
|
484
|
+
|
|
485
|
+
##### API-ORDER-003: Update Order Status
|
|
486
|
+
- **Method + Endpoint:** `PATCH /api/v1/orders/ord_001/status`
|
|
487
|
+
- **Request body:** `{"status": "confirmed"}`
|
|
488
|
+
- **Headers:** `Authorization: Bearer {valid_token}`, `Content-Type: application/json`
|
|
489
|
+
- **Expected status:** 200
|
|
490
|
+
- **Expected response:** `{orderId: "ord_001", status: "confirmed", updatedAt: string (ISO date)}`
|
|
491
|
+
- **Priority:** P0
|
|
492
|
+
|
|
493
|
+
##### API-PAY-001: Charge Payment for Order
|
|
494
|
+
- **Method + Endpoint:** `POST /api/v1/payments/charge`
|
|
495
|
+
- **Request body:** `{"orderId": "ord_001", "paymentMethodId": "pm_test_visa"}`
|
|
496
|
+
- **Headers:** `Authorization: Bearer {valid_token}`, `Content-Type: application/json`
|
|
497
|
+
- **Expected status:** 200
|
|
498
|
+
- **Expected response:** `{paymentId: string, status: "succeeded", amount: number (matches order total)}`
|
|
499
|
+
- **Priority:** P0
|
|
500
|
+
|
|
501
|
+
##### API-PROD-001: List Products with Pagination
|
|
502
|
+
- **Method + Endpoint:** `GET /api/v1/products?page=1&limit=10`
|
|
503
|
+
- **Request body:** N/A
|
|
504
|
+
- **Headers:** None (public endpoint)
|
|
505
|
+
- **Expected status:** 200
|
|
506
|
+
- **Expected response:** `{products: [{id: string, name: string, price: number, sku: string, category: string}], total: number, page: 1}`
|
|
507
|
+
- **Priority:** P1
|
|
508
|
+
|
|
509
|
+
---
|
|
510
|
+
|
|
511
|
+
### E2E Smoke Tests (2 tests -- 4%)
|
|
512
|
+
|
|
513
|
+
##### E2E-FLOW-001: Complete Purchase Flow
|
|
514
|
+
- **User journey:**
|
|
515
|
+
1. User navigates to homepage (`/`)
|
|
516
|
+
2. User clicks a product card to view product detail (`/products/:id`)
|
|
517
|
+
3. User clicks "Add to Cart" button
|
|
518
|
+
4. User navigates to cart page (`/cart`)
|
|
519
|
+
5. User verifies item in cart with correct price and quantity
|
|
520
|
+
6. User clicks "Checkout" button
|
|
521
|
+
7. User fills checkout form (shipping address + payment card)
|
|
522
|
+
8. User clicks "Place Order" button
|
|
523
|
+
9. User sees order confirmation with order ID and "pending" status
|
|
524
|
+
- **Pages involved:** HomePage, ProductDetailPage, CartPage, CheckoutForm, OrderConfirmationPage
|
|
525
|
+
- **Expected outcome:** Order confirmation page displays with a valid order ID (UUID format), status shows "pending", order total matches the product price, and the user can navigate to order history (`/orders`) to see the new order listed
|
|
526
|
+
- **Priority:** P0
|
|
527
|
+
|
|
528
|
+
##### E2E-FLOW-002: User Registration to First Order
|
|
529
|
+
- **User journey:**
|
|
530
|
+
1. User navigates to registration page (`/register`)
|
|
531
|
+
2. User fills registration form (name: "E2E Test User", email: "e2e-test@shopflow.com", password: "SecureP@ss123!")
|
|
532
|
+
3. User clicks "Create Account" button
|
|
533
|
+
4. User is redirected to homepage, logged in (sees user name in navbar)
|
|
534
|
+
5. User adds a product to cart
|
|
535
|
+
6. User completes checkout flow
|
|
536
|
+
7. User navigates to order history (`/orders`)
|
|
537
|
+
8. User sees the new order with correct status
|
|
538
|
+
- **Pages involved:** RegisterPage, HomePage, ProductDetailPage, CartPage, CheckoutForm, OrderConfirmationPage, OrderHistoryPage
|
|
539
|
+
- **Expected outcome:** Order history page shows exactly 1 order with status "pending", the navbar displays "E2E Test User", and the user can log out and log back in successfully
|
|
540
|
+
- **Priority:** P0
|
|
541
|
+
|
|
542
|
+
---
|
|
543
|
+
|
|
544
|
+
## Guidelines
|
|
545
|
+
|
|
546
|
+
### DO
|
|
547
|
+
|
|
548
|
+
- **DO** use concrete values in every input and expected outcome field -- `239.47`, not "the correct total"
|
|
549
|
+
- **DO** include both happy-path and error cases for each module (at minimum 1 success + 1 failure per function)
|
|
550
|
+
- **DO** specify exact error types and messages in expected outcomes -- `Throws InvalidTransitionError` is better than `Throws an error`
|
|
551
|
+
- **DO** fill in the Mocks field for every test case -- "None (pure function)" is a valid and useful answer
|
|
552
|
+
- **DO** group unit tests by module with clear section headers
|
|
553
|
+
- **DO** ensure test IDs are unique across the entire inventory -- no duplicate `UT-PRICE-001` in different sections
|
|
554
|
+
- **DO** match test targets to the Top 10 Unit Test Targets from `QA_ANALYSIS.md`
|
|
555
|
+
- **DO** include the exact JSON payload for API test request bodies
|
|
556
|
+
|
|
557
|
+
### DON'T
|
|
558
|
+
|
|
559
|
+
- **DON'T** write "returns correct data" as an expected outcome -- specify the exact data
|
|
560
|
+
- **DON'T** write "handles error properly" -- specify what "properly" means (status code, error message, state change)
|
|
561
|
+
- **DON'T** skip the Mocks field -- downstream agents need to know what to mock
|
|
562
|
+
- **DON'T** use "valid data" or "correct input" as concrete inputs -- use actual values
|
|
563
|
+
- **DON'T** assign P2 to payment or authentication tests -- those are always P0
|
|
564
|
+
- **DON'T** include more than 8 E2E tests -- if you need more, some should be API or integration tests instead
|
|
565
|
+
- **DON'T** create test IDs that don't follow the naming convention (UT-MODULE-NNN, INT-MODULE-NNN, API-RESOURCE-NNN, E2E-FLOW-NNN)
|
|
566
|
+
|
|
567
|
+
---
|
|
568
|
+
|
|
569
|
+
## Quality Gate
|
|
570
|
+
|
|
571
|
+
Before delivering this artifact, verify all of the following:
|
|
572
|
+
|
|
573
|
+
- [ ] Every test case has a unique ID following the naming convention
|
|
574
|
+
- [ ] Every test case has an explicit expected outcome with a concrete value (not "works correctly")
|
|
575
|
+
- [ ] Every unit test has all 7 mandatory fields filled (ID, target, what to validate, inputs, mocks, outcome, priority)
|
|
576
|
+
- [ ] Every API test includes exact HTTP method, endpoint, request body, and expected status code
|
|
577
|
+
- [ ] Summary counts match the actual number of test cases in each section
|
|
578
|
+
- [ ] Summary percentages approximately match the testing pyramid (60-70% unit, 10-15% integration, 20-25% API, 3-5% E2E)
|
|
579
|
+
- [ ] Priority is assigned to every test case (P0, P1, or P2)
|
|
580
|
+
- [ ] No expected outcome contains vague words: "correct", "proper", "appropriate", "valid", or "works" without defining what those mean
|
|
581
|
+
- [ ] Test targets reference file paths and function names from `QA_ANALYSIS.md`
|
|
582
|
+
- [ ] Both happy-path and error cases are included for critical modules (auth, payments, orders)
|