Vitest Testing
Test File Placement
| Source location |
Test location |
app/composables/<name>.ts |
tests/app/composables/<name>.test.ts |
app/components/<Name>.vue |
app/components/__tests__/<Name>.test.ts (DOM tests) OR tests/app/components/<Name>.test.ts (logic-only) |
app/utils/<name>.ts |
tests/app/utils/<name>.test.ts |
services/<name>.ts |
tests/services/<name>.test.ts |
utils/<name>.ts |
tests/utils/<name>.test.ts |
terraform/lambda/src/<Name>/index.ts |
terraform/lambda/src/<Name>/__tests__/index.test.ts |
Use __tests__/ co-location only for component DOM tests and Lambda handlers. Everything else goes in the top-level tests/ mirror tree.
Environment Selection
- Default:
node (composables, services, utils, Lambda handlers)
- DOM tests only: Add
/** @vitest-environment happy-dom */ as the first line of the test file
- Never change
vitest.config.ts environment globally
Test Writing Rules
- Imports — always explicit:
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
- Nuxt auto-imports — call
mockNuxtImports() from tests/helpers in beforeEach for any code using useRuntimeConfig, useState, computed, ref, watch, onMounted, onUnmounted, navigateTo
- Naming — always
*.test.ts, never *.spec.ts
- Timers — use
vi.useFakeTimers() in beforeEach and vi.useRealTimers() in afterEach for async/timer tests
- Console noise — suppress with
vi.spyOn(console, 'log').mockImplementation(() => {}) in beforeEach
- Logic extraction — prefer testing extracted logic over DOM rendering; test behavior, not templates
- Component DOM tests — use
@vue/test-utils mount() with stubbed Nuxt UI components
- AWS service mocks — use
mockSend + vi.mock('@aws-sdk/...') pattern (see references/testing-patterns.md)
What to Test (per code type)
- Composables: return values, state mutations, reactive updates, edge cases
- Components: props, emits, slot rendering, conditional rendering (via logic extraction where possible)
- Services: success path, error handling (custom error classes), edge cases (empty input, missing fields)
- Utils: pure function I/O, boundary conditions
- Lambda handlers: each resolver action, valid/invalid input, DynamoDB mock responses, error paths
Running Tests
bun run test # Single run
bun run test:watch # Watch mode
bun run test:coverage # With v8 coverage report
Coverage
Coverage uses @vitest/coverage-v8. Config is in vitest.config.ts. Thresholds: lines 80%, functions 80%, branches 70%, statements 80%.
Reference
Read references/testing-patterns.md for detailed mock patterns, full templates, and real codebase examples.
1---2name: vitest-testing3description: Write and run Vitest unit tests for this Nuxt 4 project. Auto-triggers when creating or modifying composables, components, services, utils, or Lambda handlers. Use this skill whenever writing tests, adding test coverage, testing new features, fixing bugs (write regression test first), or when the user mentions testing, unit tests, vitest, TDD, coverage, or test coverage. Also use when creating any new file in app/composables/, app/components/, app/utils/, services/, or terraform/lambda/src/.4---56# Vitest Testing78## Test File Placement910| Source location | Test location |11|---|---|12| `app/composables/<name>.ts` | `tests/app/composables/<name>.test.ts` |13| `app/components/<Name>.vue` | `app/components/__tests__/<Name>.test.ts` (DOM tests) OR `tests/app/components/<Name>.test.ts` (logic-only) |14| `app/utils/<name>.ts` | `tests/app/utils/<name>.test.ts` |15| `services/<name>.ts` | `tests/services/<name>.test.ts` |16| `utils/<name>.ts` | `tests/utils/<name>.test.ts` |17| `terraform/lambda/src/<Name>/index.ts` | `terraform/lambda/src/<Name>/__tests__/index.test.ts` |1819Use `__tests__/` co-location only for component DOM tests and Lambda handlers. Everything else goes in the top-level `tests/` mirror tree.2021## Environment Selection2223- **Default:** `node` (composables, services, utils, Lambda handlers)24- **DOM tests only:** Add `/** @vitest-environment happy-dom */` as the first line of the test file25- Never change `vitest.config.ts` environment globally2627## Test Writing Rules28291. **Imports** — always explicit: `import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'`302. **Nuxt auto-imports** — call `mockNuxtImports()` from `tests/helpers` in `beforeEach` for any code using `useRuntimeConfig`, `useState`, `computed`, `ref`, `watch`, `onMounted`, `onUnmounted`, `navigateTo`313. **Naming** — always `*.test.ts`, never `*.spec.ts`324. **Timers** — use `vi.useFakeTimers()` in `beforeEach` and `vi.useRealTimers()` in `afterEach` for async/timer tests335. **Console noise** — suppress with `vi.spyOn(console, 'log').mockImplementation(() => {})` in `beforeEach`346. **Logic extraction** — prefer testing extracted logic over DOM rendering; test behavior, not templates357. **Component DOM tests** — use `@vue/test-utils` `mount()` with stubbed Nuxt UI components368. **AWS service mocks** — use `mockSend` + `vi.mock('@aws-sdk/...')` pattern (see `references/testing-patterns.md`)3738## What to Test (per code type)3940- **Composables:** return values, state mutations, reactive updates, edge cases41- **Components:** props, emits, slot rendering, conditional rendering (via logic extraction where possible)42- **Services:** success path, error handling (custom error classes), edge cases (empty input, missing fields)43- **Utils:** pure function I/O, boundary conditions44- **Lambda handlers:** each resolver action, valid/invalid input, DynamoDB mock responses, error paths4546## Running Tests4748```bash49bun run test # Single run50bun run test:watch # Watch mode51bun run test:coverage # With v8 coverage report52```5354## Coverage5556Coverage uses `@vitest/coverage-v8`. Config is in `vitest.config.ts`. Thresholds: lines 80%, functions 80%, branches 70%, statements 80%.5758## Reference5960Read `references/testing-patterns.md` for detailed mock patterns, full templates, and real codebase examples.