import { render, screen, fireEvent, act } from '@testing-library/react'; import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import React from 'react'; import { MapTimeline } from './map-timeline'; describe('MapTimeline', () => { beforeEach(() => { vi.useFakeTimers(); // jsdom has no matchMedia; the component must cope. window.matchMedia = vi.fn().mockImplementation((query: string) => ({ matches: false, media: query, addEventListener: vi.fn(), removeEventListener: vi.fn(), })) as unknown as typeof window.matchMedia; }); afterEach(() => { vi.useRealTimers(); }); it('formats the current value for the reader', () => { render( {}} formatValue={v => `${Math.floor(v / 60)}:${String(v % 60).padStart(2, '0')}`} /> ); expect(screen.getByText('17:32')).toBeInTheDocument(); }); it('offers the playback speeds', () => { render( {}} speeds={[1, 2, 4]} />); expect(screen.getByRole('button', { name: '1×' })).toHaveAttribute('aria-pressed', 'true'); expect(screen.getByRole('button', { name: '4×' })).toHaveAttribute('aria-pressed', 'false'); }); it('advances while playing', () => { const onChange = vi.fn(); render( ); act(() => { vi.advanceTimersByTime(100); }); expect(onChange).toHaveBeenCalledWith(5); }); it('multiplies the step by the chosen speed', () => { const onChange = vi.fn(); render( ); act(() => { vi.advanceTimersByTime(100); }); expect(onChange).toHaveBeenCalledWith(20); }); it('stops itself at the end of the range', () => { const onChange = vi.fn(); const onPlayingChange = vi.fn(); render( ); act(() => { vi.advanceTimersByTime(100); }); expect(onChange).toHaveBeenCalledWith(10); expect(onPlayingChange).toHaveBeenCalledWith(false); }); it('does not advance while paused', () => { const onChange = vi.fn(); render(); act(() => { vi.advanceTimersByTime(500); }); expect(onChange).not.toHaveBeenCalled(); }); it('offers a restart once the end is reached', () => { const onChange = vi.fn(); const onPlayingChange = vi.fn(); render( ); fireEvent.click(screen.getByRole('button', { name: 'Restart' })); expect(onChange).toHaveBeenCalledWith(0); expect(onPlayingChange).toHaveBeenCalledWith(true); }); it('announces that auto-advance is off under reduced motion', () => { window.matchMedia = vi.fn().mockImplementation((query: string) => ({ matches: query.includes('reduced-motion'), media: query, addEventListener: vi.fn(), removeEventListener: vi.fn(), })) as unknown as typeof window.matchMedia; render( {}} />); expect(screen.getByText(/reduced motion/i)).toBeInTheDocument(); }); });