Files
shiftcraft/test/CLAUDE.md
2026-04-17 23:26:01 +00:00

2.6 KiB

CLAUDE.md — test/

Skill precedence

When writing or modifying tests, load the nuxt-testing skill first:

/nuxt-testing

It takes precedence over other testing skills (vue-testing-best-practices, vitest, etc.) because it covers the exact @nuxt/test-utils setup used here.

Test structure

Directory Project Environment Purpose
test/unit/ unit node Pure logic, Zod schemas, utilities
test/nuxt/ nuxt nuxt (happy-dom) Components and composables that need Nuxt runtime
test/e2e/ e2e node Browser tests against the running dev server

Run a single project: pnpm test --project unit / nuxt / e2e

Known gotchas

Nuxt component tests — mock stores in vi.hoisted, not in it()

Global middleware (e.g. 00.fetchUser.global.ts) runs during mountSuspended before the test body executes. If a mocked store returns undefined at that point, Nuxt throws and the test crashes.

Wrong — mock is set up too late:

const useUserMock = vi.fn()
mockNuxtImport('useUser', () => useUserMock)

it('...', async () => {
  useUserMock.mockReturnValue({ isAuthenticated: false, authRefresh: vi.fn() })
  // ❌ middleware already ran with undefined
})

Correct — default implementation lives in vi.hoisted:

const { useUserMock } = vi.hoisted(() => ({
  useUserMock: vi.fn(() => ({ isAuthenticated: false, user: null, authRefresh: vi.fn() }))
}))
mockNuxtImport('useUser', () => useUserMock)

E2E tests — do not pass a path to createPage() on this SPA

createPage('/some-path') internally calls waitForHydration, which polls window.useNuxtApp?.().isHydrating === false. Because useNuxtApp is not exposed on window in SPA mode, this never resolves and the test times out.

Wrong:

const page = await createPage('/login') // ❌ hangs forever

Correct — call without a path, then navigate manually:

const page = await createPage()
await page.goto('http://localhost:3000/login', { waitUntil: 'networkidle' })

E2E tests — use isVisible() + Vitest expect, not Playwright matchers

@playwright/test is not installed (only playwright-core). Playwright's expect(locator).toBeVisible() is not available.

// ❌ crashes — @playwright/test not installed
import { expect } from '@playwright/test'
await expect(page.locator('input')).toBeVisible()

// ✅ use the async boolean method with Vitest's expect
import { expect } from 'vitest'
expect(await page.locator('input').isVisible()).toBe(true)