Files
fusion/docs/solutions/developer-experience/browser-testing-dashboard-from-worktree-safely.md

3.8 KiB

module, date, problem_type, title, applies_when, tags
module date problem_type title applies_when tags
dashboard-testing 2026-06-04 developer_experience Browser-testing the Fusion dashboard from a worktree safely (no engine, fresh bundle, free port) Running browser/E2E verification of dashboard changes from a linked worktree during a pipeline (ce-test-browser or manual agent-browser sessions)
browser-testing
fn-dashboard
worktree
stale-dist
port-4040
fusion-daemon

Browser-testing the Fusion dashboard from a worktree safely

Context

During the step-inversion pipeline (PR #1424), browser verification of dashboard changes from a linked worktree hit three traps in sequence, two of them dangerous:

  1. fn daemon --paused still executed real tasks. The daemon shares the user's central DB; within ~60s it spun up executor sessions on live tasks (racing the user's main instance — a dual-engine hazard) despite --paused. The --paused flag does not prevent engine dispatch in this path.
  2. fn dashboard --dev (no --port) bound the reserved port 4040 — the default in packages/cli/src/bin.ts is 4040, which is reserved for the user's own dashboard (see dev-server-port-detect.ts: RESERVED_DASHBOARD_PORT).
  3. The served UI bundle was stale. fn dashboard serves packages/cli/dist/client (the CLI's own copy of the dashboard build), NOT packages/dashboard/dist/client. Rebuilding @fusion/dashboard does not update the CLI copy — newly added React Flow node types rendered as react-flow__node-default and foreach template children were missing from the DOM entirely, which looked exactly like a source bug (it wasn't).

Guidance

The safe recipe for worktree browser testing:

pnpm --filter @fusion/core --filter @fusion/engine --filter @fusion/dashboard \
     --filter "@fusion-plugin-examples/*" build

FUSION_ALLOW_NESTED_PROJECT=1 FUSION_SKIP_ONBOARDING=1 \
FUSION_CLIENT_DIR=$PWD/packages/dashboard/dist/client \
node packages/cli/bin.mjs dashboard --dev --port 4101 --token cetest123 &
# open: http://localhost:4101/?token=cetest123
  • fn dashboard --dev = web UI only, AI engine disabled. Never use fn daemon/fn serve for UI verification — they run the engine against the shared central DB.
  • Always pass --port <free> (anything but 4040). The dashboard subcommand's default is the reserved 4040.
  • FUSION_CLIENT_DIR pointed at the fresh packages/dashboard/dist/client beats the CLI's stale packages/cli/dist/client copy. Without it, UI changes silently don't appear.
  • Killing your own spawned test server is fine; the no-kill rule protects the user's live instance on 4040.
  • If the canvas "renders nothing": check the served bundle hash before debugging source — agent-browser eval on document.querySelectorAll('.react-flow__node') distinguishes "nodes absent" from "nodes mis-typed" (react-flow__node-default = nodeType not registered in the served bundle).

Why This Matters

The daemon trap is a data hazard, not just wasted time: two engines on one SQLite central DB race task leases and can strand tasks in limbo. The stale-bundle trap costs hours because it perfectly mimics a source-level rendering bug — the jsdom tests pass (they test source) while the browser shows old behavior (it serves dist).

When to Apply

Any time a pipeline or agent verifies dashboard behavior in a real browser from a worktree: ce-test-browser runs, manual agent-browser sessions, screenshot verification of editor/board changes.

Examples

Diagnosing the stale bundle (PR #1424): source WorkflowNodeTypes.tsx registered foreach, jsdom tests green, but live DOM showed react-flow__node-default for the foreach node and no steps::* children. grep nodeTypes in the served WorkflowNodeEditor-*.js chunk showed the registry ending at join — a pre-U8 bundle from packages/cli/dist/client.