start-vibing 2.0.11 → 2.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +177 -177
- package/dist/cli.js +19 -2
- package/package.json +42 -42
- package/template/.claude/CLAUDE.md +174 -174
- package/template/.claude/agents/01-orchestration/agent-selector.md +130 -130
- package/template/.claude/agents/01-orchestration/checkpoint-manager.md +142 -142
- package/template/.claude/agents/01-orchestration/context-manager.md +138 -138
- package/template/.claude/agents/01-orchestration/error-recovery.md +182 -182
- package/template/.claude/agents/01-orchestration/orchestrator.md +114 -114
- package/template/.claude/agents/01-orchestration/parallel-coordinator.md +141 -141
- package/template/.claude/agents/01-orchestration/task-decomposer.md +121 -121
- package/template/.claude/agents/01-orchestration/workflow-router.md +114 -114
- package/template/.claude/agents/02-typescript/bun-runtime-expert.md +197 -197
- package/template/.claude/agents/02-typescript/esm-resolver.md +193 -193
- package/template/.claude/agents/02-typescript/import-alias-enforcer.md +158 -158
- package/template/.claude/agents/02-typescript/ts-generics-helper.md +183 -183
- package/template/.claude/agents/02-typescript/ts-migration-helper.md +238 -238
- package/template/.claude/agents/02-typescript/ts-strict-checker.md +180 -180
- package/template/.claude/agents/02-typescript/ts-types-analyzer.md +199 -199
- package/template/.claude/agents/02-typescript/type-definition-writer.md +187 -187
- package/template/.claude/agents/02-typescript/zod-schema-designer.md +212 -212
- package/template/.claude/agents/02-typescript/zod-validator.md +158 -158
- package/template/.claude/agents/03-testing/playwright-assertions.md +265 -265
- package/template/.claude/agents/03-testing/playwright-e2e.md +247 -247
- package/template/.claude/agents/03-testing/playwright-fixtures.md +234 -234
- package/template/.claude/agents/03-testing/playwright-multi-viewport.md +256 -256
- package/template/.claude/agents/03-testing/playwright-page-objects.md +247 -247
- package/template/.claude/agents/03-testing/test-cleanup-manager.md +248 -248
- package/template/.claude/agents/03-testing/test-data-generator.md +254 -254
- package/template/.claude/agents/03-testing/tester-integration.md +278 -278
- package/template/.claude/agents/03-testing/tester-unit.md +207 -207
- package/template/.claude/agents/03-testing/vitest-config.md +287 -287
- package/template/.claude/agents/04-docker/container-health.md +255 -255
- package/template/.claude/agents/04-docker/deployment-validator.md +225 -225
- package/template/.claude/agents/04-docker/docker-compose-designer.md +281 -281
- package/template/.claude/agents/04-docker/docker-env-manager.md +235 -235
- package/template/.claude/agents/04-docker/docker-multi-stage.md +241 -241
- package/template/.claude/agents/04-docker/dockerfile-optimizer.md +208 -208
- package/template/.claude/agents/05-database/database-seeder.md +273 -273
- package/template/.claude/agents/05-database/mongodb-query-optimizer.md +230 -230
- package/template/.claude/agents/05-database/mongoose-aggregation.md +306 -306
- package/template/.claude/agents/05-database/mongoose-index-optimizer.md +182 -182
- package/template/.claude/agents/05-database/mongoose-schema-designer.md +267 -267
- package/template/.claude/agents/06-security/auth-session-validator.md +68 -68
- package/template/.claude/agents/06-security/input-sanitizer.md +80 -80
- package/template/.claude/agents/06-security/owasp-checker.md +97 -97
- package/template/.claude/agents/06-security/permission-auditor.md +100 -100
- package/template/.claude/agents/06-security/security-auditor.md +84 -84
- package/template/.claude/agents/06-security/sensitive-data-scanner.md +83 -83
- package/template/.claude/agents/07-documentation/api-documenter.md +136 -136
- package/template/.claude/agents/07-documentation/changelog-manager.md +105 -105
- package/template/.claude/agents/07-documentation/documenter.md +76 -76
- package/template/.claude/agents/07-documentation/domain-updater.md +81 -81
- package/template/.claude/agents/07-documentation/jsdoc-generator.md +114 -114
- package/template/.claude/agents/07-documentation/readme-generator.md +135 -135
- package/template/.claude/agents/08-git/branch-manager.md +58 -58
- package/template/.claude/agents/08-git/commit-manager.md +63 -63
- package/template/.claude/agents/08-git/pr-creator.md +76 -76
- package/template/.claude/agents/09-quality/code-reviewer.md +71 -71
- package/template/.claude/agents/09-quality/quality-checker.md +67 -67
- package/template/.claude/agents/10-research/best-practices-finder.md +89 -89
- package/template/.claude/agents/10-research/competitor-analyzer.md +106 -106
- package/template/.claude/agents/10-research/pattern-researcher.md +93 -93
- package/template/.claude/agents/10-research/research-cache-manager.md +76 -76
- package/template/.claude/agents/10-research/research-web.md +98 -98
- package/template/.claude/agents/10-research/tech-evaluator.md +101 -101
- package/template/.claude/agents/11-ui-ux/accessibility-auditor.md +136 -136
- package/template/.claude/agents/11-ui-ux/design-system-enforcer.md +125 -125
- package/template/.claude/agents/11-ui-ux/skeleton-generator.md +118 -118
- package/template/.claude/agents/11-ui-ux/ui-desktop.md +132 -132
- package/template/.claude/agents/11-ui-ux/ui-mobile.md +98 -98
- package/template/.claude/agents/11-ui-ux/ui-tablet.md +110 -110
- package/template/.claude/agents/12-performance/api-latency-analyzer.md +156 -156
- package/template/.claude/agents/12-performance/bundle-analyzer.md +113 -113
- package/template/.claude/agents/12-performance/memory-leak-detector.md +137 -137
- package/template/.claude/agents/12-performance/performance-profiler.md +115 -115
- package/template/.claude/agents/12-performance/query-optimizer.md +124 -124
- package/template/.claude/agents/12-performance/render-optimizer.md +154 -154
- package/template/.claude/agents/13-debugging/build-error-fixer.md +207 -207
- package/template/.claude/agents/13-debugging/debugger.md +149 -149
- package/template/.claude/agents/13-debugging/error-stack-analyzer.md +141 -141
- package/template/.claude/agents/13-debugging/network-debugger.md +208 -208
- package/template/.claude/agents/13-debugging/runtime-error-fixer.md +181 -181
- package/template/.claude/agents/13-debugging/type-error-resolver.md +185 -185
- package/template/.claude/agents/14-validation/final-validator.md +93 -93
- package/template/.claude/agents/_backup/analyzer.md +134 -134
- package/template/.claude/agents/_backup/code-reviewer.md +279 -279
- package/template/.claude/agents/_backup/commit-manager.md +219 -219
- package/template/.claude/agents/_backup/debugger.md +280 -280
- package/template/.claude/agents/_backup/documenter.md +237 -237
- package/template/.claude/agents/_backup/domain-updater.md +197 -197
- package/template/.claude/agents/_backup/final-validator.md +169 -169
- package/template/.claude/agents/_backup/orchestrator.md +149 -149
- package/template/.claude/agents/_backup/performance.md +232 -232
- package/template/.claude/agents/_backup/quality-checker.md +240 -240
- package/template/.claude/agents/_backup/research.md +315 -315
- package/template/.claude/agents/_backup/security-auditor.md +192 -192
- package/template/.claude/agents/_backup/tester.md +566 -566
- package/template/.claude/agents/_backup/ui-ux-reviewer.md +247 -247
- package/template/.claude/config/README.md +30 -30
- package/template/.claude/config/mcp-config.json +344 -344
- package/template/.claude/config/project-config.json +53 -53
- package/template/.claude/config/quality-gates.json +46 -46
- package/template/.claude/config/security-rules.json +45 -45
- package/template/.claude/config/testing-config.json +164 -164
- package/template/.claude/hooks/SETUP.md +126 -126
- package/template/.claude/hooks/run-hook.ts +176 -176
- package/template/.claude/hooks/stop-validator.ts +914 -824
- package/template/.claude/hooks/user-prompt-submit.ts +886 -886
- package/template/.claude/scripts/mcp-quick-install.ts +151 -151
- package/template/.claude/scripts/setup-mcps.ts +651 -651
- package/template/.claude/settings.json +275 -275
- package/template/.claude/skills/bun-runtime/SKILL.md +430 -430
- package/template/.claude/skills/codebase-knowledge/domains/claude-system.md +431 -431
- package/template/.claude/skills/codebase-knowledge/domains/mcp-integration.md +295 -295
- package/template/.claude/skills/debugging-patterns/SKILL.md +485 -485
- package/template/.claude/skills/docker-patterns/SKILL.md +555 -555
- package/template/.claude/skills/git-workflow/SKILL.md +454 -454
- package/template/.claude/skills/mongoose-patterns/SKILL.md +499 -499
- package/template/.claude/skills/nextjs-app-router/SKILL.md +327 -327
- package/template/.claude/skills/performance-patterns/SKILL.md +547 -547
- package/template/.claude/skills/playwright-automation/SKILL.md +438 -438
- package/template/.claude/skills/react-patterns/SKILL.md +389 -389
- package/template/.claude/skills/research-cache/SKILL.md +222 -222
- package/template/.claude/skills/shadcn-ui/SKILL.md +511 -511
- package/template/.claude/skills/tailwind-patterns/SKILL.md +465 -465
- package/template/.claude/skills/test-coverage/SKILL.md +467 -467
- package/template/.claude/skills/trpc-api/SKILL.md +434 -434
- package/template/.claude/skills/typescript-strict/SKILL.md +367 -367
- package/template/.claude/skills/zod-validation/SKILL.md +403 -403
- package/template/CLAUDE.md +117 -117
|
@@ -1,248 +1,248 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: test-cleanup-manager
|
|
3
|
-
description: 'AUTOMATICALLY invoke when tests are flaky or share state. Triggers: flaky tests, test isolation issues, database state leakage. Ensures proper cleanup between tests. PROACTIVELY manages test data lifecycle.'
|
|
4
|
-
model: haiku
|
|
5
|
-
tools: Read, Write, Edit, Bash, Grep, Glob
|
|
6
|
-
skills: test-coverage
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
# Test Cleanup Manager Agent
|
|
10
|
-
|
|
11
|
-
You ensure proper test data cleanup and isolation.
|
|
12
|
-
|
|
13
|
-
## Cleanup Strategy
|
|
14
|
-
|
|
15
|
-
### The Golden Rule
|
|
16
|
-
|
|
17
|
-
> **Every piece of test data MUST be tracked and cleaned up.**
|
|
18
|
-
|
|
19
|
-
### Cleanup Timing
|
|
20
|
-
|
|
21
|
-
| When | What | How |
|
|
22
|
-
| ---------- | ------------------ | --------------------------- |
|
|
23
|
-
| beforeEach | Reset shared state | Clear caches, mocks |
|
|
24
|
-
| afterEach | Clean created data | Delete tracked records |
|
|
25
|
-
| afterAll | Close connections | Disconnect DB, close server |
|
|
26
|
-
|
|
27
|
-
## Fixture-Based Cleanup
|
|
28
|
-
|
|
29
|
-
```typescript
|
|
30
|
-
// tests/e2e/fixtures/cleanup.fixture.ts
|
|
31
|
-
import { test as base } from '@playwright/test';
|
|
32
|
-
import { ObjectId, Db } from 'mongodb';
|
|
33
|
-
|
|
34
|
-
type CleanupFixture = {
|
|
35
|
-
createdIds: Map<string, ObjectId[]>;
|
|
36
|
-
trackCreated: (collection: string, id: ObjectId) => void;
|
|
37
|
-
cleanup: () => Promise<void>;
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
export const cleanupFixture = base.extend<CleanupFixture>({
|
|
41
|
-
createdIds: async ({}, use) => {
|
|
42
|
-
await use(new Map());
|
|
43
|
-
},
|
|
44
|
-
|
|
45
|
-
trackCreated: async ({ createdIds }, use) => {
|
|
46
|
-
await use((collection, id) => {
|
|
47
|
-
const ids = createdIds.get(collection) || [];
|
|
48
|
-
ids.push(id);
|
|
49
|
-
createdIds.set(collection, ids);
|
|
50
|
-
});
|
|
51
|
-
},
|
|
52
|
-
|
|
53
|
-
cleanup: async ({ db, createdIds }, use) => {
|
|
54
|
-
await use(async () => {
|
|
55
|
-
for (const [collection, ids] of createdIds.entries()) {
|
|
56
|
-
if (ids.length > 0) {
|
|
57
|
-
await db.collection(collection).deleteMany({
|
|
58
|
-
_id: { $in: ids },
|
|
59
|
-
});
|
|
60
|
-
console.log(`Cleaned ${ids.length} from ${collection}`);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
createdIds.clear();
|
|
64
|
-
});
|
|
65
|
-
},
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
// AUTO-CLEANUP after each test
|
|
69
|
-
cleanupFixture.afterEach(async ({ cleanup }) => {
|
|
70
|
-
await cleanup();
|
|
71
|
-
});
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
## Tracking Pattern
|
|
75
|
-
|
|
76
|
-
```typescript
|
|
77
|
-
// In test file
|
|
78
|
-
test('should create and cleanup user', async ({ page, db, trackCreated }) => {
|
|
79
|
-
// Create via UI
|
|
80
|
-
await page.goto('/register');
|
|
81
|
-
await page.getByTestId('email').fill('test@example.com');
|
|
82
|
-
await page.getByRole('button', { name: 'Register' }).click();
|
|
83
|
-
|
|
84
|
-
// Get created record
|
|
85
|
-
const user = await db.collection('users').findOne({
|
|
86
|
-
email: 'test@example.com',
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
// TRACK FOR CLEANUP - MANDATORY
|
|
90
|
-
trackCreated('users', user!._id);
|
|
91
|
-
|
|
92
|
-
// Continue test...
|
|
93
|
-
// Cleanup happens automatically in afterEach
|
|
94
|
-
});
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
## Cleanup for Related Data
|
|
98
|
-
|
|
99
|
-
```typescript
|
|
100
|
-
// When creating related records
|
|
101
|
-
test('should create order with items', async ({ page, db, trackCreated }) => {
|
|
102
|
-
// Create user
|
|
103
|
-
const user = await createTestUser(db);
|
|
104
|
-
trackCreated('users', user._id);
|
|
105
|
-
|
|
106
|
-
// Create product
|
|
107
|
-
const product = await createTestProduct(db);
|
|
108
|
-
trackCreated('products', product._id);
|
|
109
|
-
|
|
110
|
-
// Create order (references user and product)
|
|
111
|
-
const order = await createTestOrder(db, {
|
|
112
|
-
userId: user._id,
|
|
113
|
-
items: [{ productId: product._id, quantity: 1 }],
|
|
114
|
-
});
|
|
115
|
-
trackCreated('orders', order._id);
|
|
116
|
-
|
|
117
|
-
// All records will be cleaned up in reverse order
|
|
118
|
-
});
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
## Cleanup Order
|
|
122
|
-
|
|
123
|
-
Clean up in dependency order (children before parents):
|
|
124
|
-
|
|
125
|
-
```typescript
|
|
126
|
-
// Correct cleanup order
|
|
127
|
-
const cleanupOrder = [
|
|
128
|
-
'orderItems', // First: depends on orders and products
|
|
129
|
-
'orders', // Second: depends on users
|
|
130
|
-
'sessions', // Third: depends on users
|
|
131
|
-
'products', // Fourth: independent
|
|
132
|
-
'users', // Last: has dependents
|
|
133
|
-
];
|
|
134
|
-
|
|
135
|
-
async function cleanupAll(db: Db, createdIds: Map<string, ObjectId[]>) {
|
|
136
|
-
for (const collection of cleanupOrder) {
|
|
137
|
-
const ids = createdIds.get(collection);
|
|
138
|
-
if (ids && ids.length > 0) {
|
|
139
|
-
await db.collection(collection).deleteMany({
|
|
140
|
-
_id: { $in: ids },
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
## Handling Cascading Deletes
|
|
148
|
-
|
|
149
|
-
```typescript
|
|
150
|
-
// If your DB has cascading deletes
|
|
151
|
-
test.afterEach(async ({ db, createdIds }) => {
|
|
152
|
-
// Delete parent records - cascade handles children
|
|
153
|
-
const userIds = createdIds.get('users') || [];
|
|
154
|
-
if (userIds.length > 0) {
|
|
155
|
-
// This cascades to orders, sessions, etc.
|
|
156
|
-
await db.collection('users').deleteMany({
|
|
157
|
-
_id: { $in: userIds },
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
});
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
## Flaky Test Prevention
|
|
164
|
-
|
|
165
|
-
```typescript
|
|
166
|
-
// Prevent flaky tests with proper isolation
|
|
167
|
-
test.describe('User CRUD', () => {
|
|
168
|
-
// Each test is completely isolated
|
|
169
|
-
test.describe.configure({ mode: 'serial' });
|
|
170
|
-
|
|
171
|
-
test.beforeEach(async ({ db }) => {
|
|
172
|
-
// Ensure clean state
|
|
173
|
-
await db.collection('users').deleteMany({
|
|
174
|
-
email: { $regex: /^test_/ },
|
|
175
|
-
});
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
test('test 1', async ({ db, trackCreated }) => {
|
|
179
|
-
// Uses unique test email
|
|
180
|
-
const email = `test_${Date.now()}@example.com`;
|
|
181
|
-
// ...
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
test('test 2', async ({ db, trackCreated }) => {
|
|
185
|
-
// Uses different unique email
|
|
186
|
-
const email = `test_${Date.now()}@example.com`;
|
|
187
|
-
// ...
|
|
188
|
-
});
|
|
189
|
-
});
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
## Debug Cleanup Issues
|
|
193
|
-
|
|
194
|
-
```typescript
|
|
195
|
-
// Add logging to debug cleanup
|
|
196
|
-
test.afterEach(async ({ db, createdIds }) => {
|
|
197
|
-
console.log('=== CLEANUP START ===');
|
|
198
|
-
|
|
199
|
-
for (const [collection, ids] of createdIds.entries()) {
|
|
200
|
-
console.log(`Collection: ${collection}, IDs: ${ids.length}`);
|
|
201
|
-
|
|
202
|
-
if (ids.length > 0) {
|
|
203
|
-
const result = await db.collection(collection).deleteMany({
|
|
204
|
-
_id: { $in: ids },
|
|
205
|
-
});
|
|
206
|
-
console.log(`Deleted: ${result.deletedCount}`);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
console.log('=== CLEANUP END ===');
|
|
211
|
-
});
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
## Cleanup Verification
|
|
215
|
-
|
|
216
|
-
```typescript
|
|
217
|
-
// Verify cleanup worked
|
|
218
|
-
test.afterEach(async ({ db, createdIds }) => {
|
|
219
|
-
// First cleanup
|
|
220
|
-
for (const [collection, ids] of createdIds.entries()) {
|
|
221
|
-
if (ids.length > 0) {
|
|
222
|
-
await db.collection(collection).deleteMany({
|
|
223
|
-
_id: { $in: ids },
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
// Verify cleanup
|
|
229
|
-
for (const [collection, ids] of createdIds.entries()) {
|
|
230
|
-
if (ids.length > 0) {
|
|
231
|
-
const remaining = await db.collection(collection).countDocuments({
|
|
232
|
-
_id: { $in: ids },
|
|
233
|
-
});
|
|
234
|
-
if (remaining > 0) {
|
|
235
|
-
console.error(`CLEANUP FAILED: ${remaining} records remain in ${collection}`);
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
});
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
## Critical Rules
|
|
243
|
-
|
|
244
|
-
1. **ALWAYS TRACK** - Every created record must be tracked
|
|
245
|
-
2. **AUTO-CLEANUP** - Use afterEach, not manual cleanup
|
|
246
|
-
3. **UNIQUE DATA** - Use timestamps in identifiers
|
|
247
|
-
4. **ORDER MATTERS** - Clean children before parents
|
|
248
|
-
5. **VERIFY CLEANUP** - Check records are actually deleted
|
|
1
|
+
---
|
|
2
|
+
name: test-cleanup-manager
|
|
3
|
+
description: 'AUTOMATICALLY invoke when tests are flaky or share state. Triggers: flaky tests, test isolation issues, database state leakage. Ensures proper cleanup between tests. PROACTIVELY manages test data lifecycle.'
|
|
4
|
+
model: haiku
|
|
5
|
+
tools: Read, Write, Edit, Bash, Grep, Glob
|
|
6
|
+
skills: test-coverage
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Test Cleanup Manager Agent
|
|
10
|
+
|
|
11
|
+
You ensure proper test data cleanup and isolation.
|
|
12
|
+
|
|
13
|
+
## Cleanup Strategy
|
|
14
|
+
|
|
15
|
+
### The Golden Rule
|
|
16
|
+
|
|
17
|
+
> **Every piece of test data MUST be tracked and cleaned up.**
|
|
18
|
+
|
|
19
|
+
### Cleanup Timing
|
|
20
|
+
|
|
21
|
+
| When | What | How |
|
|
22
|
+
| ---------- | ------------------ | --------------------------- |
|
|
23
|
+
| beforeEach | Reset shared state | Clear caches, mocks |
|
|
24
|
+
| afterEach | Clean created data | Delete tracked records |
|
|
25
|
+
| afterAll | Close connections | Disconnect DB, close server |
|
|
26
|
+
|
|
27
|
+
## Fixture-Based Cleanup
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
// tests/e2e/fixtures/cleanup.fixture.ts
|
|
31
|
+
import { test as base } from '@playwright/test';
|
|
32
|
+
import { ObjectId, Db } from 'mongodb';
|
|
33
|
+
|
|
34
|
+
type CleanupFixture = {
|
|
35
|
+
createdIds: Map<string, ObjectId[]>;
|
|
36
|
+
trackCreated: (collection: string, id: ObjectId) => void;
|
|
37
|
+
cleanup: () => Promise<void>;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const cleanupFixture = base.extend<CleanupFixture>({
|
|
41
|
+
createdIds: async ({}, use) => {
|
|
42
|
+
await use(new Map());
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
trackCreated: async ({ createdIds }, use) => {
|
|
46
|
+
await use((collection, id) => {
|
|
47
|
+
const ids = createdIds.get(collection) || [];
|
|
48
|
+
ids.push(id);
|
|
49
|
+
createdIds.set(collection, ids);
|
|
50
|
+
});
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
cleanup: async ({ db, createdIds }, use) => {
|
|
54
|
+
await use(async () => {
|
|
55
|
+
for (const [collection, ids] of createdIds.entries()) {
|
|
56
|
+
if (ids.length > 0) {
|
|
57
|
+
await db.collection(collection).deleteMany({
|
|
58
|
+
_id: { $in: ids },
|
|
59
|
+
});
|
|
60
|
+
console.log(`Cleaned ${ids.length} from ${collection}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
createdIds.clear();
|
|
64
|
+
});
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// AUTO-CLEANUP after each test
|
|
69
|
+
cleanupFixture.afterEach(async ({ cleanup }) => {
|
|
70
|
+
await cleanup();
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Tracking Pattern
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
// In test file
|
|
78
|
+
test('should create and cleanup user', async ({ page, db, trackCreated }) => {
|
|
79
|
+
// Create via UI
|
|
80
|
+
await page.goto('/register');
|
|
81
|
+
await page.getByTestId('email').fill('test@example.com');
|
|
82
|
+
await page.getByRole('button', { name: 'Register' }).click();
|
|
83
|
+
|
|
84
|
+
// Get created record
|
|
85
|
+
const user = await db.collection('users').findOne({
|
|
86
|
+
email: 'test@example.com',
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// TRACK FOR CLEANUP - MANDATORY
|
|
90
|
+
trackCreated('users', user!._id);
|
|
91
|
+
|
|
92
|
+
// Continue test...
|
|
93
|
+
// Cleanup happens automatically in afterEach
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Cleanup for Related Data
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
// When creating related records
|
|
101
|
+
test('should create order with items', async ({ page, db, trackCreated }) => {
|
|
102
|
+
// Create user
|
|
103
|
+
const user = await createTestUser(db);
|
|
104
|
+
trackCreated('users', user._id);
|
|
105
|
+
|
|
106
|
+
// Create product
|
|
107
|
+
const product = await createTestProduct(db);
|
|
108
|
+
trackCreated('products', product._id);
|
|
109
|
+
|
|
110
|
+
// Create order (references user and product)
|
|
111
|
+
const order = await createTestOrder(db, {
|
|
112
|
+
userId: user._id,
|
|
113
|
+
items: [{ productId: product._id, quantity: 1 }],
|
|
114
|
+
});
|
|
115
|
+
trackCreated('orders', order._id);
|
|
116
|
+
|
|
117
|
+
// All records will be cleaned up in reverse order
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Cleanup Order
|
|
122
|
+
|
|
123
|
+
Clean up in dependency order (children before parents):
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
// Correct cleanup order
|
|
127
|
+
const cleanupOrder = [
|
|
128
|
+
'orderItems', // First: depends on orders and products
|
|
129
|
+
'orders', // Second: depends on users
|
|
130
|
+
'sessions', // Third: depends on users
|
|
131
|
+
'products', // Fourth: independent
|
|
132
|
+
'users', // Last: has dependents
|
|
133
|
+
];
|
|
134
|
+
|
|
135
|
+
async function cleanupAll(db: Db, createdIds: Map<string, ObjectId[]>) {
|
|
136
|
+
for (const collection of cleanupOrder) {
|
|
137
|
+
const ids = createdIds.get(collection);
|
|
138
|
+
if (ids && ids.length > 0) {
|
|
139
|
+
await db.collection(collection).deleteMany({
|
|
140
|
+
_id: { $in: ids },
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Handling Cascading Deletes
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
// If your DB has cascading deletes
|
|
151
|
+
test.afterEach(async ({ db, createdIds }) => {
|
|
152
|
+
// Delete parent records - cascade handles children
|
|
153
|
+
const userIds = createdIds.get('users') || [];
|
|
154
|
+
if (userIds.length > 0) {
|
|
155
|
+
// This cascades to orders, sessions, etc.
|
|
156
|
+
await db.collection('users').deleteMany({
|
|
157
|
+
_id: { $in: userIds },
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Flaky Test Prevention
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
// Prevent flaky tests with proper isolation
|
|
167
|
+
test.describe('User CRUD', () => {
|
|
168
|
+
// Each test is completely isolated
|
|
169
|
+
test.describe.configure({ mode: 'serial' });
|
|
170
|
+
|
|
171
|
+
test.beforeEach(async ({ db }) => {
|
|
172
|
+
// Ensure clean state
|
|
173
|
+
await db.collection('users').deleteMany({
|
|
174
|
+
email: { $regex: /^test_/ },
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test('test 1', async ({ db, trackCreated }) => {
|
|
179
|
+
// Uses unique test email
|
|
180
|
+
const email = `test_${Date.now()}@example.com`;
|
|
181
|
+
// ...
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
test('test 2', async ({ db, trackCreated }) => {
|
|
185
|
+
// Uses different unique email
|
|
186
|
+
const email = `test_${Date.now()}@example.com`;
|
|
187
|
+
// ...
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Debug Cleanup Issues
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
// Add logging to debug cleanup
|
|
196
|
+
test.afterEach(async ({ db, createdIds }) => {
|
|
197
|
+
console.log('=== CLEANUP START ===');
|
|
198
|
+
|
|
199
|
+
for (const [collection, ids] of createdIds.entries()) {
|
|
200
|
+
console.log(`Collection: ${collection}, IDs: ${ids.length}`);
|
|
201
|
+
|
|
202
|
+
if (ids.length > 0) {
|
|
203
|
+
const result = await db.collection(collection).deleteMany({
|
|
204
|
+
_id: { $in: ids },
|
|
205
|
+
});
|
|
206
|
+
console.log(`Deleted: ${result.deletedCount}`);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
console.log('=== CLEANUP END ===');
|
|
211
|
+
});
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Cleanup Verification
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
// Verify cleanup worked
|
|
218
|
+
test.afterEach(async ({ db, createdIds }) => {
|
|
219
|
+
// First cleanup
|
|
220
|
+
for (const [collection, ids] of createdIds.entries()) {
|
|
221
|
+
if (ids.length > 0) {
|
|
222
|
+
await db.collection(collection).deleteMany({
|
|
223
|
+
_id: { $in: ids },
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Verify cleanup
|
|
229
|
+
for (const [collection, ids] of createdIds.entries()) {
|
|
230
|
+
if (ids.length > 0) {
|
|
231
|
+
const remaining = await db.collection(collection).countDocuments({
|
|
232
|
+
_id: { $in: ids },
|
|
233
|
+
});
|
|
234
|
+
if (remaining > 0) {
|
|
235
|
+
console.error(`CLEANUP FAILED: ${remaining} records remain in ${collection}`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## Critical Rules
|
|
243
|
+
|
|
244
|
+
1. **ALWAYS TRACK** - Every created record must be tracked
|
|
245
|
+
2. **AUTO-CLEANUP** - Use afterEach, not manual cleanup
|
|
246
|
+
3. **UNIQUE DATA** - Use timestamps in identifiers
|
|
247
|
+
4. **ORDER MATTERS** - Clean children before parents
|
|
248
|
+
5. **VERIFY CLEANUP** - Check records are actually deleted
|