This content originally appeared on DEV Community and was authored by Doan Trong Nam
Testing is a critical part of building robust and reliable applications. While Nuxt 3 makes creating server routes incredibly simple, setting up a proper testing environment for them can seem a bit daunting. Fear not! With the power of vitest
and @nuxt/test-utils
, you can create a clean, efficient, and powerful testing suite for your server-side logic.
This guide will walk you through setting up unit tests for your Nuxt 3 server routes, from initial configuration to mocking dependencies and writing comprehensive tests.
1. Configuring Vitest for Your Nuxt Environment
The first step is to ensure vitest
knows how to run your tests within a Nuxt context. This is crucial for auto-imports and other Nuxt-specific features to work correctly in your test files.
The @nuxt/test-utils
package provides a handy defineVitestConfig
function that simplifies this process. Here’s what a typical vitest.config.ts
looks like:
// vitest.config.ts
import { defineVitestConfig } from '@nuxt/test-utils/config'
export default defineVitestConfig({
test: {
// Enable the Nuxt environment.
environment: 'nuxt',
environmentOptions: {
nuxt: {
// You can specify a DOM environment for components testing if needed.
domEnvironment: 'happy-dom',
},
},
},
})
By setting environment: 'nuxt'
, you're telling Vitest to use a custom environment that boots up a Nuxt instance, making all its magic available to your tests.
Read more at Official Nuxt Testing Doc
2. Creating a Global Test Setup File
To avoid repetitive mocking in every test file, it's best to create a global setup file. Vitest can be configured to run this file before your test suite starts. A common location for this is test/setup.ts
.
This file is the perfect place to mock global utilities, especially the h3
functions that power Nuxt's server routes (defineEventHandler
, readBody
, etc.).
Here’s how you can create a reusable utility to mock h3
functions:
// test/setup.ts
import type { H3Event, EventHandlerRequest } from 'h3'
import { vi } from 'vitest'
type Handler = (event: H3Event<EventHandlerRequest>) => Promise<unknown>
export function useH3TestUtils() {
const h3 = vi.hoisted(() => ({
defineEventHandler: vi.fn((handler: Handler) => handler),
readBody: vi.fn(async (event: H3Event) => {
if (event._requestBody && typeof event._requestBody === 'string') {
return JSON.parse(event._requestBody)
}
return event._requestBody || {}
}),
getRouterParams: vi.fn((event: H3Event) => event.context?.params || {}),
getQuery: vi.fn((event: H3Event) => event.context?.query || {}),
}))
// Stub the global functions to support auto-imports in your tests
vi.stubGlobal('defineEventHandler', h3.defineEventHandler)
vi.stubGlobal('readBody', h3.readBody)
vi.stubGlobal('getRouterParams', h3.getRouterParams)
vi.stubGlobal('getQuery', h3.getQuery)
return h3
}
Key Concepts:
-
vi.hoisted()
: This lifts the mock to the top of the module, ensuring that any subsequent imports ofh3
receive our mocked version. -
vi.stubGlobal()
: Since Nuxt relies on auto-imports, these functions are effectively global. This function replaces the global instance with our mock, making it available seamlessly in our test files.
3. Mocking the H3Event Object
Your server handlers receive an event
object that contains all the request details (body, params, query, headers). To test your handlers effectively, you need a way to create mock versions of this event.
Let's create a helper function for this in test/mocks/h3-event.ts
.
// test/mocks/h3-event.ts
import type { H3Event } from 'h3'
import { merge } from 'lodash'
export const createMockH3Event = (
partialEvent: Partial<H3Event> & {
body?: Record<string, any>
params?: Record<string, any>
query?: Record<string, any>
}
): H3Event => {
const event = {
node: {
req: {
headers: { 'content-type': 'application/json' },
method: 'POST',
},
},
context: {
params: partialEvent.params || {},
query: partialEvent.query || {},
},
// Our mock readBody function will look for this property
_requestBody: partialEvent.body,
} as unknown as H3Event
// Deeply merge the partial event to allow for overrides
return merge(event, partialEvent) as H3Event
}
This powerful helper lets you easily simulate any request scenario. Need to test a POST
request with a specific body? Or a GET
request with query parameters? This function has you covered.
4. Writing Your First Server Route Test
With the setup complete, you're ready to write a test. Let's use an example API route that calls an external service. We'll look at test/server/api/test.post.test.ts
.
// test/server/api/test.post.test.ts
import { describe, expect, vi, it, beforeEach } from 'vitest'
import { mockNuxtImport } from '@nuxt/test-utils/runtime'
// Import our test utilities
import { useH3TestUtils } from '~/test/setup'
import { createMockH3Event } from '~/test/mocks/h3-event'
const { defineEventHandler } = useH3TestUtils()
describe('POST /api/test', async () => {
// 3. Dynamically import the handler *after* mocks are set up
const handler = await import('~/server/api/test.post')
it('is registered as an event handler', () => expect(defineEventHandler).toHaveBeenCalled())
it('return success response for valid request', async () => {
const event = createMockH3Event({
body: {
// Simulate a valid request body
},
})
const response = await handler.default(event)
expect(response).toEqual({ data: 'mocked data' })
})
})
5. Mocking Built-in Composables
In Nuxt 3, many server-side functionalities are encapsulated in composables. For example, useRuntimeConfig
is commonly used to access environment variables or configuration settings.
To mock these composables, you can use mockNuxtImport
from @nuxt/test-utils/runtime
. This allows you to provide a mock implementation that your handler can use during tests.
// test/server/api/test.post.test.ts
import { vi } from 'vitest'
import { mockNuxtImport } from '@nuxt/test-utils/runtime'
const { useRuntimeConfigMock } = vi.hoisted(() => ({
useRuntimeConfigMock: vi.fn(() => ({
gemini: {
apiKey: 'test-api-key',
},
})),
}))
mockNuxtImport('useRuntimeConfig', () => useRuntimeConfigMock)
6. Mocking Custom Functions
If your server route relies on custom functions (like fetching data from an external API), you can mock these as well. This allows you to control the responses and test how your handler behaves under different scenarios.
// test/server/api/test.post.test.ts
import { vi } from 'vitest'
// Mock custom functions
const { formatDate } = vi.hoisted(() => ({
formatDate: vi.fn(),
}))
vi.mock('~/server/utils/datetime', () => ({
formatDate,
}))
describe('POST /api/test', () => {
it('formats date correctly', async () => {
formatDate.mockReturnValue('2023-10-01')
const event = createMockH3Event({
body: { date: '2023-10-01T00:00:00Z' },
})
const response = await handler.default(event)
expect(response).toEqual({ formattedDate: '2023-10-01' })
expect(formatDate).toHaveBeenCalledWith('2023-10-01T00:00:00Z')
})
})
Breakdown of the Test File:
- Mock Composables: Use
mockNuxtImport
from@nuxt/test-utils/runtime
to provide a mock implementation for server-side composables likeuseRuntimeConfig
. - Initialize Utilities: Call the test utility functions (
useH3TestUtils
, etc.) at the top level to set up the global mocks. - Dynamic Import: Import your API handler inside the
describe
block. This is critical to ensure that all your mocks are in place before the handler module is loaded. - Simulate Requests: Use
createMockH3Event
to craft the specific request context for each test case. - Assert: Make assertions against the handler's return value and check if your mocked functions were called with the expected arguments.
Follow-up Steps
In next article, we will explore how to:
- Mock third-party libraries and services.
Conclusion
By combining a global setup file, a flexible event factory, and targeted mocking, you can build a comprehensive and maintainable test suite for your Nuxt 3 server routes. This setup not only isolates your handlers for true unit testing but also provides a clear and repeatable pattern for testing all your server-side logic.
Happy testing!
References
This content originally appeared on DEV Community and was authored by Doan Trong Nam

Doan Trong Nam | Sciencx (2025-07-03T07:46:04+00:00) A Developer’s Guide to Unit Testing Nuxt 3 Server Routes. Retrieved from https://www.scien.cx/2025/07/03/a-developers-guide-to-unit-testing-nuxt-3-server-routes/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.