diff --git a/src/hooks/useNoticeTimer.ts b/src/hooks/useNoticeTimer.ts index dafc03ea..d055f6f0 100644 --- a/src/hooks/useNoticeTimer.ts +++ b/src/hooks/useNoticeTimer.ts @@ -32,6 +32,7 @@ export default function useNoticeTimer( const onPause = React.useCallback(() => { syncPassTime(); + lastRafTimeRef.current = null; setWalking(false); }, []); diff --git a/tests/useNoticeTimer.test.tsx b/tests/useNoticeTimer.test.tsx new file mode 100644 index 00000000..ff499a2f --- /dev/null +++ b/tests/useNoticeTimer.test.tsx @@ -0,0 +1,43 @@ +import { act, renderHook } from '@testing-library/react'; +import useNoticeTimer from '../src/hooks/useNoticeTimer'; + +describe('useNoticeTimer', () => { + beforeEach(() => { + vi.useFakeTimers(); + }); + + afterEach(() => { + vi.useRealTimers(); + }); + + it('preserves the remaining duration when paused repeatedly', () => { + const onClose = vi.fn(); + const onUpdate = vi.fn(); + const { result, unmount } = renderHook(() => useNoticeTimer(1, onClose, onUpdate)); + + act(() => vi.advanceTimersByTime(200)); + act(() => result.current[1]()); + const updateCount = onUpdate.mock.calls.length; + + for (let i = 0; i < 3; i += 1) { + act(() => vi.advanceTimersByTime(2000)); + act(() => result.current[1]()); + } + + expect(onUpdate).toHaveBeenCalledTimes(updateCount); + expect(onClose).not.toHaveBeenCalled(); + + act(() => result.current[0]()); + expect(onUpdate).toHaveBeenLastCalledWith(0.2); + expect(onClose).not.toHaveBeenCalled(); + + act(() => vi.advanceTimersByTime(700)); + expect(onClose).not.toHaveBeenCalled(); + + act(() => vi.advanceTimersByTime(200)); + expect(onUpdate).toHaveBeenLastCalledWith(1); + expect(onClose).toHaveBeenCalledTimes(1); + + unmount(); + }); +});