agent-bober 0.4.2 → 0.5.0
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 +60 -4
- package/agents/bober-evaluator.md +84 -8
- package/agents/bober-generator.md +102 -0
- package/agents/bober-planner.md +24 -0
- package/dist/cli/commands/init.js +1 -0
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/evaluators/builtin/playwright.d.ts +11 -0
- package/dist/evaluators/builtin/playwright.d.ts.map +1 -1
- package/dist/evaluators/builtin/playwright.js +259 -12
- package/dist/evaluators/builtin/playwright.js.map +1 -1
- package/package.json +1 -1
- package/skills/bober.eval/SKILL.md +145 -148
- package/skills/bober.playwright/SKILL.md +429 -0
- package/skills/bober.playwright/references/playwright-patterns.md +377 -0
- package/skills/bober.run/SKILL.md +433 -119
- package/skills/bober.sprint/SKILL.md +147 -57
- package/templates/presets/nextjs/bober.config.json +2 -1
|
@@ -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.
|