install
source · Clone the upstream repo
git clone https://github.com/Intense-Visions/harness-engineering
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/Intense-Visions/harness-engineering "$T" && mkdir -p ~/.claude/skills && cp -r "$T/agents/skills/claude-code/nuxt-testing-patterns" ~/.claude/skills/intense-visions-harness-engineering-nuxt-testing-patterns && rm -rf "$T"
manifest:
agents/skills/claude-code/nuxt-testing-patterns/SKILL.mdsource content
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
, or other Nuxt auto-imports in testsuseRoute - You are testing async components that use
or<Suspense>useAsyncData - You need end-to-end tests against a running Nuxt server using Playwright
Instructions
Setup:
- Install
and configure Vitest with the Nuxt environment:@nuxt/test-utils
// vitest.config.ts import { defineVitestConfig } from '@nuxt/test-utils/config'; export default defineVitestConfig({ test: { environment: 'nuxt', environmentOptions: { nuxt: { rootDir: '.', }, }, }, });
Mounting components:
- Use
instead ofmountSuspended
for components that usemount
,useAsyncData
, or other async composables. It wraps the component inuseFetch
and waits for resolution:<Suspense>
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
for testing withrenderSuspended
patterns:@testing-library/vue
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
to mock any auto-imported composable. Call it once at the top of the test file — it persists across the file:mockNuxtImport
import { mockNuxtImport } from '@nuxt/test-utils/runtime'; mockNuxtImport('useFetch', () => { return () => ({ data: ref({ users: [{ id: 1, name: 'Alice' }] }), error: ref(null), pending: ref(false), }); });
- Mock
to simulate navigation params:useRoute
mockNuxtImport('useRoute', () => { return () => ({ params: { id: '42' }, query: { tab: 'settings' }, path: '/users/42', }); });
- Use
withvi.mocked
for per-test overrides:mockNuxtImport
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
from$fetch
to make real HTTP requests against a test Nuxt server:@nuxt/test-utils
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.
vs. mountSuspended
:mount
— synchronous, works for components with no async composablesmount
— wraps inmountSuspended
, awaits all<Suspense>
/useAsyncData
calls, returns after data is resolveduseFetch
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.