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.
- package/.claude/settings.local.json +26 -0
- package/.claude/skills/uisnap/README.md +48 -0
- package/.claude/skills/uisnap/REFERENCE.md +1261 -0
- package/.claude/skills/uisnap/SETUP.md +75 -0
- package/.claude/skills/uisnap/SKILL.md +130 -0
- package/.claude/skills/uisnap/snapshot-capture-and-analysis.md +452 -0
- package/.claude/skills/uisnap/trace-capture-and-analysis.md +472 -0
- package/CHANGELOG.md +96 -0
- package/LICENSE +21 -0
- package/README.md +394 -0
- package/SKILL-INSTALLATION.md +103 -0
- package/dist/analyze-console.d.ts +3 -0
- package/dist/analyze-console.d.ts.map +1 -0
- package/dist/analyze-console.js +153 -0
- package/dist/analyze-console.js.map +1 -0
- package/dist/analyze-network.d.ts +3 -0
- package/dist/analyze-network.d.ts.map +1 -0
- package/dist/analyze-network.js +156 -0
- package/dist/analyze-network.js.map +1 -0
- package/dist/chrome-trace-analyze.d.ts +3 -0
- package/dist/chrome-trace-analyze.d.ts.map +1 -0
- package/dist/chrome-trace-analyze.js +119 -0
- package/dist/chrome-trace-analyze.js.map +1 -0
- package/dist/chrome-trace-import.d.ts +3 -0
- package/dist/chrome-trace-import.d.ts.map +1 -0
- package/dist/chrome-trace-import.js +90 -0
- package/dist/chrome-trace-import.js.map +1 -0
- package/dist/commands/snapshot.d.ts +4 -0
- package/dist/commands/snapshot.d.ts.map +1 -0
- package/dist/commands/snapshot.js +154 -0
- package/dist/commands/snapshot.js.map +1 -0
- package/dist/diagnose.d.ts +3 -0
- package/dist/diagnose.d.ts.map +1 -0
- package/dist/diagnose.js +244 -0
- package/dist/diagnose.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/pw.d.ts +3 -0
- package/dist/pw.d.ts.map +1 -0
- package/dist/pw.js +289 -0
- package/dist/pw.js.map +1 -0
- package/dist/query-a11y.d.ts +3 -0
- package/dist/query-a11y.d.ts.map +1 -0
- package/dist/query-a11y.js +208 -0
- package/dist/query-a11y.js.map +1 -0
- package/dist/trace-import.d.ts +3 -0
- package/dist/trace-import.d.ts.map +1 -0
- package/dist/trace-import.js +93 -0
- package/dist/trace-import.js.map +1 -0
- package/dist/types.d.ts +70 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/chromeTraceAnalyze.d.ts +40 -0
- package/dist/utils/chromeTraceAnalyze.d.ts.map +1 -0
- package/dist/utils/chromeTraceAnalyze.js +113 -0
- package/dist/utils/chromeTraceAnalyze.js.map +1 -0
- package/dist/utils/chromeTraceHelpers.d.ts +4 -0
- package/dist/utils/chromeTraceHelpers.d.ts.map +1 -0
- package/dist/utils/chromeTraceHelpers.js +68 -0
- package/dist/utils/chromeTraceHelpers.js.map +1 -0
- package/dist/utils/chromeTraceImport.d.ts +14 -0
- package/dist/utils/chromeTraceImport.d.ts.map +1 -0
- package/dist/utils/chromeTraceImport.js +77 -0
- package/dist/utils/chromeTraceImport.js.map +1 -0
- package/dist/utils/helpers.d.ts +3 -0
- package/dist/utils/helpers.d.ts.map +1 -0
- package/dist/utils/helpers.js +88 -0
- package/dist/utils/helpers.js.map +1 -0
- package/dist/utils/projectRoot.d.ts +2 -0
- package/dist/utils/projectRoot.d.ts.map +1 -0
- package/dist/utils/projectRoot.js +56 -0
- package/dist/utils/projectRoot.js.map +1 -0
- package/dist/utils/traceHelpers.d.ts +4 -0
- package/dist/utils/traceHelpers.d.ts.map +1 -0
- package/dist/utils/traceHelpers.js +67 -0
- package/dist/utils/traceHelpers.js.map +1 -0
- package/dist/utils/traceImport.d.ts +20 -0
- package/dist/utils/traceImport.d.ts.map +1 -0
- package/dist/utils/traceImport.js +124 -0
- package/dist/utils/traceImport.js.map +1 -0
- package/dist/utils/webVitals.d.ts +9 -0
- package/dist/utils/webVitals.d.ts.map +1 -0
- package/dist/utils/webVitals.js +54 -0
- package/dist/utils/webVitals.js.map +1 -0
- package/examples/login-flow.js +37 -0
- package/examples/scroll-perf-trace.js +43 -0
- package/examples/simple-capture.js +28 -0
- 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
|
+
```
|