Skip to content

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.

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.

Terminal window
pnpm --filter <package-name> type-check
pnpm --filter <package-name> lint
pnpm --filter <package-name> test # when behaviour changed

<package-name> is the name in the package’s package.json, for example @teamhud/widget-hello.

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() and shutdown(), assert what registered. See plugins/widget-window-focus/src/WidgetWindowFocusPlugin.test.ts.
  • A widget element test. @teamhud/widget-mixins/testing gives you createMockWidgetHostContext, createMockCapBridge and createRecordingRegionCaps, 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.

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.

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.

  1. 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.ts

    TEAMHUD_E2E_QUIET=1 stops windows stealing focus. Start only one virtual display per machine.

  2. 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 changed
    node scripts/e2e-affected.mjs --run # run exactly those
  3. 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.

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.

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.

  • 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 old dist/. Run pnpm 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.