{"id":15642504,"url":"https://github.com/johannschopplich/nitro-test-utils","last_synced_at":"2026-04-10T09:01:00.266Z","repository":{"id":232837110,"uuid":"785243856","full_name":"johannschopplich/nitro-test-utils","owner":"johannschopplich","description":"🧪 Testing toolkit for Nitro full-stack servers","archived":false,"fork":false,"pushed_at":"2026-04-09T08:24:58.000Z","size":1320,"stargazers_count":109,"open_issues_count":2,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-04-09T10:16:33.173Z","etag":null,"topics":["nitro","nitropack","nuxt-test"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/johannschopplich.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-04-11T13:47:53.000Z","updated_at":"2026-04-09T08:25:00.000Z","dependencies_parsed_at":"2026-04-10T09:00:58.208Z","dependency_job_id":null,"html_url":"https://github.com/johannschopplich/nitro-test-utils","commit_stats":null,"previous_names":["johannschopplich/nitro-test-utils"],"tags_count":41,"template":false,"template_full_name":null,"purl":"pkg:github/johannschopplich/nitro-test-utils","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johannschopplich%2Fnitro-test-utils","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johannschopplich%2Fnitro-test-utils/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johannschopplich%2Fnitro-test-utils/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johannschopplich%2Fnitro-test-utils/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/johannschopplich","download_url":"https://codeload.github.com/johannschopplich/nitro-test-utils/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johannschopplich%2Fnitro-test-utils/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31635969,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-10T07:40:12.752Z","status":"ssl_error","status_checked_at":"2026-04-10T07:40:11.664Z","response_time":98,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["nitro","nitropack","nuxt-test"],"created_at":"2024-10-03T11:56:29.601Z","updated_at":"2026-04-10T09:01:00.253Z","avatar_url":"https://github.com/johannschopplich.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"# Nitro Test Utils\n\nA simple and easy-to-use testing toolkit for [Nitro](https://nitro.build) servers, built on top of [Vitest](https://vitest.dev). Use it to write tests for your API routes and event handlers.\n\n## Features\n\n- 🚀 Automatic Nitro build (development or production mode)\n- ↪️ Reruns tests whenever Nitro source files change\n- 🥜 Run Nitro per test suite or globally\n- ✅ Seamless integration with Vitest\n- 🪝 Conditional code execution based on test mode (`import.meta.test`)\n- ☁️ Cloudflare Workers support with local bindings emulation (KV, D1, R2, …)\n- 📡 Familiar [`$fetchRaw`](#fetchraw) helper similar to Nuxt test utils\n\n## Installation\n\nAdd `nitro-test-utils` as well as `nitro` and `vitest` to your project with your favorite package manager:\n\n```bash\n# pnpm\npnpm add -D nitro-test-utils nitro vitest\n\n# npm\nnpm install -D nitro-test-utils nitro vitest\n\n# yarn\nyarn add -D nitro-test-utils nitro vitest\n```\n\n\u003e [!IMPORTANT]\n\u003e Requires Nitro v3 and Vitest v4 or later.\n\u003e\n\u003e Looking for Nitro v2 support? Use [v0.11](https://github.com/johannschopplich/nitro-test-utils/tree/v0) (`nitro-test-utils@^0.11`).\n\n## Setup\n\nThere are two ways to set up the test environment: **globally** (one Nitro server for all tests) or **per test suite** (different servers per test file).\n\n\u003e [!NOTE]\n\u003e If you are using **Nitro as a Vite plugin** (`nitro/vite`), no additional configuration is needed. Since `nitro.config.ts` is required even in Vite projects, `nitro-test-utils` loads it directly and creates a standalone Nitro server for testing.\n\n### Global Setup (Recommended)\n\nGetting started with the global setup is as simple as creating a `vitest.config.ts` in your project root. Pass `{ global: true }` as the second argument to enable a shared Nitro server for all tests:\n\n```ts\nimport { defineConfig } from 'nitro-test-utils/config'\n\nexport default defineConfig({}, {\n  global: true,\n})\n```\n\nYou can also pass an options object to `global` with additional options like `rootDir`, `mode`, and `preset`:\n\n```ts\nimport { defineConfig } from 'nitro-test-utils/config'\n\nexport default defineConfig({}, {\n  global: {\n    rootDir: 'backend',\n    mode: 'production',\n  },\n})\n```\n\nNow, write your tests in a dedicated directory. You can use the `$fetchRaw` function to make requests to the Nitro server that is started by the test environment. A simple test case could look like this:\n\n```ts\nimport { $fetchRaw } from 'nitro-test-utils/e2e'\nimport { describe, expect, it } from 'vitest'\n\ndescribe('api', () =\u003e {\n  it('responds successfully', async () =\u003e {\n    const { data, status } = await $fetchRaw('/api/health')\n\n    expect(status).toBe(200)\n    expect(data).toMatchSnapshot()\n  })\n})\n```\n\n\u003e [!TIP]\n\u003e The global setup is recommended for most use cases. It keeps the Nitro dev server running in the background during Vitest watch mode, so you can develop and test at the same time. Whenever Nitro rebuilds, tests rerun automatically.\n\n### Per-Suite Setup\n\nIf you have multiple Nitro servers as part of your project, you can set up the test environment per test suite instead. The Vitest config needs no nitro options:\n\n```ts\nimport { defineConfig } from 'nitro-test-utils/config'\n\nexport default defineConfig()\n```\n\nContrary to the global setup, the Nitro server is not started automatically. Instead, call the `setup` function in each test suite to start a Nitro server. After each test suite, the server is shut down:\n\n```ts\nimport { resolve } from 'node:path'\nimport { $fetchRaw, setup } from 'nitro-test-utils/e2e'\nimport { describe, expect, it } from 'vitest'\n\ndescribe('api', async () =\u003e {\n  await setup({\n    rootDir: resolve(import.meta.dirname, 'fixture'),\n    mode: 'production',\n  })\n\n  it('responds successfully', async () =\u003e {\n    const { data, status } = await $fetchRaw('/api/health')\n\n    expect(status).toBe(200)\n    expect(data).toMatchSnapshot()\n  })\n})\n```\n\n## Configuration\n\n### Environment Variables\n\nYou can set custom environment variables for your tests by creating a `.env.test` file in your Nitro project root. The variables will be loaded automatically when the Nitro server starts:\n\n```ini\n# .env.test\nFOO=bar\n```\n\n### Deployment Presets\n\nBy default, `nitro-test-utils` uses Node.js-compatible presets (`nitro-dev` for development, `node-middleware` for production). If your application targets a different deployment platform, you can set the `preset` option to match your deployment target.\n\n\u003e [!NOTE]\n\u003e Non-Node presets like `cloudflare-module` only work in development mode, since Vitest runs inside a Node.js process.\n\n#### Cloudflare Workers\n\nTo test Cloudflare-specific features like KV, D1, or R2 bindings locally, set the preset to `cloudflare-module`. Nitro automatically resolves this to the `cloudflare-dev` preset in development mode, which emulates Cloudflare bindings locally via wrangler's `getPlatformProxy()`.\n\nMake sure `wrangler` is installed as a dev dependency and a `wrangler.json` (or `wrangler.toml`) with your bindings configuration exists in your Nitro project root.\n\n```ts\nawait setup({\n  rootDir: resolve(import.meta.dirname, 'fixture'),\n  preset: 'cloudflare-module',\n})\n```\n\nInside your Nitro handlers, access Cloudflare bindings through `event.req.runtime.cloudflare.env`:\n\n```ts\nimport { defineHandler } from 'nitro/h3'\n\nexport default defineHandler((event) =\u003e {\n  const { env } = (event.req as any).runtime.cloudflare\n  return env.KV.get('my-key')\n})\n```\n\n### Detecting Test Environment\n\nYou can detect whether your code is running in a Nitro build during tests by checking the `import.meta.test` property. This is useful if you want to conditionally run code only in tests, but not in production:\n\n```ts\nimport { defineHandler } from 'nitro/h3'\n\nexport default defineHandler(async () =\u003e {\n  if (import.meta.test) {\n    return { foo: 'bar' }\n  }\n\n  const db = await connectToDatabase()\n  return db.query()\n})\n```\n\nTo get proper TypeScript support for `import.meta.test`, add a triple-slash reference in your `env.d.ts` (or any `.d.ts` file included by your `tsconfig.json`):\n\n```ts\n/// \u003creference types=\"nitro-test-utils/env\" /\u003e\n```\n\n## API Reference\n\n### `defineConfig`\n\nConfigures Vitest for Nitro testing. Accepts an optional Vite/Vitest config as the first argument and Nitro test options as the second.\n\n```ts\nimport { defineConfig } from 'nitro-test-utils/config'\n\nexport default defineConfig(\n  // Vite/Vitest config (optional)\n  { test: { dir: './tests' } },\n  // Nitro test options (optional)\n  { global: true }\n)\n```\n\n**Type Declaration:**\n\n```ts\nfunction defineConfig(\n  userConfig?: UserConfig,\n  testConfig?: NitroTestConfig\n): Promise\u003cUserConfig\u003e\n\ninterface NitroTestConfig {\n  /** Watch Nitro source files and rerun tests on changes. Default: `true`. */\n  rerunOnSourceChanges?: boolean\n  /** Enable a global Nitro server for all tests. Set to `true` for defaults, or pass options. */\n  global?: boolean | NitroTestOptions\n}\n\ninterface NitroTestOptions {\n  /** Path to the Nitro project root. Default: Vitest working directory. */\n  rootDir?: string\n  /** `'development'` (default) or `'production'`. */\n  mode?: 'development' | 'production'\n  /** Nitro deployment preset. */\n  preset?: string\n}\n```\n\n### `setup`\n\nStarts a Nitro server for the current test suite. Used with the per-suite setup. The server is automatically stopped after the suite completes.\n\n```ts\nimport { setup } from 'nitro-test-utils/e2e'\n\nawait setup({ rootDir: './fixture' })\n```\n\n**Type Declaration:**\n\n```ts\nfunction setup(options?: NitroTestOptions): Promise\u003cvoid\u003e\n```\n\nSee [`NitroTestOptions`](#defineconfig) for available options.\n\n### `$fetchRaw`\n\nA simple wrapper around the custom [`ofetch`](https://github.com/unjs/ofetch) instance created by `createNitroFetch`. It simplifies requesting data from your Nitro server during testing and will dynamically use the base URL of the active test server.\n\n`$fetchRaw` returns a promise that resolves with the raw response from [`ofetch.raw`](https://github.com/unjs/ofetch?tab=readme-ov-file#-access-to-raw-response). This is useful because it allows you to access the response status code, headers, and body, even if the response failed.\n\n```ts\nimport { $fetchRaw } from 'nitro-test-utils/e2e'\nimport { describe, expect, it } from 'vitest'\n\ndescribe('api', () =\u003e {\n  it('responds with data', async () =\u003e {\n    // Use `data` instead of `body` for the parsed response body\n    const { data, status, headers } = await $fetchRaw('/api/hello')\n\n    expect(status).toBe(200)\n    expect(data).toMatchSnapshot()\n  })\n})\n```\n\n\u003e [!TIP]\n\u003e All additional options set in [`createNitroFetch`](#createnitrofetch) apply here as well, such as [`ignoreResponseError`](https://github.com/unjs/ofetch?tab=readme-ov-file#%EF%B8%8F-handling-errors) set to `true` to prevent the function from throwing an error when the response status code is not in the range of 200-299, and `retry: 0` to disable retries.\n\n**Type Declaration:**\n\n```ts\ninterface NitroFetchResponse\u003cT\u003e extends FetchResponse\u003cT\u003e {\n  /** Alias for `response._data` */\n  data?: T\n}\n\nfunction $fetchRaw\u003cT = any, R extends ResponseType = 'json'\u003e(\n  path: string,\n  options?: FetchOptions\u003cR\u003e\n): Promise\u003cNitroFetchResponse\u003cMappedResponseType\u003cR, T\u003e\u003e\u003e\n```\n\n### `createNitroFetch`\n\nCreates a custom [`ofetch`](https://github.com/unjs/ofetch) instance with the Nitro server URL as the base URL.\n\n\u003e [!TIP]\n\u003e The following additional fetch options have been set as defaults:\n\u003e\n\u003e - `ignoreResponseError: true` to prevent throwing errors on non-2xx responses.\n\u003e - `redirect: 'manual'` to prevent automatic redirects.\n\u003e - `retry: 0` to disable retries, preventing masked failures and slow test suites.\n\u003e - `headers: { accept: 'application/json' }` to force a JSON error response when Nitro returns an error.\n\nUse `createNitroFetch` to get a `$fetch` instance pre-configured for your Nitro test server – no extra setup needed:\n\n```ts\nimport { createNitroFetch } from 'nitro-test-utils/e2e'\nimport { describe, expect, it } from 'vitest'\n\ndescribe('api', () =\u003e {\n  const $fetch = createNitroFetch()\n\n  it('responds with data', async () =\u003e {\n    const data = await $fetch('/api/health')\n    expect(data).toEqual({ ok: true })\n  })\n})\n```\n\n**Type Declaration:**\n\n```ts\nfunction createNitroFetch(options?: FetchHooks): $Fetch\n```\n\nYou can pass `ofetch` interceptors (`onRequest`, `onResponse`, `onRequestError`, `onResponseError`) to customize request/response handling.\n\n### `createNitroSession`\n\nCreates a session-aware fetch instance that persists cookies across requests. Useful for testing authentication flows.\n\n```ts\nimport { createNitroSession } from 'nitro-test-utils/e2e'\nimport { describe, expect, it } from 'vitest'\n\ndescribe('auth', () =\u003e {\n  it('persists session cookies', async () =\u003e {\n    const session = createNitroSession()\n\n    // Login sets a session cookie\n    await session.$fetch('/api/login', { method: 'POST' })\n\n    // Subsequent requests include the cookie automatically\n    const profile = await session.$fetch('/api/profile')\n    expect(profile).toEqual({ user: 'authenticated' })\n\n    // Inspect cookies directly\n    expect(session.cookies.get('session')).toBeDefined()\n\n    // Clear cookies to simulate logout\n    session.clearCookies()\n  })\n})\n```\n\n**Type Declaration:**\n\n```ts\ninterface NitroSession {\n  $fetch: $Fetch\n  cookies: Map\u003cstring, string\u003e\n  clearCookies: () =\u003e void\n}\n\nfunction createNitroSession(): NitroSession\n```\n\n### `injectServerUrl`\n\nTo get the URL of the active test server for the current test suite or global test environment, you can use the `injectServerUrl` function.\n\n```ts\nimport { injectServerUrl } from 'nitro-test-utils/e2e'\nimport { describe, it } from 'vitest'\n\ndescribe('api', () =\u003e {\n  it('logs Nitro server URL', () =\u003e {\n    const serverUrl = injectServerUrl()\n    console.log(serverUrl) // http://localhost:3000\n  })\n})\n```\n\n**Type Declaration:**\n\n```ts\nfunction injectServerUrl(): string\n```\n\n## Migration\n\n### From v1 to v2\n\nThe `nitro` key on Vite's `UserConfig` has been replaced with a second argument to `defineConfig`. This resolves a type collision with Nitro's own Vite plugin (`nitro/vite`), which claims the same `nitro` key.\n\n```diff\n import { defineConfig } from 'nitro-test-utils/config'\n\n-export default defineConfig({\n-  nitro: {\n-    global: true,\n-  },\n-})\n+export default defineConfig({}, {\n+  global: true,\n+})\n```\n\nWith custom options:\n\n```diff\n-export default defineConfig({\n-  nitro: {\n-    global: {\n-      rootDir: 'backend',\n-      mode: 'production',\n-    },\n-    rerunOnSourceChanges: false,\n-  },\n-})\n+export default defineConfig({}, {\n+  global: {\n+    rootDir: 'backend',\n+    mode: 'production',\n+  },\n+  rerunOnSourceChanges: false,\n+})\n```\n\n### From v0.x (Nitro v2)\n\nIf you are upgrading from an earlier version of `nitro-test-utils` that targeted Nitro v2 (`nitropack`), the following breaking changes apply:\n\n- **Peer dependency**: `nitropack` replaced by `nitro` (v3).\n- **Renamed types**: `TestOptions` → `NitroTestOptions`, `TestContext` → `NitroTestContext`, `TestServer` → `NitroTestServer`, `TestFetchResponse` → `NitroFetchResponse`.\n\nFor Nitro v3 API changes, see the [official Nitro v3 migration guide](https://nitro.build/guide/migration).\n\n## License\n\n[MIT](./LICENSE) License (c) 2024-PRESENT [Johann Schopplich](https://github.com/johannschopplich)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohannschopplich%2Fnitro-test-utils","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjohannschopplich%2Fnitro-test-utils","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohannschopplich%2Fnitro-test-utils/lists"}