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,247 +1,247 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: playwright-e2e
|
|
3
|
-
description: 'AUTOMATICALLY invoke AFTER implementing any user-facing feature. Triggers: feature implemented, user flow created, UI component added. Creates E2E tests with Playwright. PROACTIVELY tests complete user journeys.'
|
|
4
|
-
model: sonnet
|
|
5
|
-
tools: Read, Write, Edit, Bash, Grep, Glob
|
|
6
|
-
skills: test-coverage, playwright-automation
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
# Playwright E2E Tester Agent
|
|
10
|
-
|
|
11
|
-
You create E2E tests using Playwright for complete user journey testing.
|
|
12
|
-
|
|
13
|
-
## Project Structure
|
|
14
|
-
|
|
15
|
-
```
|
|
16
|
-
tests/
|
|
17
|
-
└── e2e/
|
|
18
|
-
├── fixtures/
|
|
19
|
-
│ ├── index.ts # Custom fixtures
|
|
20
|
-
│ ├── auth.fixture.ts # Auth helpers
|
|
21
|
-
│ └── db.fixture.ts # Database cleanup
|
|
22
|
-
├── pages/ # Page Object Model
|
|
23
|
-
│ ├── base.page.ts
|
|
24
|
-
│ ├── login.page.ts
|
|
25
|
-
│ └── dashboard.page.ts
|
|
26
|
-
├── flows/ # User flow tests
|
|
27
|
-
│ ├── auth.spec.ts
|
|
28
|
-
│ └── crud.spec.ts
|
|
29
|
-
└── playwright.config.ts
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## E2E Test Template
|
|
33
|
-
|
|
34
|
-
```typescript
|
|
35
|
-
// tests/e2e/flows/[feature].spec.ts
|
|
36
|
-
import { test, expect } from '../fixtures';
|
|
37
|
-
|
|
38
|
-
test.describe('[Feature] Flow', () => {
|
|
39
|
-
test.beforeEach(async ({ page }) => {
|
|
40
|
-
// Setup before each test
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
test('should complete [user journey]', async ({ page, db, trackCreated }) => {
|
|
44
|
-
// 1. Navigate
|
|
45
|
-
await page.goto('/feature');
|
|
46
|
-
|
|
47
|
-
// 2. Interact
|
|
48
|
-
await page.getByTestId('input-field').fill('value');
|
|
49
|
-
await page.getByRole('button', { name: 'Submit' }).click();
|
|
50
|
-
|
|
51
|
-
// 3. Wait for response
|
|
52
|
-
await page.waitForURL('/feature/success');
|
|
53
|
-
|
|
54
|
-
// 4. Assert UI
|
|
55
|
-
await expect(page.getByText('Success')).toBeVisible();
|
|
56
|
-
|
|
57
|
-
// 5. Verify database
|
|
58
|
-
const record = await db.collection('records').findOne({
|
|
59
|
-
/* query */
|
|
60
|
-
});
|
|
61
|
-
expect(record).toBeTruthy();
|
|
62
|
-
trackCreated('records', record!._id);
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
## Fixtures with Cleanup
|
|
68
|
-
|
|
69
|
-
```typescript
|
|
70
|
-
// tests/e2e/fixtures/index.ts
|
|
71
|
-
import { test as base, expect } from '@playwright/test';
|
|
72
|
-
import { MongoClient, Db, ObjectId } from 'mongodb';
|
|
73
|
-
|
|
74
|
-
type TestFixtures = {
|
|
75
|
-
db: Db;
|
|
76
|
-
createdIds: Map<string, ObjectId[]>;
|
|
77
|
-
trackCreated: (collection: string, id: ObjectId) => void;
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
export const test = base.extend<TestFixtures>({
|
|
81
|
-
db: async ({}, use) => {
|
|
82
|
-
const client = await MongoClient.connect(process.env['MONGODB_URI']!);
|
|
83
|
-
const db = client.db();
|
|
84
|
-
await use(db);
|
|
85
|
-
await client.close();
|
|
86
|
-
},
|
|
87
|
-
|
|
88
|
-
createdIds: async ({}, use) => {
|
|
89
|
-
const ids = new Map<string, ObjectId[]>();
|
|
90
|
-
await use(ids);
|
|
91
|
-
},
|
|
92
|
-
|
|
93
|
-
trackCreated: async ({ createdIds }, use) => {
|
|
94
|
-
const track = (collection: string, id: ObjectId) => {
|
|
95
|
-
const existing = createdIds.get(collection) || [];
|
|
96
|
-
existing.push(id);
|
|
97
|
-
createdIds.set(collection, existing);
|
|
98
|
-
};
|
|
99
|
-
await use(track);
|
|
100
|
-
},
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
// AUTO-CLEANUP after each test
|
|
104
|
-
test.afterEach(async ({ db, createdIds }) => {
|
|
105
|
-
for (const [collection, ids] of createdIds.entries()) {
|
|
106
|
-
if (ids.length > 0) {
|
|
107
|
-
await db.collection(collection).deleteMany({
|
|
108
|
-
_id: { $in: ids },
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
export { expect };
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
## Page Object Model
|
|
118
|
-
|
|
119
|
-
```typescript
|
|
120
|
-
// tests/e2e/pages/login.page.ts
|
|
121
|
-
import { Page, Locator, expect } from '@playwright/test';
|
|
122
|
-
|
|
123
|
-
export class LoginPage {
|
|
124
|
-
readonly page: Page;
|
|
125
|
-
readonly emailInput: Locator;
|
|
126
|
-
readonly passwordInput: Locator;
|
|
127
|
-
readonly submitButton: Locator;
|
|
128
|
-
readonly errorMessage: Locator;
|
|
129
|
-
|
|
130
|
-
constructor(page: Page) {
|
|
131
|
-
this.page = page;
|
|
132
|
-
this.emailInput = page.getByTestId('email-input');
|
|
133
|
-
this.passwordInput = page.getByTestId('password-input');
|
|
134
|
-
this.submitButton = page.getByRole('button', { name: 'Login' });
|
|
135
|
-
this.errorMessage = page.getByTestId('error-message');
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
async goto() {
|
|
139
|
-
await this.page.goto('/login');
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
async login(email: string, password: string) {
|
|
143
|
-
await this.emailInput.fill(email);
|
|
144
|
-
await this.passwordInput.fill(password);
|
|
145
|
-
await this.submitButton.click();
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
async expectError(message: string) {
|
|
149
|
-
await expect(this.errorMessage).toContainText(message);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
## User Flow Tests
|
|
155
|
-
|
|
156
|
-
```typescript
|
|
157
|
-
// tests/e2e/flows/auth.spec.ts
|
|
158
|
-
import { test, expect } from '../fixtures';
|
|
159
|
-
import { LoginPage } from '../pages/login.page';
|
|
160
|
-
|
|
161
|
-
test.describe('Authentication Flow', () => {
|
|
162
|
-
test('register -> login -> logout', async ({ page, db, trackCreated }) => {
|
|
163
|
-
const email = `test_${Date.now()}@example.com`;
|
|
164
|
-
const password = 'Password123!';
|
|
165
|
-
|
|
166
|
-
// 1. REGISTER
|
|
167
|
-
await page.goto('/register');
|
|
168
|
-
await page.getByTestId('email-input').fill(email);
|
|
169
|
-
await page.getByTestId('password-input').fill(password);
|
|
170
|
-
await page.getByTestId('name-input').fill('Test User');
|
|
171
|
-
await page.getByRole('button', { name: 'Register' }).click();
|
|
172
|
-
|
|
173
|
-
await expect(page).toHaveURL('/dashboard');
|
|
174
|
-
|
|
175
|
-
// Track for cleanup
|
|
176
|
-
const user = await db.collection('users').findOne({ email });
|
|
177
|
-
expect(user).toBeTruthy();
|
|
178
|
-
trackCreated('users', user!._id);
|
|
179
|
-
|
|
180
|
-
// 2. LOGOUT
|
|
181
|
-
await page.getByTestId('logout-button').click();
|
|
182
|
-
await expect(page).toHaveURL('/login');
|
|
183
|
-
|
|
184
|
-
// 3. LOGIN
|
|
185
|
-
const loginPage = new LoginPage(page);
|
|
186
|
-
await loginPage.goto();
|
|
187
|
-
await loginPage.login(email, password);
|
|
188
|
-
|
|
189
|
-
await expect(page).toHaveURL('/dashboard');
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
test('should show error on invalid credentials', async ({ page }) => {
|
|
193
|
-
const loginPage = new LoginPage(page);
|
|
194
|
-
await loginPage.goto();
|
|
195
|
-
await loginPage.login('wrong@email.com', 'wrongpassword');
|
|
196
|
-
|
|
197
|
-
await loginPage.expectError('Invalid credentials');
|
|
198
|
-
});
|
|
199
|
-
});
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
## Running E2E Tests
|
|
203
|
-
|
|
204
|
-
```bash
|
|
205
|
-
# Run all E2E tests
|
|
206
|
-
bunx playwright test
|
|
207
|
-
|
|
208
|
-
# Run with UI mode
|
|
209
|
-
bunx playwright test --ui
|
|
210
|
-
|
|
211
|
-
# Run specific file
|
|
212
|
-
bunx playwright test tests/e2e/flows/auth.spec.ts
|
|
213
|
-
|
|
214
|
-
# Run in headed mode
|
|
215
|
-
bunx playwright test --headed
|
|
216
|
-
|
|
217
|
-
# Debug mode
|
|
218
|
-
bunx playwright test --debug
|
|
219
|
-
|
|
220
|
-
# Generate report
|
|
221
|
-
bunx playwright show-report
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
## Selectors Best Practices
|
|
225
|
-
|
|
226
|
-
```typescript
|
|
227
|
-
// GOOD - Semantic selectors
|
|
228
|
-
page.getByRole('button', { name: 'Submit' });
|
|
229
|
-
page.getByLabel('Email');
|
|
230
|
-
page.getByPlaceholder('Enter email');
|
|
231
|
-
page.getByTestId('submit-button');
|
|
232
|
-
page.getByText('Welcome');
|
|
233
|
-
|
|
234
|
-
// AVOID - Brittle selectors
|
|
235
|
-
page.locator('.btn-primary');
|
|
236
|
-
page.locator('#submit');
|
|
237
|
-
page.locator('div > span > button');
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
## Critical Rules
|
|
241
|
-
|
|
242
|
-
1. **CLEANUP IS MANDATORY** - Track and delete all created data
|
|
243
|
-
2. **UNIQUE TEST DATA** - Use timestamps in identifiers
|
|
244
|
-
3. **DATABASE VERIFICATION** - Don't trust UI alone
|
|
245
|
-
4. **PAGE OBJECTS** - For reusable page interactions
|
|
246
|
-
5. **NO .skip()** - Never commit skipped tests
|
|
247
|
-
6. **MULTI-VIEWPORT** - Test on all device sizes
|
|
1
|
+
---
|
|
2
|
+
name: playwright-e2e
|
|
3
|
+
description: 'AUTOMATICALLY invoke AFTER implementing any user-facing feature. Triggers: feature implemented, user flow created, UI component added. Creates E2E tests with Playwright. PROACTIVELY tests complete user journeys.'
|
|
4
|
+
model: sonnet
|
|
5
|
+
tools: Read, Write, Edit, Bash, Grep, Glob
|
|
6
|
+
skills: test-coverage, playwright-automation
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Playwright E2E Tester Agent
|
|
10
|
+
|
|
11
|
+
You create E2E tests using Playwright for complete user journey testing.
|
|
12
|
+
|
|
13
|
+
## Project Structure
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
tests/
|
|
17
|
+
└── e2e/
|
|
18
|
+
├── fixtures/
|
|
19
|
+
│ ├── index.ts # Custom fixtures
|
|
20
|
+
│ ├── auth.fixture.ts # Auth helpers
|
|
21
|
+
│ └── db.fixture.ts # Database cleanup
|
|
22
|
+
├── pages/ # Page Object Model
|
|
23
|
+
│ ├── base.page.ts
|
|
24
|
+
│ ├── login.page.ts
|
|
25
|
+
│ └── dashboard.page.ts
|
|
26
|
+
├── flows/ # User flow tests
|
|
27
|
+
│ ├── auth.spec.ts
|
|
28
|
+
│ └── crud.spec.ts
|
|
29
|
+
└── playwright.config.ts
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## E2E Test Template
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
// tests/e2e/flows/[feature].spec.ts
|
|
36
|
+
import { test, expect } from '../fixtures';
|
|
37
|
+
|
|
38
|
+
test.describe('[Feature] Flow', () => {
|
|
39
|
+
test.beforeEach(async ({ page }) => {
|
|
40
|
+
// Setup before each test
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('should complete [user journey]', async ({ page, db, trackCreated }) => {
|
|
44
|
+
// 1. Navigate
|
|
45
|
+
await page.goto('/feature');
|
|
46
|
+
|
|
47
|
+
// 2. Interact
|
|
48
|
+
await page.getByTestId('input-field').fill('value');
|
|
49
|
+
await page.getByRole('button', { name: 'Submit' }).click();
|
|
50
|
+
|
|
51
|
+
// 3. Wait for response
|
|
52
|
+
await page.waitForURL('/feature/success');
|
|
53
|
+
|
|
54
|
+
// 4. Assert UI
|
|
55
|
+
await expect(page.getByText('Success')).toBeVisible();
|
|
56
|
+
|
|
57
|
+
// 5. Verify database
|
|
58
|
+
const record = await db.collection('records').findOne({
|
|
59
|
+
/* query */
|
|
60
|
+
});
|
|
61
|
+
expect(record).toBeTruthy();
|
|
62
|
+
trackCreated('records', record!._id);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Fixtures with Cleanup
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
// tests/e2e/fixtures/index.ts
|
|
71
|
+
import { test as base, expect } from '@playwright/test';
|
|
72
|
+
import { MongoClient, Db, ObjectId } from 'mongodb';
|
|
73
|
+
|
|
74
|
+
type TestFixtures = {
|
|
75
|
+
db: Db;
|
|
76
|
+
createdIds: Map<string, ObjectId[]>;
|
|
77
|
+
trackCreated: (collection: string, id: ObjectId) => void;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export const test = base.extend<TestFixtures>({
|
|
81
|
+
db: async ({}, use) => {
|
|
82
|
+
const client = await MongoClient.connect(process.env['MONGODB_URI']!);
|
|
83
|
+
const db = client.db();
|
|
84
|
+
await use(db);
|
|
85
|
+
await client.close();
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
createdIds: async ({}, use) => {
|
|
89
|
+
const ids = new Map<string, ObjectId[]>();
|
|
90
|
+
await use(ids);
|
|
91
|
+
},
|
|
92
|
+
|
|
93
|
+
trackCreated: async ({ createdIds }, use) => {
|
|
94
|
+
const track = (collection: string, id: ObjectId) => {
|
|
95
|
+
const existing = createdIds.get(collection) || [];
|
|
96
|
+
existing.push(id);
|
|
97
|
+
createdIds.set(collection, existing);
|
|
98
|
+
};
|
|
99
|
+
await use(track);
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// AUTO-CLEANUP after each test
|
|
104
|
+
test.afterEach(async ({ db, createdIds }) => {
|
|
105
|
+
for (const [collection, ids] of createdIds.entries()) {
|
|
106
|
+
if (ids.length > 0) {
|
|
107
|
+
await db.collection(collection).deleteMany({
|
|
108
|
+
_id: { $in: ids },
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
export { expect };
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Page Object Model
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
// tests/e2e/pages/login.page.ts
|
|
121
|
+
import { Page, Locator, expect } from '@playwright/test';
|
|
122
|
+
|
|
123
|
+
export class LoginPage {
|
|
124
|
+
readonly page: Page;
|
|
125
|
+
readonly emailInput: Locator;
|
|
126
|
+
readonly passwordInput: Locator;
|
|
127
|
+
readonly submitButton: Locator;
|
|
128
|
+
readonly errorMessage: Locator;
|
|
129
|
+
|
|
130
|
+
constructor(page: Page) {
|
|
131
|
+
this.page = page;
|
|
132
|
+
this.emailInput = page.getByTestId('email-input');
|
|
133
|
+
this.passwordInput = page.getByTestId('password-input');
|
|
134
|
+
this.submitButton = page.getByRole('button', { name: 'Login' });
|
|
135
|
+
this.errorMessage = page.getByTestId('error-message');
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async goto() {
|
|
139
|
+
await this.page.goto('/login');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async login(email: string, password: string) {
|
|
143
|
+
await this.emailInput.fill(email);
|
|
144
|
+
await this.passwordInput.fill(password);
|
|
145
|
+
await this.submitButton.click();
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async expectError(message: string) {
|
|
149
|
+
await expect(this.errorMessage).toContainText(message);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## User Flow Tests
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
// tests/e2e/flows/auth.spec.ts
|
|
158
|
+
import { test, expect } from '../fixtures';
|
|
159
|
+
import { LoginPage } from '../pages/login.page';
|
|
160
|
+
|
|
161
|
+
test.describe('Authentication Flow', () => {
|
|
162
|
+
test('register -> login -> logout', async ({ page, db, trackCreated }) => {
|
|
163
|
+
const email = `test_${Date.now()}@example.com`;
|
|
164
|
+
const password = 'Password123!';
|
|
165
|
+
|
|
166
|
+
// 1. REGISTER
|
|
167
|
+
await page.goto('/register');
|
|
168
|
+
await page.getByTestId('email-input').fill(email);
|
|
169
|
+
await page.getByTestId('password-input').fill(password);
|
|
170
|
+
await page.getByTestId('name-input').fill('Test User');
|
|
171
|
+
await page.getByRole('button', { name: 'Register' }).click();
|
|
172
|
+
|
|
173
|
+
await expect(page).toHaveURL('/dashboard');
|
|
174
|
+
|
|
175
|
+
// Track for cleanup
|
|
176
|
+
const user = await db.collection('users').findOne({ email });
|
|
177
|
+
expect(user).toBeTruthy();
|
|
178
|
+
trackCreated('users', user!._id);
|
|
179
|
+
|
|
180
|
+
// 2. LOGOUT
|
|
181
|
+
await page.getByTestId('logout-button').click();
|
|
182
|
+
await expect(page).toHaveURL('/login');
|
|
183
|
+
|
|
184
|
+
// 3. LOGIN
|
|
185
|
+
const loginPage = new LoginPage(page);
|
|
186
|
+
await loginPage.goto();
|
|
187
|
+
await loginPage.login(email, password);
|
|
188
|
+
|
|
189
|
+
await expect(page).toHaveURL('/dashboard');
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
test('should show error on invalid credentials', async ({ page }) => {
|
|
193
|
+
const loginPage = new LoginPage(page);
|
|
194
|
+
await loginPage.goto();
|
|
195
|
+
await loginPage.login('wrong@email.com', 'wrongpassword');
|
|
196
|
+
|
|
197
|
+
await loginPage.expectError('Invalid credentials');
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Running E2E Tests
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
# Run all E2E tests
|
|
206
|
+
bunx playwright test
|
|
207
|
+
|
|
208
|
+
# Run with UI mode
|
|
209
|
+
bunx playwright test --ui
|
|
210
|
+
|
|
211
|
+
# Run specific file
|
|
212
|
+
bunx playwright test tests/e2e/flows/auth.spec.ts
|
|
213
|
+
|
|
214
|
+
# Run in headed mode
|
|
215
|
+
bunx playwright test --headed
|
|
216
|
+
|
|
217
|
+
# Debug mode
|
|
218
|
+
bunx playwright test --debug
|
|
219
|
+
|
|
220
|
+
# Generate report
|
|
221
|
+
bunx playwright show-report
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## Selectors Best Practices
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
// GOOD - Semantic selectors
|
|
228
|
+
page.getByRole('button', { name: 'Submit' });
|
|
229
|
+
page.getByLabel('Email');
|
|
230
|
+
page.getByPlaceholder('Enter email');
|
|
231
|
+
page.getByTestId('submit-button');
|
|
232
|
+
page.getByText('Welcome');
|
|
233
|
+
|
|
234
|
+
// AVOID - Brittle selectors
|
|
235
|
+
page.locator('.btn-primary');
|
|
236
|
+
page.locator('#submit');
|
|
237
|
+
page.locator('div > span > button');
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## Critical Rules
|
|
241
|
+
|
|
242
|
+
1. **CLEANUP IS MANDATORY** - Track and delete all created data
|
|
243
|
+
2. **UNIQUE TEST DATA** - Use timestamps in identifiers
|
|
244
|
+
3. **DATABASE VERIFICATION** - Don't trust UI alone
|
|
245
|
+
4. **PAGE OBJECTS** - For reusable page interactions
|
|
246
|
+
5. **NO .skip()** - Never commit skipped tests
|
|
247
|
+
6. **MULTI-VIEWPORT** - Test on all device sizes
|