- Add a 'when to use / when not to use' gate: UI behavior questions default to Vitest/jsdom, E2E only for behavior spanning server + browser; description updated so the skill triggers less eagerly - Pin the browser driver to Chrome DevTools MCP and explain why kimi-webbridge (user's real browser) is not a substitute - Drop generic MCP pattern boilerplate duplicated by references/mcp-cheatsheet.md (SKILL.md 385 -> 145 lines) - Move recipe rematch fixture / fresh-state / cancel-gap notes to references/recipe-rematch-fixtures.md
7.3 KiB
name, description
| name | description |
|---|---|
| lora-manager-e2e | End-to-end testing and validation for LoRa Manager features. Use ONLY for sandboxed E2E validation of LoRa Manager standalone mode: start the standalone server on a free port with --settings-path, drive the web UI (http://127.0.0.1:{PORT}/loras) via Chrome DevTools MCP, and verify frontend-to-backend integration. NOT for UI behavior checks that unit tests (Vitest/jsdom) can cover. Trigger keywords: E2E, standalone, Chrome DevTools MCP, lora-manager-e2e, sandbox. |
LoRa Manager E2E Testing
End-to-end testing of LoRa Manager standalone mode using Chrome DevTools MCP.
When to Use — and When NOT To
E2E runs are slow and token-heavy. Reach for them only when the question genuinely spans server + browser (routing, scan persistence, websocket updates, EXIF writes).
- Default to unit/component tests first:
npm run test:js(Vitest/jsdom) covers DOM rendering, modal behavior, event handling and API-client calls deterministically in seconds. Backend logic goes throughpytest. A UI-behavior question answered by jsdom MUST NOT be escalated to E2E. - Use E2E only when the behavior cannot be observed without a live server and a real browser, e.g. template rendering through the aiohttp server, scanner → SQLite persistence → API → DOM round-trips, or real EXIF/image writes.
- If you start an E2E and realize a unit test would answer the question, stop and switch.
Browser driver is fixed: Chrome DevTools MCP. Do not substitute kimi-webbridge —
it operates on the user's real browser (real tabs, real sessions, synthetic
isTrusted=false events), which breaks the isolation this skill requires and lacks
the console/network inspection E2E debugging relies on. kimi-webbridge is for
interactive browsing with the user's real login sessions, not for sandboxed E2E.
Conventions
{PORT}: default candidate8188, but it is commonly occupied by a live ComfyUI — always check first (ss -tlnp | grep ':{PORT}') and use a free port (e.g.8199). Substitute the chosen port everywhere below. Never kill a process you did not start for this E2E.<repo-root>: the repository/worktree root; run all commands from there.<sandbox>: a throwaway dir, e.g./tmp/opencode/<plan>-e2e.
SANDBOX (MANDATORY)
Every E2E run MUST target a throwaway sandbox, never real user data.
-
Explicit settings directory: always launch with
--settings-path <sandbox>/settings. This pins ALL runtime data (settings.json,cache/,backups/,logs/,stats/,wildcards/) under the sandbox. Never create<repo-root>/settings.json— the repo folder is usually the real ComfyUI plugin folder and a portable settings file there is read by the real instance. -
Sandboxed library paths: point
folder_paths/recipes_path/example_images_pathat disposable dirs under<sandbox>— never the real library, real recipe dir, or real settings:{ "folder_paths": { "loras": ["<sandbox>/models/loras"], "checkpoints": ["<sandbox>/models/checkpoints"], "unet": ["<sandbox>/models/checkpoints"], "diffusers": [] }, "recipes_path": "<sandbox>/recipes", "example_images_path": "<sandbox>/example_images" } -
Real-data protection proof: before starting and after finishing, snapshot the real config and recipe library and confirm they are byte-identical; also confirm
<repo-root>gained nosettings.jsonorcache/:sha256sum ~/.config/ComfyUI-LoRA-Manager/settings.json > <sandbox>/settings.before.sha256 ls ~/models/recipes/*.recipe.json 2>/dev/null | wc -l > <sandbox>/recipes-count.before.txt # AFTER the run: record again and diff. Any change = the run leaked into real data.
Quick Start
cd <repo-root>
# 1. Sandbox
mkdir -p <sandbox>/settings <sandbox>/models/{loras,checkpoints} <sandbox>/{recipes,example_images}
# write <sandbox>/settings/settings.json per the SANDBOX example
# 2. Port
ss -tlnp | grep ':{PORT}' || echo "port {PORT} is free"
# 3. Server — MUST be fully detached (a plain background & dies with the shell);
# the helper enforces this and manages its own pidfile
python .agents/skills/lora-manager-e2e/scripts/start_server.py \
--port {PORT} --settings-path <sandbox>/settings --wait --timeout 30 --detach
ss -tlnp | grep ':{PORT}' # verify listening BEFORE proceeding
# 4. Chrome with remote debugging, then connect Chrome DevTools MCP (verify via list_pages)
google-chrome --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-lora-manager http://127.0.0.1:{PORT}/loras
Then drive the UI with the MCP tools (take_snapshot, click, fill, fill_form,
evaluate_script, wait_for, list_network_requests, list_console_messages) —
see references/mcp-cheatsheet.md for patterns.
Server restart after config/fixture changes:
python .agents/skills/lora-manager-e2e/scripts/start_server.py \
--port {PORT} --settings-path <sandbox>/settings --restart --wait --detach
# then reload the browser page (ignoreCache=True)
--restart only kills the E2E server the script itself started (via its pidfile) and
aborts instead of killing unrelated processes on the port.
Abort Rule
A sandboxed E2E should finish in well under 30 minutes. If any phase exceeds ~2x its
expected duration (server readiness > 60 s, MCP connect > 2 min, a single scenario >
10 min), or any single tool call fails 3+ times in a row, STOP — do not retry
blindly. Report BLOCKED with the phase, last observed state (server PID,
ss -tlnp output, page snapshot, last API response) and suspected cause. A clean
BLOCKED report beats an hour of retries.
Troubleshooting
- "browser is already running" /
list_pagesfails: a stale Chrome holds the profile dir. Find it (ps -ef | grep -i '[c]hrome.*user-data-dir'), confirm it is a leftover QA Chrome (not the live ComfyUI, not your current MCP browser), kill only that PID, then retrylist_pages. - MCP refuses to write screenshots into the worktree: save to
/tmpviatake_screenshot(filePath="/tmp/...")and copy into the evidence dir from the shell.
Cleanup
- Stop the standalone server:
kill <recorded-pid>(only the PID you started), then confirmss -tlnp | grep ':{PORT}'is empty. - Close browser pages (keep at least one open).
rm -rf <sandbox>; verify<repo-root>gained nosettings.jsonorcache/.- Re-run the real-data protection check from the SANDBOX section and record the result.
References & Scripts
- references/mcp-cheatsheet.md — Chrome DevTools MCP command patterns (navigation, waiting, snapshots, forms, network, console, performance).
- references/test-scenarios.md — detailed test scenarios (list display, metadata editing, recipes, settings, import/export).
- references/recipe-rematch-fixtures.md — fixture format, fresh-state reset and known gaps for recipe rematch/repair E2E runs.
scripts/start_server.py— start/restart the standalone server (--port --settings-path --restart --wait --timeout --detach); refuses to touch unrelated processes on the port.scripts/wait_for_server.py— poll readiness (--port --timeout).