
# Testing

> Test your server routes, plugins and runtime utilities with Vitest.

[Vitest](https://vitest.dev) picks up the `nitro()` plugin from your Vite config. Test files run in the `nitro` Vite environment, so `nitro/*` runtime utilities, routes, plugins and runtime config work the same as in your server code.

## Setup

Install `vitest` as a dev dependency:

:pm-install{name="-D vitest"}

No extra config is needed, as long as `vite.config.ts` (or `vitest.config.ts`) registers the `nitro()` plugin. A project with only a `nitro.config.ts` needs to add one:

```ts [vite.config.ts]
import { defineConfig } from "vite";
import { nitro } from "nitro/vite";

export default defineConfig({
  plugins: [nitro()],
});
```

Then run `vitest`.

## Writing tests

Use `serverFetch` to send requests to your Nitro app, and call runtime utilities directly:

```ts [test/app.test.ts]
import { expect, test } from "vitest";
import { serverFetch } from "nitro";
import { useKV } from "nitro/kv";

test("GET /api/hello", async () => {
  const res = await serverFetch("/api/hello");
  expect(await res.json()).toEqual({ hello: "world" });
});

test("kv", async () => {
  await useKV().setItem("foo", "bar");
  expect(await useKV().getItem("foo")).toBe("bar");
});
```

Tests run in Vitest workers, without starting the Nitro dev server. With Vitest's default isolation, each test file gets its own Nitro app instance, and its `close` hooks run when the file finishes.

`vi.mock` works as usual, including for modules imported by your routes and [Nitro plugins](/docs/plugins): the app is created after the test file's mocks are registered.

::read-more{to="/examples/vitest"}
See the [Vitest example](/examples/vitest) for a complete project.
::

## Watch mode

In watch mode, editing a route, middleware or plugin reruns the tests that use the app. Adding or removing one rescans the server directories first, and changing the Nitro config restarts Vitest.

## SSR entry

Pages rendered by an [SSR entry](/docs/vite#frontend-frameworks) (`entry-server.ts`) work with `serverFetch` too. In tests, service entries such as `ssr` are loaded in the `nitro` environment rather than their own environment, so plugins and options that only apply to that environment are not used.

Frameworks that rely on several server environments (such as React Server Components) are not supported yet.

## Choosing the environment

The `nitro` test environment is used when `test.environment` is not set. To use another environment, set `test.environment` and opt individual files back in with a `// @vitest-environment nitro` comment, or the other way around.

Projects defined inline in `test.projects` don't get the default environment. Set `environment: "nitro"` in each project that runs server tests:

```ts [vite.config.ts]
import { defineConfig } from "vitest/config";
import { nitro } from "nitro/vite";

export default defineConfig({
  plugins: [nitro()],
  test: {
    projects: [{ extends: true, test: { name: "server", environment: "nitro" } }],
  },
});
```

## Limitations

- The `vmThreads` and `vmForks` pools don't support the `nitro` environment.
- Tests always run in Node.js: the [`devServer.runner`](/config#devserver) option, including the one set by a preset (such as `miniflare` for Cloudflare), is not used, so platform modules and bindings (such as `cloudflare:workers`) are not available.
