start-vibing 3.0.7 → 3.0.9
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 +64 -51
- package/package.json +1 -1
- package/template/.claude/CLAUDE.md +717 -229
- package/template/.claude/agents/claude-md-compactor.md +2 -14
- package/template/.claude/agents/documenter.md +0 -7
- package/template/.claude/agents/domain-updater.md +2 -7
- package/template/.claude/config/README.md +10 -8
- package/template/.claude/config/domain-mapping.json +1 -1
- package/template/.claude/settings.json +0 -129
- package/template/.claude/skills/api-docs/SKILL.md +206 -0
- package/template/.claude/skills/claude-seo/SKILL.md +84 -0
- package/template/.claude/skills/codebase-knowledge/domains/claude-system.md +51 -416
- package/template/.claude/skills/codebase-knowledge/domains/mcp-integration.md +37 -204
- package/template/.claude/skills/mongoose-patterns/SKILL.md +141 -452
- package/template/.claude/skills/playwright-testing/SKILL.md +251 -0
- package/template/.claude/skills/skill-creator/SKILL.md +106 -0
- package/template/.claude/skills/test-infrastructure/SKILL.md +242 -0
- package/template/CLAUDE.md +65 -701
- package/template/.claude/agents/_archive/01-orchestration/agent-selector.md +0 -130
- package/template/.claude/agents/_archive/01-orchestration/checkpoint-manager.md +0 -142
- package/template/.claude/agents/_archive/01-orchestration/context-manager.md +0 -138
- package/template/.claude/agents/_archive/01-orchestration/error-recovery.md +0 -182
- package/template/.claude/agents/_archive/01-orchestration/orchestrator.md +0 -114
- package/template/.claude/agents/_archive/01-orchestration/parallel-coordinator.md +0 -141
- package/template/.claude/agents/_archive/01-orchestration/task-decomposer.md +0 -121
- package/template/.claude/agents/_archive/01-orchestration/workflow-router.md +0 -119
- package/template/.claude/agents/_archive/02-typescript/bun-runtime-expert.md +0 -197
- package/template/.claude/agents/_archive/02-typescript/esm-resolver.md +0 -193
- package/template/.claude/agents/_archive/02-typescript/import-alias-enforcer.md +0 -158
- package/template/.claude/agents/_archive/02-typescript/ts-generics-helper.md +0 -183
- package/template/.claude/agents/_archive/02-typescript/ts-migration-helper.md +0 -238
- package/template/.claude/agents/_archive/02-typescript/ts-strict-checker.md +0 -180
- package/template/.claude/agents/_archive/02-typescript/ts-types-analyzer.md +0 -199
- package/template/.claude/agents/_archive/02-typescript/type-definition-writer.md +0 -187
- package/template/.claude/agents/_archive/02-typescript/zod-schema-designer.md +0 -212
- package/template/.claude/agents/_archive/02-typescript/zod-validator.md +0 -158
- package/template/.claude/agents/_archive/03-testing/playwright-assertions.md +0 -265
- package/template/.claude/agents/_archive/03-testing/playwright-e2e.md +0 -247
- package/template/.claude/agents/_archive/03-testing/playwright-fixtures.md +0 -234
- package/template/.claude/agents/_archive/03-testing/playwright-multi-viewport.md +0 -256
- package/template/.claude/agents/_archive/03-testing/playwright-page-objects.md +0 -247
- package/template/.claude/agents/_archive/03-testing/test-cleanup-manager.md +0 -248
- package/template/.claude/agents/_archive/03-testing/test-data-generator.md +0 -254
- package/template/.claude/agents/_archive/03-testing/tester-integration.md +0 -278
- package/template/.claude/agents/_archive/03-testing/tester-unit.md +0 -207
- package/template/.claude/agents/_archive/03-testing/vitest-config.md +0 -287
- package/template/.claude/agents/_archive/04-docker/container-health.md +0 -255
- package/template/.claude/agents/_archive/04-docker/deployment-validator.md +0 -225
- package/template/.claude/agents/_archive/04-docker/docker-compose-designer.md +0 -281
- package/template/.claude/agents/_archive/04-docker/docker-env-manager.md +0 -235
- package/template/.claude/agents/_archive/04-docker/docker-multi-stage.md +0 -241
- package/template/.claude/agents/_archive/04-docker/dockerfile-optimizer.md +0 -208
- package/template/.claude/agents/_archive/05-database/database-seeder.md +0 -273
- package/template/.claude/agents/_archive/05-database/mongodb-query-optimizer.md +0 -230
- package/template/.claude/agents/_archive/05-database/mongoose-aggregation.md +0 -306
- package/template/.claude/agents/_archive/05-database/mongoose-index-optimizer.md +0 -182
- package/template/.claude/agents/_archive/05-database/mongoose-schema-designer.md +0 -267
- package/template/.claude/agents/_archive/06-security/auth-session-validator.md +0 -68
- package/template/.claude/agents/_archive/06-security/input-sanitizer.md +0 -80
- package/template/.claude/agents/_archive/06-security/owasp-checker.md +0 -97
- package/template/.claude/agents/_archive/06-security/permission-auditor.md +0 -100
- package/template/.claude/agents/_archive/06-security/security-auditor.md +0 -84
- package/template/.claude/agents/_archive/06-security/sensitive-data-scanner.md +0 -83
- package/template/.claude/agents/_archive/07-documentation/api-documenter.md +0 -136
- package/template/.claude/agents/_archive/07-documentation/changelog-manager.md +0 -105
- package/template/.claude/agents/_archive/07-documentation/claude-md-compactor.md +0 -214
- package/template/.claude/agents/_archive/07-documentation/documenter.md +0 -184
- package/template/.claude/agents/_archive/07-documentation/domain-updater.md +0 -138
- package/template/.claude/agents/_archive/07-documentation/jsdoc-generator.md +0 -114
- package/template/.claude/agents/_archive/07-documentation/readme-generator.md +0 -135
- package/template/.claude/agents/_archive/08-git/branch-manager.md +0 -58
- package/template/.claude/agents/_archive/08-git/commit-manager.md +0 -78
- package/template/.claude/agents/_archive/09-quality/code-reviewer.md +0 -71
- package/template/.claude/agents/_archive/09-quality/quality-checker.md +0 -67
- package/template/.claude/agents/_archive/10-research/best-practices-finder.md +0 -89
- package/template/.claude/agents/_archive/10-research/competitor-analyzer.md +0 -106
- package/template/.claude/agents/_archive/10-research/pattern-researcher.md +0 -93
- package/template/.claude/agents/_archive/10-research/research-cache-manager.md +0 -76
- package/template/.claude/agents/_archive/10-research/research-web.md +0 -98
- package/template/.claude/agents/_archive/10-research/tech-evaluator.md +0 -101
- package/template/.claude/agents/_archive/11-ui-ux/accessibility-auditor.md +0 -136
- package/template/.claude/agents/_archive/11-ui-ux/design-system-enforcer.md +0 -125
- package/template/.claude/agents/_archive/11-ui-ux/skeleton-generator.md +0 -118
- package/template/.claude/agents/_archive/11-ui-ux/ui-desktop.md +0 -132
- package/template/.claude/agents/_archive/11-ui-ux/ui-mobile.md +0 -125
- package/template/.claude/agents/_archive/11-ui-ux/ui-tablet.md +0 -110
- package/template/.claude/agents/_archive/12-performance/api-latency-analyzer.md +0 -156
- package/template/.claude/agents/_archive/12-performance/bundle-analyzer.md +0 -113
- package/template/.claude/agents/_archive/12-performance/memory-leak-detector.md +0 -137
- package/template/.claude/agents/_archive/12-performance/performance-profiler.md +0 -115
- package/template/.claude/agents/_archive/12-performance/query-optimizer.md +0 -124
- package/template/.claude/agents/_archive/12-performance/render-optimizer.md +0 -154
- package/template/.claude/agents/_archive/13-debugging/build-error-fixer.md +0 -207
- package/template/.claude/agents/_archive/13-debugging/debugger.md +0 -149
- package/template/.claude/agents/_archive/13-debugging/error-stack-analyzer.md +0 -141
- package/template/.claude/agents/_archive/13-debugging/network-debugger.md +0 -208
- package/template/.claude/agents/_archive/13-debugging/runtime-error-fixer.md +0 -181
- package/template/.claude/agents/_archive/13-debugging/type-error-resolver.md +0 -185
- package/template/.claude/agents/_archive/14-validation/final-validator.md +0 -93
- package/template/.claude/agents/_archive/_backup/analyzer.md +0 -134
- package/template/.claude/agents/_archive/_backup/code-reviewer.md +0 -279
- package/template/.claude/agents/_archive/_backup/commit-manager.md +0 -219
- package/template/.claude/agents/_archive/_backup/debugger.md +0 -280
- package/template/.claude/agents/_archive/_backup/documenter.md +0 -237
- package/template/.claude/agents/_archive/_backup/domain-updater.md +0 -197
- package/template/.claude/agents/_archive/_backup/final-validator.md +0 -169
- package/template/.claude/agents/_archive/_backup/orchestrator.md +0 -149
- package/template/.claude/agents/_archive/_backup/performance.md +0 -232
- package/template/.claude/agents/_archive/_backup/quality-checker.md +0 -240
- package/template/.claude/agents/_archive/_backup/research.md +0 -315
- package/template/.claude/agents/_archive/_backup/security-auditor.md +0 -192
- package/template/.claude/agents/_archive/_backup/tester.md +0 -566
- package/template/.claude/agents/_archive/_backup/ui-ux-reviewer.md +0 -247
- package/template/.claude/commands/feature.md +0 -48
- package/template/.claude/commands/fix.md +0 -80
- package/template/.claude/commands/research.md +0 -107
- package/template/.claude/commands/validate.md +0 -72
- package/template/.claude/config/mcp-config.json +0 -344
- package/template/.claude/hooks/SETUP.md +0 -126
- package/template/.claude/hooks/run-hook.cmd +0 -46
- package/template/.claude/hooks/run-hook.sh +0 -43
- package/template/.claude/hooks/run-hook.ts +0 -230
- package/template/.claude/hooks/security-check.js +0 -202
- package/template/.claude/hooks/stop-validator.ts +0 -1667
- package/template/.claude/hooks/user-prompt-submit.ts +0 -104
- package/template/.claude/scripts/mcp-quick-install.ts +0 -151
- package/template/.claude/scripts/setup-mcps.ts +0 -651
- package/template/.claude/skills/hook-development/SKILL.md +0 -343
- package/template/.claude/skills/playwright-automation/SKILL.md +0 -438
|
@@ -1,234 +0,0 @@
|
|
|
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,256 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: playwright-multi-viewport
|
|
3
|
-
description: 'AUTOMATICALLY invoke AFTER any UI implementation. Triggers: UI feature implemented, responsive design, component created. Tests on desktop (1280px), tablet (768px), and mobile (375px) viewports. PROACTIVELY ensures cross-device compatibility.'
|
|
4
|
-
model: sonnet
|
|
5
|
-
tools: Read, Write, Edit, Bash, Grep, Glob
|
|
6
|
-
skills: test-coverage, playwright-automation
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
# Playwright Multi-Viewport Agent
|
|
10
|
-
|
|
11
|
-
You create tests that run across multiple device viewports.
|
|
12
|
-
|
|
13
|
-
## Required Viewports (from CLAUDE.md)
|
|
14
|
-
|
|
15
|
-
| Platform | Width | Device | Key Features |
|
|
16
|
-
| -------- | ------- | --------- | ------------------------------- |
|
|
17
|
-
| Mobile | 375px | iPhone SE | Bottom nav, full-screen modals |
|
|
18
|
-
| Tablet | 768px | iPad | Collapsible sidebar, hybrid nav |
|
|
19
|
-
| Desktop | 1280px+ | Chrome | Sidebar + topbar, high density |
|
|
20
|
-
|
|
21
|
-
## Playwright Config
|
|
22
|
-
|
|
23
|
-
```typescript
|
|
24
|
-
// playwright.config.ts
|
|
25
|
-
import { defineConfig, devices } from '@playwright/test';
|
|
26
|
-
|
|
27
|
-
export default defineConfig({
|
|
28
|
-
testDir: './tests/e2e',
|
|
29
|
-
|
|
30
|
-
projects: [
|
|
31
|
-
// Desktop
|
|
32
|
-
{
|
|
33
|
-
name: 'Desktop Chrome',
|
|
34
|
-
use: { ...devices['Desktop Chrome'] },
|
|
35
|
-
},
|
|
36
|
-
|
|
37
|
-
// Tablet
|
|
38
|
-
{
|
|
39
|
-
name: 'iPad',
|
|
40
|
-
use: { ...devices['iPad'] },
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
name: 'iPad landscape',
|
|
44
|
-
use: { ...devices['iPad landscape'] },
|
|
45
|
-
},
|
|
46
|
-
|
|
47
|
-
// Mobile
|
|
48
|
-
{
|
|
49
|
-
name: 'iPhone SE',
|
|
50
|
-
use: { ...devices['iPhone SE'] },
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
name: 'iPhone 14',
|
|
54
|
-
use: { ...devices['iPhone 14'] },
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
name: 'iPhone 14 landscape',
|
|
58
|
-
use: { ...devices['iPhone 14 landscape'] },
|
|
59
|
-
},
|
|
60
|
-
],
|
|
61
|
-
});
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
## Viewport-Aware Tests
|
|
65
|
-
|
|
66
|
-
```typescript
|
|
67
|
-
// tests/e2e/flows/responsive.spec.ts
|
|
68
|
-
import { test, expect } from '../fixtures';
|
|
69
|
-
|
|
70
|
-
test.describe('Responsive Navigation', () => {
|
|
71
|
-
test('should show correct navigation', async ({ page, isMobile }) => {
|
|
72
|
-
await page.goto('/');
|
|
73
|
-
|
|
74
|
-
if (isMobile) {
|
|
75
|
-
// MOBILE: Bottom nav, hamburger menu
|
|
76
|
-
await expect(page.getByTestId('bottom-nav')).toBeVisible();
|
|
77
|
-
await expect(page.getByTestId('hamburger-menu')).toBeVisible();
|
|
78
|
-
await expect(page.getByTestId('desktop-sidebar')).toBeHidden();
|
|
79
|
-
|
|
80
|
-
// Open mobile menu
|
|
81
|
-
await page.getByTestId('hamburger-menu').click();
|
|
82
|
-
await expect(page.getByTestId('mobile-menu')).toBeVisible();
|
|
83
|
-
} else {
|
|
84
|
-
// DESKTOP/TABLET: Sidebar visible
|
|
85
|
-
await expect(page.getByTestId('desktop-sidebar')).toBeVisible();
|
|
86
|
-
await expect(page.getByTestId('hamburger-menu')).toBeHidden();
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
});
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
## Viewport-Specific Tests
|
|
93
|
-
|
|
94
|
-
```typescript
|
|
95
|
-
test.describe('Mobile-Only Tests', () => {
|
|
96
|
-
test.skip(({ isMobile }) => !isMobile, 'Mobile only');
|
|
97
|
-
|
|
98
|
-
test('should have bottom navigation', async ({ page }) => {
|
|
99
|
-
await page.goto('/');
|
|
100
|
-
await expect(page.getByTestId('bottom-nav')).toBeVisible();
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
test('should open full-screen modal', async ({ page }) => {
|
|
104
|
-
await page.goto('/');
|
|
105
|
-
await page.getByTestId('search-icon').click();
|
|
106
|
-
|
|
107
|
-
const modal = page.getByTestId('search-modal');
|
|
108
|
-
await expect(modal).toBeVisible();
|
|
109
|
-
|
|
110
|
-
// Verify full-screen
|
|
111
|
-
const box = await modal.boundingBox();
|
|
112
|
-
const viewport = page.viewportSize()!;
|
|
113
|
-
expect(box?.width).toBe(viewport.width);
|
|
114
|
-
expect(box?.height).toBe(viewport.height);
|
|
115
|
-
});
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
test.describe('Desktop-Only Tests', () => {
|
|
119
|
-
test.skip(({ isMobile }) => isMobile, 'Desktop only');
|
|
120
|
-
|
|
121
|
-
test('should have sidebar with search bar', async ({ page }) => {
|
|
122
|
-
await page.goto('/');
|
|
123
|
-
await expect(page.getByTestId('sidebar')).toBeVisible();
|
|
124
|
-
await expect(page.getByTestId('topbar-search')).toBeVisible();
|
|
125
|
-
});
|
|
126
|
-
});
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
## Custom Viewport Detection
|
|
130
|
-
|
|
131
|
-
```typescript
|
|
132
|
-
// tests/e2e/fixtures/viewport.fixture.ts
|
|
133
|
-
import { test as base } from '@playwright/test';
|
|
134
|
-
|
|
135
|
-
type ViewportType = 'mobile' | 'tablet' | 'desktop';
|
|
136
|
-
|
|
137
|
-
type ViewportFixture = {
|
|
138
|
-
viewportType: ViewportType;
|
|
139
|
-
isMobile: boolean;
|
|
140
|
-
isTablet: boolean;
|
|
141
|
-
isDesktop: boolean;
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
export const viewportFixture = base.extend<ViewportFixture>({
|
|
145
|
-
viewportType: async ({ page }, use) => {
|
|
146
|
-
const width = page.viewportSize()?.width || 1280;
|
|
147
|
-
if (width < 768) {
|
|
148
|
-
await use('mobile');
|
|
149
|
-
} else if (width < 1024) {
|
|
150
|
-
await use('tablet');
|
|
151
|
-
} else {
|
|
152
|
-
await use('desktop');
|
|
153
|
-
}
|
|
154
|
-
},
|
|
155
|
-
|
|
156
|
-
isMobile: async ({ viewportType }, use) => {
|
|
157
|
-
await use(viewportType === 'mobile');
|
|
158
|
-
},
|
|
159
|
-
|
|
160
|
-
isTablet: async ({ viewportType }, use) => {
|
|
161
|
-
await use(viewportType === 'tablet');
|
|
162
|
-
},
|
|
163
|
-
|
|
164
|
-
isDesktop: async ({ viewportType }, use) => {
|
|
165
|
-
await use(viewportType === 'desktop');
|
|
166
|
-
},
|
|
167
|
-
});
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
## Cross-Viewport Test Pattern
|
|
171
|
-
|
|
172
|
-
```typescript
|
|
173
|
-
test.describe('Feature works on all viewports', () => {
|
|
174
|
-
test('should complete checkout flow', async ({ page, isMobile, isTablet, isDesktop }) => {
|
|
175
|
-
await page.goto('/products');
|
|
176
|
-
|
|
177
|
-
// Add to cart (different buttons per viewport)
|
|
178
|
-
if (isMobile) {
|
|
179
|
-
await page.getByTestId('product-card').first().tap();
|
|
180
|
-
await page.getByTestId('add-to-cart-mobile').tap();
|
|
181
|
-
} else {
|
|
182
|
-
await page.getByTestId('product-card').first().hover();
|
|
183
|
-
await page.getByTestId('quick-add').click();
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// Verify cart
|
|
187
|
-
await expect(page.getByTestId('cart-count')).toHaveText('1');
|
|
188
|
-
|
|
189
|
-
// Go to checkout
|
|
190
|
-
if (isMobile) {
|
|
191
|
-
await page.getByTestId('bottom-nav-cart').tap();
|
|
192
|
-
} else {
|
|
193
|
-
await page.getByTestId('header-cart').click();
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
await expect(page).toHaveURL('/checkout');
|
|
197
|
-
});
|
|
198
|
-
});
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
## Visual Regression Per Viewport
|
|
202
|
-
|
|
203
|
-
```typescript
|
|
204
|
-
test.describe('Visual Snapshots', () => {
|
|
205
|
-
test('homepage matches snapshot', async ({ page }, testInfo) => {
|
|
206
|
-
await page.goto('/');
|
|
207
|
-
await page.waitForLoadState('networkidle');
|
|
208
|
-
|
|
209
|
-
// Snapshot includes project name (viewport)
|
|
210
|
-
await expect(page).toHaveScreenshot(`homepage-${testInfo.project.name}.png`);
|
|
211
|
-
});
|
|
212
|
-
});
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
## Running Multi-Viewport Tests
|
|
216
|
-
|
|
217
|
-
```bash
|
|
218
|
-
# Run all viewports
|
|
219
|
-
bunx playwright test
|
|
220
|
-
|
|
221
|
-
# Run specific viewport
|
|
222
|
-
bunx playwright test --project="iPhone SE"
|
|
223
|
-
|
|
224
|
-
# Run mobile only
|
|
225
|
-
bunx playwright test --project="iPhone SE" --project="iPhone 14"
|
|
226
|
-
|
|
227
|
-
# Run desktop only
|
|
228
|
-
bunx playwright test --project="Desktop Chrome"
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
## Viewport Checklist
|
|
232
|
-
|
|
233
|
-
```markdown
|
|
234
|
-
### Feature: [name]
|
|
235
|
-
|
|
236
|
-
- [ ] Desktop (1280px+)
|
|
237
|
-
- [ ] Sidebar visible
|
|
238
|
-
- [ ] Topbar with search
|
|
239
|
-
- [ ] Hover interactions work
|
|
240
|
-
- [ ] Tablet (768px)
|
|
241
|
-
- [ ] Collapsible sidebar works
|
|
242
|
-
- [ ] Touch + click both work
|
|
243
|
-
- [ ] Mobile (375px)
|
|
244
|
-
- [ ] Bottom nav visible
|
|
245
|
-
- [ ] No horizontal scroll
|
|
246
|
-
- [ ] Touch targets 44x44px+
|
|
247
|
-
- [ ] Full-screen modals work
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
## Critical Rules
|
|
251
|
-
|
|
252
|
-
1. **TEST ALL VIEWPORTS** - Desktop, tablet, mobile minimum
|
|
253
|
-
2. **SEPARATE UIs** - Not just responsive (from CLAUDE.md)
|
|
254
|
-
3. **TOUCH TARGETS** - 44x44px minimum on mobile
|
|
255
|
-
4. **NO HORIZONTAL SCROLL** - Never on mobile
|
|
256
|
-
5. **VIEWPORT-SPECIFIC LOGIC** - Use isMobile/isTablet/isDesktop
|