v3.0.0
🚨 Breaking Changes
- Infer
$fetchRawresponses from Nitro'sInternalApi- by @johannschopplich (92017) - Replace HTTP test server with in-process dispatch - by @johannschopplich (f62b5)
🚀 Features
- Add
listRouteshelper for route introspection - by @johannschopplich (f450a)
📖 Migration Guide
In-process request dispatch
v3 stops starting a real HTTP listener for your tests. Instead, the Nitro app is dispatched in-process – each request is handed directly to the app's Web Request handler, the same code path every cloud preset invokes at runtime. No ports, no sockets, no localhost round-trip.
This removes injectServerUrl. Replace it with injectNitroFetch, which returns the raw request dispatcher:
-import { injectServerUrl } from 'nitro-test-utils/e2e'
-const url = injectServerUrl()
+import { injectNitroFetch } from 'nitro-test-utils/e2e'
+const nitroFetch = injectNitroFetch()
+const response = await nitroFetch(new Request('http://nitro.test/api/health'))Typed $fetchRaw responses
$fetchRaw now inherits route-level typing from Nitro's InternalApi augmentation. Its first generic default changed from T = any to T = unknown, so call sites that dereference data without narrowing will fail to type-check.
The preferred fix is to set up Nitro's type augmentation so $fetchRaw picks up handler return types automatically – see Route-Level Response Types. Where that isn't practical, pass an explicit generic:
-const { data } = await $fetchRaw('/api/users')
-expect(data.id).toBe(1)
+const { data } = await $fetchRaw<{ id: number }>('/api/users')
+expect(data?.id).toBe(1)Note
The second generic on $fetchRaw previously accepted ofetch's ResponseType ('json', 'text', …). It now represents the request route. This only affects code that passed an explicit second generic – a rarely-used call shape.