stably 4.12.6 → 4.12.8
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/dist/index.mjs +1 -1
- package/dist/node_modules/playwright/lib/cli/daemon/daemon.js +0 -99
- package/dist/node_modules/playwright/lib/index.js +1 -32
- package/dist/node_modules/playwright/lib/mcp/browser/browserServerBackend.js +0 -27
- package/dist/node_modules/playwright/lib/mcp/browser/context.js +0 -52
- package/dist/node_modules/playwright/lib/mcp/browser/sessionLog.js +0 -50
- package/dist/node_modules/playwright/lib/mcp/test/browserBackend.js +1 -6
- package/dist/pwtrace.js +7185 -0
- package/dist/stably-browser.js +20 -7
- package/dist/stably-plugin-cli/skills/debugging-test-failures/SKILL.md +4 -3
- package/dist/stably-plugin-cli/skills/pwtrace-debugging/SKILL.md +108 -0
- package/package.json +3 -2
- package/dist/node_modules/playwright/lib/mcp/browser/config.js.rej +0 -11
package/dist/stably-browser.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
// ../../app/node_modules/.pnpm/@stablyai-internal+playwright-cli@0.4.
|
|
3
|
+
// ../../app/node_modules/.pnpm/@stablyai-internal+playwright-cli@0.4.19/node_modules/@stablyai-internal/playwright-cli/playwright-cli.js
|
|
4
4
|
var fs = require("fs");
|
|
5
5
|
var path = require("path");
|
|
6
|
+
if (process.platform === "darwin" && !process.env.PLAYWRIGHT_DAEMON_SOCKETS_DIR) {
|
|
7
|
+
process.env.PLAYWRIGHT_DAEMON_SOCKETS_DIR = "/tmp/playwright-cli";
|
|
8
|
+
}
|
|
6
9
|
var argv = process.argv.slice(2);
|
|
7
10
|
var cmdIndex = argv.findIndex((arg) => !arg.startsWith("-"));
|
|
8
11
|
if (cmdIndex !== -1 && argv[cmdIndex] === "run-file") {
|
|
@@ -193,10 +196,19 @@ const test = realPw.test.extend({
|
|
|
193
196
|
|
|
194
197
|
page: async ({ context }, use) => {
|
|
195
198
|
const page = context.pages()[0] || await context.newPage();
|
|
199
|
+
// Clear any stale device emulation left by a prior test's page.setViewportSize() call.
|
|
200
|
+
// setViewportSize sets Emulation.setDeviceMetricsOverride which persists across run-test
|
|
201
|
+
// invocations on the same daemon. Without clearing, window.innerWidth returns the emulated
|
|
202
|
+
// (fake) size, corrupting decoration measurements and causing progressive window shrink.
|
|
203
|
+
try {
|
|
204
|
+
const clearSession = await context.newCDPSession(page);
|
|
205
|
+
await clearSession.send('Emulation.clearDeviceMetricsOverride').catch(() => {});
|
|
206
|
+
await clearSession.detach();
|
|
207
|
+
} catch (_) {}
|
|
196
208
|
// Resize the browser window to match the user's configured viewport.
|
|
197
209
|
// Strategy: resize the OS window via Browser.setWindowBounds when the viewport fits
|
|
198
210
|
// on screen (no device emulation needed). When it doesn't fit, maximize the window
|
|
199
|
-
// and use
|
|
211
|
+
// and use Emulation.setDeviceMetricsOverride to force the exact dimensions \u2014 this is
|
|
200
212
|
// safe because the emulated viewport is larger than the window, so no white borders.
|
|
201
213
|
const vp = process.env.PLAYWRIGHT_CLI_VIEWPORT;
|
|
202
214
|
if (vp) {
|
|
@@ -228,15 +240,16 @@ const test = realPw.test.extend({
|
|
|
228
240
|
if (currentBounds.windowState === 'maximized' || currentBounds.windowState === 'fullscreen') {
|
|
229
241
|
await cdpSession.send('Browser.setWindowBounds', { windowId, bounds: { windowState: 'normal' } });
|
|
230
242
|
}
|
|
231
|
-
// Clear any prior device emulation so innerWidth/Height reflect actual window size.
|
|
232
|
-
await cdpSession.send('Emulation.clearDeviceMetricsOverride').catch(() => {});
|
|
233
243
|
const { bounds: measuredBounds } = await cdpSession.send('Browser.getWindowBounds', { windowId });
|
|
234
244
|
const inner = await page.evaluate(() => ({ width: window.innerWidth, height: window.innerHeight }));
|
|
235
245
|
const decoW = measuredBounds.width - inner.width;
|
|
236
246
|
const decoH = measuredBounds.height - inner.height;
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
247
|
+
// Sanity check: negative decorations means measurement is corrupted \u2014 skip resize.
|
|
248
|
+
if (decoW >= 0 && decoH >= 0) {
|
|
249
|
+
const targetW = w + decoW;
|
|
250
|
+
const targetH = h + decoH;
|
|
251
|
+
await cdpSession.send('Browser.setWindowBounds', { windowId, bounds: { width: targetW, height: targetH } });
|
|
252
|
+
}
|
|
240
253
|
}
|
|
241
254
|
await cdpSession.detach();
|
|
242
255
|
} catch (_) { /* best-effort \u2014 headed only, fails silently in headless */ }
|
|
@@ -88,9 +88,10 @@ Five types of issues cause test failures:
|
|
|
88
88
|
4. **Fix or explore**:
|
|
89
89
|
- If error-context clearly explains the issue (wrong text, element missing, on wrong page) → fix the code directly
|
|
90
90
|
- If error-context is insufficient → open the browser and explore manually (see below)
|
|
91
|
-
5. **
|
|
92
|
-
6. **
|
|
93
|
-
7. **
|
|
91
|
+
5. **Analyze traces**: If `trace.zip` exists in test-results/, use `pwtrace show <trace.zip>` for step-by-step replay. See the `pwtrace-debugging` skill for the full workflow.
|
|
92
|
+
6. **Verify**: Run the test again. Run at least **twice** to confirm the fix is stable.
|
|
93
|
+
7. **One fix at a time**: Fix the first failure point, re-run. Do not speculatively rewrite multiple parts at once.
|
|
94
|
+
8. **Group related failures**: Only group tests that share the same root cause
|
|
94
95
|
|
|
95
96
|
## When to Open the Browser for Manual Exploration
|
|
96
97
|
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pwtrace-debugging
|
|
3
|
+
description: Debug Playwright test failures by analyzing trace files using pwtrace CLI. Use after stably-browser run-test fails and a trace.zip exists. Provides systematic debugging from overview to detailed DOM/console/network inspection.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Trace-Based Test Debugging with pwtrace
|
|
7
|
+
|
|
8
|
+
After a `stably-browser run-test` failure, use `pwtrace` to analyze the trace file without re-running the test.
|
|
9
|
+
|
|
10
|
+
## When to Use
|
|
11
|
+
|
|
12
|
+
- After `stably-browser run-test` fails and `trace.zip` exists in test-results/
|
|
13
|
+
- When error messages are unclear and you need DOM state, console errors, or network failures
|
|
14
|
+
- To understand what the page looked like at the moment of failure
|
|
15
|
+
|
|
16
|
+
## Workflow: Progressive Disclosure
|
|
17
|
+
|
|
18
|
+
Always start broad, then drill down:
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
pwtrace show → identify failed step
|
|
22
|
+
pwtrace step N → get error details
|
|
23
|
+
pwtrace dom/console/network → understand why
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Step 1: Overview
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pwtrace show test-results/<test-name>/trace.zip
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
This shows all actions with status, duration, and errors. Find the step number(s) marked as failed.
|
|
33
|
+
|
|
34
|
+
### Step 2: Failed Step Details
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pwtrace step test-results/<test-name>/trace.zip <N>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Shows the specific action, its parameters, duration, and error message.
|
|
41
|
+
|
|
42
|
+
### Step 3: Investigate Root Cause
|
|
43
|
+
|
|
44
|
+
Based on the error type, use the appropriate command:
|
|
45
|
+
|
|
46
|
+
**Element not found / wrong element:**
|
|
47
|
+
```bash
|
|
48
|
+
# See all interactive elements at that step
|
|
49
|
+
pwtrace dom --step <N> --interactive test-results/<test-name>/trace.zip
|
|
50
|
+
|
|
51
|
+
# Search for specific elements
|
|
52
|
+
pwtrace dom --step <N> --selector "button" test-results/<test-name>/trace.zip
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**JavaScript errors:**
|
|
56
|
+
```bash
|
|
57
|
+
# All console errors
|
|
58
|
+
pwtrace console --level error test-results/<test-name>/trace.zip
|
|
59
|
+
|
|
60
|
+
# Errors around a specific step
|
|
61
|
+
pwtrace console --step <N> --level error test-results/<test-name>/trace.zip
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**API/network failures:**
|
|
65
|
+
```bash
|
|
66
|
+
# Show only failed requests (4xx/5xx) with response bodies
|
|
67
|
+
pwtrace network --failed test-results/<test-name>/trace.zip
|
|
68
|
+
|
|
69
|
+
# All network requests
|
|
70
|
+
pwtrace network test-results/<test-name>/trace.zip
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Debugging Decision Tree
|
|
74
|
+
|
|
75
|
+
| Symptom | Command | What to look for |
|
|
76
|
+
|---------|---------|-----------------|
|
|
77
|
+
| Timeout waiting for selector | `dom --step N --interactive` | Element missing, different name, or disabled |
|
|
78
|
+
| Assertion failed | `dom --step N` | Actual page content vs expected |
|
|
79
|
+
| Click did nothing | `console --step N --level error` | JS errors preventing handler |
|
|
80
|
+
| Page didn't load | `network --failed` | 4xx/5xx responses, CORS, timeouts |
|
|
81
|
+
| Wrong page state | `dom --step N` vs `dom --step N-1` | Compare before/after |
|
|
82
|
+
|
|
83
|
+
## Example: Debugging a Login Test Failure
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
# 1. See what failed
|
|
87
|
+
pwtrace show test-results/login-test/trace.zip
|
|
88
|
+
# Output: Step 8 (click "Sign In") failed
|
|
89
|
+
|
|
90
|
+
# 2. Get error details
|
|
91
|
+
pwtrace step test-results/login-test/trace.zip 8
|
|
92
|
+
# Output: TimeoutError waiting for selector
|
|
93
|
+
|
|
94
|
+
# 3. Check what elements exist
|
|
95
|
+
pwtrace dom --step 8 --interactive test-results/login-test/trace.zip
|
|
96
|
+
# Output: Button says "Log In" not "Sign In"
|
|
97
|
+
|
|
98
|
+
# 4. Check for JS errors
|
|
99
|
+
pwtrace console --step 8 --level error test-results/login-test/trace.zip
|
|
100
|
+
# Output: No errors — selector is just wrong
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Important Notes
|
|
104
|
+
|
|
105
|
+
- Trace files are only generated when `trace` is enabled in playwright config or via `--trace=on`
|
|
106
|
+
- The `--interactive` flag on `dom` filters to actionable elements only — use it first
|
|
107
|
+
- All commands support `--format json` for programmatic analysis
|
|
108
|
+
- Use `pwtrace dom --step N --after` to see DOM state after the action (default is before)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stably",
|
|
3
|
-
"version": "4.12.
|
|
3
|
+
"version": "4.12.8",
|
|
4
4
|
"packageManager": "pnpm@10.24.0",
|
|
5
5
|
"description": "AI-powered E2E Playwright testing CLI. Stably can understand your codebase, edit/run tests, and handle complex test scenarios for you.",
|
|
6
6
|
"main": "dist/index.mjs",
|
|
@@ -87,7 +87,8 @@
|
|
|
87
87
|
"playwright": "1.59.0-alpha-1771104257000",
|
|
88
88
|
"@stablyai/codegen-agent-constants": "workspace:*",
|
|
89
89
|
"@stablyai-internal/api-client": "workspace:*",
|
|
90
|
-
"@stablyai-internal/playwright-cli": "0.4.
|
|
90
|
+
"@stablyai-internal/playwright-cli": "0.4.19",
|
|
91
|
+
"@stablyai-internal/pwtrace": "0.3.1",
|
|
91
92
|
"@stablyai/agent-hooks": "workspace:*",
|
|
92
93
|
"@stablyai/agent-schemas": "workspace:*",
|
|
93
94
|
"@stablyai/agent-security-hooks": "workspace:*",
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
--- lib/mcp/browser/config.js
|
|
2
|
-
+++ lib/mcp/browser/config.js
|
|
3
|
-
@@ -305,7 +305,7 @@
|
|
4
|
-
function outputDir(config, clientInfo) {
|
|
5
|
-
if (config.outputDir)
|
|
6
|
-
return import_path.default.resolve(config.outputDir);
|
|
7
|
-
const rootPath = (0, import_server2.firstRootPath)(clientInfo);
|
|
8
|
-
if (rootPath)
|
|
9
|
-
- return import_path.default.resolve(rootPath, config.skillMode ? ".playwright-cli" : ".playwright-mcp");
|
|
10
|
-
+ return import_path.default.resolve(rootPath, config.skillMode ? ".stably-browser" : ".playwright-mcp");
|
|
11
|
-
const tmpDir = process.env.PW_TMPDIR_FOR_TEST ?? import_os.default.tmpdir();
|