# Test an app in the browser

Drive your application's UI while its server uses the real vendor SDK inside a World. An HTTP request script is useful, but it does not exercise forms, login, cookies or the rendered result.

## Start from the runnable example

Use the [browser signup cookbook](../../cookbook/browser-signup/README.md). It includes the complete complete app, exact dependency versions, a World configuration helper and a eight-assertion Playwright test. Node 22.6 or newer and npm are required; no platform account or vendor key is needed.

The example registers its server as an `app` service after the Stripe twin. `up` waits for `/health` and records `app-url`. Read that URL with `npx volter-world app-url browser-signup --root .`; do not parse a credentials/env file to discover it. Run browser tests through `world run` so they receive the same app endpoint as the server.

## Walk the user journey

1. Open the app URL and create an account using an `example.com` email and a fresh random password for this run. Never use a seed password or capture the password field.
2. The application creates a Stripe customer through its SDK. Assert the account heading, stored email and customer ID on the rendered page.
3. Assert the signed callback status. The receiver verifies the endpoint's signature before accepting an event.
4. Reload the account page. Assert the existing session still opens it.
5. Send an invalid signed callback and assert HTTP 400.
6. Sign out, then request `/account` with the browser session's request client. Require the redirect to `/login`, then sign back in with the displayed form and assert the account returns.

Use accessible roles/labels and assertions that wait for the expected state, not sleeps. Browser cookies authenticate to the app; they are separate from vendor keys and the console's session. The app's user/session state is not in the vendor log and is not erased by resetting a twin. Give parallel browser workers separate application and World roots, as [CI isolation](./use-in-ci.md#parallel-workers) explains.

## Read the score honestly

The provided test prints `Workflow assertions: 8 / 8 passed` only after all eight checks pass. This quick score measures the declared app workflow. The [catalog](https://world.volter.ai/twins) separately reports supported operations, exercised vendor operations and replay; browser, DOM, source-code and transition coverage remain unmeasured unless that release's report says otherwise. Never label eight UI assertions as full vendor coverage.

After a failure, inspect the app error, World log and handler matches using [recovery](./recover-a-failed-call.md). Keep the test result with its exact dependencies, World config, clock and seed. [Run a full stack](./run-a-full-stack.md) explains adding databases and other services; [reproduce a failure](./reproduce-a-failure.md) explains branches and their state limits.
