384 lines
13 KiB
Markdown
384 lines
13 KiB
Markdown
# Performance Analysis Workflows
|
|
|
|
Advanced tools for JavaScript execution, performance tracing, device emulation, and automation utilities.
|
|
|
|
## Tools in This Group
|
|
|
|
### evaluate_script
|
|
Executes JavaScript code in the page context and returns JSON-serializable results.
|
|
|
|
**Required:** `--function FUNCTION_STRING`
|
|
**Optional:** `--args JSON_ARRAY`
|
|
|
|
```bash
|
|
# Simple extraction
|
|
node scripts/evaluate_script.js --function "() => document.title"
|
|
|
|
# With parameters
|
|
node scripts/evaluate_script.js --function "(x, y) => x + y" --args '[5, 3]'
|
|
|
|
# Complex extraction
|
|
node scripts/evaluate_script.js --function "() => Array.from(document.querySelectorAll('h2')).map(h => h.textContent)"
|
|
```
|
|
|
|
### wait_for
|
|
Waits for specific text to appear on the page (for dynamic content loading).
|
|
|
|
**Required:** `--text TEXT`
|
|
**Optional:** `--timeout MILLISECONDS`
|
|
|
|
```bash
|
|
# Wait up to 10 seconds
|
|
node scripts/wait_for.js --text "Loading complete" --timeout 10000
|
|
|
|
# Wait for error message
|
|
node scripts/wait_for.js --text "Error" --timeout 5000
|
|
```
|
|
|
|
### handle_dialog
|
|
Handles browser dialogs (alert, confirm, prompt).
|
|
|
|
**Required:** `--action [accept|dismiss]`
|
|
**Optional:** `--promptText TEXT`
|
|
|
|
```bash
|
|
# Accept alert
|
|
node scripts/handle_dialog.js --action accept
|
|
|
|
# Dismiss confirm
|
|
node scripts/handle_dialog.js --action dismiss
|
|
|
|
# Accept prompt with text
|
|
node scripts/handle_dialog.js --action accept --promptText "User input"
|
|
```
|
|
|
|
### emulate
|
|
Emulates network conditions and CPU throttling.
|
|
|
|
**Optional:** `--networkConditions JSON`, `--cpuThrottlingRate NUMBER`
|
|
|
|
```bash
|
|
# Slow 3G network
|
|
node scripts/emulate.js --networkConditions '{"downloadThroughput":50000,"uploadThroughput":50000,"latency":2000}'
|
|
|
|
# 4x CPU throttling
|
|
node scripts/emulate.js --cpuThrottlingRate 4
|
|
|
|
# Both
|
|
node scripts/emulate.js --networkConditions '{"downloadThroughput":100000,"uploadThroughput":50000,"latency":100}' --cpuThrottlingRate 2
|
|
```
|
|
|
|
### performance_start_trace
|
|
Starts recording performance trace for Core Web Vitals and performance insights.
|
|
|
|
**Required:** `--reload [true|false]`, `--autoStop [true|false]`
|
|
|
|
```bash
|
|
# Start tracing with page reload
|
|
node scripts/performance_start_trace.js --reload true --autoStop false
|
|
|
|
# Start tracing without reload
|
|
node scripts/performance_start_trace.js --reload false --autoStop true
|
|
```
|
|
|
|
### performance_stop_trace
|
|
Stops the active performance trace and returns results.
|
|
|
|
```bash
|
|
node scripts/performance_stop_trace.js
|
|
```
|
|
|
|
**Output includes:**
|
|
- Core Web Vitals: LCP, FID, CLS scores
|
|
- Performance insights and recommendations
|
|
- Insight set IDs for detailed analysis
|
|
|
|
### performance_analyze_insight
|
|
Gets detailed information about a specific performance insight.
|
|
|
|
**Required:** `--insightSetId SET_ID`, `--insightName INSIGHT_NAME`
|
|
|
|
```bash
|
|
node scripts/performance_analyze_insight.js --insightSetId set_abc123 --insightName LargestContentfulPaint
|
|
```
|
|
|
|
## Workflows
|
|
|
|
### Workflow: Extract Structured Data
|
|
|
|
Scrape data from pages using JavaScript:
|
|
|
|
- [ ] Open page: `node scripts/new_page.js --url https://example.com/products`
|
|
- [ ] Wait for load: `node scripts/wait_for.js --text "Products" --timeout 10000`
|
|
- [ ] Extract product titles:
|
|
```bash
|
|
node scripts/evaluate_script.js --function "() => Array.from(document.querySelectorAll('.product-title')).map(el => el.textContent)"
|
|
```
|
|
- [ ] Extract product prices:
|
|
```bash
|
|
node scripts/evaluate_script.js --function "() => Array.from(document.querySelectorAll('.product-price')).map(el => el.textContent)"
|
|
```
|
|
- [ ] Extract complete product data:
|
|
```bash
|
|
node scripts/evaluate_script.js --function "() => Array.from(document.querySelectorAll('.product')).map(p => ({title: p.querySelector('.title').textContent, price: p.querySelector('.price').textContent, id: p.dataset.id}))"
|
|
```
|
|
|
|
**Expected Output:**
|
|
Structured JSON data extracted from page, ready for processing.
|
|
|
|
### Workflow: Comprehensive Performance Analysis
|
|
|
|
Measure page performance and Core Web Vitals:
|
|
|
|
- [ ] Open page: `node scripts/new_page.js --url https://example.com/landing`
|
|
- [ ] Start trace with reload: `node scripts/performance_start_trace.js --reload true --autoStop false`
|
|
- [ ] Wait for page load: `node scripts/wait_for.js --text "Get Started" --timeout 20000`
|
|
- [ ] Interact with page: `node scripts/click.js --uid button_cta`
|
|
- [ ] Wait for interaction: `node scripts/wait_for.js --text "Form" --timeout 5000`
|
|
- [ ] Stop trace: `node scripts/performance_stop_trace.js`
|
|
- [ ] Review output for:
|
|
- LCP (Largest Contentful Paint) - should be < 2.5s
|
|
- FID (First Input Delay) - should be < 100ms
|
|
- CLS (Cumulative Layout Shift) - should be < 0.1
|
|
- Performance insights list
|
|
- [ ] Analyze specific insight: `node scripts/performance_analyze_insight.js --insightSetId <set-id> --insightName LargestContentfulPaint`
|
|
|
|
**Expected Output:**
|
|
Full performance profile, CWV scores, actionable insights for optimization.
|
|
|
|
### Workflow: Test Under Network Constraints
|
|
|
|
Simulate slow connections:
|
|
|
|
- [ ] Set up slow 3G: `node scripts/emulate.js --networkConditions '{"downloadThroughput":50000,"uploadThroughput":50000,"latency":2000}'`
|
|
- [ ] Open page: `node scripts/new_page.js --url https://example.com --timeout 60000`
|
|
- [ ] Start performance trace: `node scripts/performance_start_trace.js --reload true --autoStop false`
|
|
- [ ] Wait for load: `node scripts/wait_for.js --text "Content" --timeout 60000`
|
|
- [ ] Stop trace: `node scripts/performance_stop_trace.js`
|
|
- [ ] Review load times: Check trace output for timing metrics
|
|
- [ ] Screenshot loaded state: `node scripts/take_screenshot.js --filePath slow_3g_loaded.png`
|
|
- [ ] Reset to fast network: `node scripts/emulate.js --networkConditions '{"downloadThroughput":10000000,"uploadThroughput":10000000,"latency":10}'`
|
|
|
|
**Expected Output:**
|
|
Page behavior under slow network documented, performance impact measured.
|
|
|
|
### Workflow: CPU Throttling Test
|
|
|
|
Test performance on low-powered devices:
|
|
|
|
- [ ] Apply 4x throttling: `node scripts/emulate.js --cpuThrottlingRate 4`
|
|
- [ ] Open app: `node scripts/new_page.js --url https://example.com/app`
|
|
- [ ] Start trace: `node scripts/performance_start_trace.js --reload true --autoStop false`
|
|
- [ ] Interact with heavy UI: `node scripts/click.js --uid button_render_chart`
|
|
- [ ] Wait for render: `node scripts/wait_for.js --text "Chart loaded" --timeout 30000`
|
|
- [ ] Stop trace: `node scripts/performance_stop_trace.js`
|
|
- [ ] Check JavaScript execution time in trace output
|
|
- [ ] Remove throttling: `node scripts/emulate.js --cpuThrottlingRate 1`
|
|
- [ ] Repeat test for comparison
|
|
|
|
**Expected Output:**
|
|
Performance comparison between throttled and normal CPU, bottlenecks identified.
|
|
|
|
### Workflow: Handle Dynamic Content Loading
|
|
|
|
Work with lazy-loaded content:
|
|
|
|
- [ ] Open page: `node scripts/new_page.js --url https://example.com/infinite-scroll`
|
|
- [ ] Wait for initial load: `node scripts/wait_for.js --text "Item 1" --timeout 5000`
|
|
- [ ] Scroll to bottom: `node scripts/evaluate_script.js --function "() => window.scrollTo(0, document.body.scrollHeight)"`
|
|
- [ ] Wait for more items: `node scripts/wait_for.js --text "Item 20" --timeout 10000`
|
|
- [ ] Take snapshot: `node scripts/take_snapshot.js`
|
|
- [ ] Scroll again: `node scripts/evaluate_script.js --function "() => window.scrollTo(0, document.body.scrollHeight)"`
|
|
- [ ] Wait for more: `node scripts/wait_for.js --text "Item 40" --timeout 10000`
|
|
- [ ] Extract all items:
|
|
```bash
|
|
node scripts/evaluate_script.js --function "() => Array.from(document.querySelectorAll('.item')).length"
|
|
```
|
|
|
|
**Expected Output:**
|
|
All lazy-loaded content triggered and captured, full list extracted.
|
|
|
|
### Workflow: Automated Dialog Handling
|
|
|
|
Automate flows with browser dialogs:
|
|
|
|
- [ ] Open page: `node scripts/new_page.js --url https://example.com/confirm-action`
|
|
- [ ] Click delete button: `node scripts/click.js --uid button_delete`
|
|
- [ ] Handle confirm dialog: `node scripts/handle_dialog.js --action accept`
|
|
- [ ] Wait for deletion: `node scripts/wait_for.js --text "Deleted successfully" --timeout 5000`
|
|
- [ ] Verify: `node scripts/take_snapshot.js`
|
|
|
|
**For prompt dialog:**
|
|
```bash
|
|
# Click button that opens prompt
|
|
node scripts/click.js --uid button_rename
|
|
|
|
# Enter new name and accept
|
|
node scripts/handle_dialog.js --action accept --promptText "New Name"
|
|
|
|
# Verify change
|
|
node scripts/wait_for.js --text "New Name" --timeout 3000
|
|
```
|
|
|
|
**Expected Output:**
|
|
Browser dialogs handled automatically, flow completes without manual intervention.
|
|
|
|
### Workflow: Custom Metrics Collection
|
|
|
|
Collect custom performance metrics:
|
|
|
|
- [ ] Open page: `node scripts/new_page.js --url https://example.com/dashboard`
|
|
- [ ] Wait for load: `node scripts/wait_for.js --text "Dashboard" --timeout 10000`
|
|
- [ ] Get page load time:
|
|
```bash
|
|
node scripts/evaluate_script.js --function "() => performance.timing.loadEventEnd - performance.timing.navigationStart"
|
|
```
|
|
- [ ] Get resource count:
|
|
```bash
|
|
node scripts/evaluate_script.js --function "() => performance.getEntriesByType('resource').length"
|
|
```
|
|
- [ ] Get memory usage (if available):
|
|
```bash
|
|
node scripts/evaluate_script.js --function "() => performance.memory ? performance.memory.usedJSHeapSize : null"
|
|
```
|
|
- [ ] Get paint timings:
|
|
```bash
|
|
node scripts/evaluate_script.js --function "() => performance.getEntriesByType('paint').map(p => ({name: p.name, time: p.startTime}))"
|
|
```
|
|
|
|
**Expected Output:**
|
|
Custom performance metrics collected via Performance API, specific to your needs.
|
|
|
|
### Workflow: A/B Test Performance Comparison
|
|
|
|
Compare performance across variants:
|
|
|
|
- [ ] **Variant A:**
|
|
- [ ] Open: `node scripts/new_page.js --url https://example.com?variant=a`
|
|
- [ ] Trace: `node scripts/performance_start_trace.js --reload true --autoStop false`
|
|
- [ ] Wait: `node scripts/wait_for.js --text "Content" --timeout 15000`
|
|
- [ ] Stop: `node scripts/performance_stop_trace.js > variant_a_trace.txt`
|
|
- [ ] Screenshot: `node scripts/take_screenshot.js --filePath variant_a.png`
|
|
- [ ] **Variant B:**
|
|
- [ ] Navigate: `node scripts/navigate_page.js --url https://example.com?variant=b`
|
|
- [ ] Trace: `node scripts/performance_start_trace.js --reload true --autoStop false`
|
|
- [ ] Wait: `node scripts/wait_for.js --text "Content" --timeout 15000`
|
|
- [ ] Stop: `node scripts/performance_stop_trace.js > variant_b_trace.txt`
|
|
- [ ] Screenshot: `node scripts/take_screenshot.js --filePath variant_b.png`
|
|
- [ ] Compare CWV scores from both trace files
|
|
|
|
**Expected Output:**
|
|
Performance metrics for both variants, data-driven comparison for optimization.
|
|
|
|
## Common Patterns
|
|
|
|
### Pattern: Safe Script Evaluation
|
|
|
|
Always return JSON-serializable data:
|
|
|
|
```bash
|
|
# Good: Returns string
|
|
node scripts/evaluate_script.js --function "() => document.title"
|
|
|
|
# Good: Returns array of strings
|
|
node scripts/evaluate_script.js --function "() => Array.from(document.querySelectorAll('a')).map(a => a.href)"
|
|
|
|
# Bad: Returns DOM nodes (not serializable)
|
|
# node scripts/evaluate_script.js --function "() => document.querySelectorAll('a')"
|
|
```
|
|
|
|
### Pattern: Wait Before Interaction
|
|
|
|
Always wait for dynamic content:
|
|
|
|
```bash
|
|
# 1. Trigger action
|
|
node scripts/click.js --uid button_load
|
|
|
|
# 2. Wait for content
|
|
node scripts/wait_for.js --text "Loaded" --timeout 10000
|
|
|
|
# 3. Now safe to interact
|
|
node scripts/take_snapshot.js
|
|
```
|
|
|
|
### Pattern: Complete Performance Workflow
|
|
|
|
Standard performance analysis sequence:
|
|
|
|
```bash
|
|
# 1. Start tracing
|
|
node scripts/performance_start_trace.js --reload true --autoStop false
|
|
|
|
# 2. Let page load completely
|
|
node scripts/wait_for.js --text "Ready" --timeout 20000
|
|
|
|
# 3. Stop tracing
|
|
node scripts/performance_stop_trace.js
|
|
|
|
# 4. Analyze specific insights
|
|
node scripts/performance_analyze_insight.js --insightSetId <id> --insightName <name>
|
|
```
|
|
|
|
### Pattern: Emulation Reset
|
|
|
|
Reset emulation to normal after testing:
|
|
|
|
```bash
|
|
# 1. Test under constraints
|
|
node scripts/emulate.js --cpuThrottlingRate 4
|
|
|
|
# ... run tests ...
|
|
|
|
# 2. Reset to normal
|
|
node scripts/emulate.js --cpuThrottlingRate 1
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
**Problem:** evaluate_script returns null or error
|
|
|
|
**Solution:**
|
|
- Ensure function returns JSON-serializable values (no DOM nodes, functions, or circular references)
|
|
- Use .map() to extract primitive values from DOM elements
|
|
- Check browser console for JavaScript errors: `list_console_messages.js --types error`
|
|
|
|
**Problem:** wait_for times out
|
|
|
|
**Solution:**
|
|
- Increase timeout: `--timeout 30000` (30 seconds)
|
|
- Verify text actually appears on page (check with `take_snapshot.js`)
|
|
- Text match is exact - check spelling and case
|
|
- Wait for network to finish if text appears after API call
|
|
|
|
**Problem:** Dialog not handled
|
|
|
|
**Solution:**
|
|
- Dialog must be already open when you call `handle_dialog.js`
|
|
- Trigger dialog first (e.g., click button), then immediately call `handle_dialog.js`
|
|
- Some "dialogs" are custom HTML, not browser dialogs - use `click.js` instead
|
|
|
|
**Problem:** Performance trace shows unexpected results
|
|
|
|
**Solution:**
|
|
- Ensure page fully loads before stopping trace
|
|
- Use `--reload true` for consistent initial page load measurement
|
|
- Clear browser cache if testing first-time load performance
|
|
- Disable browser extensions that might affect performance
|
|
|
|
**Problem:** Emulation not working
|
|
|
|
**Solution:**
|
|
- Emulation settings persist for the session
|
|
- To remove emulation, set back to normal values
|
|
- Network conditions JSON must be valid with all three properties
|
|
- CPU throttling rate of 1 = normal, higher = slower
|
|
|
|
**Problem:** Script evaluation with args fails
|
|
|
|
**Solution:**
|
|
- Args must be valid JSON array: `--args '[1, 2, 3]'`
|
|
- Function must accept the correct number of parameters
|
|
- Use single quotes around JSON, double quotes inside
|
|
- Example: `--function "(a, b) => a + b" --args '[5, 10]'`
|