Test and debug
Work in small slices: write a little, run the checks for the package you touched, look at the live app, repeat. This page lists what to run and where to look.
Before you start
Section titled “Before you start”- A working clone. See Contribute to TeamHUD.
- For the debugging half, an agent connected to the app. See Connect an agent.
Check the package you changed
Section titled “Check the package you changed”Run the checks for one package, not the whole repository. The repository-wide type-check fails on unrelated packages, so a scoped run is the signal.
pnpm --filter <package-name> type-checkpnpm --filter <package-name> lintpnpm --filter <package-name> test # when behaviour changed<package-name> is the name in the package’s package.json, for example @teamhud/widget-hello.
Unit tests
Section titled “Unit tests”Plugins and packages use vitest: *.test.ts files beside the code, run with pnpm --filter <package-name> test. Two patterns to copy:
- A plugin lifecycle test. Mock the logger and the bundle registry, call
startup()andshutdown(), assert what registered. Seeplugins/widget-window-focus/src/WidgetWindowFocusPlugin.test.ts. - A widget element test.
@teamhud/widget-mixins/testinggives youcreateMockWidgetHostContext,createMockCapBridgeandcreateRecordingRegionCaps, so you can mount a widget without the real app.
For a bug, write the test first, watch it fail for the right reason, then fix.
Contract checks
Section titled “Contract checks”Run these from the repository root before you finish. They fail on the mistakes that would otherwise only show as a broken look.
| Command | Fails when |
|---|---|
pnpm check:widget-contract |
A hub widget hand-rolls drag, snap or panel placement. |
pnpm check:theme-tokens |
A raw colour or pixel literal, a dead --th-* variable, or a hand-made control with no th-* element or marker. |
pnpm check:src-artifacts |
Build output (.js, .d.ts) sits next to a .ts source. |
Never run a bare tsc that writes into src/. Use the package’s build script, or tsc --noEmit.
End-to-end tests
Section titled “End-to-end tests”Anything a person can see or click needs an end-to-end spec in the same change. Specs drive the real app with Playwright and assert the rendered result, not that a function was called. Watch the spec fail first.
-
Use the virtual display. The suite opens real windows, so on macOS it runs on one shared virtual display that it starts for you. It never needs your screen.
Terminal window cd apps/desktop-lite && TEAMHUD_E2E_QUIET=1 npx playwright test e2e/tests/<your-spec>.spec.tsTEAMHUD_E2E_QUIET=1stops windows stealing focus. Start only one virtual display per machine. -
Run only the suites your change touches. The whole suite takes about 40 minutes.
Terminal window node scripts/e2e-affected.mjs # which suites cover what you changednode scripts/e2e-affected.mjs --run # run exactly those -
Say what you ran. Continuous integration runs only part of the suite per change, so your local run is the main signal. In your pull request, name the buckets you ran.
Warn anyone nearby before running audio specs: two instances send and receive sound, so open speakers cause feedback.
Debug with logs and state
Section titled “Debug with logs and state”Prefer the app’s own logs and the MCP tools over guessing from code. With an agent connected:
| Question | Tool |
|---|---|
| What is happening? | get_recent_logs with a small count and a search word |
| Which widgets and windows exist? | get_widget_windows, get_widget_library, get_all_windows |
| Is the overlay up, and where are the clickable regions? | get_overlay_status, get_interactive_regions, get_overlay_dom |
| What did a plugin save? | get_store, get_preferences, get_widget_component_state |
| What does it look like? | capture_window (a screenshot), probe_ui_styles |
Always filter logs on the server: get_recent_logs with count: 50 and search: "WidgetWindow" returns only matching lines. Keep count at 100 or less. Add a log line at each strategic point when you fix a bug, so the next person can find it with search.
What you’ll see
Section titled “What you’ll see”Scoped checks end with no errors. An end-to-end run prints one result per spec. Logs filtered by your search word show only your plugin’s lines.
If it goes wrong
Section titled “If it goes wrong”- A blank panel with no error. A renderer import failed quietly. Search the logs for your plugin’s name and check
get_overlay_dom. - “Edits don’t take effect”. Stale build output in
src/or an olddist/. Runpnpm check:src-artifacts, delete what it names, and rebuild the package. - An end-to-end run refuses to start. It needs the virtual display. See
tools/virtual-display-viewer/README.md. - Type-check is green but the spec is broken. You did not run
type-check:e2e.