import { describe, it, expect, vi } from 'vitest'; import { render, waitFor } from '@testing-library/react'; import { VideoPlayer } from './VideoPlayer'; describe('VideoPlayer', () => { const defaultProps = { src: 'https://example.com/video.mp4', }; it('renders video player container', () => { const { container } = render(); expect(container.querySelector('.video-player')).toBeInTheDocument(); }); it('renders video element', () => { const { container } = render(); const video = container.querySelector('video'); expect(video).toBeInTheDocument(); }); it('renders with autoplay prop', () => { const { container } = render(); const video = container.querySelector('video'); // VideoElement handles autoplay programmatically via play() method expect(video).toBeInTheDocument(); }); it('renders with muted prop', () => { const { container } = render(); const video = container.querySelector('video'); // Muted state is managed through VideoElement expect(video).toBeInTheDocument(); }); it('applies loop when enabled', () => { const { container } = render(); const video = container.querySelector('video'); expect(video).toHaveAttribute('loop'); }); it('applies custom className', () => { const className = 'custom-player'; const { container } = render(); expect(container.querySelector('.video-player')).toHaveClass('video-player', className); }); it('calls onPlay callback when play event fires', async () => { const onPlay = vi.fn(); const { container } = render(); const video = container.querySelector('video') as HTMLVideoElement; video.dispatchEvent(new Event('play')); await waitFor(() => { expect(onPlay).toHaveBeenCalled(); }); }); it('calls onPause callback when pause event fires', async () => { const onPause = vi.fn(); const { container } = render(); const video = container.querySelector('video') as HTMLVideoElement; video.dispatchEvent(new Event('pause')); await waitFor(() => { expect(onPause).toHaveBeenCalled(); }); }); it('calls onEnded callback when ended event fires', async () => { const onEnded = vi.fn(); const { container } = render(); const video = container.querySelector('video') as HTMLVideoElement; video.dispatchEvent(new Event('ended')); await waitFor(() => { expect(onEnded).toHaveBeenCalled(); }); }); it('calls onTimeUpdate callback with current time', async () => { const onTimeUpdate = vi.fn(); const { container } = render(); const video = container.querySelector('video') as HTMLVideoElement; Object.defineProperty(video, 'currentTime', { value: 10.5, configurable: true }); video.dispatchEvent(new Event('timeupdate')); await waitFor(() => { expect(onTimeUpdate).toHaveBeenCalledWith(10.5); }); }); it('renders with subtitles prop', () => { const subtitles = [ { src: 'subtitles-en.vtt', srcLang: 'en', label: 'English' }, { src: 'subtitles-tr.vtt', srcLang: 'tr', label: 'Türkçe' }, ]; const { container } = render(); const video = container.querySelector('video') as HTMLVideoElement; // Subtitles are added dynamically by VideoElement expect(video).toBeInTheDocument(); }); it('renders without errors', () => { const onError = vi.fn(); const { container } = render(); const video = container.querySelector('video') as HTMLVideoElement; expect(video).toBeInTheDocument(); // Error handling is tested separately in integration tests }); it('hides controls when controls prop is false', () => { const { container } = render(); const controls = container.querySelector('.controls'); expect(controls).not.toBeInTheDocument(); }); it('applies custom style', () => { const style = { width: '800px', height: '450px' }; const { container } = render(); const playerElement = container.querySelector('.video-player') as HTMLElement; expect(playerElement.style.width).toBe('800px'); expect(playerElement.style.height).toBe('450px'); }); });