Testing & debugging
Test UI behavior with an explicit mock bridge, validate your Backend protocol, and inspect real Host logs.
Verified September 11, 2026
On this page
Test at the right boundary#
Use browser tests for your own UI behavior, real Host sessions for native integration, and installed packages for distribution checks. A mock returning your expected value does not prove a native service exists or that a release package contains its assets.
| Layer | Verify |
|---|---|
| UI with a mock bridge | Loading, success, empty state, structured failure, and user cancellation |
| Real Host | Manifest compatibility, service contracts, permissions, and subscription cleanup |
| Backend protocol | Framing, handshake, concurrent messages, errors, and shutdown |
| Installed package | Production assets, native entry, and behavior without development servers |
An explicit browser mock#
This example runs with the SDK installed in your test environment. It uses an independent client; your production code should keep using the Host-backed client.
import {
createMockBridge,
createTroveClient,
TroveError,
} from "@trove/plugin-sdk";
const bridge = createMockBridge({
"host.runtime.echo": (params) => params,
"example.failure": () => {
throw new TroveError({ code: "example.unavailable", message: "Try again" });
},
});
const client = createTroveClient({
bridge,
context: {
curioId: "dev.example.test",
curioVersion: "0.1.0",
instanceId: "test-instance",
apiVersion: 1,
mode: "development",
},
});
try {
const response = await client.call("host.runtime", "echo", { value: 42 });
console.log(response); // { value: 42 }
const subscription = await client.subscribe(
"example", "changed", {}, (event) => console.log(event),
);
bridge.emit("example", "changed", { value: 43 });
await subscription.close();
// In a separate test, call example.failure and assert the error UI.
} finally {
client.disconnect();
}
Handlers receive (params, { signal }); use the signal to stop asynchronous mock work. Unregistered mock methods reject with service.not_found. bridge.emit(service, topic, data) explicitly sends to matching mock subscriptions. The mock does not validate real service contracts or emulate macOS.
Validate a native Backend#
trove protocol test
trove protocol test --command node -- backend/index.mjs
The first reads the project’s development Backend command, otherwise its production entry and args. The second runs your explicit command in a temporary isolated protocol session. A successful probe checks transport behavior; add independent tests for your service’s actual business contracts.
Use Trove’s debug console#
Open My Curios, then choose the Curio’s bug icon or the page’s debug button. Select your Curio and filter by WebView console, Backend, UI development process, or stderr. Search for a method name, error code, or trace ID. Copy the filtered output when sharing a reproducible failure.
WebView capture includes console.log/info/debug/warn/error, uncaught errors, and unhandled promise rejections. Backend and UI development processes use stdout/stderr. stderr is an output stream, not always an application error level.
Pause freezes the view; resume reads fresh output. Clear only resets the visible read position and does not delete log files. The console remains available while switching workspace pages.
Know the log limits#
The console reads the latest 32 KiB from each stream and shows at most 400 lines per stream. WebView logs rotate at 5 MiB per file with one backup. High-frequency capture is bounded and may report omitted messages; a crash or forced termination may lose the last batch.
Use host.runtime.getPaths to discover your Curio’s log directory and inspect disk files when the console excerpt is insufficient. Do not log session tokens, secrets, or unnecessary user file contents.
Reproduce before shipping#
- Start a clean development session and exercise a real native call.
- Trigger a recoverable failure and verify the UI leaves its loading state.
- Close the screen during pending work; check cancellation and subscription cleanup.
- Stop development, package and install the Curio, and repeat the core flow.
- For a Backend, close and reopen the Curio and check the configured lifecycle.
If a check fails, use troubleshooting to narrow the cause before publishing.