agent-bober 0.4.3 → 0.5.1

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.
@@ -0,0 +1,429 @@
1
+ ---
2
+ name: bober.playwright
3
+ description: "Set up Playwright E2E testing and generate test files for your project. Use to initialize Playwright config, write E2E tests for existing UI, or debug failing E2E tests."
4
+ argument-hint: "[what to test or 'setup' to initialize]"
5
+ handoffs:
6
+ - label: "Evaluate with E2E"
7
+ command: /bober-eval
8
+ prompt: "Run evaluation including Playwright E2E tests"
9
+ ---
10
+
11
+ # bober.playwright — Playwright E2E Testing Skill
12
+
13
+ You are running the **bober.playwright** skill. Your job is to set up Playwright end-to-end testing in the project, generate robust E2E test files for UI features, or debug failing E2E tests. This skill operates in three modes depending on the argument provided.
14
+
15
+ ## Mode Detection
16
+
17
+ Determine the mode from the argument:
18
+
19
+ - **`setup`** or no argument with no existing `playwright.config.ts` -> **Setup Mode**
20
+ - **`debug`** -> **Debug Mode**
21
+ - **Any other argument** (e.g., `"test the login flow"`, `"test the dashboard"`) -> **Generate Tests Mode**
22
+
23
+ ---
24
+
25
+ ## Mode 1: Setup (`/bober-playwright setup`)
26
+
27
+ Initialize Playwright E2E testing infrastructure in the project.
28
+
29
+ ### Step 1: Check Prerequisites
30
+
31
+ 1. Verify `package.json` exists (this is a Node.js project).
32
+ 2. Check if Playwright is already installed:
33
+ ```bash
34
+ grep -q '@playwright/test' package.json 2>/dev/null
35
+ ```
36
+ 3. If already installed, inform the user and ask if they want to reconfigure.
37
+
38
+ ### Step 2: Install Playwright
39
+
40
+ ```bash
41
+ npm install -D @playwright/test
42
+ npx playwright install chromium
43
+ ```
44
+
45
+ Only install `chromium` — it is the fastest and most reliable for CI. Users can add more browsers later.
46
+
47
+ ### Step 3: Read Project Configuration
48
+
49
+ Read `bober.config.json` to determine:
50
+ - `commands.dev`: The dev server start command (e.g., `npm run dev`)
51
+ - The dev server port: Parse it from the dev command or default to `3000`
52
+
53
+ Also check for common framework configurations:
54
+ - `vite.config.ts` -> default port is typically `5173`
55
+ - `next.config.js` / `next.config.ts` -> default port is typically `3000`
56
+ - `package.json` scripts -> look for port flags in the dev command
57
+
58
+ ### Step 4: Create `playwright.config.ts`
59
+
60
+ Create the Playwright configuration file at the project root:
61
+
62
+ ```typescript
63
+ import { defineConfig, devices } from '@playwright/test';
64
+
65
+ /**
66
+ * Playwright E2E test configuration.
67
+ * Generated by bober.playwright — edit freely.
68
+ *
69
+ * @see https://playwright.dev/docs/test-configuration
70
+ */
71
+ export default defineConfig({
72
+ testDir: './e2e',
73
+ fullyParallel: false,
74
+ forbidOnly: !!process.env.CI,
75
+ retries: 1,
76
+ workers: 1,
77
+ reporter: [
78
+ ['list'],
79
+ ['json', { outputFile: 'e2e-results/results.json' }],
80
+ ],
81
+ use: {
82
+ baseURL: 'http://localhost:<PORT>',
83
+ trace: 'on-first-retry',
84
+ screenshot: 'only-on-failure',
85
+ },
86
+ projects: [
87
+ {
88
+ name: 'chromium',
89
+ use: { ...devices['Desktop Chrome'] },
90
+ },
91
+ ],
92
+ webServer: {
93
+ command: '<DEV_COMMAND>',
94
+ port: <PORT>,
95
+ reuseExistingServer: !process.env.CI,
96
+ timeout: 30_000,
97
+ },
98
+ });
99
+ ```
100
+
101
+ Replace `<PORT>` with the detected port and `<DEV_COMMAND>` with the dev command from `bober.config.json` (e.g., `npm run dev`).
102
+
103
+ ### Step 5: Create the `e2e/` Directory and Example Test
104
+
105
+ Create `e2e/example.spec.ts`:
106
+
107
+ ```typescript
108
+ import { test, expect } from '@playwright/test';
109
+
110
+ test.describe('Smoke Test', () => {
111
+ test('page loads successfully', async ({ page }) => {
112
+ await page.goto('/');
113
+ await page.waitForLoadState('networkidle');
114
+
115
+ // Verify the page has a title
116
+ const title = await page.title();
117
+ expect(title).toBeTruthy();
118
+ });
119
+
120
+ test('page has no console errors', async ({ page }) => {
121
+ const errors: string[] = [];
122
+ page.on('console', (msg) => {
123
+ if (msg.type() === 'error') {
124
+ errors.push(msg.text());
125
+ }
126
+ });
127
+
128
+ await page.goto('/');
129
+ await page.waitForLoadState('networkidle');
130
+
131
+ expect(errors).toEqual([]);
132
+ });
133
+ });
134
+ ```
135
+
136
+ ### Step 6: Create `e2e-results/` Directory and Update `.gitignore`
137
+
138
+ ```bash
139
+ mkdir -p e2e-results
140
+ ```
141
+
142
+ Add to `.gitignore` (check if entries already exist before appending):
143
+ ```
144
+ # Playwright
145
+ e2e-results/
146
+ test-results/
147
+ playwright-report/
148
+ blob-report/
149
+ ```
150
+
151
+ ### Step 7: Verify the Setup
152
+
153
+ Run Playwright to confirm the installation works:
154
+
155
+ ```bash
156
+ npx playwright test --reporter=list 2>&1 | head -50
157
+ ```
158
+
159
+ If the dev server fails to start, report the error and suggest the user verify their `commands.dev` configuration.
160
+
161
+ ### Step 8: Report
162
+
163
+ ```
164
+ ## Playwright Setup Complete
165
+
166
+ - Installed: @playwright/test + chromium browser
167
+ - Config: playwright.config.ts (baseURL: http://localhost:<PORT>)
168
+ - Test directory: e2e/
169
+ - Example test: e2e/example.spec.ts
170
+ - Results output: e2e-results/results.json
171
+
172
+ ### Run Tests
173
+ npx playwright test # run all E2E tests
174
+ npx playwright test --ui # open interactive UI mode
175
+ npx playwright test --reporter=list # run with detailed output
176
+
177
+ ### Next Steps
178
+ - Write E2E tests: /bober-playwright "test the <feature>"
179
+ - Run full evaluation: /bober-eval
180
+ ```
181
+
182
+ ---
183
+
184
+ ## Mode 2: Generate Tests (`/bober-playwright "test the login flow"`)
185
+
186
+ Generate Playwright E2E test files that verify specific UI features.
187
+
188
+ ### Step 1: Verify Playwright is Installed
189
+
190
+ Check for `playwright.config.ts` at the project root. If it does not exist:
191
+ - Tell the user to run `/bober-playwright setup` first
192
+ - Stop execution
193
+
194
+ ### Step 2: Understand What to Test
195
+
196
+ 1. Read the user's argument to understand the target feature
197
+ 2. Read the current sprint contract from `.bober/contracts/` (most recent `in-progress` contract):
198
+ - Extract `successCriteria` that relate to UI behavior
199
+ - Note the `estimatedFiles` to understand which source files are relevant
200
+ 3. If no sprint contract exists, use the user's description directly
201
+
202
+ ### Step 3: Read Relevant Source Files
203
+
204
+ Based on the sprint contract and user description:
205
+ 1. Read the UI component files that implement the feature
206
+ 2. Read the routing configuration (e.g., `App.tsx`, `app/` directory for Next.js)
207
+ 3. Read any API endpoints the UI interacts with
208
+ 4. Note existing `data-testid` attributes in the source code
209
+
210
+ ### Step 4: Generate Test Files
211
+
212
+ Create test files in `e2e/` following these rules:
213
+
214
+ **File naming:** `e2e/<feature-slug>.spec.ts`
215
+
216
+ **Structure:**
217
+ ```typescript
218
+ import { test, expect } from '@playwright/test';
219
+
220
+ test.describe('Feature: <Feature Name>', () => {
221
+ test.beforeEach(async ({ page }) => {
222
+ // Navigate to the feature's page
223
+ await page.goto('/<route>');
224
+ await page.waitForLoadState('networkidle');
225
+ });
226
+
227
+ test('<success criterion description>', async ({ page }) => {
228
+ // Use data-testid selectors exclusively
229
+ const element = page.getByTestId('<testid>');
230
+ await expect(element).toBeVisible();
231
+
232
+ // Perform user actions
233
+ await page.getByTestId('<input-testid>').fill('test value');
234
+ await page.getByTestId('<submit-testid>').click();
235
+
236
+ // Assert outcomes
237
+ await expect(page.getByTestId('<result-testid>')).toBeVisible();
238
+ await expect(page.getByTestId('<result-testid>')).toHaveText(/expected text/);
239
+ });
240
+ });
241
+ ```
242
+
243
+ **Selector rules (non-negotiable):**
244
+ - Use `page.getByTestId('...')` for all element selectors
245
+ - Never use CSS selectors (`page.locator('.class-name')`)
246
+ - Never use tag name selectors (`page.locator('button')`)
247
+ - Use `page.getByRole(...)` or `page.getByText(...)` only as a fallback when `data-testid` is genuinely not appropriate (e.g., checking visible text content)
248
+
249
+ **Assertion patterns:**
250
+ - Use `await expect(locator).toBeVisible()` for visibility checks
251
+ - Use `await expect(locator).toHaveText(...)` for text content
252
+ - Use `await expect(locator).toHaveAttribute(...)` for attribute checks
253
+ - Use `await expect(page).toHaveURL(...)` for navigation assertions
254
+ - Use `await expect(locator).toBeDisabled()` / `toBeEnabled()` for interactive state
255
+ - Never use raw `expect(await locator.textContent()).toBe(...)` -- use Playwright's auto-waiting assertions
256
+
257
+ **Wait patterns:**
258
+ - Use `page.waitForLoadState('networkidle')` after navigation in SPAs
259
+ - Use `await expect(locator).toBeVisible()` instead of manual waits for element appearance
260
+ - Use `page.waitForResponse(...)` when waiting for specific API calls
261
+ - Never use `page.waitForTimeout()` -- it is flaky and unreliable
262
+
263
+ ### Step 5: Check for Missing `data-testid` Attributes
264
+
265
+ After generating tests, check if the source components have the required `data-testid` attributes.
266
+
267
+ For each `data-testid` used in tests, search the source files:
268
+ ```bash
269
+ grep -r 'data-testid="<testid>"' src/ app/ components/ 2>/dev/null
270
+ ```
271
+
272
+ If any are missing, list them clearly:
273
+
274
+ ```
275
+ ## Missing data-testid Attributes
276
+
277
+ The following data-testid attributes must be added to your components
278
+ for these tests to work:
279
+
280
+ - `data-testid="login-form"` -> src/components/LoginForm.tsx
281
+ - `data-testid="email-input"` -> src/components/LoginForm.tsx
282
+ - `data-testid="submit-button"` -> src/components/LoginForm.tsx
283
+ - `data-testid="error-message"` -> src/components/LoginForm.tsx
284
+
285
+ The generator must add these attributes in the next sprint iteration.
286
+ ```
287
+
288
+ ### Step 6: Verify Tests Are Syntactically Valid
289
+
290
+ Run a quick check:
291
+ ```bash
292
+ npx playwright test --list 2>&1
293
+ ```
294
+
295
+ This lists all discovered tests without executing them. If there are syntax errors, fix them.
296
+
297
+ ### Step 7: Report
298
+
299
+ ```
300
+ ## E2E Tests Generated
301
+
302
+ Created: e2e/<feature-slug>.spec.ts
303
+ Tests: <N> test cases covering <M> success criteria
304
+
305
+ ### Test Cases
306
+ 1. <criterion> -> <test description>
307
+ 2. <criterion> -> <test description>
308
+ ...
309
+
310
+ ### Missing data-testid Attributes
311
+ <list if any>
312
+
313
+ ### Run Tests
314
+ npx playwright test e2e/<feature-slug>.spec.ts --reporter=list
315
+ ```
316
+
317
+ ---
318
+
319
+ ## Mode 3: Debug (`/bober-playwright debug`)
320
+
321
+ Analyze failing Playwright tests and provide actionable diagnostic information.
322
+
323
+ ### Step 1: Find Test Results
324
+
325
+ Look for test results in this order:
326
+ 1. `e2e-results/results.json` (JSON reporter output)
327
+ 2. `test-results/` directory (Playwright default output with screenshots/traces)
328
+ 3. If neither exists, run the tests:
329
+ ```bash
330
+ npx playwright test --reporter=json 2>e2e-results/results.json
331
+ ```
332
+
333
+ ### Step 2: Parse Results
334
+
335
+ Read `e2e-results/results.json` and extract:
336
+ - Total tests, passed, failed, skipped
337
+ - For each failed test:
338
+ - Test name and file location
339
+ - Error message and stack trace
340
+ - Screenshot path (if available in `test-results/`)
341
+ - Trace file path (if available)
342
+
343
+ ### Step 3: Analyze Failures
344
+
345
+ For each failed test, determine the likely cause:
346
+
347
+ **Category 1: Selector failures** (`locator.click: Error: strict mode violation` or `waiting for locator`)
348
+ - The `data-testid` attribute is missing from the DOM
349
+ - The element exists but is not visible
350
+ - The element has not rendered yet (timing issue)
351
+ - Suggestion: Check if the component renders the element with the expected `data-testid`
352
+
353
+ **Category 2: Assertion failures** (`expect(received).toHaveText(expected)`)
354
+ - The text content does not match the expected value
355
+ - Suggestion: Check the component's rendered output, verify data flow
356
+
357
+ **Category 3: Navigation failures** (`page.goto: net::ERR_CONNECTION_REFUSED`)
358
+ - The dev server is not running or not reachable
359
+ - The port is wrong
360
+ - Suggestion: Check `playwright.config.ts` webServer config and `bober.config.json` commands.dev
361
+
362
+ **Category 4: Timeout failures** (`Test exceeded timeout of 30000ms`)
363
+ - The page or element takes too long to load
364
+ - An API call is hanging
365
+ - An infinite loop or unresolved promise in the application
366
+ - Suggestion: Check network requests, look for hanging promises
367
+
368
+ **Category 5: JavaScript errors** (console errors captured in test)
369
+ - Runtime errors in the application code
370
+ - Missing environment variables
371
+ - Suggestion: Check the browser console output, look for unhandled errors
372
+
373
+ ### Step 4: Check Screenshots
374
+
375
+ If screenshots exist in `test-results/`:
376
+ ```bash
377
+ find test-results/ -name '*.png' 2>/dev/null
378
+ ```
379
+
380
+ List them with their associated test names so the user (or generator) can inspect them.
381
+
382
+ ### Step 5: Report
383
+
384
+ ```
385
+ ## Playwright Debug Report
386
+
387
+ ### Summary
388
+ - Total: <N> tests
389
+ - Passed: <N>
390
+ - Failed: <N>
391
+ - Skipped: <N>
392
+
393
+ ### Failures
394
+
395
+ #### 1. <Test Name>
396
+ - File: e2e/<file>.spec.ts:<line>
397
+ - Error: <error message>
398
+ - Category: <selector/assertion/navigation/timeout/runtime>
399
+ - Likely Cause: <analysis>
400
+ - Investigate: <which source file to look at>
401
+ - Screenshot: <path if available>
402
+
403
+ #### 2. <Test Name>
404
+ ...
405
+
406
+ ### Suggested Actions
407
+ - <action 1>
408
+ - <action 2>
409
+ ...
410
+
411
+ Note: This skill diagnoses failures but does not fix them.
412
+ Use /bober-sprint to have the generator fix the identified issues.
413
+ ```
414
+
415
+ ---
416
+
417
+ ## General Rules
418
+
419
+ 1. **Never generate tests that use CSS class selectors.** The `data-testid` requirement is non-negotiable when Playwright is the evaluation strategy. This produces stable, refactor-resistant tests.
420
+
421
+ 2. **Never use `page.waitForTimeout()`.** It introduces flakiness. Use Playwright's auto-waiting assertions or `waitForLoadState` / `waitForResponse` instead.
422
+
423
+ 3. **One test file per feature.** Do not create a single mega-test file. Map files to sprint features or logical UI areas.
424
+
425
+ 4. **Tests must be independent.** Each test should be able to run in isolation. Use `test.beforeEach` for common setup, not test ordering.
426
+
427
+ 5. **Handle authentication state.** If tests require a logged-in user, use Playwright's `storageState` to save and reuse auth cookies. Create an `e2e/auth.setup.ts` file for the auth flow and reference it as a setup project in `playwright.config.ts`.
428
+
429
+ 6. **Keep tests focused on user behavior.** Test what users see and do, not internal implementation details. "User can submit the form and see a success message" is a good test. "The Redux store dispatches ACTION_X" is a bad test.