How to test the two layers most Remix code lives in: HTTP behavior and DOM behavior. Read this when the task involves:
- Driving the router with `router.fetch(new Request(...))` and asserting on the returned `Response`
- Building a fresh router per test for session, storage, or database isolation
- Rendering components into a real DOM with `render(...)` or `createRoot(...)`
- Configuring `remix test` discovery, excludes, and coverage
- Using adjacent CLI checks such as `remix routes`, `remix doctor`, and `remix version`
- Choosing which layer to test for a given behavior
For session and auth test setup, see `auth-and-sessions.md`. For component lifecycle, see `component-model.md`.
## Two Shapes
Remix tests run with `remix test`, use `remix/test` for the test framework, and use `remix/assert` for assertions. Two main shapes:
- **Server / router tests** — drive the router with `router.fetch(new Request(...))` and assert on the returned `Response`. No DOM, no browser harness.
- **Component tests** — render a component into a real DOM `Element` with `render(...)`, or use `createRoot(...)` directly when you need lower-level root control.
## Server / Router Tests
Treat the router as a pure `(Request) => Promise<Response>` function. Build a fresh app router per test (or per suite) so middleware state — sessions, in-memory storage, the database — stays isolated.
assert.match(awaitresponse.text(),/Welcome to the Bookstore/)
})
})
```
Use `routes.<name>.href(...)` to build URLs in tests so they stay in sync with the route definition. For form-style POSTs, attach a `FormData` body to the `Request`. For tests that need a known session, swap in `createMemorySessionStorage()` and a test cookie when constructing the router.
Use `createTestServer` from `remix/node-fetch-server/test` when the behavior depends on a real HTTP origin, redirects, streaming, cookies through a network boundary, or browser-style `fetch`:
Use `remix test --coverage` to enable coverage with defaults. Use `exclude` when discovery would otherwise enter generated output, symlinked workspaces, or other paths that should not produce tests.
Use `render(...)` from `remix/ui/test` for most component tests. It creates a real DOM container, flushes the initial render, and returns `act(...)` so interactions can flush pending updates before assertions. Use `createRoot(container)` from `remix/ui` directly when a test needs explicit control over root rendering, flushing, or disposal.