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,234 +1,234 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: playwright-fixtures
|
|
3
|
-
description: "AUTOMATICALLY invoke when creating E2E tests that need shared setup. Triggers: 'fixture', shared test setup, database cleanup, auth helpers needed. Creates reusable Playwright fixtures. PROACTIVELY designs test infrastructure."
|
|
4
|
-
model: sonnet
|
|
5
|
-
tools: Read, Write, Edit, Grep, Glob
|
|
6
|
-
skills: test-coverage, playwright-automation
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
# Playwright Fixtures Agent
|
|
10
|
-
|
|
11
|
-
You create reusable Playwright test fixtures for shared setup and cleanup.
|
|
12
|
-
|
|
13
|
-
## Fixture Types
|
|
14
|
-
|
|
15
|
-
| Type | Purpose | Example |
|
|
16
|
-
| ------ | --------------------------------- | ------------------- |
|
|
17
|
-
| Worker | Shared across all tests in worker | Database connection |
|
|
18
|
-
| Test | Unique per test | Authenticated page |
|
|
19
|
-
| Auto | Runs automatically | Cleanup |
|
|
20
|
-
|
|
21
|
-
## Database Fixture
|
|
22
|
-
|
|
23
|
-
```typescript
|
|
24
|
-
// tests/e2e/fixtures/db.fixture.ts
|
|
25
|
-
import { test as base } from '@playwright/test';
|
|
26
|
-
import { MongoClient, Db, ObjectId } from 'mongodb';
|
|
27
|
-
|
|
28
|
-
type DbFixture = {
|
|
29
|
-
db: Db;
|
|
30
|
-
cleanupCollection: (name: string) => Promise<void>;
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export const dbFixture = base.extend<DbFixture>({
|
|
34
|
-
db: async ({}, use) => {
|
|
35
|
-
const client = await MongoClient.connect(process.env['MONGODB_URI']!);
|
|
36
|
-
const db = client.db();
|
|
37
|
-
await use(db);
|
|
38
|
-
await client.close();
|
|
39
|
-
},
|
|
40
|
-
|
|
41
|
-
cleanupCollection: async ({ db }, use) => {
|
|
42
|
-
const cleanup = async (name: string) => {
|
|
43
|
-
await db.collection(name).deleteMany({});
|
|
44
|
-
};
|
|
45
|
-
await use(cleanup);
|
|
46
|
-
},
|
|
47
|
-
});
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
## Tracking Fixture (CRITICAL)
|
|
51
|
-
|
|
52
|
-
```typescript
|
|
53
|
-
// tests/e2e/fixtures/tracking.fixture.ts
|
|
54
|
-
import { test as base } from '@playwright/test';
|
|
55
|
-
import { ObjectId } from 'mongodb';
|
|
56
|
-
|
|
57
|
-
type TrackingFixture = {
|
|
58
|
-
createdIds: Map<string, ObjectId[]>;
|
|
59
|
-
trackCreated: (collection: string, id: ObjectId) => void;
|
|
60
|
-
getCreatedIds: (collection: string) => ObjectId[];
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
export const trackingFixture = base.extend<TrackingFixture>({
|
|
64
|
-
createdIds: async ({}, use) => {
|
|
65
|
-
const ids = new Map<string, ObjectId[]>();
|
|
66
|
-
await use(ids);
|
|
67
|
-
},
|
|
68
|
-
|
|
69
|
-
trackCreated: async ({ createdIds }, use) => {
|
|
70
|
-
await use((collection: string, id: ObjectId) => {
|
|
71
|
-
const existing = createdIds.get(collection) || [];
|
|
72
|
-
existing.push(id);
|
|
73
|
-
createdIds.set(collection, existing);
|
|
74
|
-
});
|
|
75
|
-
},
|
|
76
|
-
|
|
77
|
-
getCreatedIds: async ({ createdIds }, use) => {
|
|
78
|
-
await use((collection: string) => {
|
|
79
|
-
return createdIds.get(collection) || [];
|
|
80
|
-
});
|
|
81
|
-
},
|
|
82
|
-
});
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
## Auth Fixture
|
|
86
|
-
|
|
87
|
-
```typescript
|
|
88
|
-
// tests/e2e/fixtures/auth.fixture.ts
|
|
89
|
-
import { test as base, Page } from '@playwright/test';
|
|
90
|
-
|
|
91
|
-
type AuthFixture = {
|
|
92
|
-
authenticatedPage: Page;
|
|
93
|
-
loginAs: (email: string, password: string) => Promise<void>;
|
|
94
|
-
createTestUser: () => Promise<{ email: string; password: string }>;
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
export const authFixture = base.extend<AuthFixture>({
|
|
98
|
-
authenticatedPage: async ({ page, createTestUser, loginAs }, use) => {
|
|
99
|
-
const user = await createTestUser();
|
|
100
|
-
await loginAs(user.email, user.password);
|
|
101
|
-
await use(page);
|
|
102
|
-
},
|
|
103
|
-
|
|
104
|
-
loginAs: async ({ page }, use) => {
|
|
105
|
-
await use(async (email: string, password: string) => {
|
|
106
|
-
await page.goto('/login');
|
|
107
|
-
await page.getByTestId('email-input').fill(email);
|
|
108
|
-
await page.getByTestId('password-input').fill(password);
|
|
109
|
-
await page.getByRole('button', { name: 'Login' }).click();
|
|
110
|
-
await page.waitForURL('/dashboard');
|
|
111
|
-
});
|
|
112
|
-
},
|
|
113
|
-
|
|
114
|
-
createTestUser: async ({ db, trackCreated }, use) => {
|
|
115
|
-
await use(async () => {
|
|
116
|
-
const email = `test_${Date.now()}@example.com`;
|
|
117
|
-
const password = 'TestPassword123!';
|
|
118
|
-
|
|
119
|
-
// Create user in database
|
|
120
|
-
const result = await db.collection('users').insertOne({
|
|
121
|
-
email,
|
|
122
|
-
password: await hashPassword(password),
|
|
123
|
-
name: 'Test User',
|
|
124
|
-
createdAt: new Date(),
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
trackCreated('users', result.insertedId);
|
|
128
|
-
|
|
129
|
-
return { email, password };
|
|
130
|
-
});
|
|
131
|
-
},
|
|
132
|
-
});
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
## Combined Fixtures
|
|
136
|
-
|
|
137
|
-
```typescript
|
|
138
|
-
// tests/e2e/fixtures/index.ts
|
|
139
|
-
import { test as base, expect } from '@playwright/test';
|
|
140
|
-
import { MongoClient, Db, ObjectId } from 'mongodb';
|
|
141
|
-
|
|
142
|
-
type AllFixtures = {
|
|
143
|
-
db: Db;
|
|
144
|
-
createdIds: Map<string, ObjectId[]>;
|
|
145
|
-
trackCreated: (collection: string, id: ObjectId) => void;
|
|
146
|
-
loginAs: (email: string, password: string) => Promise<void>;
|
|
147
|
-
createTestUser: () => Promise<{ email: string; password: string }>;
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
export const test = base.extend<AllFixtures>({
|
|
151
|
-
// Database connection
|
|
152
|
-
db: async ({}, use) => {
|
|
153
|
-
const client = await MongoClient.connect(process.env['MONGODB_URI']!);
|
|
154
|
-
await use(client.db());
|
|
155
|
-
await client.close();
|
|
156
|
-
},
|
|
157
|
-
|
|
158
|
-
// Tracking for cleanup
|
|
159
|
-
createdIds: async ({}, use) => {
|
|
160
|
-
await use(new Map());
|
|
161
|
-
},
|
|
162
|
-
|
|
163
|
-
trackCreated: async ({ createdIds }, use) => {
|
|
164
|
-
await use((collection, id) => {
|
|
165
|
-
const existing = createdIds.get(collection) || [];
|
|
166
|
-
existing.push(id);
|
|
167
|
-
createdIds.set(collection, existing);
|
|
168
|
-
});
|
|
169
|
-
},
|
|
170
|
-
|
|
171
|
-
// Auth helpers
|
|
172
|
-
loginAs: async ({ page }, use) => {
|
|
173
|
-
await use(async (email, password) => {
|
|
174
|
-
await page.goto('/login');
|
|
175
|
-
await page.getByTestId('email-input').fill(email);
|
|
176
|
-
await page.getByTestId('password-input').fill(password);
|
|
177
|
-
await page.getByRole('button', { name: 'Login' }).click();
|
|
178
|
-
await page.waitForURL('/dashboard');
|
|
179
|
-
});
|
|
180
|
-
},
|
|
181
|
-
|
|
182
|
-
createTestUser: async ({ db, trackCreated }, use) => {
|
|
183
|
-
await use(async () => {
|
|
184
|
-
const email = `test_${Date.now()}@example.com`;
|
|
185
|
-
const result = await db.collection('users').insertOne({
|
|
186
|
-
email,
|
|
187
|
-
password: 'hashed',
|
|
188
|
-
name: 'Test',
|
|
189
|
-
createdAt: new Date(),
|
|
190
|
-
});
|
|
191
|
-
trackCreated('users', result.insertedId);
|
|
192
|
-
return { email, password: 'TestPassword123!' };
|
|
193
|
-
});
|
|
194
|
-
},
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
// AUTO-CLEANUP - Runs after EVERY test
|
|
198
|
-
test.afterEach(async ({ db, createdIds }) => {
|
|
199
|
-
for (const [collection, ids] of createdIds.entries()) {
|
|
200
|
-
if (ids.length > 0) {
|
|
201
|
-
await db.collection(collection).deleteMany({
|
|
202
|
-
_id: { $in: ids },
|
|
203
|
-
});
|
|
204
|
-
console.log(`Cleaned ${ids.length} from ${collection}`);
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
export { expect };
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
## Usage in Tests
|
|
213
|
-
|
|
214
|
-
```typescript
|
|
215
|
-
// tests/e2e/flows/feature.spec.ts
|
|
216
|
-
import { test, expect } from '../fixtures';
|
|
217
|
-
|
|
218
|
-
test('should work with fixtures', async ({ page, db, trackCreated, loginAs, createTestUser }) => {
|
|
219
|
-
// Use fixtures
|
|
220
|
-
const user = await createTestUser();
|
|
221
|
-
await loginAs(user.email, user.password);
|
|
222
|
-
|
|
223
|
-
// Test...
|
|
224
|
-
// Cleanup happens automatically via afterEach
|
|
225
|
-
});
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
## Critical Rules
|
|
229
|
-
|
|
230
|
-
1. **AUTO-CLEANUP** - afterEach must clean tracked data
|
|
231
|
-
2. **TRACK EVERYTHING** - All created records must be tracked
|
|
232
|
-
3. **ISOLATION** - Each test creates fresh data
|
|
233
|
-
4. **REUSABILITY** - Common patterns in fixtures
|
|
234
|
-
5. **COMPOSITION** - Combine fixtures for complex scenarios
|
|
1
|
+
---
|
|
2
|
+
name: playwright-fixtures
|
|
3
|
+
description: "AUTOMATICALLY invoke when creating E2E tests that need shared setup. Triggers: 'fixture', shared test setup, database cleanup, auth helpers needed. Creates reusable Playwright fixtures. PROACTIVELY designs test infrastructure."
|
|
4
|
+
model: sonnet
|
|
5
|
+
tools: Read, Write, Edit, Grep, Glob
|
|
6
|
+
skills: test-coverage, playwright-automation
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Playwright Fixtures Agent
|
|
10
|
+
|
|
11
|
+
You create reusable Playwright test fixtures for shared setup and cleanup.
|
|
12
|
+
|
|
13
|
+
## Fixture Types
|
|
14
|
+
|
|
15
|
+
| Type | Purpose | Example |
|
|
16
|
+
| ------ | --------------------------------- | ------------------- |
|
|
17
|
+
| Worker | Shared across all tests in worker | Database connection |
|
|
18
|
+
| Test | Unique per test | Authenticated page |
|
|
19
|
+
| Auto | Runs automatically | Cleanup |
|
|
20
|
+
|
|
21
|
+
## Database Fixture
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
// tests/e2e/fixtures/db.fixture.ts
|
|
25
|
+
import { test as base } from '@playwright/test';
|
|
26
|
+
import { MongoClient, Db, ObjectId } from 'mongodb';
|
|
27
|
+
|
|
28
|
+
type DbFixture = {
|
|
29
|
+
db: Db;
|
|
30
|
+
cleanupCollection: (name: string) => Promise<void>;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const dbFixture = base.extend<DbFixture>({
|
|
34
|
+
db: async ({}, use) => {
|
|
35
|
+
const client = await MongoClient.connect(process.env['MONGODB_URI']!);
|
|
36
|
+
const db = client.db();
|
|
37
|
+
await use(db);
|
|
38
|
+
await client.close();
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
cleanupCollection: async ({ db }, use) => {
|
|
42
|
+
const cleanup = async (name: string) => {
|
|
43
|
+
await db.collection(name).deleteMany({});
|
|
44
|
+
};
|
|
45
|
+
await use(cleanup);
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Tracking Fixture (CRITICAL)
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
// tests/e2e/fixtures/tracking.fixture.ts
|
|
54
|
+
import { test as base } from '@playwright/test';
|
|
55
|
+
import { ObjectId } from 'mongodb';
|
|
56
|
+
|
|
57
|
+
type TrackingFixture = {
|
|
58
|
+
createdIds: Map<string, ObjectId[]>;
|
|
59
|
+
trackCreated: (collection: string, id: ObjectId) => void;
|
|
60
|
+
getCreatedIds: (collection: string) => ObjectId[];
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const trackingFixture = base.extend<TrackingFixture>({
|
|
64
|
+
createdIds: async ({}, use) => {
|
|
65
|
+
const ids = new Map<string, ObjectId[]>();
|
|
66
|
+
await use(ids);
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
trackCreated: async ({ createdIds }, use) => {
|
|
70
|
+
await use((collection: string, id: ObjectId) => {
|
|
71
|
+
const existing = createdIds.get(collection) || [];
|
|
72
|
+
existing.push(id);
|
|
73
|
+
createdIds.set(collection, existing);
|
|
74
|
+
});
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
getCreatedIds: async ({ createdIds }, use) => {
|
|
78
|
+
await use((collection: string) => {
|
|
79
|
+
return createdIds.get(collection) || [];
|
|
80
|
+
});
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Auth Fixture
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
// tests/e2e/fixtures/auth.fixture.ts
|
|
89
|
+
import { test as base, Page } from '@playwright/test';
|
|
90
|
+
|
|
91
|
+
type AuthFixture = {
|
|
92
|
+
authenticatedPage: Page;
|
|
93
|
+
loginAs: (email: string, password: string) => Promise<void>;
|
|
94
|
+
createTestUser: () => Promise<{ email: string; password: string }>;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export const authFixture = base.extend<AuthFixture>({
|
|
98
|
+
authenticatedPage: async ({ page, createTestUser, loginAs }, use) => {
|
|
99
|
+
const user = await createTestUser();
|
|
100
|
+
await loginAs(user.email, user.password);
|
|
101
|
+
await use(page);
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
loginAs: async ({ page }, use) => {
|
|
105
|
+
await use(async (email: string, password: string) => {
|
|
106
|
+
await page.goto('/login');
|
|
107
|
+
await page.getByTestId('email-input').fill(email);
|
|
108
|
+
await page.getByTestId('password-input').fill(password);
|
|
109
|
+
await page.getByRole('button', { name: 'Login' }).click();
|
|
110
|
+
await page.waitForURL('/dashboard');
|
|
111
|
+
});
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
createTestUser: async ({ db, trackCreated }, use) => {
|
|
115
|
+
await use(async () => {
|
|
116
|
+
const email = `test_${Date.now()}@example.com`;
|
|
117
|
+
const password = 'TestPassword123!';
|
|
118
|
+
|
|
119
|
+
// Create user in database
|
|
120
|
+
const result = await db.collection('users').insertOne({
|
|
121
|
+
email,
|
|
122
|
+
password: await hashPassword(password),
|
|
123
|
+
name: 'Test User',
|
|
124
|
+
createdAt: new Date(),
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
trackCreated('users', result.insertedId);
|
|
128
|
+
|
|
129
|
+
return { email, password };
|
|
130
|
+
});
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Combined Fixtures
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
// tests/e2e/fixtures/index.ts
|
|
139
|
+
import { test as base, expect } from '@playwright/test';
|
|
140
|
+
import { MongoClient, Db, ObjectId } from 'mongodb';
|
|
141
|
+
|
|
142
|
+
type AllFixtures = {
|
|
143
|
+
db: Db;
|
|
144
|
+
createdIds: Map<string, ObjectId[]>;
|
|
145
|
+
trackCreated: (collection: string, id: ObjectId) => void;
|
|
146
|
+
loginAs: (email: string, password: string) => Promise<void>;
|
|
147
|
+
createTestUser: () => Promise<{ email: string; password: string }>;
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
export const test = base.extend<AllFixtures>({
|
|
151
|
+
// Database connection
|
|
152
|
+
db: async ({}, use) => {
|
|
153
|
+
const client = await MongoClient.connect(process.env['MONGODB_URI']!);
|
|
154
|
+
await use(client.db());
|
|
155
|
+
await client.close();
|
|
156
|
+
},
|
|
157
|
+
|
|
158
|
+
// Tracking for cleanup
|
|
159
|
+
createdIds: async ({}, use) => {
|
|
160
|
+
await use(new Map());
|
|
161
|
+
},
|
|
162
|
+
|
|
163
|
+
trackCreated: async ({ createdIds }, use) => {
|
|
164
|
+
await use((collection, id) => {
|
|
165
|
+
const existing = createdIds.get(collection) || [];
|
|
166
|
+
existing.push(id);
|
|
167
|
+
createdIds.set(collection, existing);
|
|
168
|
+
});
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
// Auth helpers
|
|
172
|
+
loginAs: async ({ page }, use) => {
|
|
173
|
+
await use(async (email, password) => {
|
|
174
|
+
await page.goto('/login');
|
|
175
|
+
await page.getByTestId('email-input').fill(email);
|
|
176
|
+
await page.getByTestId('password-input').fill(password);
|
|
177
|
+
await page.getByRole('button', { name: 'Login' }).click();
|
|
178
|
+
await page.waitForURL('/dashboard');
|
|
179
|
+
});
|
|
180
|
+
},
|
|
181
|
+
|
|
182
|
+
createTestUser: async ({ db, trackCreated }, use) => {
|
|
183
|
+
await use(async () => {
|
|
184
|
+
const email = `test_${Date.now()}@example.com`;
|
|
185
|
+
const result = await db.collection('users').insertOne({
|
|
186
|
+
email,
|
|
187
|
+
password: 'hashed',
|
|
188
|
+
name: 'Test',
|
|
189
|
+
createdAt: new Date(),
|
|
190
|
+
});
|
|
191
|
+
trackCreated('users', result.insertedId);
|
|
192
|
+
return { email, password: 'TestPassword123!' };
|
|
193
|
+
});
|
|
194
|
+
},
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
// AUTO-CLEANUP - Runs after EVERY test
|
|
198
|
+
test.afterEach(async ({ db, createdIds }) => {
|
|
199
|
+
for (const [collection, ids] of createdIds.entries()) {
|
|
200
|
+
if (ids.length > 0) {
|
|
201
|
+
await db.collection(collection).deleteMany({
|
|
202
|
+
_id: { $in: ids },
|
|
203
|
+
});
|
|
204
|
+
console.log(`Cleaned ${ids.length} from ${collection}`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
export { expect };
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Usage in Tests
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
// tests/e2e/flows/feature.spec.ts
|
|
216
|
+
import { test, expect } from '../fixtures';
|
|
217
|
+
|
|
218
|
+
test('should work with fixtures', async ({ page, db, trackCreated, loginAs, createTestUser }) => {
|
|
219
|
+
// Use fixtures
|
|
220
|
+
const user = await createTestUser();
|
|
221
|
+
await loginAs(user.email, user.password);
|
|
222
|
+
|
|
223
|
+
// Test...
|
|
224
|
+
// Cleanup happens automatically via afterEach
|
|
225
|
+
});
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Critical Rules
|
|
229
|
+
|
|
230
|
+
1. **AUTO-CLEANUP** - afterEach must clean tracked data
|
|
231
|
+
2. **TRACK EVERYTHING** - All created records must be tracked
|
|
232
|
+
3. **ISOLATION** - Each test creates fresh data
|
|
233
|
+
4. **REUSABILITY** - Common patterns in fixtures
|
|
234
|
+
5. **COMPOSITION** - Combine fixtures for complex scenarios
|