uisnap 0.1.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.
Files changed (91) hide show
  1. package/.claude/settings.local.json +26 -0
  2. package/.claude/skills/uisnap/README.md +48 -0
  3. package/.claude/skills/uisnap/REFERENCE.md +1261 -0
  4. package/.claude/skills/uisnap/SETUP.md +75 -0
  5. package/.claude/skills/uisnap/SKILL.md +130 -0
  6. package/.claude/skills/uisnap/snapshot-capture-and-analysis.md +452 -0
  7. package/.claude/skills/uisnap/trace-capture-and-analysis.md +472 -0
  8. package/CHANGELOG.md +96 -0
  9. package/LICENSE +21 -0
  10. package/README.md +394 -0
  11. package/SKILL-INSTALLATION.md +103 -0
  12. package/dist/analyze-console.d.ts +3 -0
  13. package/dist/analyze-console.d.ts.map +1 -0
  14. package/dist/analyze-console.js +153 -0
  15. package/dist/analyze-console.js.map +1 -0
  16. package/dist/analyze-network.d.ts +3 -0
  17. package/dist/analyze-network.d.ts.map +1 -0
  18. package/dist/analyze-network.js +156 -0
  19. package/dist/analyze-network.js.map +1 -0
  20. package/dist/chrome-trace-analyze.d.ts +3 -0
  21. package/dist/chrome-trace-analyze.d.ts.map +1 -0
  22. package/dist/chrome-trace-analyze.js +119 -0
  23. package/dist/chrome-trace-analyze.js.map +1 -0
  24. package/dist/chrome-trace-import.d.ts +3 -0
  25. package/dist/chrome-trace-import.d.ts.map +1 -0
  26. package/dist/chrome-trace-import.js +90 -0
  27. package/dist/chrome-trace-import.js.map +1 -0
  28. package/dist/commands/snapshot.d.ts +4 -0
  29. package/dist/commands/snapshot.d.ts.map +1 -0
  30. package/dist/commands/snapshot.js +154 -0
  31. package/dist/commands/snapshot.js.map +1 -0
  32. package/dist/diagnose.d.ts +3 -0
  33. package/dist/diagnose.d.ts.map +1 -0
  34. package/dist/diagnose.js +244 -0
  35. package/dist/diagnose.js.map +1 -0
  36. package/dist/index.d.ts +4 -0
  37. package/dist/index.d.ts.map +1 -0
  38. package/dist/index.js +26 -0
  39. package/dist/index.js.map +1 -0
  40. package/dist/pw.d.ts +3 -0
  41. package/dist/pw.d.ts.map +1 -0
  42. package/dist/pw.js +289 -0
  43. package/dist/pw.js.map +1 -0
  44. package/dist/query-a11y.d.ts +3 -0
  45. package/dist/query-a11y.d.ts.map +1 -0
  46. package/dist/query-a11y.js +208 -0
  47. package/dist/query-a11y.js.map +1 -0
  48. package/dist/trace-import.d.ts +3 -0
  49. package/dist/trace-import.d.ts.map +1 -0
  50. package/dist/trace-import.js +93 -0
  51. package/dist/trace-import.js.map +1 -0
  52. package/dist/types.d.ts +70 -0
  53. package/dist/types.d.ts.map +1 -0
  54. package/dist/types.js +3 -0
  55. package/dist/types.js.map +1 -0
  56. package/dist/utils/chromeTraceAnalyze.d.ts +40 -0
  57. package/dist/utils/chromeTraceAnalyze.d.ts.map +1 -0
  58. package/dist/utils/chromeTraceAnalyze.js +113 -0
  59. package/dist/utils/chromeTraceAnalyze.js.map +1 -0
  60. package/dist/utils/chromeTraceHelpers.d.ts +4 -0
  61. package/dist/utils/chromeTraceHelpers.d.ts.map +1 -0
  62. package/dist/utils/chromeTraceHelpers.js +68 -0
  63. package/dist/utils/chromeTraceHelpers.js.map +1 -0
  64. package/dist/utils/chromeTraceImport.d.ts +14 -0
  65. package/dist/utils/chromeTraceImport.d.ts.map +1 -0
  66. package/dist/utils/chromeTraceImport.js +77 -0
  67. package/dist/utils/chromeTraceImport.js.map +1 -0
  68. package/dist/utils/helpers.d.ts +3 -0
  69. package/dist/utils/helpers.d.ts.map +1 -0
  70. package/dist/utils/helpers.js +88 -0
  71. package/dist/utils/helpers.js.map +1 -0
  72. package/dist/utils/projectRoot.d.ts +2 -0
  73. package/dist/utils/projectRoot.d.ts.map +1 -0
  74. package/dist/utils/projectRoot.js +56 -0
  75. package/dist/utils/projectRoot.js.map +1 -0
  76. package/dist/utils/traceHelpers.d.ts +4 -0
  77. package/dist/utils/traceHelpers.d.ts.map +1 -0
  78. package/dist/utils/traceHelpers.js +67 -0
  79. package/dist/utils/traceHelpers.js.map +1 -0
  80. package/dist/utils/traceImport.d.ts +20 -0
  81. package/dist/utils/traceImport.d.ts.map +1 -0
  82. package/dist/utils/traceImport.js +124 -0
  83. package/dist/utils/traceImport.js.map +1 -0
  84. package/dist/utils/webVitals.d.ts +9 -0
  85. package/dist/utils/webVitals.d.ts.map +1 -0
  86. package/dist/utils/webVitals.js +54 -0
  87. package/dist/utils/webVitals.js.map +1 -0
  88. package/examples/login-flow.js +37 -0
  89. package/examples/scroll-perf-trace.js +43 -0
  90. package/examples/simple-capture.js +28 -0
  91. package/package.json +74 -0
@@ -0,0 +1,75 @@
1
+ # Setup Instructions
2
+
3
+ ## Installation
4
+
5
+ This skill requires the uisnap to be installed.
6
+
7
+ ### Option 1: Global Installation (Recommended for Skill)
8
+
9
+ ```bash
10
+ npm install -g uisnap
11
+ npx playwright install chromium
12
+ ```
13
+
14
+ After global install, the commands are available everywhere:
15
+ - `uisnap`
16
+ - `uisnap-analyze-console`
17
+ - `uisnap-analyze-network`
18
+ - `uisnap-query-a11y`
19
+
20
+ ### Option 2: Local Development
21
+
22
+ If you're working on the toolkit itself:
23
+
24
+ ```bash
25
+ cd uisnap
26
+ npm install
27
+ npm run build
28
+ npx playwright install chromium
29
+
30
+ # Use with node dist/pw.js instead of uisnap
31
+ node dist/pw.js snapshot https://example.com
32
+ ```
33
+
34
+ ## Verify Installation
35
+
36
+ ```bash
37
+ # Check that commands are available
38
+ uisnap --help
39
+ uisnap-analyze-console --help
40
+ uisnap-query-a11y --help
41
+
42
+ # Test with a simple capture
43
+ uisnap snapshot https://example.com
44
+ ls snapshots/example.com/latest/
45
+ ```
46
+
47
+ ## Skill Location
48
+
49
+ This skill should be installed in one of:
50
+
51
+ **Project skill** (shared with team via git):
52
+ ```
53
+ your-project/.claude/skills/uisnap/
54
+ ```
55
+
56
+ **Personal skill** (available across all projects):
57
+ ```
58
+ ~/.claude/skills/uisnap/
59
+ ```
60
+
61
+ To share with your team, commit `.claude/skills/` to your repository.
62
+
63
+ ## Troubleshooting
64
+
65
+ **"uisnap: command not found"**
66
+ - Run `npm install -g uisnap`
67
+ - Make sure npm global bin is in your PATH
68
+
69
+ **"Browser not found"**
70
+ - Run `npx playwright install chromium`
71
+
72
+ **Skill not activating**
73
+ - Check YAML frontmatter is valid (no tabs, proper indentation)
74
+ - Ensure file is named `SKILL.md`
75
+ - Try mentioning keywords from description: "debug", "console errors", "network failures"
@@ -0,0 +1,130 @@
1
+ ---
2
+ name: uisnap
3
+ description: Captures browser state to disk for token-efficient debugging. Use for frontend debugging, performance analysis, accessibility testing, or when investigating page behavior. Supports snapshots (functional debugging) and Chrome traces (performance profiling).
4
+ ---
5
+
6
+ # uisnap
7
+
8
+ Disk-based debugging for Claude Code. **Capture once, query many.**
9
+
10
+ ## Quick Decision Tree
11
+
12
+ **User reports functional issues** → Snapshot capture
13
+ - "Button doesn't work"
14
+ - "Form submission fails"
15
+ - "Console errors"
16
+ - "API returns 404"
17
+ - "Page doesn't load"
18
+
19
+ → See [snapshot-capture-and-analysis.md](snapshot-capture-and-analysis.md)
20
+
21
+ **User reports performance issues** → Trace capture
22
+ - "Page is slow/laggy"
23
+ - "Scrolling is janky"
24
+ - "Animations stutter"
25
+ - "UI freezes"
26
+ - "Long blocking tasks"
27
+
28
+ → See [trace-capture-and-analysis.md](trace-capture-and-analysis.md)
29
+
30
+ **Not sure?** → Start with snapshot (faster, cheaper), escalate to trace if needed
31
+
32
+ ## Common Commands
33
+
34
+ ### Snapshot Workflow
35
+ ```bash
36
+ # Capture
37
+ uisnap snapshot https://myapp.com
38
+
39
+ # Analyze
40
+ uisnap-analyze-console snapshots/myapp.com/latest/console.jsonl
41
+ uisnap-analyze-network snapshots/myapp.com/latest/network.jsonl
42
+ uisnap-query-a11y snapshots/myapp.com/latest/a11y.yaml "Submit"
43
+ ```
44
+
45
+ ### Trace Workflow
46
+ ```bash
47
+ # Capture
48
+ uisnap exec examples/scroll-perf-trace.js https://myapp.com
49
+
50
+ # Analyze
51
+ uisnap-chrome-trace-analyze snapshots/myapp.com/latest/chrome-trace.db --full
52
+ ```
53
+
54
+ ## Available Tools
55
+
56
+ **Capture commands**:
57
+ - `uisnap snapshot <url>` - Capture page state (a11y, console, network)
58
+ - `uisnap exec <script.js> <url>` - Run custom script with Playwright context
59
+
60
+ **Analysis commands**:
61
+ - `uisnap-analyze-console <console.jsonl>` - Summarize console messages
62
+ - `uisnap-analyze-network <network.jsonl>` - Summarize network activity
63
+ - `uisnap-query-a11y <a11y.yaml> <query>` - Query accessibility tree
64
+ - `uisnap-chrome-trace-analyze <trace.db>` - Analyze performance trace
65
+
66
+ ## Installation
67
+
68
+ ```bash
69
+ npm install -g uisnap
70
+ npx playwright install chromium
71
+ ```
72
+
73
+ ## When to Read Reference Docs
74
+
75
+ **For snapshot debugging**: See [snapshot-capture-and-analysis.md](snapshot-capture-and-analysis.md)
76
+ - Complete capture and analysis guide
77
+ - Multi-step flows with `utils.captureStep()`
78
+ - Output formats and querying patterns
79
+ - Examples and troubleshooting
80
+
81
+ **For performance debugging**: See [trace-capture-and-analysis.md](trace-capture-and-analysis.md)
82
+ - Chrome tracing setup and workflow
83
+ - DuckDB schema and canned queries
84
+ - Custom SQL for advanced analysis
85
+ - Examples and troubleshooting
86
+
87
+ ## Progressive Workflow
88
+
89
+ 1. **Start with snapshot** - Check for functional errors first
90
+ 2. **If no errors but issues persist** - Capture trace for performance analysis
91
+ 3. **For comprehensive debugging** - Combine both approaches
92
+
93
+ Example combining both:
94
+ ```javascript
95
+ // Capture functional state
96
+ await utils.captureStep(page, 'initial-load', async () => {
97
+ await page.goto('https://myapp.com');
98
+ });
99
+
100
+ // Start performance tracing
101
+ const cdp = await context.newCDPSession(page);
102
+ await utils.startChromeTrace(cdp);
103
+
104
+ // Perform interactions (traced)
105
+ await page.evaluate(() => window.scrollTo({ top: 1000 }));
106
+
107
+ // Capture final state
108
+ await utils.captureStep(page, 'after-scroll', async () => {});
109
+
110
+ // Stop trace and auto-import
111
+ const tracePath = path.join(utils.baseOutputDir, 'chrome-trace.json');
112
+ await utils.stopChromeTraceAndImport(cdp, tracePath);
113
+ ```
114
+
115
+ ## Output Structure
116
+
117
+ Auto-generated timestamped directories:
118
+ ```
119
+ snapshots/
120
+ ├── myapp.com/
121
+ │ ├── 2025-12-30-120000/
122
+ │ │ ├── a11y.yaml
123
+ │ │ ├── console.jsonl
124
+ │ │ ├── network.jsonl
125
+ │ │ └── metadata.json
126
+ │ ├── 2025-12-30-130000/
127
+ │ └── latest -> 2025-12-30-130000/
128
+ ```
129
+
130
+ Use `latest` symlink for most recent capture.
@@ -0,0 +1,452 @@
1
+ # Snapshot Capture and Analysis
2
+
3
+ Complete reference for functional debugging with Playwright snapshots.
4
+
5
+ ## When to Use Snapshots
6
+
7
+ Use snapshot capture for functional debugging:
8
+ - Console errors or warnings
9
+ - Network request failures (4xx, 5xx)
10
+ - Missing or disabled UI elements
11
+ - Incorrect page state
12
+ - Accessibility issues
13
+ - Multi-step user flows (login, checkout, forms)
14
+
15
+ ## Capture Commands
16
+
17
+ ### Basic Snapshot
18
+
19
+ ```bash
20
+ uisnap snapshot <url> [output-dir]
21
+ ```
22
+
23
+ **Auto-generated output** (when output-dir omitted):
24
+ ```
25
+ snapshots/{hostname}/{timestamp}/
26
+ ├── a11y.yaml # ARIA accessibility tree
27
+ ├── console.jsonl # Console messages
28
+ ├── network.jsonl # Network requests
29
+ └── metadata.json # Page metadata
30
+ ```
31
+
32
+ **Example**:
33
+ ```bash
34
+ uisnap snapshot https://myapp.com
35
+ # Creates: snapshots/myapp.com/2025-12-30-143052/
36
+ # Symlinks: snapshots/myapp.com/latest -> 2025-12-30-143052/
37
+ ```
38
+
39
+ **Explicit output path**:
40
+ ```bash
41
+ uisnap snapshot https://myapp.com snapshots/baseline/
42
+ # Creates exactly: snapshots/baseline/
43
+ # No timestamp, no symlink
44
+ ```
45
+
46
+ Use explicit paths for baselines or comparisons.
47
+
48
+ ### Multi-Step Flows with captureStep
49
+
50
+ For complex user flows, use `utils.captureStep()` to capture state at each step:
51
+
52
+ ```javascript
53
+ // examples/login-flow.js
54
+ // Usage: uisnap exec examples/login-flow.js https://myapp.com
55
+
56
+ // Step 1: Navigate
57
+ await utils.captureStep(page, 'goto-login', async () => {
58
+ await page.goto('https://myapp.com/login');
59
+ });
60
+
61
+ // Step 2: Fill email (use role-based selectors)
62
+ await utils.captureStep(page, 'fill-email', async () => {
63
+ await page.getByLabel('Email').fill('test@example.com');
64
+ });
65
+
66
+ // Step 3: Fill password
67
+ await utils.captureStep(page, 'fill-password', async () => {
68
+ await page.getByLabel('Password').fill('password123');
69
+ });
70
+
71
+ // Step 4: Submit
72
+ await utils.captureStep(page, 'click-submit', async () => {
73
+ await page.getByRole('button', { name: 'Submit' }).click();
74
+ });
75
+
76
+ // Step 5: Verify redirect
77
+ await utils.captureStep(page, 'after-login', async () => {
78
+ await page.waitForURL('**/dashboard');
79
+ });
80
+ ```
81
+
82
+ **Output structure**:
83
+ ```
84
+ snapshots/myapp.com/login-flow-2025-12-30-143052/
85
+ ├── step-1-goto-login/
86
+ │ ├── a11y.yaml
87
+ │ └── metadata.json
88
+ ├── step-2-fill-email/
89
+ │ ├── a11y.yaml
90
+ │ └── metadata.json
91
+ ├── step-3-fill-password/
92
+ │ └── ...
93
+ ├── step-4-click-submit/
94
+ │ └── ...
95
+ └── step-5-after-login/
96
+ └── ...
97
+ ```
98
+
99
+ ### Available Context in Scripts
100
+
101
+ Scripts executed with `uisnap exec` have access to:
102
+
103
+ - `page, context, browser` - Playwright instances
104
+ - `args` - Command-line arguments (after URL and output-dir)
105
+ - `fs, path` - Node.js modules (already loaded, don't require)
106
+ - `utils.captureStep(page, name, action)` - Capture step with auto-numbering
107
+ - `utils.writeJson(path, data)` - Write formatted JSON
108
+ - `utils.writeJsonl(path, items)` - Write JSONL
109
+ - `utils.appendJsonl(path, item)` - Append to JSONL
110
+ - `utils.baseOutputDir` - Output directory path
111
+
112
+ ## Analysis Commands
113
+
114
+ ### Analyze Console Messages
115
+
116
+ ```bash
117
+ uisnap-analyze-console <console.jsonl>
118
+ ```
119
+
120
+ **Output**:
121
+ - Message counts by type (error, warning, log, info)
122
+ - Grouped errors with counts and locations
123
+ - Grouped warnings with counts and locations
124
+
125
+ **Example**:
126
+ ```bash
127
+ uisnap-analyze-console snapshots/myapp.com/latest/console.jsonl
128
+
129
+ # Output:
130
+ # === Console Summary ===
131
+ # Total messages: 47
132
+ # Errors: 2
133
+ # Warnings: 5
134
+ # Logs: 40
135
+ #
136
+ # === Grouped Errors ===
137
+ # 1. "Cannot read property 'submit' of null" (2 occurrences)
138
+ # app.js:123
139
+ # form.js:45
140
+ ```
141
+
142
+ ### Analyze Network Requests
143
+
144
+ ```bash
145
+ uisnap-analyze-network <network.jsonl>
146
+ ```
147
+
148
+ **Output**:
149
+ - Request counts by resource type (fetch, xhr, script, stylesheet, etc.)
150
+ - Request counts by HTTP method (GET, POST, etc.)
151
+ - Request counts by status code
152
+ - Failed requests (4xx, 5xx)
153
+ - Slow requests (>1s)
154
+ - Requests by domain
155
+
156
+ **Example**:
157
+ ```bash
158
+ uisnap-analyze-network snapshots/myapp.com/latest/network.jsonl
159
+
160
+ # Output:
161
+ # === Network Summary ===
162
+ # Total requests: 87
163
+ #
164
+ # === By Resource Type ===
165
+ # document: 1
166
+ # fetch: 23
167
+ # script: 18
168
+ # stylesheet: 8
169
+ #
170
+ # === Failed Requests (4xx/5xx) ===
171
+ # 1. POST https://api.myapp.com/submit - 500 Internal Server Error
172
+ # 2. GET https://cdn.myapp.com/missing.js - 404 Not Found
173
+ ```
174
+
175
+ ### Query Accessibility Tree
176
+
177
+ ```bash
178
+ uisnap-query-a11y <a11y.yaml> <query>
179
+ ```
180
+
181
+ **Query options**:
182
+ - `--buttons` - List all buttons
183
+ - `--links` - List all links
184
+ - `--headings` - List all headings
185
+ - `--inputs` - List all input fields
186
+ - `--interactive` - List all interactive elements
187
+ - `--images` - List all images
188
+ - `--disabled` - List disabled elements
189
+ - `<text>` - Search by text content (case-insensitive)
190
+
191
+ **Example**:
192
+ ```bash
193
+ # Find all buttons
194
+ uisnap-query-a11y snapshots/myapp.com/latest/a11y.yaml --buttons
195
+ # Output: button "Submit" [disabled]
196
+ # button "Cancel"
197
+
198
+ # Search for specific text
199
+ uisnap-query-a11y snapshots/myapp.com/latest/a11y.yaml "Submit"
200
+ # Output: button "Submit" [disabled]
201
+
202
+ # Find all inputs
203
+ uisnap-query-a11y snapshots/myapp.com/latest/a11y.yaml --inputs
204
+ # Output: textbox "Email" [required]
205
+ # textbox "Password" [required]
206
+ ```
207
+
208
+ ## Output Formats
209
+
210
+ ### ARIA Snapshot (YAML)
211
+
212
+ Human-readable accessibility tree:
213
+
214
+ ```yaml
215
+ - heading "Example Domain" [level=1]
216
+ - paragraph: This domain is for use in examples.
217
+ - link "Learn more":
218
+ - /url: https://iana.org/domains/example
219
+ - button "Submit" [disabled]
220
+ - textbox "Email" [required]
221
+ ```
222
+
223
+ ### Console Logs (JSONL)
224
+
225
+ One JSON object per line:
226
+
227
+ ```jsonl
228
+ {"timestamp":"2025-12-30T10:30:00.000Z","type":"error","text":"Cannot read property 'submit' of null","location":{"url":"https://myapp.com/app.js","lineNumber":123}}
229
+ {"timestamp":"2025-12-30T10:30:01.000Z","type":"log","text":"User clicked submit","location":{"url":"https://myapp.com/app.js","lineNumber":100}}
230
+ ```
231
+
232
+ ### Network Requests (JSONL)
233
+
234
+ One JSON object per line:
235
+
236
+ ```jsonl
237
+ {"url":"https://api.myapp.com/users","status":200,"statusText":"OK","method":"GET","resourceType":"fetch","timing":{"startTime":1234.5,"responseEnd":1456.7}}
238
+ {"url":"https://api.myapp.com/submit","status":500,"statusText":"Internal Server Error","method":"POST","resourceType":"fetch"}
239
+ ```
240
+
241
+ ### Metadata (JSON)
242
+
243
+ Page information:
244
+
245
+ ```json
246
+ {
247
+ "title": "My App - Dashboard",
248
+ "url": "https://myapp.com/dashboard",
249
+ "timestamp": "2025-12-30T10:30:00.000Z",
250
+ "viewport": {
251
+ "width": 1280,
252
+ "height": 720
253
+ }
254
+ }
255
+ ```
256
+
257
+ ## Common Workflows
258
+
259
+ ### Basic Debugging Workflow
260
+
261
+ ```bash
262
+ # 1. Capture page state
263
+ uisnap snapshot https://myapp.com
264
+
265
+ # 2. Check for errors (use "latest" symlink)
266
+ uisnap-analyze-console snapshots/myapp.com/latest/console.jsonl
267
+ # Found: "Cannot read property 'submit' of null"
268
+
269
+ # 3. Check network failures
270
+ uisnap-analyze-network snapshots/myapp.com/latest/network.jsonl
271
+ # Found: POST /api/submit - 500 Internal Server Error
272
+
273
+ # 4. Find the submit button
274
+ uisnap-query-a11y snapshots/myapp.com/latest/a11y.yaml "Submit"
275
+ # Found: button "Submit" [disabled]
276
+
277
+ # Diagnosis: Button is disabled, API returns 500, JS error on submit
278
+ ```
279
+
280
+ ### Iterative Debugging Workflow
281
+
282
+ ```bash
283
+ # First capture
284
+ uisnap snapshot https://myapp.com
285
+ # Creates: snapshots/myapp.com/2025-12-30-143052/
286
+
287
+ # Make code changes...
288
+
289
+ # Second capture (doesn't overwrite!)
290
+ uisnap snapshot https://myapp.com
291
+ # Creates: snapshots/myapp.com/2025-12-30-144315/
292
+ # Updates: snapshots/myapp.com/latest -> 2025-12-30-144315/
293
+
294
+ # "latest" always points to most recent
295
+ uisnap-analyze-console snapshots/myapp.com/latest/console.jsonl
296
+
297
+ # View history
298
+ ls snapshots/myapp.com/
299
+ # 2025-12-30-143052/
300
+ # 2025-12-30-144315/
301
+ # latest -> 2025-12-30-144315/
302
+ ```
303
+
304
+ ### Multi-Step Flow Debugging
305
+
306
+ ```bash
307
+ # 1. Capture entire flow
308
+ uisnap exec examples/login-flow.js https://myapp.com
309
+
310
+ # 2. Analyze specific step
311
+ uisnap-query-a11y snapshots/myapp.com/latest/step-4-click-submit/a11y.yaml --buttons
312
+
313
+ # 3. Check console for step 5
314
+ uisnap-analyze-console snapshots/myapp.com/latest/step-5-after-login/console.jsonl
315
+
316
+ # 4. Examine step directories
317
+ ls snapshots/myapp.com/latest/
318
+ # step-1-goto-login/
319
+ # step-2-fill-email/
320
+ # step-3-fill-password/
321
+ # step-4-click-submit/
322
+ # step-5-after-login/
323
+ ```
324
+
325
+ ### Regression Testing Workflow
326
+
327
+ ```bash
328
+ # Before deployment (explicit path for baseline)
329
+ uisnap snapshot https://myapp.com snapshots/baseline/
330
+
331
+ # After deployment (auto-generated)
332
+ uisnap snapshot https://myapp.com
333
+ # Creates: snapshots/myapp.com/2025-12-30-150000/
334
+
335
+ # Compare console logs
336
+ diff snapshots/baseline/console.jsonl snapshots/myapp.com/latest/console.jsonl
337
+
338
+ # Compare a11y trees
339
+ diff snapshots/baseline/a11y.yaml snapshots/myapp.com/latest/a11y.yaml
340
+ ```
341
+
342
+ ## Playwright Selector Best Practices
343
+
344
+ Use role-based selectors that align with ARIA snapshots:
345
+
346
+ **Recommended** (matches a11y.yaml):
347
+ ```javascript
348
+ await page.getByRole('button', { name: 'Submit' }) // button "Submit"
349
+ await page.getByLabel('Email') // textbox "Email"
350
+ await page.getByText('Welcome') // text: Welcome
351
+ await page.getByRole('link', { name: 'Learn more' }) // link "Learn more"
352
+ ```
353
+
354
+ **Avoid** (brittle, doesn't match a11y.yaml):
355
+ ```javascript
356
+ await page.click('button[type="submit"]') // CSS selector
357
+ await page.click('#submit-btn') // ID selector
358
+ await page.click('.btn-primary') // Class selector
359
+ ```
360
+
361
+ Role-based selectors make it easy to correlate captured a11y.yaml with your script actions.
362
+
363
+ ## Custom Data Extraction
364
+
365
+ For extracting custom data without step capture:
366
+
367
+ ```javascript
368
+ // examples/extract-links.js
369
+ await page.goto(args[0]);
370
+
371
+ const data = await page.evaluate(() => {
372
+ return {
373
+ links: Array.from(document.links).map(l => ({ href: l.href, text: l.textContent })),
374
+ headings: Array.from(document.querySelectorAll('h1, h2, h3')).map(h => ({
375
+ level: h.tagName,
376
+ text: h.textContent
377
+ }))
378
+ };
379
+ });
380
+
381
+ utils.writeJson(path.join(utils.baseOutputDir, 'extracted.json'), data);
382
+ console.log(`Extracted ${data.links.length} links, ${data.headings.length} headings`);
383
+ ```
384
+
385
+ ## Troubleshooting
386
+
387
+ ### Snapshot directory not found
388
+
389
+ ```bash
390
+ uisnap snapshot https://myapp.com
391
+ # Error: ENOENT: no such file or directory
392
+
393
+ # Solution: Check that snapshots/ directory exists
394
+ mkdir -p snapshots
395
+ ```
396
+
397
+ ### "latest" symlink points to wrong snapshot
398
+
399
+ ```bash
400
+ # Symlinks update automatically on each capture
401
+ # To manually fix:
402
+ cd snapshots/myapp.com
403
+ rm latest
404
+ ln -s 2025-12-30-143052 latest
405
+ ```
406
+
407
+ ### captureStep doesn't capture console/network
408
+
409
+ `captureStep()` only captures a11y.yaml and metadata.json. For console/network, use the snapshot command or add listeners in your script:
410
+
411
+ ```javascript
412
+ // Capture console in custom script
413
+ const consoleLogs = [];
414
+ page.on('console', msg => consoleLogs.push({
415
+ type: msg.type(),
416
+ text: msg.text(),
417
+ timestamp: new Date().toISOString()
418
+ }));
419
+
420
+ // Later, write to file
421
+ utils.writeJsonl(path.join(utils.baseOutputDir, 'console.jsonl'), consoleLogs);
422
+ ```
423
+
424
+ ### Query returns no results
425
+
426
+ Check file path and query syntax:
427
+
428
+ ```bash
429
+ # Correct: use relative or absolute path
430
+ uisnap-query-a11y snapshots/myapp.com/latest/a11y.yaml --buttons
431
+
432
+ # Incorrect: missing path
433
+ uisnap-query-a11y --buttons # Error: file not found
434
+ ```
435
+
436
+ ## Advanced: Manual JSONL Processing
437
+
438
+ For custom analysis, use standard Unix tools:
439
+
440
+ ```bash
441
+ # Count error messages
442
+ grep '"type":"error"' snapshots/myapp.com/latest/console.jsonl | wc -l
443
+
444
+ # Extract all API requests
445
+ grep '"resourceType":"fetch"' snapshots/myapp.com/latest/network.jsonl > api-requests.jsonl
446
+
447
+ # Find specific error message
448
+ grep "Cannot read property" snapshots/myapp.com/latest/console.jsonl
449
+
450
+ # Use jq for complex queries
451
+ jq 'select(.status >= 400)' snapshots/myapp.com/latest/network.jsonl
452
+ ```