makepad/libs/makepad_test/DESKTOP_VISIBLE.md
andodeki 477421e314 nigig: NIGIG test-mode forwarding, custom manifest hook, ortho camera support
- makepad_test/runtime.rs: forward NIGIG_TEST_MODE from host env to the
  Android app via 'am start' intent extra; add wait_timeout (60s) used by
  wait_visible/wait_hidden/wait_count; make query_widgets tolerant of
  snapshot timeouts; grant READ_CONTACTS during adb setup
- makepad-platform android_jni.rs: read makepad.NIGIG_TEST_MODE intent
  extra and surface it as the NIGIG_TEST_MODE env var via apply_studio_env
- cargo_makepad compile.rs: support verbatim custom AndroidManifest.xml in
  addition to the templated variant
- makepad-xr xr_root.rs: add ortho camera controls (ortho, ortho_height,
  min/max), derive Debug on XrCamera
- docs: ANDROID.md and DESKTOP_VISIBLE.md for makepad_test
2026-09-03 10:55:00 +03:00

6.4 KiB

makepad_test on Desktop (Visible Studio Mode)

How to run the same makepad_test UI tests in visible mode, where the app opens a real window on your desktop and you can watch every UI response as the test drives it. This is the opposite of the default headless mode documented in GUIDE.md; it is the desktop companion to the Android doc in ANDROID.md.

What this mode is for

  • you want to see the app react to the test (clicks, typing, widget state)
  • you want to debug a flaky interaction by watching it happen in real time
  • you want to inspect screenshots / widget dumps as the test progresses

The test body is identical to headless mode — same TestApp, Locator, Selector, screenshot(), and widget_dump() APIs. Only the launch transport changes.

How it works

When MAKEPAD_TEST_VISIBLE=1 is set, the runtime (start_visible_app in libs/makepad_test/src/runtime.rs):

  1. connects a StudioRemoteClient to an already running Makepad Studio instance at 127.0.0.1:8001
  2. sends ListBuilds, then ClearBuild for any existing build of the same mount + package (so you get a fresh run tab)
  3. sends a Run for the current package and waits for BuildStarted + AppStarted
  4. drives the test over the Studio protocol — the app runs with a real, visible window, and clicks / typing / screenshots / widget dumps go through Studio

No in-process hub is used here: the hub is the real Studio desktop process, which mounts its working directory as makepad. The test just talks to it like any Studio remote bridge client.

Prerequisites

  1. Build the Studio remote tool:

    cargo build --release -p cargo-makepad
    
  2. Start Studio (it stays running for the whole interaction):

    target/release/cargo-makepad studio --studio=127.0.0.1:8001
    

    Keep that process running in its own terminal.

  3. Launch Studio from the makepad repo root. Studio mounts its current working directory as the default mount named makepad (studio/desktop/src/app_backend.rs), so starting it from the makepad repo exposes every workspace package — including makepad-example-counter — as a runnable item on the makepad mount.

    The makepad repo is fully self-contained: the nigig-org parent workspace excludes makepad-native-glue/makepad, and no crate in the makepad workspace references an out-of-repo path (the counter example's old ../../../makepad-native-glue dep was dropped). So nigig-org is not mounted and not required — Studio just needs the makepad repo as its working directory.

    If your Studio session uses a different mount name, set MAKEPAD_TEST_STUDIO_MOUNT.

Environment variables

Variable Purpose Default
MAKEPAD_TEST_VISIBLE enable visible mode (truthy: 1 / true / yes / on) unset (headless)
MAKEPAD_TEST_STUDIO Studio remote address 127.0.0.1:8001
MAKEPAD_TEST_STUDIO_MOUNT Studio mount name of the app makepad
MAKEPAD_TEST_STARTUP_DELAY_MS pause after the app appears before the test starts 0
MAKEPAD_TEST_ACTION_DELAY_MS pause after each interaction (click/type) so you can watch it 0
MAKEPAD_TEST_KEEP_OPEN_MS keep the app open this long before the test shuts it down 0

The delay variables are the key to "seeing the responses": with a large ACTION_DELAY_MS the test walks through the UI slowly and you can follow every step.

Running

Basic visible run:

MAKEPAD_TEST_VISIBLE=1 cargo test --release -p makepad-example-counter --test ui -- --test-threads=1

Watchable run (slow, so each interaction is visible):

MAKEPAD_TEST_VISIBLE=1 \
MAKEPAD_TEST_STARTUP_DELAY_MS=1000 \
MAKEPAD_TEST_ACTION_DELAY_MS=750 \
MAKEPAD_TEST_KEEP_OPEN_MS=3000 \
cargo test --release -p makepad-example-counter --test ui -- --test-threads=1

If Studio is not on 8001 (or you started it on 8002), point the test at it:

MAKEPAD_TEST_VISIBLE=1 MAKEPAD_TEST_STUDIO=127.0.0.1:8002 \
cargo test --release -p makepad-example-counter --test ui -- --test-threads=1

--test-threads=1 is required: the suite is serial and each test takes over the visible app session.

What you see

  • the app opens in a normal desktop window (not a Studio overlay — the real app process)
  • each click, key press, and text entry happens in that window, paced by MAKEPAD_TEST_ACTION_DELAY_MS
  • Studio shows the run in its runview/log tab (BuildStarted / AppStarted / BuildStopped, query results)
  • screenshot() / widget_dump() / widget_snapshot() results still work and are written to the failure-artifact dir; on a failing test you get failure.txt, failure-screenshot.png, widget-tree.txt, etc. under target/makepad_test/<package>/<test>/

Notes

  • Studio must already be running before the test starts; the test does not spawn Studio.
  • Older builds of the same package are cleared first, so the app you watch is always the fresh run the test launched.
  • Visible mode uses the normal Studio launch path, so it does not use the direct-stdio script that headless mode uses — the app is connected through Studio's websocket gateway and windowed normally.
  • You can combine this with MAKEPAD_STUDIO_HUB_DEBUG=1 for protocol-level diagnostics (only meaningful for the in-process/hub side; in visible mode the interesting debug output is in Studio itself).

Troubleshooting

Symptom Likely cause / fix
connection refused / no response from Studio Studio is not running; start cargo-makepad studio --studio=127.0.0.1:8001 first
request errors with no active websocket the app was not connected yet; wait for startup, retry the query
app launches but the test times out waiting for AppStarted wrong mount name or Studio started from the wrong directory; launch Studio from the makepad repo root, or set MAKEPAD_TEST_STUDIO_MOUNT
wrong Studio instance set MAKEPAD_TEST_STUDIO to the correct ip:port (use 8002 if Studio reported 8001 occupied)
test passes headless but fails visibly visible runs go through Studio's build/run path (different target dir / fingerprint state); verify with MAKEPAD_STUDIO_HUB_DEBUG=1 and check the Studio runview log tab

Current limitations

  • requires a manually started Studio instance
  • one visible app session per test (serial suite)
  • no visual diffing; screenshot/artifact inspection is manual