Testing
Use Nuxt's runtime test environment for components and composables. Use its end-to-end test environment for HTTP requests to a running application. See Nuxt's testing setup for the Vitest configuration for each environment.
Mocking useUserSession
mockNuxtImport is hoisted. Register it once at the top level of the test file and create the mock with vi.hoisted. Set its return value in beforeEach so each test receives fresh state.
For example, this component reads the signed-in state:
<script setup lang="ts">
const { loggedIn } = useUserSession()
</script>
<template>
<p>{{ loggedIn ? 'Signed in' : 'Signed out' }}</p>
</template>
Test it in the Nuxt runtime environment:
import { mockNuxtImport, mountSuspended } from '@nuxt/test-utils/runtime'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { ref } from 'vue'
import AuthStatus from '~/components/AuthStatus.vue'
const { useUserSessionMock } = vi.hoisted(() => ({
useUserSessionMock: vi.fn(),
}))
mockNuxtImport('useUserSession', () => useUserSessionMock)
beforeEach(() => {
useUserSessionMock.mockReset()
useUserSessionMock.mockReturnValue({ loggedIn: ref(false) })
})
describe('AuthStatus', () => {
it('shows the signed-out state', async () => {
const component = await mountSuspended(AuthStatus)
expect(component.text()).toBe('Signed out')
})
it('shows the signed-in state', async () => {
useUserSessionMock.mockReturnValue({ loggedIn: ref(true) })
const component = await mountSuspended(AuthStatus)
expect(component.text()).toBe('Signed in')
})
})
This mock supplies the field the component reads. Add user, session, ready, or methods when the component uses them. useUserSession does not return signIn or signUp; mock useSignIn or useSignUp separately when testing an authentication action.
Testing protected API routes
Run HTTP tests against a prepared Nuxt fixture. For example, create a minimal application in tests/fixtures/auth with the module configured and this route:
export default defineEventHandler(async (event) => {
const { user } = await requireUserSession(event)
return { id: user.id }
})
The end-to-end setup builds and starts that fixture. Use the response's HTTP status to verify access is denied:
import { fileURLToPath } from 'node:url'
import { setup, url } from '@nuxt/test-utils/e2e'
import { describe, expect, it } from 'vitest'
describe('GET /api/protected', async () => {
await setup({
rootDir: fileURLToPath(new URL('../fixtures/auth', import.meta.url)),
})
it('returns 401 without a session', async () => {
const response = await fetch(url('/api/protected'))
expect(response.status).toBe(401)
})
})