Skip to content

test(e2e): dashboard GUI tests with side-by-side app + dashboard videos - #487

Open
sgedda wants to merge 31 commits into
mainfrom
cursor/e2e-dashboard-gui-videos-7d37
Open

sgedda wants to merge 31 commits into
mainfrom
cursor/e2e-dashboard-gui-videos-7d37

Conversation

@sgedda

@sgedda sgedda commented Oct 27, 2026 •

Copy link
Copy Markdown
Owner

Summary

Adds eight Playwright GUI tests (tag @gui) that drive the real Mockifyer dashboard UI in a second, desktop-sized browser context while the WanderWeird app runs in the first:

  • seven in e2e/tests/dashboard-gui.spec.ts, on the demo stack (including a tracing walkthrough and a per-endpoint delay/status test);
  • one in e2e/tests/dashboard-gui-scratch.spec.ts, a from-scratch flow on an empty dashboard.

Every test ends by asserting the changed value on screen in the app. CI records both pages on every run and composes one side-by-side mp4 per test (app on the left, dashboard on the right) with ffmpeg. Each mp4 has a generated Markdown description with the same base name, and the run gets a summary (e2e-run-summary.md, also written to the job summary). An opt-in presentation mode (E2E_PRESENTATION=1) slows the GUI tests down at each value change so the clips are readable.

Both panes start at their entry screen, and the two recordings start together. The GUI beforeEach opens the dashboard first, so the dashboard waits on its start screen while the app signs in. The app opens at its login screen in a fresh browser context (no stored session), types the demo user and password into the form, clicks Sign in, then clicks the Discover tab to reach the Atlantis Temperature tile. Login is not interleaved with dashboard steps.

The dashboard starts on its start screen (/), its only direct URL load. It then reaches each page by visible clicks:

  • mock editor: sidebar Mocks → search latitude=37.9838 → Expand all → the "forecast" card;
  • Overrides: sidebar Overrides → "Open mock for overlays" picker → Athens forecast → Edit overlays;
  • Client lanes: sidebar Settings → Client lanes card;
  • the header Scenario picker;
  • Network: sidebar Network → lane filter;
  • Hops: sidebar Hops → expand hop rows.

The selectors are existing labels, placeholders, aria-labels and the two data-testids from #484.

One dashboard fix (@sgedda/mockifyer-dashboard 1.5.94 → 1.5.95). Reaching Overrides by in-app navigation exposed a bug in OverridesView.tsx: the "Open mock for overlays" picker stayed disabled on "Loading mocks…" until a full reload. The already-loaded mock list filled the picker while the picker's own fetch ran; the effect was cancelled, and pickerLoading was never reset. The effect cleanup now resets it (a two-line change).

Test Dashboard UI steps App shows
mock editor: response body Form Editor, current → temperature_2m = 37, Save Changes 99° → 37°
overrides page: field override Add field override current.temperature_2m = 61, Save overlays, Open mock 61°, while the editor still shows the stored 99
mock editor: delay and status override (Open-Meteo only) Request tab: Response Delay 2500 ms, then Status Override 503 (delay kept), then Clear each; Network trace for the first two 99° after ≥ 2.5 s → 18° after ≥ 2.5 s (wander-api fallback) → 18° fast → 99° fast
Settings client lane Client lanes select: heatwave → rainy-weekend → guide-demo-2 44° → 11° → 99°
header Scenario picker remove lane, header picker → heatwave, tick "Lane global fallback" strict default (#484): live weather, not 44°; with fallback on: 44°
Network view lane → heatwave, header → heatwave, Network filtered to the lane, Clear, app reload 44°, and the trace shows the Open-Meteo Mock hop under wander-api GET /discover
tracing walkthrough Network: Bodies on, Clear, Paused; Trace: expand GET /api/discover → GET /discover → Open-Meteo hop; Details and Client connections, then a heatwave lane switch and a 503 override 99° (Mock, body "temperature_2m": 99) → 44° (Last resolved heatwave) → 18° (hop 503, wander-api body "source": "fallback")
from scratch empty dashboard → lane → Hops: Open-Meteo hop → Use saved mock → scenarios A and B live weather → the captured value → 55° / 66°, following the lane

The optional date-override test (f) is not included. The app renders no date taken from the mocks, so it could not show a change on screen, which is a hard requirement. Dates remain covered at API level in dates.spec.ts.

Delay and status override on one endpoint

This extends the former "503 status override" test instead of adding a second one; its 503 → 18° assertion is still part of it. It uses the per-endpoint Response Simulation fields in the mock editor (Request tab: Status Override and Response Delay (ms), served through the proxy since #485) on the Athens Open-Meteo mock only:

  1. Response Delay 2500. The app's Discover request, timed in the browser (POST /api/proxy for /api/discover), takes ≥ 2500 ms and the tile still shows 99°. The app has no loading indicator on a refetch (the old card stays until the answer arrives), so the clip shows the delay as the hop's Duration in the Network trace: the Open-Meteo hop is Mock, Status 200, Duration ≥ 2500 ms, while GET /countries/name/greece stays Upstream, Status 200, under 2500 ms.
  2. Plus Status Override 503. ≥ 2500 ms and 18° (wander-api's fallback). The Open-Meteo hop shows Status 503 and Duration ≥ 2500 ms; the countries hop stays 200 and fast. wander-api treats any non-2xx the same (if (!response.ok) → fallback), so 404 or 500 would show the same 18°; only 503 is tested.
  3. Stored per endpoint. Only this mock has statusOverride 503 / responseDelayMs 2500. Every other mock of guide-demo-2, and the heatwave copy of the same endpoint, keeps the settings it had before the test.
  4. Clear the delay, then the status (each field's Clear button). The request is fast again: 18°, then 99°, and the mock stores neither setting.

afterEach also resets responseDelayMs.

Tracing walkthrough

Tracing views that exist in the dashboard UI:

  • Network (/network): List / Trace / Waterfall / Gantt / Journey views. The Details pane shows URL, Method, Source (Mock / Upstream / Error), Transport, Request id, Triggered by, Status, Duration, Lane, a Call chain strip and Request/Response headers. With Bodies on for that scenario it also shows "Request body" and "Response body" (new traffic only).
  • Hops (/hops): stored chains. A hop opens its mock editor, whose Request / Response / Metadata tabs are the closest thing to "Req / Res".
  • Client connections (header panel): per client, Scenario (lane), Last resolved, Last seen and Status. This is where scenario/lane resolution shows.

There is no separate Atlas trace page (/atlas redirects to Network). The walkthrough uses the Network trace, because the demo's Athens forecast mock is stored without a parent link, so Hops does not nest it under GET /discover; the live trace does.

The test generates traffic through the app UI only. For each case it clears the lane's log, reloads Discover, waits for the fresh hop, clicks Live → Paused, then Collapse all and expands GET /api/discover → GET /discover → the Open-Meteo hop:

  • (a) Open-Meteo hop: Source Mock, Status 200, Duration, Lane wanderweird-demo, a request header x-mockifyer-client-id: wanderweird-demo, and a response body with "temperature_2m": 99. wander-api GET /discover: Source Upstream, and a response body with 99. The app shows 99°.
  • (b) Lane → heatwave and header → heatwave, with Bodies on for heatwave. The Open-Meteo hop is a Mock with "temperature_2m": 44, and Client connections shows Scenario (lane) heatwave and Last resolved heatwave. The app shows 44°.
  • (c) Lane and header back to base. Mock editor: Status Override 503. The Open-Meteo hop shows Status 503, and wander-api's response body has "source": "fallback", "temperature_2m": 18 and "Upstream 503 for …". The app shows 18°.

afterEach turns body capture off again for both scenarios.

From-scratch test (dashboard-gui-scratch.spec.ts)

The from-scratch test starts with completely empty data, on a throw-away branch-built dashboard at :3022 with a fresh sqlite dir (scripts/scratch-dashboard.sh). For this file only, the gateway and wander-api are restarted to proxy through it without the record env (scripts/ww-service.sh <service> start with MOCKIFYER_DASHBOARD_URL=http://127.0.0.1:3022 WW_RECORD=off). The app and the other services stay on the demo dashboard. afterAll restores the gateway and wander-api and deletes the scratch data, so the test is idempotent; two back-to-back runs both passed.

Flow, all through the UI with the same start-screen navigation and presentation holds:

  1. Empty start screen. The app (from its login screen) loads Discover, and everything is live and nothing is stored: there is no lane yet, so strict lane mode passes calls through. Mocks shows "No mocks found", Network shows the live GET /discover and Open-Meteo hops as "Upstream", and Hops is empty.
  2. "Switch to default", then Settings > Client lanes > Add lane wanderweird-demo. One app load runs with the header Record: On (the default), which stores one request-only placeholder per called endpoint: no response body, served live. Then Record: Off.
  3. On the Hops page, expand GET /api/discover → GET /discover. The Open-Meteo hop appears only after expanding, with a "Pending" badge. Click it → its mock editor → Use saved mock.
  4. The next app load captures that single response. Hops shows the forecast as "Replay" and the rest as "Pending"; Network shows the forecast as "Mock" and /discover and countries as "Upstream"; the Mocks › Domains tree shows api.open-meteo.com "1 mocked" and every other host "0 mocked". The API check confirms that only the forecast has a stored body, and the app tile matches it.
  5. Settings > Create New Scenario: A from default and B from A, each with Use saved mock and its own value (55°, 66°). Switching the lane A ↔ B moves the app each time.

What the dashboard offers for "mock one endpoint". The per-endpoint controls are a mock's replay mode (mock editor, reached from a hop) and a path folder's Record response rule (Mocks › Domains tree; the server rule is recordResponses + autoMock per host/path). Both need the endpoint to be stored first, and the Hops page lists stored entries only. The Network page shows live hops but has no per-endpoint toggle. Hence the one placeholder load (Record On, no bodies) before switching Record off. A product option that would remove that step: a "Record response for this path" action in the Network view's Details pane (not built here).

Demo fix (WanderWeird, not a published package). packages/mock-bootstrap passed recordOnMiss: MOCKIFYER_RECORD === 'true', so an unset env became an explicit record: false on every /api/proxy request and the dashboard's Record switch never applied to the services. It now passes recordOnMiss only when the env is set; core then omits record, as documented. The CI stack sets MOCKIFYER_RECORD=true, so its behavior is unchanged.

How it works

The dash fixture opens the dashboard in its own context with its own recordVideo (URL from the dashboardUrl option), loads the start screen, then attaches that video to the result. Playwright's own video attachment is the app page:

// e2e/lib/gui.ts
dash: async ({ browser, page, dashboardUrl }, use, testInfo) => {
  const context = await browser.newContext({
    baseURL: dashboardUrl, viewport: DASHBOARD_VIEWPORT,
    recordVideo: { dir: testInfo.outputPath('dashboard-video'), size: DASHBOARD_VIEWPORT },
  });
  const dash = new DashboardUi(await context.newPage());
  await dash.openStartScreen(); // the only page.goto; everything after is clicked
  await use(dash);
  // ...hold, close, attach the dashboard video
},

The GUI specs' beforeEach({ page, dash }) requests dash first, so both recordings start together, then signs in through the app's login screen (openAppFromLogin).

The GUI tests run in their own project (dashboard-gui*.spec.ts), which always records and traces. The existing chromium project ignores them and keeps retain-on-failure, or on when E2E_VIDEO=on.

Each test carries its own description as annotations, so the description reaches the JSON report. Login and navigation steps are listed too:

test('Settings client lane: heatwave 44 -> rainy-weekend 11 -> base 99 in the app', gui(
  'Switching the demo client lane scenario in Settings moves the app between the scenario values.',
  [
    NAV.clientLanes, // [UI, 'Navigate: sidebar Settings -> scroll down to the Client lanes card']
    [UI, 'Client lanes: "Scenario for wanderweird-demo" select = heatwave, toast: Lane "wanderweird-demo" updated.'],
    [APP, 'Refetch until 44°'],
    // ...
  ],
), async ({ page, dash }) => { /* ... */ });

The 33 existing API and app tests get a one-line documented('asserts …') annotation.

npm run artifacts (scripts/build-run-artifacts.ts) reads test-results/results.json and writes everything into gui-videos/:

  • Clips. For each GUI test, ffmpeg runs scale=-2:800 on each video and then hstack, giving <spec>--<title>.mp4 at 1662×800. The two sources are copied to individual/<name>.{app,dashboard}.webm.
  • Per-test description. <name>.md sits next to each mp4, and other-tests/<name>.md covers every other test. Each file has:
    • result, duration, presentation mode, file:line, project and tags, plus where the videos and trace are in the artifacts;
    • the step-by-step actions and assertions, labelled by actor: Mockifyer dashboard UI (including navigation), Mockifyer dashboard API, Mockifyer MCP server, WanderWeird app (including login and navigation), or helper (e.g. scripts/scratch-dashboard.sh, scripts/ww-service.sh);
    • the exact command (config.argv from the report, e.g. npx playwright test), the working directory (e2e) and env (CI, E2E_VIDEO, E2E_PRESENTATION, MAIN_*, URL overrides), recorded in config metadata with repo paths as <repo>;
    • the workflow steps of e2e.yml in order, each tagged Mockifyer, Demo app (WanderWeird), Test run or Helper, with its command;
    • local reproduce commands, ending with npx playwright test tests/<file>:<line> --project=<project>.
  • Run summary. e2e-run-summary.md has the run link, presentation mode, passed/failed/flaky/skipped counts, every test with its "asserts" line, the artifacts, the workflow steps and the reproduce commands. In CI it is also appended to $GITHUB_STEP_SUMMARY.
  • Workflow steps source. In CI the step list comes from the running job via the Actions API (GITHUB_TOKEN, job permissions contents: read, actions: read), with each step's status. Elsewhere, or if that call fails, it comes from the workflow YAML (parsed with yaml, a new devDependency).
  • Hostname. Any machine hostname is replaced by <host> in the generated files. Recordings contain only the two browser pages.

Last frames of two local clips:

Field override: app 61°, editor shows stored 99
Network view: Open-Meteo Mock hop under wander-api GET /discover

Presentation mode (E2E_PRESENTATION=1)

Off by default, and off for pull requests: normal runs keep exactly the current timing and assertions. When it is on, only the GUI tests slow down:

  • the element being changed is outlined in orange, with a 2.5 s hold before and after the edit, save or apply, while the toast is visible;
  • values are typed key by key (pressSequentially, 120 ms per key);
  • each new value in the app is outlined and held for 2.5 s;
  • each navigation click (sidebar link, search, Expand all, mock card, picker option, hop or trace expand) and each app login step (username, password, Sign in, Discover tab) is outlined, with a 1 s hold before and after.

Page loads keep their normal speed. It is implemented as one small helper set in lib/gui.ts:

export async function presentChange(target: Locator, action: () => Promise<unknown>, holdMs = PRESENTATION_HOLD_MS) {
  if (!PRESENTATION) { await action(); return; }
  // outline target, presentationPause(holdMs), action(), presentationPause(holdMs), remove outline
}
// navigation clicks and app login steps use the same helper with PRESENTATION_NAV_HOLD_MS (1 s)
async function navigateBy(target: Locator, action = () => target.click()) {
  await presentChange(target, action, PRESENTATION_NAV_HOLD_MS);
}

The workflow turns it on for schedule runs and workflow_dispatch runs; the new presentation input defaults to true and can be unticked. Pull requests keep it off. The run summary and each test's Markdown file show a "Presentation mode" row, and E2E_PRESENTATION appears in the env and reproduce commands.

Local GUI project timings, off vs on:

Test Off On
mock editor: response body 5.2 s 42.8 s
overrides page: field override 4.7 s 51.0 s
mock editor: delay and status override 14.6 s 3.1 min
Settings client lane 7.3 s 51.7 s
header Scenario picker 7.2 s 46.0 s
Network view 9.5 s 66 s
tracing walkthrough 24.7 s 4.3 min
from scratch 29.2 s 4.4 min

CI (.github/workflows/e2e.yml)

  • Runs npm run artifacts after the tests, also when tests fail. ffmpeg comes from the ffmpeg-static devDependency, a static build with libx264. There is no apt step: slow apt mirrors made an earlier run's capped install give up. FFMPEG_PATH overrides the binary.
  • Uploads these artifacts on every run, under fixed names and with 30-day retention:
Artifact Contents
e2e-gui-videos side-by-side mp4 + same-name .md per GUI test, e2e-run-summary.md, other-tests/*.md
e2e-videos individual *.app.webm / *.dashboard.webm, plus other tests' videos (failures, or all with E2E_VIDEO=on)
e2e-report Playwright HTML report
e2e-traces trace.zip per GUI test plus traces of failed tests
e2e-logs failure only: test-results/ and service logs, including the gateway and the scratch dashboard (replaces the old e2e-report-<n>)
  • The old e2e-videos-<run_number> upload, which only ran on scheduled or manual runs, is replaced by the above. retries is unchanged.

Other changes

  • Shared helpers, used by both the new specs and the existing ones (hooks only, no assertions changed):
    • untilAfterRefetch / expectTemperatureOtherThanAfterRefetch / temperatureTile / shownTemperature / timedRefetchDiscover in lib/app.ts
    • openDiscover(page, { ui, fromLoginScreen }) in lib/app.ts: GUI tests pass presentation-aware clicks and typing (openAppFromLogin in lib/gui.ts); the other tests keep plain fill/click
    • followLaneAndWait / pinToBaseAndWait / scratchStack in lib/stack.ts
    • clearFieldOverrides / restoreDemoScenarios / setNetworkBodies in lib/dashboard.ts
    • setResponseSimulation (set or Clear), traceChild and detailDurationMs in lib/gui.ts; the spec-level traceAppLoad is shared by the tracing and delay/status tests
  • scripts/ww-service.sh runs the gateway or wander-api against any dashboard (wander.sh now wraps it). Also new: scripts/scratch-dashboard.sh and a shared scripts/port-lib.sh.
  • State is restored in afterEach: Athens body, status override, response delay, field overrides, lane (re-created if removed), global scenario, lane global fallback and network body capture. wander-api follows the lane for the demo GUI file and is pinned back in afterAll. The Network, tracing and delay/status tests clear only the demo lane's network log, which is telemetry and is not restored.
  • Spec paths in the generated docs are resolved from the report's rootDir, giving e2e/tests/<spec>:<line>. This replaces a branch commit that dropped the tests/ prefix.
  • README: documents the GUI tests, the delay/status test, the tracing views and walkthrough, the from-scratch test, the app login and dashboard click-through navigation, presentation mode, the run docs, local commands (npm run test:gui, npm run artifacts, --headed) and the artifacts. It also removes the stale "Known gaps" entries (header picker, proxy status/delay) that fix: Mockifyer and WanderWeird fixes found by the e2e suite (#481) #485 fixed.

Testing

  • Local full stack, set up as in CI: npx playwright test → 41 passed (2.5 min), of which 33 are existing and 8 are GUI. In CI the from-scratch test takes about 30 s, the tracing walkthrough about 25 s, and the delay/status test 19 s (about 14 s more than the 503-only test it replaces); the test step varies by about ±30 s between runs.
  • GUI project with E2E_PRESENTATION=1: all GUI tests pass. Frames were checked: each clip starts with the app login next to the dashboard start screen, login, navigation and expand clicks are outlined, and the toast and the new app value are held on screen.
  • npm run artifacts writes one mp4 and one .md per GUI test, per-test .md files for the other tests, and the summary. No hostname appears in any generated file.
  • Root npm test: 137 suites passed. Dashboard frontend and backend builds pass; frontend lint shows only a warning that was already there (OverridesView.tsx line 428).

To show artifacts inline, enable in settings.

Open in Web Open in Cursor 

Note

Medium Risk
Large E2E and CI pipeline changes plus a behavioral tweak to proxy recordOnMiss when the record env is unset; core product risk is low but nightly CI runtime and demo-stack recording semantics change.

Reviewed by Cursor Bugbot for commit 55d8e27. Bugbot is set up for automated code reviews on this repo. Configure here.

cursoragent and others added 7 commits October 27, 2026 12:36
Co-authored-by: Sebastian Gedda <sebastian.gedda@gmail.com>
…to the app

Six @GUI tests in their own Playwright project (video and trace always on):
mock editor body edit, field override on the Overrides page, status override 503,
Settings client lane select, header Scenario picker with strict lane default and
lane global fallback, and the Network trace after an app load. Each asserts the
new value on screen in the app.

Co-authored-by: Sebastian Gedda <sebastian.gedda@gmail.com>
…artifacts

Co-authored-by: Sebastian Gedda <sebastian.gedda@gmail.com>
… drop fixed known gaps

Co-authored-by: Sebastian Gedda <sebastian.gedda@gmail.com>
…tests step by step

Co-authored-by: Sebastian Gedda <sebastian.gedda@gmail.com>
… the GUI videos

npm run artifacts (scripts/build-run-artifacts.ts) now also writes gui-videos/<name>.md next to each
side-by-side clip, other-tests/<name>.md for the rest and e2e-run-summary.md (also the job summary):
test command from config.argv, cwd and env from report metadata, the annotated steps and assertions,
the workflow steps (job API with statuses, else the YAML) and local reproduce commands.

Co-authored-by: Sebastian Gedda <sebastian.gedda@gmail.com>
Co-authored-by: Sebastian Gedda <sebastian.gedda@gmail.com>

@cursor cursor Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Docs prefix tests path twice
    • Removed duplicate tests/ prefix from four locations in run-docs.ts since Playwright JSON reporter already includes it in spec.file relative to e2e/.

You can send follow-ups to the cloud agent here.

Comment thread e2e/lib/run-docs.ts Outdated
cursoragent and others added 15 commits October 27, 2026 12:55
Playwright JSON reporter already includes tests/ in spec.file (relative to e2e/),
so prepending tests/ again created invalid paths like tests/tests/... in reproduce
commands and spec links. Updated run-docs.ts to use test.file directly without
the extra prefix.
Outline the element being changed, hold 2.5 s before and after the edit / save / toast, type values
key by key and hold on each new app value. Off (default) keeps the current timing.

Co-authored-by: Sebastian Gedda <sebastian.gedda@gmail.com>
…the run docs

Co-authored-by: Sebastian Gedda <sebastian.gedda@gmail.com>
Co-authored-by: Sebastian Gedda <sebastian.gedda@gmail.com>
Playwright's JSON report gives spec.file relative to rootDir (e2e/tests), without a tests/ prefix,
so the previous commit produced e2e/<spec> and an unscoped test filter. TestRun.file is now the path
relative to e2e/, which works whatever the reporter's base is.

Co-authored-by: Sebastian Gedda <sebastian.gedda@gmail.com>
… tests

Co-authored-by: Sebastian Gedda <sebastian.gedda@gmail.com>
apt mirrors were slow enough on the runners that the capped install gave up and no clip was
composed. The static binary (with libx264) comes with npm ci in e2e/; FFMPEG_PATH overrides it.

Co-authored-by: Sebastian Gedda <sebastian.gedda@gmail.com>
…ter in-app navigation

When the dashboard's mock list was already loaded, it filled the picker while the picker's own
fetch was running; the effect was cancelled and pickerLoading never reset, so the picker stayed
disabled until a full page reload. Reset it in the effect cleanup.

chore(release): bump @sgedda/mockifyer-dashboard 1.5.94 -> 1.5.95

Co-authored-by: Sebastian Gedda <sebastian.gedda@gmail.com>
…rough to each page

The only direct load is /; the mock editor, Overrides, Settings > Client lanes and Network are
reached via sidebar links, mock search, Expand all, the mock card and the Overrides picker. In
presentation mode each navigation click is outlined with 1 s holds. Steps are listed in the docs.

Co-authored-by: Sebastian Gedda <sebastian.gedda@gmail.com>
…olds in presentation mode

Co-authored-by: Sebastian Gedda <sebastian.gedda@gmail.com>
…ings start together

beforeEach requests the dashboard fixture first, so the dashboard waits on its start screen while
the app (fresh context) types the demo credentials, clicks Sign in and the Discover tab. The same
openDiscover flow takes presentation-aware clicks and typing for GUI tests only; other tests keep
plain fill/click. Login and app navigation are listed as WanderWeird app steps in the docs.

Co-authored-by: Sebastian Gedda <sebastian.gedda@gmail.com>
…ER_RECORD is unset

mock-bootstrap passed recordOnMiss: MOCKIFYER_RECORD === 'true', so an unset env became an explicit
record=false on every /api/proxy request and the dashboard's Record switch never applied to the
services. Pass recordOnMiss only when the env is set (core then omits `record`, as documented).

Co-authored-by: Sebastian Gedda <sebastian.gedda@gmail.com>
…estarts

ww-service.sh stops/starts the gateway or wander-api against any dashboard, optionally without the
record env (wander.sh now wraps it); scratch-dashboard.sh runs an empty branch-build dashboard on
:3022 with a fresh sqlite dir. lib/stack.ts gets scratchStack.start/stop.

Co-authored-by: Sebastian Gedda <sebastian.gedda@gmail.com>
…then create and switch scenarios

Empty dashboard, app all live and nothing stored; lane added, one load with Record On (request-only
placeholders), Record Off; Hops: expand GET /api/discover -> GET /discover, Open-Meteo hop -> Use saved
mock; the next load captures only that endpoint (Hops Replay, Network Mock, others live). Scenario A
from default and B from A with their own values; switching the lane moves the app each time.

Co-authored-by: Sebastian Gedda <sebastian.gedda@gmail.com>
… dashboard logs on failure

Co-authored-by: Sebastian Gedda <sebastian.gedda@gmail.com>

@cursor cursor Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread e2e/scripts/ww-service.sh
Comment thread e2e/lib/gui.ts Outdated
Comment thread e2e/lib/gui.ts
- Explicitly unset MOCKIFYER_RECORD env vars when WW_RECORD=off
- Allow whitespace in domain folder name regex
- Fix hop expand toggle xpath to find sibling button

@cursor cursor Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: env -u flags after assignments fail
    • Moved record_env array to the beginning of the env command so -u options appear before NAME=VALUE assignments, fixing the command syntax error.

You can send follow-ups to the cloud agent here.

Comment thread e2e/scripts/ww-service.sh
cursoragent and others added 4 commits October 27, 2026 17:21
Move record_env array to the beginning of the env command to ensure
-u flags appear before NAME=VALUE assignments. GNU and BSD env require
options before assignments; placing -u after assignments caused env to
treat -u as the command to execute, failing with 'No such file or directory'.
…r a mock hit, a lane switch and a 503 fallback

Network: Bodies on, Clear, Paused; Trace: expand GET /api/discover -> GET /discover -> Open-Meteo hop;
Details show Source Mock/Upstream, Status, Duration, Lane, request headers and response bodies with
the value the app shows (99, heatwave 44, 503 + wander-api fallback 18); Client connections shows the
lane's last resolved scenario. afterEach turns body capture off again.

Co-authored-by: Sebastian Gedda <sebastian.gedda@gmail.com>
Co-authored-by: Sebastian Gedda <sebastian.gedda@gmail.com>
The lane title also appears on the Network Details pane, so the row matched two elements in
presentation mode (scrollIntoView is strict).

Co-authored-by: Sebastian Gedda <sebastian.gedda@gmail.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

Reviewed by Cursor Bugbot for commit b972be4. Configure here.

Comment thread e2e/lib/gui.ts
cursoragent and others added 4 commits October 27, 2026 17:39
… 503 step too

Co-authored-by: Sebastian Gedda <sebastian.gedda@gmail.com>
…he 503 test)

Mock editor on the Open-Meteo mock only: Response Delay 2500 ms -> the app's Discover request takes
>= 2.5 s (browser timing) and still shows 99; + Status Override 503 -> 18 (wander-api fallback) after
>= 2.5 s; clear each -> fast again, 99. Network trace: the Open-Meteo hop's status/duration change while
the countries hop stays 200 and fast; only that mock stores the settings. Shared traceAppLoad and
setResponseSimulation (set or Clear) for this and the tracing walkthrough.

Co-authored-by: Sebastian Gedda <sebastian.gedda@gmail.com>
Co-authored-by: Sebastian Gedda <sebastian.gedda@gmail.com>
…of reading it once

The header panel stays mounted and only calls getClientLanes on mount and every 15 s; opening it
does not refetch, so right after a lane switch it can still show the previous scenario. The
Scenario (lane) / Last resolved assertions now retry for one poll interval plus margin (20 s).

Co-authored-by: Sebastian Gedda <sebastian.gedda@gmail.com>
cursor Bot pushed a commit that referenced this pull request Oct 28, 2026
…ack walkthrough

- Create new /e2e-tutorial page with complete tutorial from PR #487
- Add route, navigation item, SEO metadata, sitemap entry
- Include all 9 scenario walkthroughs with neutral terminal prompts
- Add branch note callout for PR #487 dependency (easy to remove after merge)
- Wire into llms.txt and llms-full.txt for AI discoverability
- Add comprehensive e2e test covering page sections and navigation
- Frontend build passes (ESLint config not present as noted in AGENTS.md)

No product package versions changed (website-only change).
Tutorial covers proxy runtime, client lanes, scenarios, network trace,
per-endpoint control, failure injection, and dashboard GUI tests.

Co-authored-by: Sebastian Gedda <sebastian.gedda@gmail.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants