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');
});
});