Nuxt Testing Patterns
Test Nuxt components, composables, and pages using @nuxt/test-utils with full Nuxt context including auto-imports
When to Use
- You are writing unit or integration tests for Nuxt components or pages that use Nuxt composables
- You need to mock
useFetch,useRoute, or other Nuxt auto-imports in tests - You are testing async components that use
<Suspense>oruseAsyncData - You need end-to-end tests against a running Nuxt server using Playwright
Instructions
Setup:
- Install
@nuxt/test-utilsand configure Vitest with the Nuxt environment:
// vitest.config.ts
import { defineVitestConfig } from '@nuxt/test-utils/config';
export default defineVitestConfig({
test: {
environment: 'nuxt',
environmentOptions: {
nuxt: {
rootDir: '.',
},
},
},
});
Mounting components:
- Use
mountSuspendedinstead ofmountfor components that useuseAsyncData,useFetch, or other async composables. It wraps the component in<Suspense>and waits for resolution:
import { mountSuspended } from '@nuxt/test-utils/runtime';
import MyComponent from '~/components/MyComponent.vue';
it('renders user data', async () => {
const wrapper = await mountSuspended(MyComponent, {
props: { userId: '123' },
});
expect(wrapper.text()).toContain('John Doe');
});
- Use
renderSuspendedfor testing with@testing-library/vuepatterns:
import { renderSuspended } from '@nuxt/test-utils/runtime';
import { screen } from '@testing-library/vue';
it('shows the title', async () => {
await renderSuspended(MyPage);
expect(screen.getByRole('heading')).toHaveTextContent('Dashboard');
});
Mocking Nuxt composables:
- Use
mockNuxtImportto mock any auto-imported composable. Call it once at the top of the test file — it persists across the file:
import { mockNuxtImport } from '@nuxt/test-utils/runtime';
mockNuxtImport('useFetch', () => {
return () => ({
data: ref({ users: [{ id: 1, name: 'Alice' }] }),
error: ref(null),
pending: ref(false),
});
});
- Mock
useRouteto simulate navigation params:
mockNuxtImport('useRoute', () => {
return () => ({
params: { id: '42' },
query: { tab: 'settings' },
path: '/users/42',
});
});
- Use
vi.mockedwithmockNuxtImportfor per-test overrides:
const { useFetch } = vi.hoisted(() => ({ useFetch: vi.fn() }));
mockNuxtImport('useFetch', () => useFetch);
beforeEach(() => {
useFetch.mockReturnValue({
data: ref(null),
error: ref('Network error'),
pending: ref(false),
});
});
Testing server routes:
- Use
$fetchfrom@nuxt/test-utilsto make real HTTP requests against a test Nuxt server:
import { setup, $fetch } from '@nuxt/test-utils/e2e';
describe('Server routes', async () => {
await setup({ rootDir: '.' });
it('returns users', async () => {
const users = await $fetch('/api/users');
expect(users).toHaveLength(3);
});
});
End-to-end testing with Playwright:
- Configure Playwright E2E tests that boot a real Nuxt dev server:
// tests/e2e/home.spec.ts
import { setup, createPage, url } from '@nuxt/test-utils/e2e';
import { test, expect } from '@playwright/test';
await setup({ rootDir: '.', browser: true });
test('home page loads', async () => {
const page = await createPage('/');
await expect(page.locator('h1')).toHaveText('Welcome');
});
Details
Why not use plain Vitest + @vue/test-utils?
Standard Vue Test Utils doesn't know about Nuxt's auto-import layer. Composables like useNuxtApp, useFetch, useRoute will throw "not in Nuxt context" errors. @nuxt/test-utils sets up a minimal Nuxt environment that makes auto-imports available in tests.
mountSuspended vs. mount:
mount— synchronous, works for components with no async composablesmountSuspended— wraps in<Suspense>, awaits alluseAsyncData/useFetchcalls, returns after data is resolved
Always prefer mountSuspended for page components or any component using useAsyncData.
Mocking modules vs. mocking composables:
mockNuxtImport mocks at the auto-import resolution layer. It's different from vi.mock('~/composables/useMyThing') — the latter only works for explicit imports. Use mockNuxtImport for anything that's auto-imported.
Test file organization:
tests/
unit/
components/ ← mountSuspended tests
composables/ ← plain Vitest + vue's renderHook
integration/
server/ ← $fetch API tests
e2e/ ← Playwright tests
Nuxt test environment options:
// vitest.config.ts
environment: 'nuxt',
environmentOptions: {
nuxt: {
rootDir: '.',
overrides: {
// Override nuxt.config.ts for tests
runtimeConfig: { public: { apiBase: 'http://localhost:3000' } }
}
}
}
Source
https://nuxt.com/docs/getting-started/testing
Process
- Read the instructions and examples in this document.
- Apply the patterns to your implementation, adapting to your specific context.
- Verify your implementation against the details and edge cases listed above.
Harness Integration
- Type: knowledge — this skill is a reference document, not a procedural workflow.
- No tools or state — consumed as context by other skills and agents.
Success Criteria
- The patterns described in this document are applied correctly in the implementation.
- Edge cases and anti-patterns listed in this document are avoided.