Player.jsx Component - Comprehensive Architecture Improvement, fix vitest

This commit is contained in:
Xavier Araque 2025-11-07 15:48:08 +01:00
parent e3534fa56b
commit d3c2beabd8
4 changed files with 48 additions and 51 deletions

View File

@ -1,22 +1,21 @@
/* eslint-env jest */
import { renderHook } from '@testing-library/react-hooks' import { renderHook } from '@testing-library/react-hooks'
import { usePlayerState } from './usePlayerState' import { usePlayerState } from './usePlayerState'
import { useDispatch, useSelector } from 'react-redux' import { useDispatch, useSelector } from 'react-redux'
import { describe, it, beforeEach, vi, expect } from 'vitest'
// Mock react-redux // Mock react-redux
jest.mock('react-redux', () => ({ vi.mock('react-redux', () => ({
useDispatch: jest.fn(), useDispatch: vi.fn(),
useSelector: jest.fn(), useSelector: vi.fn(),
})) }))
// Mock actions // Mock actions
jest.mock('../../actions', () => ({ vi.mock('../../actions', () => ({
clearQueue: jest.fn(() => ({ type: 'CLEAR_QUEUE' })), clearQueue: vi.fn(() => ({ type: 'CLEAR_QUEUE' })),
currentPlaying: jest.fn(() => ({ type: 'CURRENT_PLAYING' })), currentPlaying: vi.fn(() => ({ type: 'CURRENT_PLAYING' })),
setPlayMode: jest.fn(() => ({ type: 'SET_PLAY_MODE' })), setPlayMode: vi.fn(() => ({ type: 'SET_PLAY_MODE' })),
setVolume: jest.fn(() => ({ type: 'SET_VOLUME' })), setVolume: vi.fn(() => ({ type: 'SET_VOLUME' })),
syncQueue: jest.fn(() => ({ type: 'SYNC_QUEUE' })), syncQueue: vi.fn(() => ({ type: 'SYNC_QUEUE' })),
})) }))
// Import the mocked actions // Import the mocked actions
@ -30,10 +29,10 @@ describe('usePlayerState', () => {
volume: 0.8, volume: 0.8,
} }
const mockDispatch = jest.fn() const mockDispatch = vi.fn()
beforeEach(() => { beforeEach(() => {
jest.clearAllMocks() vi.clearAllMocks()
useDispatch.mockReturnValue(mockDispatch) useDispatch.mockReturnValue(mockDispatch)
useSelector.mockReturnValue(mockPlayerState) useSelector.mockReturnValue(mockPlayerState)
}) })

View File

@ -1,7 +1,6 @@
/* eslint-env jest */
import { renderHook, act } from '@testing-library/react-hooks' import { renderHook, act } from '@testing-library/react-hooks'
import { usePreloading } from './usePreloading' import { usePreloading } from './usePreloading'
import { describe, it, beforeEach, afterEach, vi, expect } from 'vitest'
describe('usePreloading', () => { describe('usePreloading', () => {
const mockPlayerState = { const mockPlayerState = {
@ -13,11 +12,11 @@ describe('usePreloading', () => {
} }
beforeEach(() => { beforeEach(() => {
jest.clearAllMocks() vi.clearAllMocks()
// Mock Audio constructor // Mock Audio constructor
global.Audio = jest.fn().mockImplementation(() => ({ global.Audio = vi.fn().mockImplementation(() => ({
src: '', src: '',
addEventListener: jest.fn(), addEventListener: vi.fn(),
})) }))
}) })
@ -96,9 +95,9 @@ describe('usePreloading', () => {
}) })
it('should handle Audio constructor errors gracefully', () => { it('should handle Audio constructor errors gracefully', () => {
const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {}) const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
global.Audio = jest.fn().mockImplementation(() => { global.Audio = vi.fn().mockImplementation(() => {
throw new Error('Audio creation failed') throw new Error('Audio creation failed')
}) })
@ -118,18 +117,18 @@ describe('usePreloading', () => {
}) })
it('should handle audio load errors gracefully', () => { it('should handle audio load errors gracefully', () => {
const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {}) const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
const mockAudioInstance = { const mockAudioInstance = {
src: '', src: '',
addEventListener: jest.fn((event, callback) => { addEventListener: vi.fn((event, callback) => {
if (event === 'error') { if (event === 'error') {
callback(new Event('error')) callback(new Event('error'))
} }
}), }),
} }
global.Audio = jest.fn().mockImplementation(() => mockAudioInstance) global.Audio = vi.fn().mockImplementation(() => mockAudioInstance)
const { result } = renderHook(() => usePreloading(mockPlayerState)) const { result } = renderHook(() => usePreloading(mockPlayerState))

View File

@ -1,11 +1,10 @@
/* eslint-env jest */
import { renderHook, act } from '@testing-library/react-hooks' import { renderHook, act } from '@testing-library/react-hooks'
import { useReplayGain } from './useReplayGain' import { useReplayGain } from './useReplayGain'
import { describe, it, beforeEach, afterEach, vi, expect } from 'vitest'
// Mock calculateGain utility // Mock calculateGain utility
jest.mock('../../utils/calculateReplayGain', () => ({ vi.mock('../../utils/calculateReplayGain', () => ({
calculateGain: jest.fn(), calculateGain: vi.fn(),
})) }))
// Import the mocked module // Import the mocked module
@ -15,17 +14,17 @@ describe('useReplayGain', () => {
const mockCalculateGain = calculateReplayGain.calculateGain const mockCalculateGain = calculateReplayGain.calculateGain
beforeEach(() => { beforeEach(() => {
jest.clearAllMocks() vi.clearAllMocks()
// Mock Web Audio API // Mock Web Audio API
global.AudioContext = jest.fn().mockImplementation(() => ({ global.AudioContext = vi.fn().mockImplementation(() => ({
createMediaElementSource: jest.fn(() => ({ createMediaElementSource: vi.fn(() => ({
connect: jest.fn(), connect: vi.fn(),
})), })),
createGain: jest.fn(() => ({ createGain: vi.fn(() => ({
gain: { gain: {
setValueAtTime: jest.fn(), setValueAtTime: vi.fn(),
}, },
connect: jest.fn(), connect: vi.fn(),
})), })),
currentTime: 0, currentTime: 0,
})) }))
@ -83,10 +82,10 @@ describe('useReplayGain', () => {
}) })
it('should handle Web Audio API errors gracefully', () => { it('should handle Web Audio API errors gracefully', () => {
const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {}) const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
// Mock AudioContext to throw error // Mock AudioContext to throw error
global.AudioContext = jest.fn().mockImplementation(() => { global.AudioContext = vi.fn().mockImplementation(() => {
throw new Error('Web Audio API not supported') throw new Error('Web Audio API not supported')
}) })
@ -108,7 +107,7 @@ describe('useReplayGain', () => {
}) })
it('should handle gain application errors gracefully', () => { it('should handle gain application errors gracefully', () => {
const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {}) const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
const mockAudioInstance = { crossOrigin: '' } const mockAudioInstance = { crossOrigin: '' }
const mockPlayerState = { const mockPlayerState = {
@ -119,17 +118,17 @@ describe('useReplayGain', () => {
// Mock gain.setValueAtTime to throw error // Mock gain.setValueAtTime to throw error
const mockGainNode = { const mockGainNode = {
gain: { gain: {
setValueAtTime: jest.fn(() => { setValueAtTime: vi.fn(() => {
throw new Error('Gain application failed') throw new Error('Gain application failed')
}), }),
}, },
} }
global.AudioContext = jest.fn().mockImplementation(() => ({ global.AudioContext = vi.fn().mockImplementation(() => ({
createMediaElementSource: jest.fn(() => ({ createMediaElementSource: vi.fn(() => ({
connect: jest.fn(), connect: vi.fn(),
})), })),
createGain: jest.fn(() => mockGainNode), createGain: vi.fn(() => mockGainNode),
currentTime: 0, currentTime: 0,
})) }))

View File

@ -1,12 +1,12 @@
/* eslint-env jest */
import { renderHook, act } from '@testing-library/react-hooks' import { renderHook, act } from '@testing-library/react-hooks'
import { useScrobbling } from './useScrobbling' import { useScrobbling } from './useScrobbling'
import { describe, it, beforeEach, vi, expect } from 'vitest'
// Mock subsonic module // Mock subsonic module
jest.mock('../../subsonic', () => ({ vi.mock('../../subsonic', () => ({
scrobble: jest.fn(), default: {},
nowPlaying: jest.fn(), scrobble: vi.fn(),
nowPlaying: vi.fn(),
})) }))
// Import the mocked module // Import the mocked module
@ -14,7 +14,7 @@ import * as subsonic from '../../subsonic'
// Mock dataProvider // Mock dataProvider
const mockDataProvider = { const mockDataProvider = {
getOne: jest.fn(), getOne: vi.fn(),
} }
describe('useScrobbling', () => { describe('useScrobbling', () => {
@ -26,10 +26,10 @@ describe('useScrobbling', () => {
current: { uuid: '1', trackId: 'track1' }, current: { uuid: '1', trackId: 'track1' },
} }
const mockDispatch = jest.fn() const mockDispatch = vi.fn()
beforeEach(() => { beforeEach(() => {
jest.clearAllMocks() vi.clearAllMocks()
mockDataProvider.getOne.mockResolvedValue({ data: {} }) mockDataProvider.getOne.mockResolvedValue({ data: {} })
}) })
@ -131,7 +131,7 @@ describe('useScrobbling', () => {
}) })
it('should handle scrobbling errors gracefully', () => { it('should handle scrobbling errors gracefully', () => {
const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {}) const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
// const mockSubsonic = subsonic // const mockSubsonic = subsonic
subsonic.scrobble.mockImplementation(() => { subsonic.scrobble.mockImplementation(() => {
throw new Error('Scrobbling failed') throw new Error('Scrobbling failed')