Nuxt offers first-class testing support through @nuxt/test-utils, providing utilities and configuration for unit testing and end-to-end testing of your Nuxt application.
Installation
Install @nuxt/test-utils with your preferred test runner and environment:
npm i --save-dev @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-core
Optional Dependencies
@nuxt/test-utils ships with optional peer dependencies:
DOM environment : Choose happy-dom or jsdom
Test runners : Choose vitest, cucumber, jest, or playwright
Browser testing : playwright-core (only if not using @playwright/test)
Unit Testing
Nuxt provides an environment for unit testing code that needs a Nuxt runtime environment. Currently supports Vitest only .
Setup
1. Add the Nuxt Test Utils Module (Optional)
Add @nuxt/test-utils/module to your nuxt.config for Vitest integration in Nuxt DevTools:
export default defineNuxtConfig ({
modules: [
'@nuxt/test-utils/module' ,
] ,
})
2. Create Vitest Configuration
Create a vitest.config.ts with project-based setup:
import { defineConfig } from 'vitest/config'
import { defineVitestProject } from '@nuxt/test-utils/config'
export default defineConfig ({
test: {
projects: [
{
test: {
name: 'unit' ,
include: [ 'test/unit/*.{test,spec}.ts' ],
environment: 'node' ,
},
},
{
test: {
name: 'e2e' ,
include: [ 'test/e2e/*.{test,spec}.ts' ],
environment: 'node' ,
},
},
await defineVitestProject ({
test: {
name: 'nuxt' ,
include: [ 'test/nuxt/*.{test,spec}.ts' ],
environment: 'nuxt' ,
},
}),
],
} ,
})
When importing @nuxt/test-utils in your Vitest config, ensure you have "type": "module" in your package.json or rename your config file to vitest.config.m{ts,js}.
Set environment variables for testing using the .env.test file.
Organizing Your Tests
With the project-based setup, organize tests as follows:
test/
├── e2e/
│ └── ssr.test.ts
├── nuxt/
│ ├── components.test.ts
│ └── composables.test.ts
├── unit/
│ └── utils.test.ts
Unit tests (test/unit/): Run in Node environment for speed
Nuxt tests (test/nuxt/): Run within Nuxt runtime environment
E2E tests (test/e2e/): Run against a built Nuxt application
Alternative: Simple Setup
For a simpler setup where all tests run in the Nuxt environment:
import { defineVitestConfig } from '@nuxt/test-utils/config'
export default defineVitestConfig ({
test: {
environment: 'nuxt' ,
} ,
})
This approach creates a hybrid environment where Nuxt Vite plugins run but the Nuxt entry and nuxtApp aren’t initialized, which can lead to hard-to-debug errors.
Running Tests
Run different test suites with the project setup:
Run all tests
Run only unit tests
Run only Nuxt tests
Watch mode
Tests run in a happy-dom or jsdom environment. A global Nuxt app initializes before tests run (including running plugins and code in your app.vue). Take care not to mutate global state in your tests, or reset it afterwards.
Testing Helpers
mountSuspended
Mount any Vue component within the Nuxt environment, allowing async setup and access to Nuxt plugins:
test/nuxt/components.test.ts
import { mountSuspended } from '@nuxt/test-utils/runtime'
import { SomeComponent } from '#components'
it ( 'can mount some component' , async () => {
const component = await mountSuspended ( SomeComponent )
expect ( component . text ()). toMatchInlineSnapshot (
'"This is an auto-imported component"' ,
)
})
mountSuspended wraps mount from @vue/test-utils. Check the Vue Test Utils documentation for available options.
renderSuspended
Render any Vue component within the Nuxt environment using @testing-library/vue:
test/nuxt/components.test.ts
import { renderSuspended } from '@nuxt/test-utils/runtime'
import { SomeComponent } from '#components'
import { screen } from '@testing-library/vue'
it ( 'can render some component' , async () => {
await renderSuspended ( SomeComponent )
expect ( screen . getByText ( 'This is an auto-imported component' )). toBeDefined ()
})
Install @testing-library/vue and enable testing globals in your Vitest config to use renderSuspended.
mockNuxtImport
Mock Nuxt’s auto import functionality:
test/nuxt/composables.test.ts
import { mockNuxtImport } from '@nuxt/test-utils/runtime'
mockNuxtImport ( 'useStorage' , () => {
return () => {
return { value: 'mocked storage' }
}
})
// your tests here
mockNuxtImport can only be used once per mocked import per test file. It’s a macro that transforms to vi.mock.
For different implementations between tests, use vi.hoisted:
import { vi } from 'vitest'
import { mockNuxtImport } from '@nuxt/test-utils/runtime'
const { useStorageMock } = vi . hoisted (() => {
return {
useStorageMock: vi . fn (() => {
return { value: 'mocked storage' }
}),
}
})
mockNuxtImport ( 'useStorage' , () => {
return useStorageMock
})
// Then, inside a test
useStorageMock . mockImplementation (() => {
return { value: 'something else' }
})
mockComponent
Mock Nuxt components:
import { mockComponent } from '@nuxt/test-utils/runtime'
mockComponent ( 'MyComponent' , {
props: {
value: String ,
},
setup ( props ) {
// ...
},
})
// Or use a factory function
mockComponent ( 'MyComponent' , () => import ( './MockComponent.vue' ))
registerEndpoint
Create Nitro endpoints that return mocked data:
import { registerEndpoint } from '@nuxt/test-utils/runtime'
registerEndpoint ( '/test/' , () => ({
test: 'test-field' ,
}))
// POST method
registerEndpoint ( '/test/' , {
method: 'POST' ,
handler : () => ({ test: 'test-field' }),
})
End-to-End Testing
Nuxt supports Vitest, Jest, Cucumber, and Playwright as end-to-end test runners.
Setup
In each describe block, set up the test context:
import { describe , test } from 'vitest'
import { $fetch , setup } from '@nuxt/test-utils/e2e'
describe ( 'My test' , async () => {
await setup ({
// test context options
})
test ( 'my test' , () => {
// ...
})
})
Setup Options
Nuxt Config
rootDir: Path to Nuxt app directory (default: '.')
configFile: Configuration file name (default: 'nuxt.config')
Timings
setupTimeout: Time for setup to complete (default: 120000ms, 240000ms on Windows)
teardownTimeout: Time for teardown (default: 30000ms)
Features
build: Run separate build step (default: true)
server: Launch server for requests (default: true)
port: Test server port (default: undefined)
host: URL for testing against deployed app (default: undefined)
browser: Launch browser for testing (default: false)
browserOptions: Playwright browser options
runner: Test runner (default: 'vitest')
Testing Against a Target Host
Test against a deployed or running application:
import { createPage , setup } from '@nuxt/test-utils/e2e'
import { describe , expect , it } from 'vitest'
describe ( 'login page' , async () => {
await setup ({
host: 'http://localhost:8787' ,
})
it ( 'displays the email and password fields' , async () => {
const page = await createPage ( '/login' )
expect ( await page . getByTestId ( 'email' ). isVisible ()). toBe ( true )
expect ( await page . getByTestId ( 'password' ). isVisible ()). toBe ( true )
})
})
E2E Testing APIs
$fetch(url)
Get the HTML of a server-rendered page:
import { $fetch } from '@nuxt/test-utils/e2e'
const html = await $fetch ( '/' )
fetch(url)
Get the response of a server-rendered page:
import { fetch } from '@nuxt/test-utils/e2e'
const res = await fetch ( '/' )
const { body , headers } = res
url(path)
Get the full URL for a given page:
import { url } from '@nuxt/test-utils/e2e'
const pageUrl = url ( '/page' )
// 'http://localhost:6840/page'
Browser Testing
createPage(url)
Create a configured Playwright browser instance:
import { createPage } from '@nuxt/test-utils/e2e'
const page = await createPage ( '/page' )
// Access all Playwright APIs from the `page` variable
Playwright Test Runner
Use Nuxt with the Playwright test runner:
Install
playwright.config.ts
tests/example.test.ts
npm i --save-dev @playwright/test @nuxt/test-utils
Best Practices
Separate test environments : Keep unit tests, Nuxt tests, and E2E tests in separate directories
Use appropriate helpers : Choose mountSuspended for components, mockNuxtImport for composables
Mock external dependencies : Use registerEndpoint for API mocking
Test user flows : Use E2E tests for critical user journeys
Keep tests isolated : Avoid mutating global state; reset after each test
Use TypeScript : Leverage type safety in your tests
Run tests in CI : Automate testing in your deployment pipeline