Testing Guardrails (Vitest)
Enforces 7 concrete testing rules for Vitest, covering mocking, timers, filesystem isolation, and teardown hygiene.
What this file does
Enforces 7 concrete testing rules for Vitest, covering mocking, timers, filesystem isolation, and teardown hygiene.
When to use it
- You use Vitest and want to prevent common mocking mistakes
- Your team needs a shared standard for unit vs integration test boundaries
- You have flaky tests due to shared state or unclosed resources
- You want to enforce AAA structure and ban.only/.skip in commits
Assumes this stack
Testing Guardrails (Vitest)
These are enforcement rules that complement testing-principles.md. Follow them for every test.
1) Unit vs Integration boundary
- Unit tests: no network/DB. Filesystem is allowed only when the unit’s contract is filesystem behavior; otherwise mock I/O. Use per-test temp dirs and clean them in
afterEachto avoid cross-test pollution.
2) Mocking & Spying (critical)
- Always spy on the module object, never on a destructured binding.
- ✅
import * as cfg from '../src/ui/config-bridge.js'; vi.spyOn(cfg, 'isLocked')… - ❌
const { isLocked } = await import(...); vi.spyOn({ isLocked }, 'isLocked')(spies a copy; your code under test won’t see it)
- ✅
- Prefer module-level mocks (
vi.mock) or module-object spies (vi.spyOn(moduleObj, 'fn')). Reset/restore inafterEach.
3) Console assertions must match call arity
- If the code calls
console.warn(msg, errorObj), assert both args. Don’t assert a single string when the implementation passes multiple arguments.
4) Time & timers
- Default timeout: 10_000 ms for async units. Use
vi.useFakeTimers()/vi.setSystemTime()for time logic. - No infinite/hanging loops: when testing lock/retry logic, make the mock transition deterministically (e.g., locked → unlocked) so the loop exits.
5) Filesystem tests
- Create a unique temp dir per test, write/read inside it, and remove it in teardown.
- Never depend on real project files or shared paths.
6) Hygiene (enforced)
- AAA structure; one behavior per test; minimal, intentional snapshots; no
.only/.skipin committed code. - Reset mocks/clock/state in
afterEach.
7) Required teardown
afterEach(() => {
vi.restoreAllMocks();
vi.useRealTimers?.();
});
What's inside
7 rule sections, 1 required teardown code block, 2 code examples
Change this for your project
- Replace
'../src/ui/config-bridge.js'with your own module path - Replace
10_000 mswith your project's default async timeout
Where it goes
Load as policy context for the agent, or keep beside the code enforcing the rules.
Related Documents
DeepSeek R1: Case Study in Failed Extrinsic Alignment
Compiles public security research and independent findings to argue that extrinsic alignment methods are insufficient for AI safety, using DeepSeek R1 as a case study.
Guardrails, Safety & Content Filtering
Implements a layered guardrail system with input validation, output validation, and content filtering to protect LLM applications from prompt injection, jailbreaks, and data leaks.
My Hyprland Rice Setup - Context for Claude Code
Documents a Hyprland rice setup with system specs, aesthetic preferences, workflow safety practices, and a list of current issues to solve.
AI Safety & Guardrails for Voice Assistants
Defines a multi-layer safety architecture for voice assistants, covering input filtering, deterministic FAQ routing, RAG-grounded AI responses, and output guardrails.