Prompt
For tests, prefer deterministic, intention-revealing assertions and keep runtime tests and type-only tests strictly separated.
Apply: 1) Use the right matcher for the claim
- Identity: use
toBeinstead of deep equality when referential identity matters. - Async rejections: prefer matcher-based assertions over try/catch.
2) Make timer-based tests fast and stable
- If you must use timers, prefer fake timers and advance/run them deterministically.
- Keep real timer durations extremely short.
3) Don’t mix runtime and type-only tests
- Put compile-time checks into
*.test-d.tsxand useexpectTypeOf(...).toEqualTypeOf(...). - In
*.test-d.tsx, don’t rely on runtime behavior insideitblocks.
4) Ensure the test can prove which code path executed
- When a hook can call different
queryFns (e.g., prefetch vs render), use distinct spies and assert call counts. Clear mocks after setup calls.
Example (async rejection + timers + type-only):
// runtime test
await expect(promise).rejects.toBe(testError)
// timer test (prefer fake timers)
vi.useFakeTimers()
vi.runAllTimersAsync()
expect(spy).toHaveBeenCalledTimes(0)
// type-only test in *.test-d.tsx
expectTypeOf(result4[0]).toEqualTypeOf<UseQueryResult<string, Error>>()
This reduces brittle/flaky tests, improves signal-to-noise, and guarantees type coverage lives where it’s actually executed by the tooling.