import React from 'react';
import { render, fireEvent, act, waitFor } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import { AudioPlayer } from '../AudioPlayer';
jest.mock('../CollapseIcon', () => ({
CollapseIcon: ({ isExpanded, toggleExpand }: any) => (
)
}));
jest.mock('../TitleScroller', () => ({
TitleScroller: ({ title }: any) => (
{title}
)
}));
jest.mock('../SeekBar', () => ({
SeekBar: ({ onSeek }: any) => (
)
}));
jest.mock('../TimeDisplay', () => ({
TimeDisplay: ({ currentTime, duration }: any) => (
{currentTime} / {duration}
)
}));
jest.mock('../PlaybackControls', () => ({
PlaybackControls: ({ isPlaying, togglePlayPause, rewind, forward }: any) => (
)
}));
jest.mock('../TabletDesktopPlayer', () => ({
TabletDesktopPlayer: ({ handleVolumeChange }: any) => (
)
}));
jest.mock('../styles', () => ({
AudioPlayerContainer: ({ children }: any) => (
{children}
)
}));
describe('AudioPlayer', () => {
let originalInnerWidth: number;
let playMock: jest.Mock;
let pauseMock: jest.Mock;
let mockPaused: boolean;
let mockDuration: number;
beforeAll(() => {
originalInnerWidth = window.innerWidth;
});
beforeEach(() => {
playMock = jest.fn().mockImplementation(() => {
mockPaused = false;
return Promise.resolve();
});
pauseMock = jest.fn().mockImplementation(() => {
mockPaused = true;
});
mockPaused = true; // Initially paused
mockDuration = 100; // Set a positive duration
jest
.spyOn(window.HTMLMediaElement.prototype, 'play')
.mockImplementation(playMock);
jest
.spyOn(window.HTMLMediaElement.prototype, 'pause')
.mockImplementation(pauseMock);
jest
.spyOn(window.HTMLMediaElement.prototype, 'paused', 'get')
.mockImplementation(() => mockPaused);
jest
.spyOn(window.HTMLMediaElement.prototype, 'duration', 'get')
.mockImplementation(() => mockDuration);
});
afterEach(() => {
jest.clearAllMocks();
});
afterAll(() => {
// Restore the original innerWidth
Object.defineProperty(window, 'innerWidth', {
writable: true,
configurable: true,
value: originalInnerWidth
});
jest.restoreAllMocks();
});
const setWindowInnerWidth = (width: number) => {
Object.defineProperty(window, 'innerWidth', {
writable: true,
configurable: true,
value: width
});
// Dispatch a resize event to notify listeners
window.dispatchEvent(new Event('resize'));
};
const renderComponent = (props = {}) =>
render();
test('renders correctly on mobile', () => {
setWindowInnerWidth(500);
const { getByTestId, queryByTestId } = renderComponent();
expect(getByTestId('audio-player-container')).toBeInTheDocument();
expect(getByTestId('collapse-icon')).toBeInTheDocument();
expect(getByTestId('title-scroller')).toHaveTextContent('Audio Title');
expect(getByTestId('seek-bar')).toBeInTheDocument();
expect(getByTestId('playback-controls')).toBeInTheDocument();
expect(queryByTestId('tablet-desktop-player')).not.toBeInTheDocument();
});
test('renders correctly on desktop', () => {
setWindowInnerWidth(1024);
const { getByTestId, queryByTestId } = renderComponent();
expect(getByTestId('tablet-desktop-player')).toBeInTheDocument();
expect(queryByTestId('audio-player-container')).not.toBeInTheDocument();
});
test('play and pause functionality', async () => {
setWindowInnerWidth(500);
const onPlay = jest.fn();
const onPause = jest.fn();
const { getByText } = renderComponent({ onPlay, onPause });
const playButton = getByText('Play');
await act(async () => {
fireEvent.click(playButton);
});
expect(playMock).toHaveBeenCalled();
await waitFor(() => expect(onPlay).toHaveBeenCalled());
expect(getByText('Pause')).toBeInTheDocument();
const pauseButton = getByText('Pause');
await act(async () => {
fireEvent.click(pauseButton);
});
expect(pauseMock).toHaveBeenCalled();
await waitFor(() => expect(onPause).toHaveBeenCalled());
expect(getByText('Play')).toBeInTheDocument();
});
test('volume change', () => {
setWindowInnerWidth(1024);
const onVolumeChange = jest.fn();
const { getByText } = renderComponent({ onVolumeChange });
const volumeButton = getByText('Set Volume to 0.5');
fireEvent.click(volumeButton);
expect(onVolumeChange).toHaveBeenCalledWith(0.5);
});
test('expand and collapse', () => {
setWindowInnerWidth(500);
const { getByTestId, queryByTestId } = renderComponent();
const collapseButton = getByTestId('collapse-icon');
expect(getByTestId('title-scroller')).toBeInTheDocument();
fireEvent.click(collapseButton);
expect(queryByTestId('title-scroller')).not.toBeInTheDocument();
fireEvent.click(collapseButton);
expect(getByTestId('title-scroller')).toBeInTheDocument();
});
test('handles isPlayingProp changes', async () => {
setWindowInnerWidth(500);
const { rerender, getByText } = render(
);
expect(getByText('Play')).toBeInTheDocument();
// Change isPlayingProp to true
await act(async () => {
rerender();
});
expect(playMock).toHaveBeenCalled();
expect(getByText('Pause')).toBeInTheDocument();
// Change isPlayingProp to false
await act(async () => {
rerender();
});
expect(pauseMock).toHaveBeenCalled();
expect(getByText('Play')).toBeInTheDocument();
});
test('handles isExpandedProp changes', () => {
setWindowInnerWidth(500);
const { rerender, getByTestId, queryByTestId } = render(
);
expect(queryByTestId('title-scroller')).not.toBeInTheDocument();
rerender();
expect(getByTestId('title-scroller')).toBeInTheDocument();
});
test('handles onTimeUpdate', () => {
setWindowInnerWidth(500);
const onTimeUpdate = jest.fn();
const { container } = renderComponent({ onTimeUpdate });
const audio = container.querySelector('audio') as HTMLAudioElement;
act(() => {
fireEvent.timeUpdate(audio);
});
expect(onTimeUpdate).toHaveBeenCalled();
});
test('handles onEnded', () => {
setWindowInnerWidth(500);
const onEnded = jest.fn();
const { container } = renderComponent({ onEnded });
const audio = container.querySelector('audio') as HTMLAudioElement;
act(() => {
fireEvent.ended(audio);
});
expect(onEnded).toHaveBeenCalled();
});
test('handles window resize', () => {
setWindowInnerWidth(500);
const { getByTestId, queryByTestId } = renderComponent();
expect(getByTestId('audio-player-container')).toBeInTheDocument();
expect(queryByTestId('tablet-desktop-player')).not.toBeInTheDocument();
setWindowInnerWidth(1024);
expect(queryByTestId('audio-player-container')).not.toBeInTheDocument();
expect(getByTestId('tablet-desktop-player')).toBeInTheDocument();
});
});