Initial commit
This commit is contained in:
290
skills/website-debug/references/css-debug.md
Normal file
290
skills/website-debug/references/css-debug.md
Normal file
@@ -0,0 +1,290 @@
|
||||
# CSS Debugging Reference
|
||||
|
||||
Advanced CSS debugging workflows and patterns for frontend development.
|
||||
|
||||
## Quick Diagnostics
|
||||
|
||||
### Check Element Visibility
|
||||
```bash
|
||||
# Is element visible?
|
||||
./browser-eval.js '(() => {
|
||||
const el = document.querySelector(".target");
|
||||
const s = getComputedStyle(el);
|
||||
return {
|
||||
display: s.display,
|
||||
visibility: s.visibility,
|
||||
opacity: s.opacity,
|
||||
hidden: el.hidden,
|
||||
height: s.height,
|
||||
width: s.width,
|
||||
overflow: s.overflow
|
||||
};
|
||||
})()'
|
||||
```
|
||||
|
||||
### Element Not Showing?
|
||||
Common causes and checks:
|
||||
|
||||
```bash
|
||||
# Check display property
|
||||
./browser-eval.js 'getComputedStyle(document.querySelector(".target")).display'
|
||||
# If "none" - element is hidden by CSS
|
||||
|
||||
# Check visibility
|
||||
./browser-eval.js 'getComputedStyle(document.querySelector(".target")).visibility'
|
||||
# If "hidden" - element takes space but invisible
|
||||
|
||||
# Check opacity
|
||||
./browser-eval.js 'getComputedStyle(document.querySelector(".target")).opacity'
|
||||
# If "0" - element is transparent
|
||||
|
||||
# Check dimensions
|
||||
./browser-eval.js 'document.querySelector(".target").getBoundingClientRect()'
|
||||
# If width/height is 0 - element has no size
|
||||
|
||||
# Check if off-screen
|
||||
./browser-eval.js '(() => {
|
||||
const r = document.querySelector(".target").getBoundingClientRect();
|
||||
return {
|
||||
inViewport: r.top >= 0 && r.left >= 0 && r.bottom <= window.innerHeight && r.right <= window.innerWidth,
|
||||
position: { top: r.top, left: r.left }
|
||||
};
|
||||
})()'
|
||||
```
|
||||
|
||||
## Layout Issues
|
||||
|
||||
### Flexbox Debugging
|
||||
```bash
|
||||
# Check flex container
|
||||
./browser-eval.js '(() => {
|
||||
const el = document.querySelector(".flex-container");
|
||||
const s = getComputedStyle(el);
|
||||
return {
|
||||
display: s.display,
|
||||
flexDirection: s.flexDirection,
|
||||
justifyContent: s.justifyContent,
|
||||
alignItems: s.alignItems,
|
||||
flexWrap: s.flexWrap,
|
||||
gap: s.gap
|
||||
};
|
||||
})()'
|
||||
|
||||
# Check flex items
|
||||
./browser-eval.js '[...document.querySelectorAll(".flex-container > *")].map(el => {
|
||||
const s = getComputedStyle(el);
|
||||
return {
|
||||
flexGrow: s.flexGrow,
|
||||
flexShrink: s.flexShrink,
|
||||
flexBasis: s.flexBasis,
|
||||
alignSelf: s.alignSelf
|
||||
};
|
||||
})'
|
||||
```
|
||||
|
||||
### Grid Debugging
|
||||
```bash
|
||||
# Check grid container
|
||||
./browser-eval.js '(() => {
|
||||
const el = document.querySelector(".grid-container");
|
||||
const s = getComputedStyle(el);
|
||||
return {
|
||||
display: s.display,
|
||||
gridTemplateColumns: s.gridTemplateColumns,
|
||||
gridTemplateRows: s.gridTemplateRows,
|
||||
gap: s.gap,
|
||||
gridAutoFlow: s.gridAutoFlow
|
||||
};
|
||||
})()'
|
||||
```
|
||||
|
||||
### Box Model
|
||||
```bash
|
||||
# Full box model breakdown
|
||||
./browser-eval.js '(() => {
|
||||
const el = document.querySelector(".target");
|
||||
const s = getComputedStyle(el);
|
||||
const r = el.getBoundingClientRect();
|
||||
return {
|
||||
content: { width: r.width, height: r.height },
|
||||
padding: { top: s.paddingTop, right: s.paddingRight, bottom: s.paddingBottom, left: s.paddingLeft },
|
||||
border: { top: s.borderTopWidth, right: s.borderRightWidth, bottom: s.borderBottomWidth, left: s.borderLeftWidth },
|
||||
margin: { top: s.marginTop, right: s.marginRight, bottom: s.marginBottom, left: s.marginLeft },
|
||||
boxSizing: s.boxSizing
|
||||
};
|
||||
})()'
|
||||
```
|
||||
|
||||
## Positioning Problems
|
||||
|
||||
### Z-Index Stacking
|
||||
```bash
|
||||
# Find all positioned elements with z-index
|
||||
./browser-eval.js '[...document.querySelectorAll("*")].filter(el => {
|
||||
const s = getComputedStyle(el);
|
||||
return s.position !== "static" && s.zIndex !== "auto";
|
||||
}).map(el => ({
|
||||
selector: el.tagName + (el.id ? "#" + el.id : "") + (el.className ? "." + el.className.split(" ")[0] : ""),
|
||||
position: getComputedStyle(el).position,
|
||||
zIndex: getComputedStyle(el).zIndex
|
||||
})).sort((a, b) => parseInt(b.zIndex) - parseInt(a.zIndex))'
|
||||
```
|
||||
|
||||
### Fixed/Sticky Elements
|
||||
```bash
|
||||
# Find fixed/sticky elements
|
||||
./browser-eval.js '[...document.querySelectorAll("*")].filter(el => {
|
||||
const pos = getComputedStyle(el).position;
|
||||
return pos === "fixed" || pos === "sticky";
|
||||
}).map(el => ({
|
||||
tag: el.tagName.toLowerCase(),
|
||||
id: el.id,
|
||||
class: el.className,
|
||||
position: getComputedStyle(el).position
|
||||
}))'
|
||||
```
|
||||
|
||||
## Responsive Issues
|
||||
|
||||
### Media Query Testing
|
||||
```bash
|
||||
# Test different breakpoints
|
||||
./browser-resize.js --mobile && ./browser-screenshot.js --output=/tmp/mobile.png
|
||||
./browser-resize.js --tablet && ./browser-screenshot.js --output=/tmp/tablet.png
|
||||
./browser-resize.js --desktop && ./browser-screenshot.js --output=/tmp/desktop.png
|
||||
```
|
||||
|
||||
### Check Current Viewport
|
||||
```bash
|
||||
./browser-eval.js '({
|
||||
viewport: { width: window.innerWidth, height: window.innerHeight },
|
||||
screen: { width: screen.width, height: screen.height },
|
||||
devicePixelRatio: window.devicePixelRatio
|
||||
})'
|
||||
```
|
||||
|
||||
## Typography Issues
|
||||
|
||||
### Font Not Loading
|
||||
```bash
|
||||
# Check computed font
|
||||
./browser-eval.js 'getComputedStyle(document.querySelector(".text")).fontFamily'
|
||||
|
||||
# Check if webfont loaded
|
||||
./browser-eval.js 'document.fonts.check("16px YourFontName")'
|
||||
|
||||
# List all loaded fonts
|
||||
./browser-eval.js '[...document.fonts].map(f => ({ family: f.family, style: f.style, weight: f.weight, status: f.status }))'
|
||||
```
|
||||
|
||||
### Text Overflow
|
||||
```bash
|
||||
# Check text overflow settings
|
||||
./browser-eval.js '(() => {
|
||||
const el = document.querySelector(".truncated-text");
|
||||
const s = getComputedStyle(el);
|
||||
return {
|
||||
overflow: s.overflow,
|
||||
textOverflow: s.textOverflow,
|
||||
whiteSpace: s.whiteSpace,
|
||||
width: s.width,
|
||||
maxWidth: s.maxWidth
|
||||
};
|
||||
})()'
|
||||
```
|
||||
|
||||
## Color & Visual
|
||||
|
||||
### Check Colors
|
||||
```bash
|
||||
# Get all colors used on element
|
||||
./browser-eval.js '(() => {
|
||||
const el = document.querySelector(".target");
|
||||
const s = getComputedStyle(el);
|
||||
return {
|
||||
color: s.color,
|
||||
backgroundColor: s.backgroundColor,
|
||||
borderColor: s.borderColor,
|
||||
outlineColor: s.outlineColor
|
||||
};
|
||||
})()'
|
||||
```
|
||||
|
||||
### Find Elements by Color
|
||||
```bash
|
||||
# Find all elements with a specific background
|
||||
./browser-eval.js '[...document.querySelectorAll("*")].filter(el =>
|
||||
getComputedStyle(el).backgroundColor === "rgb(255, 0, 0)"
|
||||
).map(el => el.tagName + (el.id ? "#" + el.id : ""))'
|
||||
```
|
||||
|
||||
## Performance Concerns
|
||||
|
||||
### Large DOM Check
|
||||
```bash
|
||||
./browser-eval.js '({
|
||||
totalElements: document.querySelectorAll("*").length,
|
||||
deepestNesting: (() => {
|
||||
let max = 0;
|
||||
document.querySelectorAll("*").forEach(el => {
|
||||
let depth = 0, node = el;
|
||||
while (node.parentElement) { depth++; node = node.parentElement; }
|
||||
if (depth > max) max = depth;
|
||||
});
|
||||
return max;
|
||||
})()
|
||||
})'
|
||||
```
|
||||
|
||||
### Reflow Triggers
|
||||
Watch for properties that cause layout recalculation:
|
||||
- offsetTop/Left/Width/Height
|
||||
- scrollTop/Left/Width/Height
|
||||
- clientTop/Left/Width/Height
|
||||
- getComputedStyle()
|
||||
- getBoundingClientRect()
|
||||
|
||||
## Animation Debugging
|
||||
|
||||
### Check Animations
|
||||
```bash
|
||||
./browser-eval.js '(() => {
|
||||
const el = document.querySelector(".animated");
|
||||
const s = getComputedStyle(el);
|
||||
return {
|
||||
animation: s.animation,
|
||||
animationName: s.animationName,
|
||||
animationDuration: s.animationDuration,
|
||||
animationTimingFunction: s.animationTimingFunction,
|
||||
animationDelay: s.animationDelay,
|
||||
transition: s.transition
|
||||
};
|
||||
})()'
|
||||
```
|
||||
|
||||
### Force Animation State
|
||||
```bash
|
||||
# Pause all animations
|
||||
./browser-eval.js 'document.querySelectorAll("*").forEach(el => el.style.animationPlayState = "paused")'
|
||||
|
||||
# Resume animations
|
||||
./browser-eval.js 'document.querySelectorAll("*").forEach(el => el.style.animationPlayState = "")'
|
||||
```
|
||||
|
||||
## Common CSS Fixes
|
||||
|
||||
### Overflow Scroll Not Working
|
||||
Check these in order:
|
||||
1. Parent has defined height
|
||||
2. `overflow` is set to `scroll` or `auto`
|
||||
3. Content is actually taller than container
|
||||
|
||||
### Element Behind Another
|
||||
1. Check z-index values
|
||||
2. Ensure positioned (relative/absolute/fixed)
|
||||
3. Check stacking context (transform, opacity < 1, etc. create new contexts)
|
||||
|
||||
### Flexbox Not Centering
|
||||
1. Container has height
|
||||
2. `align-items` for vertical, `justify-content` for horizontal
|
||||
3. Check `flex-direction` - swaps main/cross axis
|
||||
259
skills/website-debug/references/js-debug.md
Normal file
259
skills/website-debug/references/js-debug.md
Normal file
@@ -0,0 +1,259 @@
|
||||
# JavaScript Debugging Reference
|
||||
|
||||
Workflows for diagnosing and fixing JavaScript issues in web applications.
|
||||
|
||||
## Error Detection
|
||||
|
||||
### Capture Runtime Errors
|
||||
```bash
|
||||
# Watch for errors in real-time
|
||||
./browser-console.js --errors --watch
|
||||
|
||||
# Inject error capture (run once per page load)
|
||||
./browser-eval.js 'window.onerror = (msg, src, line, col, err) => {
|
||||
window.__jsErrors = window.__jsErrors || [];
|
||||
window.__jsErrors.push({ message: msg, source: src, line, col, stack: err?.stack });
|
||||
return false;
|
||||
}'
|
||||
|
||||
# Check captured errors
|
||||
./browser-eval.js 'window.__jsErrors || []'
|
||||
```
|
||||
|
||||
### Unhandled Promise Rejections
|
||||
```bash
|
||||
# Capture unhandled rejections
|
||||
./browser-eval.js 'window.addEventListener("unhandledrejection", e => {
|
||||
window.__promiseErrors = window.__promiseErrors || [];
|
||||
window.__promiseErrors.push({ reason: e.reason?.message || String(e.reason) });
|
||||
})'
|
||||
|
||||
# Check promise errors
|
||||
./browser-eval.js 'window.__promiseErrors || []'
|
||||
```
|
||||
|
||||
## Common Error Types
|
||||
|
||||
### TypeError: Cannot read property 'x' of undefined
|
||||
**Cause**: Accessing property on null/undefined
|
||||
**Debug**:
|
||||
```bash
|
||||
# Check if element exists
|
||||
./browser-eval.js 'document.querySelector(".my-element")'
|
||||
|
||||
# Check if variable/property exists
|
||||
./browser-eval.js 'typeof window.myApp?.myProperty'
|
||||
```
|
||||
|
||||
### ReferenceError: x is not defined
|
||||
**Cause**: Variable not in scope or not declared
|
||||
**Debug**:
|
||||
```bash
|
||||
# Check if global exists
|
||||
./browser-eval.js '"myVariable" in window'
|
||||
|
||||
# List all globals matching pattern
|
||||
./browser-eval.js 'Object.keys(window).filter(k => k.includes("my"))'
|
||||
```
|
||||
|
||||
### SyntaxError
|
||||
**Cause**: Invalid JavaScript syntax
|
||||
**Debug**: Check browser console for file and line number
|
||||
```bash
|
||||
./browser-console.js --errors
|
||||
```
|
||||
|
||||
## State Inspection
|
||||
|
||||
### Check Global Variables
|
||||
```bash
|
||||
# List all custom globals (excluding built-ins)
|
||||
./browser-eval.js '(() => {
|
||||
const iframe = document.createElement("iframe");
|
||||
document.body.appendChild(iframe);
|
||||
const builtins = new Set(Object.keys(iframe.contentWindow));
|
||||
iframe.remove();
|
||||
return Object.keys(window).filter(k => !builtins.has(k) && !k.startsWith("__"));
|
||||
})()'
|
||||
```
|
||||
|
||||
### Inspect Application State
|
||||
```bash
|
||||
# React state (if using React DevTools globals)
|
||||
./browser-eval.js 'window.__REACT_DEVTOOLS_GLOBAL_HOOK__?.renderers'
|
||||
|
||||
# Redux store (if exposed)
|
||||
./browser-eval.js 'window.__store?.getState()'
|
||||
|
||||
# Vue instance (if exposed)
|
||||
./browser-eval.js 'document.querySelector("#app")?.__vue__?.$data'
|
||||
```
|
||||
|
||||
### Local Storage / Session Storage
|
||||
```bash
|
||||
# View localStorage
|
||||
./browser-eval.js 'Object.fromEntries(Object.entries(localStorage))'
|
||||
|
||||
# View sessionStorage
|
||||
./browser-eval.js 'Object.fromEntries(Object.entries(sessionStorage))'
|
||||
```
|
||||
|
||||
## Event Debugging
|
||||
|
||||
### Check Event Listeners
|
||||
```bash
|
||||
# Get listeners on element (Chrome only)
|
||||
./browser-eval.js 'getEventListeners(document.querySelector(".button"))'
|
||||
|
||||
# Alternative: Check if onclick exists
|
||||
./browser-eval.js 'typeof document.querySelector(".button").onclick'
|
||||
```
|
||||
|
||||
### Debug Event Firing
|
||||
```bash
|
||||
# Log all click events
|
||||
./browser-eval.js 'document.addEventListener("click", e => console.log("Click:", e.target.tagName, e.target.className), true)'
|
||||
|
||||
# Log all form submissions
|
||||
./browser-eval.js 'document.addEventListener("submit", e => console.log("Form submit:", e.target.action), true)'
|
||||
```
|
||||
|
||||
### Simulate Events
|
||||
```bash
|
||||
# Click element
|
||||
./browser-eval.js 'document.querySelector(".button").click()'
|
||||
|
||||
# Dispatch custom event
|
||||
./browser-eval.js 'document.querySelector(".target").dispatchEvent(new Event("input", { bubbles: true }))'
|
||||
|
||||
# Submit form
|
||||
./browser-eval.js 'document.querySelector("form").submit()'
|
||||
```
|
||||
|
||||
## Async Debugging
|
||||
|
||||
### Track Pending Promises
|
||||
```bash
|
||||
# Wrap fetch to log all requests
|
||||
./browser-eval.js '(() => {
|
||||
const orig = window.fetch;
|
||||
window.fetch = (...args) => {
|
||||
console.log("Fetch:", args[0]);
|
||||
return orig.apply(window, args);
|
||||
};
|
||||
})()'
|
||||
```
|
||||
|
||||
### Debug setTimeout/setInterval
|
||||
```bash
|
||||
# List all active timers (approximate)
|
||||
./browser-eval.js '(() => {
|
||||
const ids = [];
|
||||
const id = setTimeout(() => {}, 0);
|
||||
clearTimeout(id);
|
||||
for (let i = 1; i < id; i++) {
|
||||
clearTimeout(i);
|
||||
clearInterval(i);
|
||||
}
|
||||
return `Cleared timers up to ID ${id}`;
|
||||
})()'
|
||||
```
|
||||
|
||||
## Network-Related JS Issues
|
||||
|
||||
### Check if Fetch Failed
|
||||
```bash
|
||||
./browser-eval.js 'fetch("/api/data").then(r => ({ status: r.status, ok: r.ok })).catch(e => ({ error: e.message }))'
|
||||
```
|
||||
|
||||
### CORS Errors
|
||||
Check console for CORS errors:
|
||||
```bash
|
||||
./browser-console.js --errors | grep -i cors
|
||||
```
|
||||
|
||||
### API Response Issues
|
||||
```bash
|
||||
# Test API and inspect response
|
||||
./browser-eval.js 'fetch("/api/endpoint").then(r => r.json()).then(d => JSON.stringify(d, null, 2)).catch(e => e.message)'
|
||||
```
|
||||
|
||||
## Module/Import Issues
|
||||
|
||||
### Check if Module Loaded
|
||||
```bash
|
||||
# Check for module in global scope
|
||||
./browser-eval.js '"ModuleName" in window'
|
||||
|
||||
# Check ES module
|
||||
./browser-eval.js 'import("./module.js").then(m => Object.keys(m)).catch(e => e.message)'
|
||||
```
|
||||
|
||||
### Script Load Order
|
||||
```bash
|
||||
# List all scripts in order
|
||||
./browser-eval.js '[...document.querySelectorAll("script")].map(s => ({ src: s.src || "(inline)", async: s.async, defer: s.defer }))'
|
||||
```
|
||||
|
||||
## Performance Issues
|
||||
|
||||
### Identify Long Tasks
|
||||
```bash
|
||||
# Monitor long tasks
|
||||
./browser-eval.js '(() => {
|
||||
const observer = new PerformanceObserver(list => {
|
||||
list.getEntries().forEach(entry => console.log("Long task:", entry.duration, "ms"));
|
||||
});
|
||||
observer.observe({ entryTypes: ["longtask"] });
|
||||
return "Long task observer started";
|
||||
})()'
|
||||
```
|
||||
|
||||
### Memory Leaks
|
||||
```bash
|
||||
# Get heap size (Chrome)
|
||||
./browser-eval.js 'performance.memory ? { usedHeap: Math.round(performance.memory.usedJSHeapSize / 1024 / 1024) + "MB", totalHeap: Math.round(performance.memory.totalJSHeapSize / 1024 / 1024) + "MB" } : "Not available"'
|
||||
```
|
||||
|
||||
## Framework-Specific
|
||||
|
||||
### React Debugging
|
||||
```bash
|
||||
# Find React components in DOM
|
||||
./browser-eval.js '(() => {
|
||||
const reactRoot = document.querySelector("[data-reactroot], #root, #app");
|
||||
return reactRoot ? "React app found" : "No React root detected";
|
||||
})()'
|
||||
|
||||
# Check for React errors
|
||||
./browser-console.js --errors | grep -i react
|
||||
```
|
||||
|
||||
### Vue Debugging
|
||||
```bash
|
||||
# Check Vue version
|
||||
./browser-eval.js 'window.Vue?.version || document.querySelector("[data-v-]") ? "Vue detected" : "No Vue"'
|
||||
```
|
||||
|
||||
### Next.js/Nuxt Hydration
|
||||
```bash
|
||||
# Check for hydration errors
|
||||
./browser-console.js --errors | grep -i hydrat
|
||||
```
|
||||
|
||||
## Quick Fixes
|
||||
|
||||
### Script Not Running
|
||||
1. Check if script loaded: `./browser-dom.js "script[src*='filename']"`
|
||||
2. Check for syntax errors: `./browser-console.js --errors`
|
||||
3. Check load order: Ensure dependencies load first
|
||||
|
||||
### Event Handler Not Working
|
||||
1. Check element exists when handler attached
|
||||
2. Verify selector is correct
|
||||
3. Check for event.preventDefault() or stopPropagation()
|
||||
|
||||
### Async Code Not Executing
|
||||
1. Check if Promise rejects: Add .catch() logging
|
||||
2. Verify await is in async function
|
||||
3. Check network requests complete successfully
|
||||
288
skills/website-debug/references/self-debug.md
Normal file
288
skills/website-debug/references/self-debug.md
Normal file
@@ -0,0 +1,288 @@
|
||||
# Self-Debugging Workflow
|
||||
|
||||
Patterns for Claude and AI agents to verify and fix their own frontend work.
|
||||
|
||||
## Core Principle
|
||||
|
||||
After making any frontend change, verify it worked:
|
||||
1. **Screenshot** - Visual verification
|
||||
2. **Console** - Check for errors
|
||||
3. **DOM** - Confirm structure
|
||||
4. **Iterate** - Fix issues and repeat
|
||||
|
||||
## Basic Verification Loop
|
||||
|
||||
```bash
|
||||
# After modifying HTML/CSS/JS files:
|
||||
|
||||
# 1. Reload the page (if not using hot reload)
|
||||
./browser-nav.js http://localhost:3000
|
||||
|
||||
# 2. Take screenshot to verify visual result
|
||||
./browser-screenshot.js
|
||||
|
||||
# 3. Check for any JavaScript errors
|
||||
./browser-console.js --errors
|
||||
|
||||
# 4. If issues found, fix and repeat
|
||||
```
|
||||
|
||||
## Structured Debugging Protocol
|
||||
|
||||
### Phase 1: Initial Assessment
|
||||
```bash
|
||||
# Get page summary
|
||||
./browser-dom.js
|
||||
|
||||
# Take baseline screenshot
|
||||
./browser-screenshot.js --output=/tmp/current-state.png
|
||||
|
||||
# Capture any errors
|
||||
./browser-console.js --errors > /tmp/errors.txt
|
||||
```
|
||||
|
||||
### Phase 2: Make Changes
|
||||
After editing source files:
|
||||
```bash
|
||||
# Force reload (bypass cache)
|
||||
./browser-eval.js 'location.reload(true)'
|
||||
|
||||
# Wait for page load
|
||||
sleep 2
|
||||
|
||||
# Take new screenshot
|
||||
./browser-screenshot.js --output=/tmp/after-change.png
|
||||
```
|
||||
|
||||
### Phase 3: Verify
|
||||
```bash
|
||||
# Check for new errors
|
||||
./browser-console.js --errors
|
||||
|
||||
# Verify element exists (example: new button)
|
||||
./browser-eval.js 'document.querySelector(".new-button") ? "Found" : "Missing"'
|
||||
|
||||
# Verify styling applied
|
||||
./browser-eval.js 'getComputedStyle(document.querySelector(".new-button")).backgroundColor'
|
||||
```
|
||||
|
||||
### Phase 4: Iterate
|
||||
If issues found:
|
||||
1. Identify the problem from screenshot/console
|
||||
2. Fix the source code
|
||||
3. Return to Phase 2
|
||||
|
||||
## Common Self-Fix Patterns
|
||||
|
||||
### CSS Not Applying
|
||||
|
||||
**Symptom**: Element exists but looks wrong
|
||||
**Diagnosis**:
|
||||
```bash
|
||||
# Check if styles computed correctly
|
||||
./browser-eval.js 'getComputedStyle(document.querySelector(".my-element")).cssText.slice(0, 500)'
|
||||
|
||||
# Check for conflicting selectors
|
||||
./browser-eval.js '(() => {
|
||||
const el = document.querySelector(".my-element");
|
||||
const sheets = [...document.styleSheets];
|
||||
const matches = [];
|
||||
sheets.forEach(sheet => {
|
||||
try {
|
||||
[...sheet.cssRules].forEach(rule => {
|
||||
if (el.matches(rule.selectorText)) matches.push(rule.selectorText);
|
||||
});
|
||||
} catch {}
|
||||
});
|
||||
return matches;
|
||||
})()'
|
||||
```
|
||||
|
||||
**Fixes to try**:
|
||||
1. Increase specificity
|
||||
2. Check for `!important` overrides
|
||||
3. Verify selector matches element
|
||||
|
||||
### Element Not Visible
|
||||
|
||||
**Symptom**: DOM shows element but not visible
|
||||
**Diagnosis**:
|
||||
```bash
|
||||
./browser-eval.js '(() => {
|
||||
const el = document.querySelector(".my-element");
|
||||
const s = getComputedStyle(el);
|
||||
const r = el.getBoundingClientRect();
|
||||
return {
|
||||
exists: !!el,
|
||||
display: s.display,
|
||||
visibility: s.visibility,
|
||||
opacity: s.opacity,
|
||||
width: r.width,
|
||||
height: r.height,
|
||||
inViewport: r.top < window.innerHeight && r.bottom > 0
|
||||
};
|
||||
})()'
|
||||
```
|
||||
|
||||
**Fixes based on result**:
|
||||
- `display: none` → Check CSS rules hiding it
|
||||
- `width/height: 0` → Add dimensions or content
|
||||
- `opacity: 0` → Check for fade animations
|
||||
- Not in viewport → Check positioning/scroll
|
||||
|
||||
### JavaScript Not Running
|
||||
|
||||
**Symptom**: Interactive features don't work
|
||||
**Diagnosis**:
|
||||
```bash
|
||||
# Check for errors
|
||||
./browser-console.js --errors
|
||||
|
||||
# Check if script loaded
|
||||
./browser-eval.js 'document.querySelectorAll("script").length'
|
||||
|
||||
# Check if function exists
|
||||
./browser-eval.js 'typeof myFunction'
|
||||
```
|
||||
|
||||
**Fixes based on result**:
|
||||
- Syntax error → Fix the JavaScript
|
||||
- Script not loaded → Check path/build process
|
||||
- Function undefined → Check load order, exports
|
||||
|
||||
### Layout Broken
|
||||
|
||||
**Symptom**: Elements positioned incorrectly
|
||||
**Diagnosis**:
|
||||
```bash
|
||||
# Take screenshot
|
||||
./browser-screenshot.js
|
||||
|
||||
# Check flex/grid container
|
||||
./browser-eval.js '(() => {
|
||||
const container = document.querySelector(".container");
|
||||
const s = getComputedStyle(container);
|
||||
return { display: s.display, flexDirection: s.flexDirection, gridTemplateColumns: s.gridTemplateColumns };
|
||||
})()'
|
||||
```
|
||||
|
||||
**Common fixes**:
|
||||
- Missing `display: flex/grid` on container
|
||||
- Wrong `flex-direction`
|
||||
- Missing `width` on flex children
|
||||
- Grid columns not matching children
|
||||
|
||||
## Responsive Verification
|
||||
|
||||
### Test All Breakpoints
|
||||
```bash
|
||||
# Mobile
|
||||
./browser-resize.js --mobile
|
||||
./browser-screenshot.js --output=/tmp/mobile.png
|
||||
./browser-console.js --errors
|
||||
|
||||
# Tablet
|
||||
./browser-resize.js --tablet
|
||||
./browser-screenshot.js --output=/tmp/tablet.png
|
||||
|
||||
# Desktop
|
||||
./browser-resize.js --desktop
|
||||
./browser-screenshot.js --output=/tmp/desktop.png
|
||||
```
|
||||
|
||||
### Compare Screenshots
|
||||
After each breakpoint, Claude should analyze the screenshot for:
|
||||
- Layout shifts
|
||||
- Overlapping elements
|
||||
- Text overflow
|
||||
- Hidden/missing elements
|
||||
- Incorrect spacing
|
||||
|
||||
## Interactive Feature Testing
|
||||
|
||||
### Form Validation
|
||||
```bash
|
||||
# Fill form with test data
|
||||
./browser-eval.js 'document.querySelector("#email").value = "test@example.com"'
|
||||
./browser-eval.js 'document.querySelector("#password").value = "test123"'
|
||||
|
||||
# Submit and check result
|
||||
./browser-eval.js 'document.querySelector("form").submit()'
|
||||
./browser-screenshot.js
|
||||
./browser-console.js --errors
|
||||
```
|
||||
|
||||
### Click/Hover States
|
||||
```bash
|
||||
# Test button click
|
||||
./browser-eval.js 'document.querySelector(".button").click()'
|
||||
./browser-screenshot.js
|
||||
|
||||
# Check state changed
|
||||
./browser-eval.js 'document.querySelector(".modal")?.style.display'
|
||||
```
|
||||
|
||||
## Automated Verification Script
|
||||
|
||||
For repeated checks, use this pattern:
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# verify-page.sh - Run after changes
|
||||
|
||||
URL="${1:-http://localhost:3000}"
|
||||
OUT_DIR="/tmp/debug-$(date +%s)"
|
||||
mkdir -p "$OUT_DIR"
|
||||
|
||||
echo "Verifying $URL..."
|
||||
|
||||
# Navigate
|
||||
./browser-nav.js "$URL"
|
||||
sleep 2
|
||||
|
||||
# Screenshot
|
||||
./browser-screenshot.js --output="$OUT_DIR/screenshot.png"
|
||||
echo "Screenshot: $OUT_DIR/screenshot.png"
|
||||
|
||||
# Errors
|
||||
./browser-console.js --errors > "$OUT_DIR/errors.txt"
|
||||
if [ -s "$OUT_DIR/errors.txt" ]; then
|
||||
echo "⚠️ Errors found:"
|
||||
cat "$OUT_DIR/errors.txt"
|
||||
else
|
||||
echo "✓ No JavaScript errors"
|
||||
fi
|
||||
|
||||
# DOM summary
|
||||
./browser-dom.js > "$OUT_DIR/dom.txt"
|
||||
echo "DOM summary saved"
|
||||
|
||||
echo "Done. Files in $OUT_DIR"
|
||||
```
|
||||
|
||||
## Error Recovery Strategies
|
||||
|
||||
### When Screenshot Shows Blank Page
|
||||
1. Check console for critical errors
|
||||
2. Verify server is running
|
||||
3. Check network requests (404, 500)
|
||||
4. Verify correct URL
|
||||
|
||||
### When Console Shows Many Errors
|
||||
1. Fix first error (often causes cascade)
|
||||
2. Reload and recheck
|
||||
3. Address errors in order
|
||||
|
||||
### When Element Is "Almost Right"
|
||||
1. Use picker to select element: `./browser-pick.js "Select the problematic element"`
|
||||
2. Get full computed styles
|
||||
3. Compare to expected values
|
||||
4. Adjust CSS incrementally
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Always screenshot after changes** - Visual verification catches most issues
|
||||
2. **Check console immediately** - Catch JS errors early
|
||||
3. **Test responsive early** - Layout issues compound
|
||||
4. **Verify one change at a time** - Easier to identify what broke
|
||||
5. **Save debug output** - Reference for comparison
|
||||
6. **Use the picker for precision** - Get exact selectors from user
|
||||
Reference in New Issue
Block a user