"토스트 사라지길 5초 기다리는 테스트는 네가 skip 할 테스트야."
왜 가짜 시간?
setTimeout, setInterval, requestAnimationFrame, 또는 Date.now() / new Date() 읽는 코드는 시간 결합돼 있어. auto-dismiss 토스트가 5,000ms 후 사라지면, 실제 테스트는 5,000ms 기다려. suite 에 timer 인식 테스트 50개 곱하면 CI 가 1분에서 1시간으로 바뀌어.
Fake timer 는 진짜 timer API 를 제어 가능한 버전으로 교체. setTimeout 은 여전히 콜백 queue 에 넣지만 알아서 발동 안 해 — 수동으로 vi.advanceTimersByTime(5000) 으로 시간 진행, 그 윈도우 안에 스케줄된 콜백 다 동기적으로 발동. 5초 걸리던 테스트가 5밀리초에 끝나.
Setup / Teardown 패턴
Fake timer 는 전역 — 한 번 켜면 모든 협력자의 모든 timer 가 끌 때까지 fake clock 써. 깔끔한 패턴은 테스트별 또는 suite 별:
beforeEach(() => vi.useFakeTimers())— 각 테스트 전에 활성화.afterEach(() => vi.useRealTimers())— 각 테스트 후 복원.
Cleanup 잊으면 다음 테스트가 요청 안 한 frozen clock 을 받아 — "왜 이 완전히 무관한 테스트가 멈춰?" 디버깅으로 몇 시간 잡아먹어.
세 advance 메서드
vi.advanceTimersByTime(ms)— 시계 ms 만큼 앞으로, 그 윈도우에 스케줄된 모든 콜백 발동. 가장 흔해.vi.runAllTimers()— 보류 중인 모든 timer 한 번에 실행, setInterval 도 (queue 빌 때까지). 모든 보류 작업 완료시키고 싶을 때 유용.vi.runOnlyPendingTimers()— 현재 queue 된 timer 만 실행, 그 콜백이 스케줄한 새 거 무시. 재귀 setTimeout 루프 빠져나올 때 유용.
await vi.advanceTimersByTimeAsync(5000) (Async 변형) 가 둘 다 처리. 이거 틀리면 timer 는 발동되는데 promise 가 resolve 안 되는 걸 보게 돼.Date 도 가짜로
Date.now() (또는 new Date()) 를 직접 읽는 시간 결합 코드도 fake clock 후보. vi.setSystemTime('2026-01-01') 가 wall clock 을 특정 순간에 고정 — 모든 읽기가 그 순간과 일관된 값 반환. vi.useFakeTimers 와 결합하면 완전히 결정적인 시간 환경 얻어.