NEVER use npx to run tests. ALWAYS use pnpm.
# ❌ WRONG
npx vitest run yjs.integ
# ✅ CORRECT
pnpm vitest run yjs.integ
# Use partial file name - Vitest auto-matches
pnpm vitest run yjs.integ
pnpm vitest run helper.spec
pnpm vitest run Button.spec
# Flaky test detection
pnpm vitest run yjs.integ --repeat=10
src/ prefix or full path needed)--project flag needed (Vitest auto-detects from file extension)turbo run test --filter @growi/app
Whenever you write a test OR review a change that adds/modifies tests, you MUST consult both skills first — they are not optional background reading:
| Skill | Apply it to |
|---|---|
essential-test-design (.claude/skills/essential-test-design/SKILL.md) |
What to assert — test the observable contract, not the mechanism. Catches brittle implementation-spies and assertion-free "it didn't throw" tests. |
essential-test-patterns (.claude/skills/essential-test-patterns/SKILL.md) |
How to build the test — Vitest globals, RTL, Jotai scopes, type-safe mocking, module mocking strategy. |
This applies in every context, including review-time skills (kiro-review,
kiro-validate-impl, kiro-verify-completion): a test diff is not "good" until it
has been checked against essential-test-design (contract) and essential-test-patterns
(mechanics).
as any, as unknown as T, as T)Mocking an interface/class? Use mock<T>() / mock<T>({ ...overrides }) from
vitest-mock-extended (already a dependency). It returns a real T (no cast),
type-checks the overrides against the type, and auto-stubs everything you don't
specify — so it is both type-safe and shorter than a hand-built object.
Every assertion form defeats the type checker in some way and lets the mock drift
out of sync with the real type silently — prefer mock<T>() over all of them:
// ❌ all of these escape type checking — the mock can rot as Crowi changes
const crowi = { searchService: { searchKeyword: vi.fn() } } as unknown as Crowi;
const crowi = { searchService: { searchKeyword: vi.fn() } } as Crowi;
const crowi = { searchService: { searchKeyword: vi.fn() } } as any;
// ✅ type-checked against Crowi, auto-stubs the rest
const crowi = mock<Crowi>({ searchService: { searchKeyword: vi.fn() } });
A type assertion in a test is only acceptable when removing it would cost more than
it saves (no type exists for the target, or one field needs real behavior). For the
full tolerance framework (4 tiers) and the mock<T> patterns, see the Type-Safe
Mocking section of the essential-test-patterns skill.