"How do you test a Nuxt application" is a question about judgement: which tests give confidence for their cost, where the seams are, what to mock and what never to mock. The toolchain in 2026 is settled: Vitest 5 (released 3 September 2026) with @nuxt/test-utils 4 for unit and component tests in a Nuxt runtime environment, and Playwright for end-to-end. What separates candidates is the strategy.
wrapper.vm or assert on internal state. Refactors should not break tests.registerEndpoint or MSW, time through fake timers, the Nuxt context through mockNuxtImport; never mock the module you are testing or its siblings. If a unit test needs five mocks, the code needs a seam.nuxt typecheck, ESLint with type-aware rules and vue-tsc catch a class of bugs no runtime test finds, for free on every commit.nuxt Vitest environment with happy-dom or jsdom; visual and browser-API-heavy components can run in Vitest browser mode (Playwright provider); user flows run in Playwright against a built app.await, a race on hydration, a test depending on order), quarantine with an owner and a deadline if you cannot fix it now, and never let retries hide a real race in production code.$fetch('/') in e2e) and in the browser; hydration errors are testable (listen for console warnings); useAsyncData needs the Nuxt environment or registerEndpoint; stores need createTestingPinia; data fetching in setup needs mountSuspended, which handles Suspense.| Page | What it covers |
|---|---|
| Unit tests with Vitest | Vitest 5 essentials, testing utilities, composables and stores, fake timers, MSW, snapshots, coverage |
| Component tests | Vue Test Utils versus Testing Library, mountSuspended, mocking Nuxt imports, endpoints and components, Suspense, browser mode |
| End-to-end with Playwright | Locators and auto-waiting, @nuxt/test-utils/e2e and the Playwright fixture, auth state, network mocking, hydration checks, visual and accessibility assertions |
| Server and API tests | Testing Nitro routes, databases in tests, contract tests, seeding and isolation |
| Quality gates and CI | Pipeline design, sharding, coverage policy, flake management, budgets, preview environments |
The strategy for one feature, "add to cart", across the levels:
Static: nuxt typecheck + eslint -> the CartItem type, the emitted payloads, floating promises
Unit: cart totals, coupon rules -> pure functions in shared/, dozens of cases in ms
Store: useCartStore add/remove/checkout -> createTestingPinia + registerEndpoint for /api/orders
Component: <CartSummary>, <AddToCartButton> -> mountSuspended, getByRole, emitted events, a11y roles
API: POST /api/orders -> validation 400s, auth 401, happy path against a test DB
E2E (few): browse -> add -> checkout -> Playwright against the built app, one browser, storageState for login
Ops: Lighthouse budget, axe wcag22aa -> in CI on the preview deployment
import { defineConfig } from 'vitest/config'
import { defineVitestProject } from '@nuxt/test-utils/config'
export default defineConfig({
test: {
projects: [
{ test: { name: 'unit', include: ['test/unit/**/*.spec.ts'], environment: 'node' } },
await defineVitestProject({
test: {
name: 'nuxt',
include: ['test/nuxt/**/*.spec.ts'],
environment: 'nuxt',
environmentOptions: { nuxt: { domEnvironment: 'happy-dom', mock: { intersectionObserver: true } } },
},
}),
],
coverage: { provider: 'v8', include: ['app/**', 'shared/**', 'server/**'], thresholds: { statements: 70 } },
},
})
A 95% coverage target produces tests that execute lines without asserting anything meaningful, and it penalises deleting code. Coverage is a map of what is untested, useful for spotting a critical module with nothing around it; the target is confidence in the flows that matter.
npx vitest --project unit and --project nuxt separately; time both."By confidence per cost. Static analysis first, because nuxt typecheck and type-aware lint catch a whole class of bugs on every commit. Pure logic, pricing rules, formatters, validators, gets fast unit tests in Node. Most of the budget goes to component and integration tests in the Nuxt Vitest environment with mountSuspended: they interact through roles and labels, assert on rendered output and emitted events, and mock only at boundaries, the network through registerEndpoint, stores through createTestingPinia. A few Playwright end-to-end tests cover the critical flows against the built app, with login state reused and hydration warnings failing the test. Accessibility and performance budgets run against the preview deployment. And flaky tests are treated as bugs with owners, not as noise to retry."
Nothing yet. Notes filed here show up on every page of this section.
Supply chain and dependency hygiene
What the 2025 npm attacks changed, OWASP's new supply-chain category, lockfiles and frozen installs, pnpm's release-age delay and blocked install scripts, provenance and trusted publishing, update automation with cooldowns, CI with least privilege, SBOMs, and how to keep Nuxt and its ecosystem patched.
Unit tests with Vitest
Vitest 5 essentials — projects, matchers, spies and mocks, fake timers, snapshots, type tests, coverage — and how to unit-test the parts of a Nuxt app that need no DOM — utilities, composables, Pinia stores, Leitner scheduling — with MSW for network boundaries.