import { beforeEach, describe, expect, it, vi } from 'vitest'
import { fireEvent, render, screen } from '@testing-library/react'
import type { AudioTrack, VideoQuality } from '../../types'
import { SettingsMenu } from './SettingsMenu'
const { contextState } = vi.hoisted(() => ({
contextState: {
value: null as any,
},
}))
vi.mock('../../contexts/PlayerContext', () => ({
usePlayerContext: () => contextState.value,
}))
const audioTracks: AudioTrack[] = [
{
name: 'English',
language: 'en',
url: '',
groupId: 'audio',
},
]
const qualities: VideoQuality[] = [
{ label: '1080p', height: 1080, levelIndex: 0 },
{ label: '720p', height: 720, levelIndex: 1 },
]
const subtitles = [{ src: '/sub.vtt', lang: 'en', label: 'English' }]
describe('SettingsMenu', () => {
beforeEach(() => {
contextState.value = {
uiState: {
controlsVisible: true,
settingsOpen: true,
volumeControlOpen: false,
qualityMenuOpen: false,
subtitleMenuOpen: false,
},
videoState: {
playing: false,
currentTime: 0,
duration: 0,
buffered: 0,
volume: 1,
muted: false,
playbackRate: 1,
fullscreen: false,
pictureInPicture: false,
loading: false,
error: null,
seeking: false,
isLiveBroadcast: false,
},
settings: {
quality: null,
subtitle: null,
subtitleStyle: {},
audioTrack: null,
playbackRate: 1,
},
setPlaybackRate: vi.fn(),
setSubtitle: vi.fn(),
setSubtitleStyle: vi.fn(),
saveSubtitleStyle: vi.fn(),
revertSubtitleStyle: vi.fn(),
setAudioTrack: vi.fn(),
setQuality: vi.fn(),
toggleSettings: vi.fn(),
subtitleStyleEditorEnabled: true,
translations: {
noSubtitlesAvailable: 'No subtitles available',
subtitles: 'Subtitles',
subtitleStyle: 'Subtitle Style',
preview: 'Preview',
save: 'Save',
cancel: 'Cancel',
reset: 'Reset',
off: 'Off',
auto: 'Auto',
quality: 'Quality',
speed: 'Speed',
fontSize: 'Font Size',
fontWeight: 'Font Weight',
textColor: 'Text Color',
backgroundColor: 'Background Color',
backgroundOpacity: 'Background Opacity',
normal: 'Normal',
default: 'Default',
audioTrack: 'Audio Track',
settings: 'Settings',
level: 'Level',
play: 'Play',
pause: 'Pause',
mute: 'Mute',
unmute: 'Unmute',
enterFullscreen: 'Enter fullscreen',
exitFullscreen: 'Exit fullscreen',
enterPictureInPicture: 'Enter picture-in-picture',
exitPictureInPicture: 'Exit picture-in-picture',
videoProgress: 'Video progress',
volume: 'Volume',
live: 'LIVE',
},
}
})
it('does not render when settings are closed', () => {
contextState.value.uiState.settingsOpen = false
render()
expect(screen.queryByText('Settings')).not.toBeInTheDocument()
})
it('changes playback speed from speed submenu', () => {
render()
fireEvent.click(screen.getByText('Speed'))
fireEvent.click(screen.getByText('1.5x'))
expect(contextState.value.setPlaybackRate).toHaveBeenCalledWith(1.5)
})
it('selects subtitle from submenu', () => {
render()
fireEvent.click(screen.getByText('Subtitles'))
fireEvent.click(screen.getByRole('button', { name: 'English' }))
expect(contextState.value.setSubtitle).toHaveBeenCalledWith(subtitles[0])
})
it('selects audio track from submenu', () => {
render()
fireEvent.click(screen.getByText('Audio Track'))
fireEvent.click(screen.getByRole('button', { name: 'English' }))
expect(contextState.value.setAudioTrack).toHaveBeenCalledWith(audioTracks[0])
})
it('selects quality from submenu', () => {
render()
fireEvent.click(screen.getByText('Quality'))
fireEvent.click(screen.getByText('720p'))
expect(contextState.value.setQuality).toHaveBeenCalledWith(qualities[1])
})
it('saves subtitle style from subtitle style editor', () => {
render()
fireEvent.click(screen.getByText('Subtitles'))
fireEvent.click(screen.getByRole('button', { name: /Subtitle Style/i }))
fireEvent.change(screen.getByLabelText('Font Size'), { target: { value: '30' } })
fireEvent.click(screen.getByRole('button', { name: 'Save' }))
expect(contextState.value.saveSubtitleStyle).toHaveBeenCalledWith(
expect.objectContaining({
fontSize: 30,
})
)
})
})