devlyn-cli 1.4.0 → 1.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.
|
@@ -35,12 +35,32 @@ $ARGUMENTS
|
|
|
35
35
|
- `--port PORT` — override detected port
|
|
36
36
|
- `--tier N` — force a specific tier (1, 2, or 3)
|
|
37
37
|
- `--mobile-only` / `--desktop-only` — limit viewport testing
|
|
38
|
+
- `--topic SLUG` — override the auto-derived screenshot topic slug
|
|
39
|
+
|
|
40
|
+
8. **Derive the screenshot topic slug**. All screenshots for this run go under `.devlyn/screenshots/<topic-slug>/` so runs for different features don't pile up together. Resolution order:
|
|
41
|
+
1. `--topic` flag value, kebab-cased
|
|
42
|
+
2. First non-blank heading/line of `.devlyn/done-criteria.md` (strip `#`, kebab-case, max 40 chars)
|
|
43
|
+
3. Current git branch name, if not `main`/`master`/`HEAD`
|
|
44
|
+
4. Fallback: `run-<YYYYMMDD-HHMM>`
|
|
45
|
+
|
|
46
|
+
Then wipe and recreate the topic dir (fresh evidence per run; don't touch other topics' dirs):
|
|
47
|
+
```bash
|
|
48
|
+
SCREENSHOT_DIR=".devlyn/screenshots/<topic-slug>"
|
|
49
|
+
rm -rf "$SCREENSHOT_DIR"
|
|
50
|
+
mkdir -p "$SCREENSHOT_DIR"/{smoke,feature,visual}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Record `$SCREENSHOT_DIR` and reuse it through the run. All screenshot paths below are **relative to `$SCREENSHOT_DIR`**:
|
|
54
|
+
- Smoke: `smoke/<route-slug>.png` (root → `smoke/root.png`)
|
|
55
|
+
- Feature: `feature/<criterion-slug>-step<N>.png`
|
|
56
|
+
- Visual: `visual/<viewport>-<route-slug>.png` (e.g., `visual/mobile-dashboard.png`)
|
|
38
57
|
|
|
39
58
|
Announce:
|
|
40
59
|
```
|
|
41
60
|
Browser validation starting
|
|
42
61
|
Feature: [what was built, from done-criteria or git diff]
|
|
43
62
|
Framework: [detected] | Port: [PORT] | Tier: [N — name]
|
|
63
|
+
Topic: [topic-slug] → .devlyn/screenshots/<topic-slug>/
|
|
44
64
|
Phases: Server → Smoke → Feature Test → Visual → Report
|
|
45
65
|
```
|
|
46
66
|
|
|
@@ -71,7 +71,12 @@ Identify fields with `find` first, then use `form_input` with the field selector
|
|
|
71
71
|
```
|
|
72
72
|
computer → screenshot action captures the visible viewport
|
|
73
73
|
```
|
|
74
|
-
Save screenshots
|
|
74
|
+
Save screenshots into the topic-scoped directory that PHASE 1 set up (`.devlyn/screenshots/<topic-slug>/`), organized by phase:
|
|
75
|
+
- Smoke: `<topic>/smoke/<route>.png` — e.g., `smoke/root.png`, `smoke/dashboard.png`
|
|
76
|
+
- Feature: `<topic>/feature/<criterion>-step<N>.png` — e.g., `feature/create-project-step3.png`
|
|
77
|
+
- Visual: `<topic>/visual/<viewport>-<route>.png` — e.g., `visual/mobile-dashboard.png`
|
|
78
|
+
|
|
79
|
+
Since `computer → screenshot` writes to a default location, move/rename the captured file into the right subdirectory immediately after taking it, so evidence paths in the report match this scheme.
|
|
75
80
|
|
|
76
81
|
### Resize viewport
|
|
77
82
|
```
|
|
@@ -89,7 +89,10 @@ test.describe('Smoke Tests', () => {
|
|
|
89
89
|
const pageUrl = page.url();
|
|
90
90
|
expect(title, 'Page shows a browser error — server may be down').not.toBe(pageUrl);
|
|
91
91
|
|
|
92
|
-
await page.screenshot({ path:
|
|
92
|
+
await page.screenshot({ path: `${SCREENSHOT_DIR}/smoke/${route.replace(/^\//, '').replace(/\//g, '-') || 'root'}.png`, fullPage: true });
|
|
93
|
+
// SCREENSHOT_DIR is the topic-scoped dir set up in PHASE 1 of SKILL.md
|
|
94
|
+
// (e.g., .devlyn/screenshots/add-login-page). Inject it at test-generation
|
|
95
|
+
// time so every test writes into the same per-run folder.
|
|
93
96
|
|
|
94
97
|
if (errors.length > 0) {
|
|
95
98
|
test.info().annotations.push({ type: 'console_errors', description: errors.join(' | ') });
|
|
@@ -123,7 +126,7 @@ test('flow: [criterion description]', async ({ page }) => {
|
|
|
123
126
|
await expect(page.locator('[verification selector]')).toBeVisible();
|
|
124
127
|
|
|
125
128
|
// Screenshot
|
|
126
|
-
await page.screenshot({ path:
|
|
129
|
+
await page.screenshot({ path: `${SCREENSHOT_DIR}/feature/[criterion-slug]-step[N].png` });
|
|
127
130
|
});
|
|
128
131
|
```
|
|
129
132
|
|
|
@@ -135,7 +138,7 @@ test.describe('Visual - Mobile', () => {
|
|
|
135
138
|
for (const route of ROUTES) {
|
|
136
139
|
test(`visual-mobile: ${route}`, async ({ page }) => {
|
|
137
140
|
await page.goto(`http://localhost:${PORT}${route}`, { waitUntil: 'networkidle' });
|
|
138
|
-
await page.screenshot({ path:
|
|
141
|
+
await page.screenshot({ path: `${SCREENSHOT_DIR}/visual/mobile-${route.replace(/^\//, '').replace(/\//g, '-') || 'root'}.png`, fullPage: true });
|
|
139
142
|
});
|
|
140
143
|
}
|
|
141
144
|
});
|
|
@@ -145,7 +148,7 @@ test.describe('Visual - Desktop', () => {
|
|
|
145
148
|
for (const route of ROUTES) {
|
|
146
149
|
test(`visual-desktop: ${route}`, async ({ page }) => {
|
|
147
150
|
await page.goto(`http://localhost:${PORT}${route}`, { waitUntil: 'networkidle' });
|
|
148
|
-
await page.screenshot({ path:
|
|
151
|
+
await page.screenshot({ path: `${SCREENSHOT_DIR}/visual/desktop-${route.replace(/^\//, '').replace(/\//g, '-') || 'root'}.png`, fullPage: true });
|
|
149
152
|
});
|
|
150
153
|
}
|
|
151
154
|
});
|
|
@@ -154,7 +157,7 @@ test.describe('Visual - Desktop', () => {
|
|
|
154
157
|
## Execution
|
|
155
158
|
|
|
156
159
|
```bash
|
|
157
|
-
mkdir -p
|
|
160
|
+
mkdir -p "$SCREENSHOT_DIR"/{smoke,feature,visual}
|
|
158
161
|
npx playwright test .devlyn/browser-test.spec.ts \
|
|
159
162
|
--reporter=json \
|
|
160
163
|
--output=.devlyn/playwright-results \
|
|
@@ -182,7 +185,7 @@ rm -rf .devlyn/playwright-results
|
|
|
182
185
|
rm -f .devlyn/playwright-output.json
|
|
183
186
|
```
|
|
184
187
|
|
|
185
|
-
Keep `.devlyn/screenshots
|
|
188
|
+
Keep `$SCREENSHOT_DIR` (`.devlyn/screenshots/<topic-slug>/`) — those are evidence referenced by the report. Don't touch other topics' directories.
|
|
186
189
|
|
|
187
190
|
## Limitations vs Tier 1
|
|
188
191
|
|