From wsbaser
Produces an Allure-style multi-scenario HTML report at .reports/{slug}.html with sidebar, step drill-down, issue cards, and a copy-fix-prompt button. Invoke after browser testing or on "generate test report". Use generate-bug-report for single-bug reports.
How this skill is triggered — by the user, by Claude, or both
Slash command
/wsbaser:generate-test-reportThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Extract test execution results from the current conversation and produce a polished, self-contained HTML report saved to `.reports/{slug}.html`.
Extract test execution results from the current conversation and produce a polished, self-contained HTML report saved to .reports/{slug}.html.
Invoke whenever:
/wsbaser:generate-test-reportverify-feature completes and requests report generationvs. generate-bug-report: Use this skill when there are multiple scenarios, step logs, or a test suite. Use generate-bug-report when a single bug was verified and you need a verdict (MITIGATED/CONFIRMED/INCONCLUSIVE).
Read the entire conversation and extract the following data model. Build it as a JSON object called REPORT_DATA.
| Field | Description |
|---|---|
title | Human-readable report title, e.g. "E2E Test Report — Invoice Module" |
slug | Kebab-case filename, 3–5 words, e.g. "invoice-module-e2e" |
subtitle | Optional subtitle or feature context |
branch | Git branch under test (run git branch --show-current if not in context) |
date | Test date YYYY-MM-DD (today if not in context) |
app_url | Base URL of app tested |
tester | Who ran the tests, e.g. "Claude automated browser test" or "Manual test" |
scenarios[] | Array of scenario objects (see below) |
screenshots[] | Flat array of all screenshot objects (see below) |
Optional fields (
screenshot_index,file_path,line_number,console_error) may benullwhen not available.screenshot_indexis the index into the top-levelscreenshots[]array.
{
"id": 0,
"name": "Login Flow",
"status": "pass",
"steps": [...],
"issues": [...],
"code_analysis": null
}
| Field | Values | Description |
|---|---|---|
id | integer | Zero-based index |
name | string | Scenario/journey name |
status | "pass" / "fail" / "issue" | fail = step failed; issue = completed but with findings; pass = all clear |
steps[] | array | Step objects |
issues[] | array | Issue objects found during this scenario |
code_analysis | object or null | Code context for failed/issue scenarios |
{
"n": 1,
"title": "Navigate to login page",
"description": "Opened http://localhost:7000/login and verified form rendered",
"status": "pass",
"screenshot_index": 0,
"console_errors": []
}
{
"description": "Form submits without validating empty required fields",
"severity": "high",
"file_path": "src/Forms/LoginForm.razor",
"line_number": 42,
"screenshot_index": 2,
"steps_to_reproduce": ["Navigate to /login", "Leave email blank", "Click Submit"],
"console_error": "TypeError: Cannot read property 'value' of null"
}
{
"filename": "src/Forms/LoginForm.razor",
"line_start": 38,
"line_end": 50,
"language": "csharp",
"code_html": "...",
"explanation": "The null check on line 42 is missing, allowing the form to submit when email is empty."
}
code_html is pre-rendered HTML with syntax highlight spans (.kw, .ty, .fnn, .nm, .co) — same convention as generate-bug-report.
{
"path": ".reports/screenshots/login-flow/01-login-page.png",
"caption": "Login page loaded",
"scenario_id": 0,
"step_n": 1,
"data_uri": ""
}
data_uri is filled in Phase 2. Gather paths from conversation; if a step has no screenshot, omit it from this array.
verify-feature outputs (sections like "Steps completed:", "Issues found:", "Screenshots taken:", "DB validation results:").mcp__chrome-* or mcp__plugin_playwright_* tool output in the conversation.status: "pass". If it has issues but completed, set status: "issue". If a step explicitly failed or the scenario could not complete, set status: "fail".tester: "Manual test", subtitle: "").Use the bundled Node.js script — do not write inline bash/node/python code for encoding. Inline scripts using backticks (template literals) break bash quoting, and python3 is not available on Windows.
Step 1 — Locate the script:
Use Glob to find:
~/.claude/plugins/cache/wsbaser-plugins/wsbaser/*/skills/generate-test-report/scripts/encode-screenshots.js
Use the most recently modified result (Glob returns paths sorted by modification time — use the first).
Step 2 — Build the path list:
Collect all path values from screenshots[] into a JSON array string, e.g.:
'[".reports/screenshots/login/01.png",".reports/screenshots/login/02.png"]'
If screenshots[] is empty, skip to Phase 3 — the script and encoding steps are not needed.
Step 3 — Run the script:
node "<script_path>" '<json-array>' > .reports/screenshot-data.tmp
Run this in bash (Git Bash on Windows). Single-quoted strings are safe in bash; if running in cmd/PowerShell, use double quotes around the JSON array instead. Always redirect to
.reports/screenshot-data.tmp— never use/tmp/or env-var paths, which may not exist or resolve to Windows 8.3 short paths.
Step 4 — Apply results:
Read .reports/screenshot-data.tmp with the Read tool. Match each result by path back to screenshots[] and set data_uri. If data_uri is null, the file was not found — keep the entry in screenshots[] with data_uri: null (the renderer silently skips it). Delete .reports/screenshot-data.tmp after reading.
Fallback: If the script is not found, set data_uri: null for all screenshots and continue — the report generates without images.
Locate and read the HTML template:
~/.claude/plugins/cache/wsbaser-plugins/wsbaser/*/skills/generate-test-report/assets/report-template.htmlCreate .reports/ if it does not exist.
Before writing the file, check whether .reports/{slug}.html already exists:
test -f .reports/{slug}.html to check..reports/{slug}-2.html, then .reports/{slug}-3.html, and so on until the filename is available.Report file .reports/{slug}.html already exists, saving as .reports/{slug}-N.html (where N is the suffix chosen).Write the resolved output file.
Embed REPORT_DATA at the {{REPORT_DATA_JSON}} placeholder. Replace {{TITLE}} in <title> with the report title (fall back to slug if title is empty).
| Status | Color var | Border | Background |
|---|---|---|---|
pass | --green | --gbd | --gbg |
fail | --red | --rbd | --rbg |
issue | --amber | --abd | --abg |
| Severity | Class | Text |
|---|---|---|
high | badge fail | HIGH |
medium | badge warn | MED |
low | badge info | LOW |
data: URIs only — never file paths..reports/ if it does not exist.REPORT_DATA_JSON must be valid JSON — escape any special characters in strings. The entire report renders from this inline JS object; malformed JSON causes a blank page.screenshots[] must include data_uri for every screenshot that exists on disk — set data_uri: null for any file not found (silently skipped in rendering).status: "issue" and one step explaining that no test results were detected in the conversation.After writing the report file, run open <output-filename> to launch it in the user's default browser (use the resolved filename from Phase 3, which may include a numeric suffix if overwrite protection renamed the file).
Guides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.
npx claudepluginhub wsbaser/claude-plugins --plugin wsbaser