digiqagent 1.2.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 (33) hide show
  1. package/.cursor-plugin/plugin.json +29 -0
  2. package/README.md +197 -0
  3. package/agents/code-reviewer.md +48 -0
  4. package/bin/cli.js +210 -0
  5. package/package.json +41 -0
  6. package/skills/playwright-test-generator/SKILL.md +563 -0
  7. package/skills/playwright-test-generator/interaction-test-patterns.md +987 -0
  8. package/skills/playwright-test-generator/page-object-patterns.md +833 -0
  9. package/skills/postman-collection-generator/SKILL.md +310 -0
  10. package/skills/postman-collection-generator/collection-patterns.md +493 -0
  11. package/skills/postman-test-suite-generator/SKILL.md +653 -0
  12. package/skills/postman-test-suite-generator/test-scenario-patterns.md +612 -0
  13. package/skills/receiving-code-review/SKILL.md +213 -0
  14. package/skills/requesting-code-review/SKILL.md +105 -0
  15. package/skills/requesting-code-review/code-reviewer.md +146 -0
  16. package/skills/review-prompts/code-quality-reviewer-prompt.md +26 -0
  17. package/skills/review-prompts/spec-reviewer-prompt.md +61 -0
  18. package/skills/swagger-generator/SKILL.md +238 -0
  19. package/skills/swagger-generator/openapi-patterns.md +667 -0
  20. package/skills/systematic-debugging/CREATION-LOG.md +119 -0
  21. package/skills/systematic-debugging/SKILL.md +296 -0
  22. package/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
  23. package/skills/systematic-debugging/condition-based-waiting.md +115 -0
  24. package/skills/systematic-debugging/defense-in-depth.md +122 -0
  25. package/skills/systematic-debugging/find-polluter.sh +63 -0
  26. package/skills/systematic-debugging/root-cause-tracing.md +169 -0
  27. package/skills/systematic-debugging/test-academic.md +14 -0
  28. package/skills/systematic-debugging/test-pressure-1.md +58 -0
  29. package/skills/systematic-debugging/test-pressure-2.md +68 -0
  30. package/skills/systematic-debugging/test-pressure-3.md +69 -0
  31. package/skills/test-driven-development/SKILL.md +371 -0
  32. package/skills/test-driven-development/testing-anti-patterns.md +299 -0
  33. package/skills/verification-before-completion/SKILL.md +139 -0
@@ -0,0 +1,653 @@
1
+ ---
2
+ name: postman-test-suite-generator
3
+ description: Use when generating Postman collection test scripts with positive and negative test scenarios that developers can run manually to verify API behavior
4
+ ---
5
+
6
+ # Postman Test Suite Generator
7
+
8
+ ## Overview
9
+
10
+ Produce a Postman collection with comprehensive test scripts covering both positive (happy path) and negative (error/edge case) scenarios for every endpoint. Developers import and run it in Postman to verify API behavior with zero test-writing effort.
11
+
12
+ **Core principle:** Every endpoint gets tested for what should work AND what should fail. If you can't prove the API rejects bad input, you don't know if it validates anything.
13
+
14
+ ## When to Use
15
+
16
+ - API needs test coverage that developers can run manually
17
+ - After generating a Postman collection with `digiqagent:postman-collection-generator`
18
+ - QA handoff — provide runnable test scenarios
19
+ - Pre-release verification — structured test pass before deployment
20
+ - Onboarding — new developers see expected API behavior through tests
21
+
22
+ ## Input Detection
23
+
24
+ ### Preferred — Existing Postman Collection
25
+
26
+ Look for `postman_collection.json` in the project. Build test scripts on top of existing requests.
27
+
28
+ If no collection exists, recommend running `digiqagent:postman-collection-generator` first.
29
+
30
+ ### Alternative — OpenAPI Spec
31
+
32
+ Parse `openapi.yaml` / `swagger.yaml` directly to build both requests and tests in one pass.
33
+
34
+ ### Alternative — Codebase Scan
35
+
36
+ If neither exists, scan the codebase for endpoints, validation rules, and auth requirements. Generate a complete test collection from code analysis.
37
+
38
+ ## Generation Process
39
+
40
+ ### Step 1 — Analyze Endpoints
41
+
42
+ For each endpoint, identify:
43
+ - **Expected success behavior** — status code, response shape, side effects
44
+ - **Required fields** — which fields trigger 400 if missing
45
+ - **Field validations** — types, formats, min/max, patterns, enums
46
+ - **Auth requirements** — which roles/permissions are needed
47
+ - **Business rules** — uniqueness constraints, state transitions, dependencies
48
+ - **Edge cases** — empty collections, boundary values, concurrent access
49
+
50
+ Build a **scenario matrix** per endpoint:
51
+
52
+ | Endpoint | Positive Scenarios | Negative Scenarios |
53
+ |----------|-------------------|-------------------|
54
+ | POST /users | Valid creation, minimal fields, all fields | Missing email, invalid email, duplicate email, short password, missing name, invalid role |
55
+ | GET /users/:id | Valid ID returns user | Non-existent ID, invalid ID format, unauthorized |
56
+ | PUT /users/:id | Valid update, partial update | Non-existent ID, invalid fields, unauthorized, forbidden |
57
+ | DELETE /users/:id | Valid deletion | Non-existent ID, unauthorized, already deleted |
58
+
59
+ ### Step 2 — Generate Positive Test Scenarios
60
+
61
+ For each endpoint, create happy-path tests that verify:
62
+
63
+ **Status code:**
64
+ ```javascript
65
+ pm.test("Status code is 201", function () {
66
+ pm.response.to.have.status(201);
67
+ });
68
+ ```
69
+
70
+ **Response time:**
71
+ ```javascript
72
+ pm.test("Response time is under 2000ms", function () {
73
+ pm.expect(pm.response.responseTime).to.be.below(2000);
74
+ });
75
+ ```
76
+
77
+ **Response body structure:**
78
+ ```javascript
79
+ pm.test("Response has correct structure", function () {
80
+ const response = pm.response.json();
81
+ pm.expect(response).to.have.property("id");
82
+ pm.expect(response).to.have.property("name");
83
+ pm.expect(response).to.have.property("email");
84
+ pm.expect(response).to.have.property("createdAt");
85
+ });
86
+ ```
87
+
88
+ **Response data types:**
89
+ ```javascript
90
+ pm.test("Response fields have correct types", function () {
91
+ const response = pm.response.json();
92
+ pm.expect(response.id).to.be.a("string");
93
+ pm.expect(response.name).to.be.a("string");
94
+ pm.expect(response.email).to.be.a("string");
95
+ pm.expect(response.active).to.be.a("boolean");
96
+ });
97
+ ```
98
+
99
+ **Response content matches request:**
100
+ ```javascript
101
+ pm.test("Created user matches request data", function () {
102
+ const request = JSON.parse(pm.request.body.raw);
103
+ const response = pm.response.json();
104
+ pm.expect(response.name).to.eql(request.name);
105
+ pm.expect(response.email).to.eql(request.email);
106
+ });
107
+ ```
108
+
109
+ **Headers:**
110
+ ```javascript
111
+ pm.test("Content-Type is application/json", function () {
112
+ pm.response.to.have.header("Content-Type");
113
+ pm.expect(pm.response.headers.get("Content-Type")).to.include("application/json");
114
+ });
115
+ ```
116
+
117
+ **Pagination (for list endpoints):**
118
+ ```javascript
119
+ pm.test("Response has pagination metadata", function () {
120
+ const response = pm.response.json();
121
+ pm.expect(response).to.have.property("meta");
122
+ pm.expect(response.meta).to.have.property("page");
123
+ pm.expect(response.meta).to.have.property("limit");
124
+ pm.expect(response.meta).to.have.property("totalItems");
125
+ pm.expect(response.meta).to.have.property("totalPages");
126
+ pm.expect(response.meta.page).to.be.a("number");
127
+ pm.expect(response.data).to.be.an("array");
128
+ });
129
+ ```
130
+
131
+ **Variable capture for chaining:**
132
+ ```javascript
133
+ if (pm.response.code === 201) {
134
+ const response = pm.response.json();
135
+ pm.environment.set("createdUserId", response.id);
136
+ }
137
+ ```
138
+
139
+ ### Step 3 — Generate Negative Test Scenarios
140
+
141
+ For each endpoint, **systematically** cover these categories:
142
+
143
+ #### 3a. Missing Required Fields (one at a time)
144
+
145
+ For a POST /users endpoint with required fields `name`, `email`, `password`:
146
+
147
+ **Missing name:**
148
+ ```json
149
+ {
150
+ "name": "Negative - Create User - Missing Name",
151
+ "request": {
152
+ "method": "POST",
153
+ "body": {
154
+ "mode": "raw",
155
+ "raw": "{\n \"email\": \"jane@example.com\",\n \"password\": \"SecureP@ss123\"\n}"
156
+ }
157
+ },
158
+ "event": [{
159
+ "listen": "test",
160
+ "script": {
161
+ "exec": [
162
+ "pm.test('Returns 400 for missing name', function () {",
163
+ " pm.response.to.have.status(400);",
164
+ "});",
165
+ "pm.test('Error message mentions name field', function () {",
166
+ " const response = pm.response.json();",
167
+ " const message = Array.isArray(response.message) ? response.message.join(' ') : response.message;",
168
+ " pm.expect(message.toLowerCase()).to.include('name');",
169
+ "});"
170
+ ]
171
+ }
172
+ }]
173
+ }
174
+ ```
175
+
176
+ **Repeat for each required field:** Remove one field at a time, verify 400 response and field-specific error message.
177
+
178
+ #### 3b. Invalid Data Types
179
+
180
+ ```javascript
181
+ // String where number expected
182
+ pm.test("Returns 400 for string price", function () {
183
+ pm.response.to.have.status(400);
184
+ });
185
+ // Body: { "price": "not-a-number" }
186
+
187
+ // Number where string expected
188
+ // Body: { "name": 12345 }
189
+
190
+ // Boolean where string expected
191
+ // Body: { "email": true }
192
+
193
+ // Array where object expected
194
+ // Body: []
195
+ ```
196
+
197
+ #### 3c. Boundary Values
198
+
199
+ ```javascript
200
+ // Empty string
201
+ pm.test("Returns 400 for empty name", function () {
202
+ pm.response.to.have.status(400);
203
+ });
204
+ // Body: { "name": "", "email": "jane@example.com", "password": "SecureP@ss123" }
205
+
206
+ // Exceeds max length (if maxLength: 100)
207
+ // Body: { "name": "A".repeat(101) }
208
+
209
+ // Below minimum (if minimum: 0)
210
+ // Body: { "price": -1 }
211
+
212
+ // Zero value
213
+ // Body: { "quantity": 0 }
214
+
215
+ // Whitespace only
216
+ // Body: { "name": " " }
217
+ ```
218
+
219
+ #### 3d. Unauthorized Access
220
+
221
+ **No token:**
222
+ ```json
223
+ {
224
+ "name": "Negative - Get Users - No Auth Token",
225
+ "request": {
226
+ "method": "GET",
227
+ "header": [],
228
+ "url": { "raw": "{{baseUrl}}/api/users" }
229
+ },
230
+ "event": [{
231
+ "listen": "test",
232
+ "script": {
233
+ "exec": [
234
+ "pm.test('Returns 401 without auth token', function () {",
235
+ " pm.response.to.have.status(401);",
236
+ "});",
237
+ "pm.test('Error indicates authentication required', function () {",
238
+ " const response = pm.response.json();",
239
+ " pm.expect(response.error || response.message).to.be.a('string');",
240
+ "});"
241
+ ]
242
+ }
243
+ }]
244
+ }
245
+ ```
246
+
247
+ **Invalid token:**
248
+ ```json
249
+ {
250
+ "name": "Negative - Get Users - Invalid Token",
251
+ "request": {
252
+ "method": "GET",
253
+ "header": [
254
+ { "key": "Authorization", "value": "Bearer invalid.token.value" }
255
+ ]
256
+ }
257
+ }
258
+ ```
259
+
260
+ **Expired token (simulated):**
261
+ ```json
262
+ {
263
+ "name": "Negative - Get Users - Expired Token",
264
+ "request": {
265
+ "method": "GET",
266
+ "header": [
267
+ { "key": "Authorization", "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiZXhwIjoxMDAwMDAwMDAwfQ.invalid" }
268
+ ]
269
+ }
270
+ }
271
+ ```
272
+
273
+ **Wrong role/insufficient permissions:**
274
+ ```json
275
+ {
276
+ "name": "Negative - Delete User - Insufficient Permissions",
277
+ "request": {
278
+ "method": "DELETE",
279
+ "header": [
280
+ { "key": "Authorization", "value": "Bearer {{regularUserToken}}" }
281
+ ]
282
+ },
283
+ "event": [{
284
+ "listen": "test",
285
+ "script": {
286
+ "exec": [
287
+ "pm.test('Returns 403 for insufficient permissions', function () {",
288
+ " pm.response.to.have.status(403);",
289
+ "});"
290
+ ]
291
+ }
292
+ }]
293
+ }
294
+ ```
295
+
296
+ #### 3e. Not Found
297
+
298
+ ```json
299
+ {
300
+ "name": "Negative - Get User - Non-Existent ID",
301
+ "request": {
302
+ "method": "GET",
303
+ "url": { "raw": "{{baseUrl}}/api/users/00000000-0000-0000-0000-000000000000" }
304
+ },
305
+ "event": [{
306
+ "listen": "test",
307
+ "script": {
308
+ "exec": [
309
+ "pm.test('Returns 404 for non-existent user', function () {",
310
+ " pm.response.to.have.status(404);",
311
+ "});",
312
+ "pm.test('Error message indicates resource not found', function () {",
313
+ " const response = pm.response.json();",
314
+ " const msg = (response.message || response.error || '').toLowerCase();",
315
+ " pm.expect(msg).to.include('not found');",
316
+ "});"
317
+ ]
318
+ }
319
+ }]
320
+ }
321
+ ```
322
+
323
+ **Invalid ID format:**
324
+ ```json
325
+ {
326
+ "name": "Negative - Get User - Invalid ID Format",
327
+ "request": {
328
+ "method": "GET",
329
+ "url": { "raw": "{{baseUrl}}/api/users/not-a-valid-id!" }
330
+ },
331
+ "event": [{
332
+ "listen": "test",
333
+ "script": {
334
+ "exec": [
335
+ "pm.test('Returns 400 or 404 for invalid ID format', function () {",
336
+ " pm.expect(pm.response.code).to.be.oneOf([400, 404]);",
337
+ "});"
338
+ ]
339
+ }
340
+ }]
341
+ }
342
+ ```
343
+
344
+ #### 3f. Duplicate / Conflict
345
+
346
+ ```json
347
+ {
348
+ "name": "Negative - Create User - Duplicate Email",
349
+ "event": [
350
+ {
351
+ "listen": "prerequest",
352
+ "script": {
353
+ "exec": [
354
+ "// Uses the same email as the previously created user"
355
+ ]
356
+ }
357
+ },
358
+ {
359
+ "listen": "test",
360
+ "script": {
361
+ "exec": [
362
+ "pm.test('Returns 409 for duplicate email', function () {",
363
+ " pm.response.to.have.status(409);",
364
+ "});",
365
+ "pm.test('Error indicates duplicate resource', function () {",
366
+ " const response = pm.response.json();",
367
+ " const msg = (response.message || '').toLowerCase();",
368
+ " pm.expect(msg).to.satisfy(function(m) {",
369
+ " return m.includes('already exists') || m.includes('duplicate') || m.includes('conflict');",
370
+ " });",
371
+ "});"
372
+ ]
373
+ }
374
+ }
375
+ ],
376
+ "request": {
377
+ "method": "POST",
378
+ "body": {
379
+ "mode": "raw",
380
+ "raw": "{\n \"name\": \"Another User\",\n \"email\": \"jane.smith@example.com\",\n \"password\": \"SecureP@ss123\"\n}"
381
+ }
382
+ }
383
+ }
384
+ ```
385
+
386
+ #### 3g. Invalid Content Type
387
+
388
+ ```json
389
+ {
390
+ "name": "Negative - Create User - Wrong Content-Type",
391
+ "request": {
392
+ "method": "POST",
393
+ "header": [
394
+ { "key": "Content-Type", "value": "text/plain" },
395
+ { "key": "Authorization", "value": "Bearer {{authToken}}" }
396
+ ],
397
+ "body": {
398
+ "mode": "raw",
399
+ "raw": "this is not json"
400
+ }
401
+ },
402
+ "event": [{
403
+ "listen": "test",
404
+ "script": {
405
+ "exec": [
406
+ "pm.test('Returns 400 or 415 for wrong content type', function () {",
407
+ " pm.expect(pm.response.code).to.be.oneOf([400, 415]);",
408
+ "});"
409
+ ]
410
+ }
411
+ }]
412
+ }
413
+ ```
414
+
415
+ #### 3h. Malformed Request Body
416
+
417
+ ```json
418
+ {
419
+ "name": "Negative - Create User - Malformed JSON",
420
+ "request": {
421
+ "method": "POST",
422
+ "header": [
423
+ { "key": "Content-Type", "value": "application/json" },
424
+ { "key": "Authorization", "value": "Bearer {{authToken}}" }
425
+ ],
426
+ "body": {
427
+ "mode": "raw",
428
+ "raw": "{invalid json content"
429
+ }
430
+ },
431
+ "event": [{
432
+ "listen": "test",
433
+ "script": {
434
+ "exec": [
435
+ "pm.test('Returns 400 for malformed JSON', function () {",
436
+ " pm.response.to.have.status(400);",
437
+ "});"
438
+ ]
439
+ }
440
+ }]
441
+ }
442
+ ```
443
+
444
+ ### Step 4 — Write Test Scripts
445
+
446
+ Embed `pm.test()` blocks in the `event` array of each request item:
447
+
448
+ ```json
449
+ {
450
+ "event": [
451
+ {
452
+ "listen": "test",
453
+ "script": {
454
+ "type": "text/javascript",
455
+ "exec": [
456
+ "// line 1",
457
+ "// line 2"
458
+ ]
459
+ }
460
+ }
461
+ ]
462
+ }
463
+ ```
464
+
465
+ Each `exec` array entry is a line of JavaScript. Keep lines short and readable.
466
+
467
+ ### Step 5 — Organize into Folders
468
+
469
+ Structure the collection with clear separation:
470
+
471
+ ```
472
+ Test Suite Root
473
+ ├── Setup
474
+ │ ├── Register Test User
475
+ │ └── Login (capture token)
476
+ ├── Users
477
+ │ ├── Positive Tests
478
+ │ │ ├── Create User - Valid Data
479
+ │ │ ├── List Users - Default Pagination
480
+ │ │ ├── List Users - Custom Page Size
481
+ │ │ ├── Get User by ID
482
+ │ │ ├── Update User - Full Update
483
+ │ │ ├── Update User - Partial Update
484
+ │ │ └── Delete User
485
+ │ └── Negative Tests
486
+ │ ├── Create User - Missing Name
487
+ │ ├── Create User - Missing Email
488
+ │ ├── Create User - Invalid Email Format
489
+ │ ├── Create User - Short Password
490
+ │ ├── Create User - Duplicate Email
491
+ │ ├── Get User - Non-Existent ID
492
+ │ ├── Get User - Invalid ID Format
493
+ │ ├── Update User - Not Found
494
+ │ ├── Delete User - Not Found
495
+ │ ├── Delete User - Insufficient Permissions
496
+ │ ├── Access Without Auth Token
497
+ │ ├── Access With Invalid Token
498
+ │ ├── Create User - Malformed JSON
499
+ │ └── Create User - Wrong Content-Type
500
+ ├── Products
501
+ │ ├── Positive Tests
502
+ │ │ └── ...
503
+ │ └── Negative Tests
504
+ │ └── ...
505
+ └── Teardown
506
+ └── Delete Test User
507
+ ```
508
+
509
+ ### Step 6 — Add Data-Driven Tests
510
+
511
+ For endpoints with many validation scenarios, suggest data file usage:
512
+
513
+ **CSV data file format (`test_data_users.csv`):**
514
+ ```csv
515
+ name,email,password,expectedStatus,testDescription
516
+ ,jane@example.com,SecureP@ss123,400,Missing name
517
+ Jane Smith,,SecureP@ss123,400,Missing email
518
+ Jane Smith,not-an-email,SecureP@ss123,400,Invalid email format
519
+ Jane Smith,jane@example.com,short,400,Password too short
520
+ Jane Smith,jane@example.com,SecureP@ss123,201,Valid data
521
+ ```
522
+
523
+ **Data-driven test script:**
524
+ ```javascript
525
+ pm.test(pm.iterationData.get("testDescription"), function () {
526
+ pm.response.to.have.status(parseInt(pm.iterationData.get("expectedStatus")));
527
+ });
528
+ ```
529
+
530
+ Include a note in the collection description explaining how to use data files with Postman Runner.
531
+
532
+ ### Step 7 — Write File
533
+
534
+ Output as: `postman_test_collection.json` at project root (or user-specified path).
535
+
536
+ The file follows the same Postman Collection v2.1 schema as the base collection, with test scripts embedded in each request's `event` array.
537
+
538
+ ### Step 8 — Verify
539
+
540
+ Before claiming the test suite is complete:
541
+
542
+ 1. **Coverage check** — every endpoint has at least one positive and multiple negative scenarios
543
+ 2. **JSON validity** — file parses without errors
544
+ 3. **Script syntax** — all `pm.test()` blocks are syntactically correct JavaScript
545
+ 4. **Variable consistency** — all `{{variables}}` used in tests are defined or captured by prior requests
546
+ 5. **Ordering** — setup (auth) runs before tests that need tokens; create runs before get-by-id
547
+ 6. Apply `digiqagent:verification-before-completion` — evidence before claims
548
+
549
+ ## Negative Scenario Matrix
550
+
551
+ Use this matrix to ensure systematic coverage. Every cell should have at least one test:
552
+
553
+ | Scenario Category | POST (Create) | GET (Read) | PUT (Update) | DELETE |
554
+ |-------------------|--------------|------------|-------------|--------|
555
+ | Missing required fields | One test per field | N/A | One test per field | N/A |
556
+ | Invalid data types | Per typed field | N/A | Per typed field | N/A |
557
+ | Empty/blank values | Per string field | N/A | Per string field | N/A |
558
+ | Boundary values | Per constrained field | N/A | Per constrained field | N/A |
559
+ | Invalid format | Email, date, UUID | Invalid ID format | Email, date, UUID | Invalid ID format |
560
+ | No auth token | Yes | Yes | Yes | Yes |
561
+ | Invalid auth token | Yes | Yes | Yes | Yes |
562
+ | Insufficient permissions | If role-based | If role-based | If role-based | If role-based |
563
+ | Resource not found | N/A | Yes | Yes | Yes |
564
+ | Duplicate/conflict | If unique constraints | N/A | If unique constraints | N/A |
565
+ | Wrong content type | Yes | N/A | Yes | N/A |
566
+ | Malformed body | Yes | N/A | Yes | N/A |
567
+
568
+ ## Test Assertion Quick Reference
569
+
570
+ | What to Assert | pm.test Code |
571
+ |---------------|-------------|
572
+ | Status code | `pm.response.to.have.status(200)` |
573
+ | Status code one of | `pm.expect(pm.response.code).to.be.oneOf([200, 201])` |
574
+ | Response time | `pm.expect(pm.response.responseTime).to.be.below(2000)` |
575
+ | Has property | `pm.expect(json).to.have.property("id")` |
576
+ | Property type | `pm.expect(json.id).to.be.a("string")` |
577
+ | Property value | `pm.expect(json.status).to.eql("active")` |
578
+ | Array length | `pm.expect(json.data).to.have.lengthOf.at.least(1)` |
579
+ | Array type | `pm.expect(json.data).to.be.an("array")` |
580
+ | String contains | `pm.expect(json.message).to.include("not found")` |
581
+ | Header exists | `pm.response.to.have.header("Content-Type")` |
582
+ | Header value | `pm.expect(pm.response.headers.get("Content-Type")).to.include("json")` |
583
+ | Not empty | `pm.expect(json.id).to.not.be.empty` |
584
+ | Null check | `pm.expect(json.deletedAt).to.be.null` |
585
+ | Nested property | `pm.expect(json.user.profile.name).to.eql("Jane")` |
586
+ | JSON Schema | `pm.response.to.have.jsonSchema(schema)` |
587
+ | Set variable | `pm.environment.set("key", json.value)` |
588
+ | Get variable | `pm.environment.get("key")` |
589
+
590
+ ## Red Flags — STOP and Fix
591
+
592
+ | Problem | Fix |
593
+ |---------|-----|
594
+ | Endpoint has only positive tests | Add negative scenarios from the matrix |
595
+ | Negative test doesn't check error message | Add assertion on error body content |
596
+ | Tests depend on hardcoded IDs | Use environment variables from setup requests |
597
+ | No setup folder for auth | Add login request at the start |
598
+ | Test scripts have syntax errors | Validate JavaScript before writing file |
599
+ | Missing coverage for auth scenarios | Add no-token, invalid-token, wrong-role tests |
600
+ | All negative tests in one request | Separate: one scenario per request for clear reporting |
601
+ | Test names are generic | Use descriptive names: "Returns 400 when email is missing" |
602
+
603
+ ## Verification Checklist
604
+
605
+ Before marking generation complete:
606
+
607
+ - [ ] Every endpoint has at least one positive test scenario
608
+ - [ ] Every mutating endpoint (POST/PUT/PATCH) has missing-field tests
609
+ - [ ] Every authenticated endpoint has no-auth and invalid-auth tests
610
+ - [ ] Every endpoint with path params has not-found and invalid-ID tests
611
+ - [ ] Tests organized into Positive/Negative folders per resource
612
+ - [ ] Setup folder with auth requests runs first
613
+ - [ ] All `pm.test()` scripts are syntactically valid JavaScript
614
+ - [ ] Environment variables are captured before they're used
615
+ - [ ] Collection JSON is valid and imports into Postman
616
+ - [ ] File written and path confirmed to user
617
+
618
+ Can't check all boxes? Fix the test suite. Incomplete negative coverage means unknown API behavior.
619
+
620
+ ## Common Patterns
621
+
622
+ See @test-scenario-patterns.md for:
623
+ - Complete CRUD test suite example
624
+ - Auth test patterns
625
+ - Schema validation patterns
626
+ - Chained test patterns
627
+ - Idempotency and rate limiting tests
628
+
629
+ ## Developer Usage
630
+
631
+ Include in the collection description:
632
+
633
+ ```
634
+ ## Running the Test Suite
635
+
636
+ 1. Import `postman_test_collection.json` into Postman
637
+ 2. Import `postman_environment.json` (from collection generator)
638
+ 3. Select the environment in the top-right dropdown
639
+ 4. Ensure your API server is running at the configured baseUrl
640
+ 5. Run the "Setup" folder first to populate auth tokens
641
+ 6. Run individual folders or the entire collection via Postman Runner
642
+
643
+ ## Understanding Results
644
+ - Green: Test passed — API behaves as expected
645
+ - Red: Test failed — investigate the endpoint
646
+ - Positive test failures: API is broken
647
+ - Negative test failures: API may be missing validation
648
+
649
+ ## Using Data-Driven Tests
650
+ 1. Open Postman Runner
651
+ 2. Select a data file (CSV/JSON) for parameterized scenarios
652
+ 3. Run — each row becomes a separate test iteration
653
+ ```