import React from 'react';
import { render, fireEvent } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import { PlaybackControls } from '../PlaybackControls';
// Mocking styled-components
jest.mock('../styles', () => ({
Row: ({ children }: any) =>
{children}
,
Controls: ({ children }: any) => {children}
,
ControlButton: ({ children, ...props }: any) => (
),
PlaybackButtonsContainer: ({ children }: any) => (
{children}
),
SpeedButton: ({ children, ...props }: any) => (
),
SpeedSelectModal: ({ children }: any) => (
{children}
),
SpeedOptionItem: ({ children, ...props }: any) => (
{children}
),
CloseButton: ({ children, ...props }: any) => (
),
SpeedOptionsContainer: ({ children }: any) => (
{children}
),
PlayPauseButton: ({ children, ...props }: any) => (
)
}));
// Mocking icons
jest.mock('@times-components/icons', () => ({
PlayIcon: () => ,
PauseIcon: () => ,
IconCheck: () => ,
PlayerBack: () => ,
PlayerFront: () =>
}));
describe('PlaybackControls', () => {
const mockTogglePlayPause = jest.fn();
const mockRewind = jest.fn();
const mockForward = jest.fn();
const mockOnSpeedChange = jest.fn();
const mockSetIsSpeedModalOpen = jest.fn();
afterEach(() => {
jest.clearAllMocks();
});
const renderComponent = (props = {}) =>
render(
);
test('renders correctly with all controls enabled and not playing', () => {
const { getByTestId, getByLabelText, queryByTestId } = renderComponent();
expect(getByTestId('row')).toBeInTheDocument();
expect(getByTestId('controls')).toBeInTheDocument();
expect(getByTestId('playback-buttons-container')).toBeInTheDocument();
// Using aria-label to query specific buttons
expect(getByLabelText('Rewind 10 seconds')).toBeInTheDocument();
expect(getByLabelText('Play')).toBeInTheDocument();
expect(getByLabelText('Forward 10 seconds')).toBeInTheDocument();
expect(getByTestId('play-icon')).toBeInTheDocument();
expect(getByTestId('speed-button')).toBeInTheDocument();
expect(queryByTestId('speed-select-modal')).not.toBeInTheDocument();
});
test('renders PlayIcon when not playing and PauseIcon when playing', () => {
const { getByTestId, rerender, queryByTestId } = renderComponent({
isPlaying: false
});
expect(getByTestId('play-icon')).toBeInTheDocument();
expect(queryByTestId('pause-icon')).not.toBeInTheDocument();
rerender(
);
expect(getByTestId('pause-icon')).toBeInTheDocument();
expect(queryByTestId('play-icon')).not.toBeInTheDocument();
});
test('calls togglePlayPause when Play/Pause button is clicked', () => {
const { getByLabelText } = renderComponent();
const playPauseButton = getByLabelText('Play');
fireEvent.click(playPauseButton);
expect(mockTogglePlayPause).toHaveBeenCalledTimes(1);
});
test('calls rewind when Rewind button is clicked', () => {
const { getByLabelText } = renderComponent();
const rewindButton = getByLabelText('Rewind 10 seconds');
fireEvent.click(rewindButton);
expect(mockRewind).toHaveBeenCalledTimes(1);
});
test('calls forward when Forward button is clicked', () => {
const { getByLabelText } = renderComponent();
const forwardButton = getByLabelText('Forward 10 seconds');
fireEvent.click(forwardButton);
expect(mockForward).toHaveBeenCalledTimes(1);
});
test('disables Rewind and Forward buttons when allowSeek is false', () => {
const { getByLabelText } = render(
);
const rewindButton = getByLabelText('Rewind 10 seconds');
const forwardButton = getByLabelText('Forward 10 seconds');
const playPauseButton = getByLabelText('Play');
expect(rewindButton).toBeDisabled();
expect(forwardButton).toBeDisabled();
expect(playPauseButton).not.toBeDisabled();
});
test('disables Play/Pause button when allowTogglePlay is false', () => {
const { getByLabelText } = render(
);
const playPauseButton = getByLabelText('Play');
expect(playPauseButton).toBeDisabled();
});
test('opens speed modal when Speed button is clicked', () => {
const { getByTestId } = renderComponent();
const speedButton = getByTestId('speed-button');
fireEvent.click(speedButton);
expect(mockSetIsSpeedModalOpen).toHaveBeenCalledWith(true);
});
test('does not open speed modal when allowPlaybackRateChange is false', () => {
const { getByTestId } = render(
);
const speedButton = getByTestId('speed-button');
fireEvent.click(speedButton);
expect(mockSetIsSpeedModalOpen).not.toHaveBeenCalled();
});
test('renders speed modal when isSpeedModalOpen is true', () => {
const { getByTestId } = render(
);
expect(getByTestId('speed-select-modal')).toBeInTheDocument();
});
test('calls onSpeedChange and closes modal when a speed option is clicked', () => {
const { getAllByTestId } = render(
);
const speedOptions = getAllByTestId('speed-option-item');
fireEvent.click(speedOptions[2]); // Click on 1.0x
expect(mockOnSpeedChange).toHaveBeenCalledWith(1.0);
expect(mockSetIsSpeedModalOpen).toHaveBeenCalledWith(false);
});
test('closes speed modal when Close button is clicked', () => {
const { getByTestId } = render(
);
const closeButton = getByTestId('close-button');
fireEvent.click(closeButton);
expect(mockSetIsSpeedModalOpen).toHaveBeenCalledWith(false);
});
test('renders correct aria-label based on isPlaying', () => {
const { getByLabelText, rerender } = renderComponent({ isPlaying: false });
const playPauseButton = getByLabelText('Play');
expect(playPauseButton).toHaveAttribute('aria-label', 'Play');
rerender(
);
const pauseButton = getByLabelText('Pause');
expect(pauseButton).toHaveAttribute('aria-label', 'Pause');
});
});