skills/dev-test/SKILL.md
This skill should be used when the user needs to 'debug web applications', 'test UI interactions', 'capture screenshots or network requests', 'test desktop automation', or needs to select between testing tools. Routes to platform-specific E2E testing skills: Chrome MCP for debugging, Playwright for CI/CD, Hammerspoon for macOS, Linux for X11/Wayland.
npx skillsauth add edwinhu/workflows dev-testInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Main Chat Task Agent
─────────────────────────────────────────────────────
/goal <condition> (set at phase entry; refires turns)
dev-implement (loads dev-tdd)
→ dev-delegate
→ Task agent ──────────────────→ uses dev-test (this skill)
↓ loads dev-tdd again
has TDD protocol + gates
→ routes to specific tool
<EXTREMELY-IMPORTANT>
## Load TDD Enforcement (REQUIRED)
Before choosing testing tools, you MUST load the TDD skill to ensure gate compliance:
Read ${CLAUDE_SKILL_DIR}/../../skills/dev-tdd/SKILL.md and follow its instructions.
This loads:
Read dev-tdd skill content now before selecting testing tools. </EXTREMELY-IMPORTANT>
This skill routes to the right testing tool. The loaded dev-tdd skill provides TDD protocol details.
YOU MUST WRITE E2E TESTS FOR USER-FACING FEATURES. This is not negotiable.
When your changes affect what users see or interact with, you MUST:
Unit tests prove components work. E2E tests prove YOUR feature works for users.
If your "E2E test" does any of these, it's NOT E2E:
| Pattern | Why It's Fake | Real E2E Alternative |
|---------|---------------|----------------------|
| grep "success" logs.txt | Only proves code ran | Verify actual output file/UI/API response |
| assert mock.called | Tests mock, not real system | Use real integration, verify real data |
| cat output.txt \| wc -l | File exists ≠ correct content | Read file, assert exact expected content |
| "I ran it manually" | No automation = no evidence | Capture manual test as automated test |
| Check log for icon name | Observability, not verification | Screenshot + visual diff of rendered icon |
| Exit code 0 | Process succeeded ≠ output correct | Verify the actual output data |
The test: If removing the actual implementation still passes your "E2E test", it's fake.
Example of fake E2E that caught nothing:
# FAKE E2E - only checks logs
def test_icon_theme_change():
run_command("set-theme papirus")
logs = read_logs()
assert "papirus" in logs # ❌ FAKE - only proves code ran
# BUG: 89% of icons weren't changed, test still passed!
Real E2E that would have caught the bug:
# REAL E2E - verifies actual output
def test_icon_theme_change():
run_command("set-theme papirus")
screenshot = capture_desktop()
assert visual_diff(screenshot, "expected_papirus.png") < threshold # ✅ REAL
# This would have shown 89% of icons were wrong
</EXTREMELY-IMPORTANT>
┌─────────────────────────────────────────────────────────────────┐
│ BROWSER TESTING REQUIRED? │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ Need to debug JS errors or API calls? │
│ (console.log, network requests, XHR) │
└─────────────────────────────────────────────┘
│ │
YES NO
│ │
▼ ▼
┌───────────────────┐ ┌──────────────────────────┐
│ CHROME MCP │ │ Running in CI/CD? │
│ (debugging) │ │ (headless, automated) │
└───────────────────┘ └──────────────────────────┘
│ │
YES NO
│ │
▼ ▼
┌──────────────┐ ┌───────────────────┐
│ PLAYWRIGHT │ │ Cross-browser │
│ MCP │ │ needed? │
└──────────────┘ └───────────────────┘
│ │
YES NO
│ │
▼ ▼
┌──────────────┐ ┌────────────┐
│ PLAYWRIGHT │ │ Either OK │
│ MCP │ │ (prefer │
└──────────────┘ │ Playwright)│
└────────────┘
<EXTREMELY-IMPORTANT>
### Iron Laws: Browser MCP Selection
YOU MUST USE CHROME MCP FOR API/CONSOLE DEBUGGING. NO EXCEPTIONS. YOU MUST USE PLAYWRIGHT MCP FOR CI/CD TESTING. NO EXCEPTIONS.
| Need | Tool | Why |
|------|------|-----|
| Debug console errors | Chrome MCP | read_console_messages |
| Inspect API calls/responses | Chrome MCP | read_network_requests |
| Execute custom JS in page | Chrome MCP | javascript_tool |
| Record interaction as GIF | Chrome MCP | gif_creator |
| Headless/CI automation | Playwright MCP | Headless mode |
| Cross-browser testing | Playwright MCP | Firefox/WebKit support |
| Standard E2E suite | Playwright MCP | Test isolation, maturity |
| Interactive debugging | Chrome MCP | Real browser, console access |
| Capability | Playwright MCP | Chrome MCP |
|------------|---------------|------------|
| Navigate/click/type | ✅ | ✅ |
| Accessibility tree | ✅ browser_snapshot | ✅ read_page |
| Screenshots | ✅ | ✅ |
| Console messages | ❌ | ✅ read_console_messages |
| Network requests | ❌ | ✅ read_network_requests |
| JavaScript execution | ❌ | ✅ javascript_tool |
| GIF recording | ❌ | ✅ gif_creator |
| Headless mode | ✅ | ❌ (requires visible browser) |
| Cross-browser | ✅ (Chromium/Firefox/WebKit) | ❌ (Chrome only) |
| Natural language find | ❌ | ✅ find |
read_console_messages, read_network_requests). Chrome MCP cannot run headless — CI/CD requires Playwright MCP. Choosing by familiarity instead of by these constraints produces a test that cannot observe what it claims to verify.read_network_requests is an unverified claim presented as fact.
</EXTREMELY-IMPORTANT>
Detect the operating system and display server to select the appropriate testing tool:
# Detect platform for desktop automation
case "$(uname -s)" in
Darwin) echo "macOS - use dev-test-hammerspoon" ;;
Linux)
if [ "$XDG_SESSION_TYPE" = "wayland" ]; then
echo "Linux/Wayland - use dev-test-linux (ydotool)"
else
echo "Linux/X11 - use dev-test-linux (xdotool)"
fi
;;
esac
┌─────────────────────────────────────────────────────────────────┐
│ DESKTOP AUTOMATION REQUIRED? │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────┐
│ Platform? │
└─────────────────┘
/ | \
macOS Linux Windows
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌─────────┐ ┌─────────┐
│ HAMMERSPOON │ │ LINUX │ │ NOT │
│ (dev-test- │ │ (dev- │ │ SUPPORTED│
│ hammerspoon) │ │ test- │ └─────────┘
└──────────────┘ │ linux) │
└─────────┘
│
┌─────────┴─────────┐
│ Display Server? │
└───────────────────┘
/ \
Wayland X11
│ │
▼ ▼
┌──────────┐ ┌──────────┐
│ ydotool │ │ xdotool │
└──────────┘ └──────────┘
Verify tools are available BEFORE proceeding. Missing tools = FULL STOP.
Each sub-skill has its own availability gate. Load the appropriate skill and follow its gate. </EXTREMELY-IMPORTANT>
| Skill | Use Case | Key Capabilities |
|-------|----------|------------------|
| skills/dev-test-chrome/SKILL.md (via cache lookup) | Debugging, console/network inspection | read_console_messages, read_network_requests, javascript_tool |
| skills/dev-test-playwright/SKILL.md (via cache lookup) | CI/CD, headless, cross-browser E2E | Headless mode, Firefox/WebKit, test isolation |
| Skill | Platform | Primary Tool |
|-------|----------|--------------|
| skills/dev-test-hammerspoon/SKILL.md (via cache lookup) | macOS | Hammerspoon (hs) |
| skills/dev-test-linux/SKILL.md (via cache lookup) | Linux | ydotool (Wayland) / xdotool (X11) |
Locate test directories and identify the test framework used in the project:
# Find test directory
ls -d tests/ test/ spec/ __tests__/ 2>/dev/null
# Find test framework
cat package.json 2>/dev/null | grep -E "(test|jest)"
cat pyproject.toml 2>/dev/null | grep -i pytest
cat Cargo.toml 2>/dev/null | grep -i "\[dev-dependencies\]"
cat meson.build 2>/dev/null | grep -i test
| Language | Framework | Command |
|----------|-----------|---------|
| Python | pytest | pytest tests/ -v |
| JavaScript | jest | npm test |
| TypeScript | vitest | npx vitest |
| Rust | cargo | cargo test |
| C/C++ | meson | meson test -C build -v |
| Go | go test | go test ./... |
Execute CLI applications with test inputs and verify outputs against expected results:
# Run with test inputs
./app --test-mode input.txt > output.txt
# Compare to expected
diff expected.txt output.txt
# Check exit code
./app --validate file && echo "PASS" || echo "FAIL"
Every test run MUST be documented in LEARNINGS.md:
## Test Run: [Description]
**Tool:** [Chrome MCP / Playwright / Hammerspoon / ydotool / pytest / etc.]
**Command:**
```bash
pytest tests/ -v
Output:
tests/test_feature.py::test_basic PASSED
tests/test_feature.py::test_edge_case PASSED
tests/test_feature.py::test_error FAILED
1 failed, 2 passed
Result: 2/3 PASS, 1 FAIL
Next: Fix test_error failure
## Integration
For TDD protocol (RED-GREEN-REFACTOR), see:
Read `${CLAUDE_SKILL_DIR}/../../skills/dev-tdd/SKILL.md` and follow its instructions.
This skill is invoked by Task agents during `dev-implement` phase.
development
Build the meeting-level proxy-voting × ownership panel on the WRDS SGE grid — ISS N-PX fund votes reduced to (item × block) direction cells, joined to institutional and mutual-fund ownership. Use when working with risk.voteanalysis_npx, N-PX fund-level votes, ISS→CRSP fund linking, index/passive/active voting blocks, or a proxy-voting panel that needs ownership attached.
development
Use when "CRSP CIZ", "CRSP v2", "CRSP flat file format 2.0", "crsp.dsf_v2 / msf_v2", "StkDlySecurityData", "StkMthSecurityData", "StkSecurityInfoHist", "stocknames_v2", "DlyRet / MthRet / DlyPrc / MthPrc", "SHRCD or EXCHCD equivalent in new CRSP", "SIZ to CIZ migration", "CRSP data after 2024", "CRSP delisting returns", "CRSP cumulative adjustment factors", "CRSP index INDNO / INDFAM", or any CRSP stock/index query where the legacy SIZ column names no longer exist.
development
Use when linking or deduping datasets by entity name rather than a shared key — 'fuzzy match', 'fuzzy name matching', 'entity resolution', 'record linkage', 'match company/person names', 'dedupe entity names', 'name-based join', 'bridge identifiers' (CIK ↔ permno ↔ gvkey ↔ wficn ↔ EIN ↔ personid), or any use of char n-gram TF-IDF, cosine similarity on names, `sparse_dot_topn`, or RapidFuzz at scale.
development
Use when building a publication-quality table in Python — 'regression table', 'results table', 'summary statistics table', 'etable', 'coefplot', 'great_tables', 'GT', 'gt table', 'format a table for the paper', 'export table to LaTeX/HTML', significance stars, spanners, or column formatting for a table headed into a paper, slide deck, or notebook.