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.
@@ -1,8 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // ../../app/node_modules/.pnpm/@stablyai-internal+playwright-cli@0.4.16/node_modules/@stablyai-internal/playwright-cli/playwright-cli.js
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 setViewportSize (device emulation) to force the exact dimensions \u2014 this is
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
- const targetW = w + decoW;
238
- const targetH = h + decoH;
239
- await cdpSession.send('Browser.setWindowBounds', { windowId, bounds: { width: targetW, height: targetH } });
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. **Verify**: Run the test again. Run at least **twice** to confirm the fix is stable.
92
- 6. **One fix at a time**: Fix the first failure point, re-run. Do not speculatively rewrite multiple parts at once.
93
- 7. **Group related failures**: Only group tests that share the same root cause
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.6",
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.16",
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();