import { describe, it, expect } from 'vitest'
import { playerReducer } from './playerReducer'
import {
PLAYER_SYNC_QUEUE,
PLAYER_CURRENT,
PLAYER_REFRESH_QUEUE,
} from '../actions'
describe('playerReducer', () => {
describe('pending track selection survives SYNC_QUEUE and premature CURRENT', () => {
const stateAfterPlayTracks = {
queue: [
{ trackId: 's1', uuid: 'aaa', name: 'Song 1' },
{ trackId: 's2', uuid: 'bbb', name: 'Song 2' },
{ trackId: 's3', uuid: 'ccc', name: 'Song 3' },
],
current: { uuid: 'ccc', name: 'Song 3' },
playIndex: 0,
savedPlayIndex: 2,
clear: true,
volume: 1,
}
it('SYNC_QUEUE preserves pending playIndex and clear', () => {
const newQueue = [
{ trackId: 's1', uuid: 'xxx', name: 'Song 1' },
{ trackId: 's2', uuid: 'yyy', name: 'Song 2' },
{ trackId: 's3', uuid: 'zzz', name: 'Song 3' },
]
const action = {
type: PLAYER_SYNC_QUEUE,
data: { audioInfo: {}, audioLists: newQueue },
}
const result = playerReducer(stateAfterPlayTracks, action)
expect(result.playIndex).toBe(0)
expect(result.clear).toBe(true)
expect(result.queue).toBe(newQueue)
})
it('SYNC_QUEUE clears playIndex when no pending selection', () => {
const stateNoPending = { ...stateAfterPlayTracks, playIndex: undefined }
const action = {
type: PLAYER_SYNC_QUEUE,
data: { audioInfo: {}, audioLists: stateNoPending.queue },
}
const result = playerReducer(stateNoPending, action)
expect(result.playIndex).toBeUndefined()
expect(result.clear).toBe(false)
})
it('CURRENT for old track preserves pending playIndex', () => {
const stateAfterSync = {
...stateAfterPlayTracks,
queue: [
{ trackId: 's1', uuid: 'xxx', name: 'Song 1' },
{ trackId: 's2', uuid: 'yyy', name: 'Song 2' },
{ trackId: 's3', uuid: 'zzz', name: 'Song 3' },
],
}
const action = {
type: PLAYER_CURRENT,
data: { uuid: 'zzz', name: 'Song 3', volume: 1 },
}
const result = playerReducer(stateAfterSync, action)
expect(result.playIndex).toBe(0)
expect(result.clear).toBe(true)
expect(result.savedPlayIndex).toBe(2)
})
it('CURRENT for correct track consumes pending playIndex', () => {
const stateAfterSync = {
...stateAfterPlayTracks,
queue: [
{ trackId: 's1', uuid: 'xxx', name: 'Song 1' },
{ trackId: 's2', uuid: 'yyy', name: 'Song 2' },
{ trackId: 's3', uuid: 'zzz', name: 'Song 3' },
],
}
const action = {
type: PLAYER_CURRENT,
data: { uuid: 'xxx', name: 'Song 1', volume: 1 },
}
const result = playerReducer(stateAfterSync, action)
expect(result.playIndex).toBeUndefined()
expect(result.clear).toBe(false)
expect(result.savedPlayIndex).toBe(0)
expect(result.current.name).toBe('Song 1')
})
})
describe('play new album after closing player (issue #5440)', () => {
it('SYNC_QUEUE preserves pending playIndex=0 after clearQueue', () => {
const stateAfterClearThenPlay = {
queue: [
{ trackId: 'b1', uuid: 'u1', name: 'B Song 1' },
{ trackId: 'b2', uuid: 'u2', name: 'B Song 2' },
{ trackId: 'b3', uuid: 'u3', name: 'B Song 3' },
],
current: {},
playIndex: 0,
savedPlayIndex: 0,
clear: true,
volume: 1,
}
const action = {
type: PLAYER_SYNC_QUEUE,
data: {
audioInfo: {},
audioLists: stateAfterClearThenPlay.queue,
},
}
const result = playerReducer(stateAfterClearThenPlay, action)
expect(result.playIndex).toBe(0)
expect(result.clear).toBe(true)
})
it('CURRENT for wrong track preserves pending playIndex=0 after clearQueue', () => {
const stateAfterClearThenPlay = {
queue: [
{ trackId: 'b1', uuid: 'u1', name: 'B Song 1' },
{ trackId: 'b2', uuid: 'u2', name: 'B Song 2' },
{ trackId: 'b3', uuid: 'u3', name: 'B Song 3' },
{ trackId: 'b4', uuid: 'u4', name: 'B Song 4' },
],
current: {},
playIndex: 0,
savedPlayIndex: 0,
clear: true,
volume: 1,
}
const action = {
type: PLAYER_CURRENT,
data: { uuid: 'u4', name: 'B Song 4', volume: 1 },
}
const result = playerReducer(stateAfterClearThenPlay, action)
expect(result.playIndex).toBe(0)
expect(result.clear).toBe(true)
})
it('CURRENT for correct track consumes pending playIndex=0', () => {
const stateAfterClearThenPlay = {
queue: [
{ trackId: 'b1', uuid: 'u1', name: 'B Song 1' },
{ trackId: 'b2', uuid: 'u2', name: 'B Song 2' },
],
current: {},
playIndex: 0,
savedPlayIndex: 0,
clear: true,
volume: 1,
}
const action = {
type: PLAYER_CURRENT,
data: { uuid: 'u1', name: 'B Song 1', volume: 1 },
}
const result = playerReducer(stateAfterClearThenPlay, action)
expect(result.playIndex).toBeUndefined()
expect(result.clear).toBe(false)
expect(result.savedPlayIndex).toBe(0)
})
})
describe('PLAYER_REFRESH_QUEUE', () => {
it('clamps negative savedPlayIndex to 0', () => {
const state = {
queue: [
{ trackId: 'song-1', musicSrc: 'old-url', uuid: 'a' },
{ trackId: 'song-2', musicSrc: 'old-url', uuid: 'b' },
],
savedPlayIndex: -1,
current: {},
clear: false,
volume: 1,
}
const action = { type: PLAYER_REFRESH_QUEUE, data: {} }
const result = playerReducer(state, action)
expect(result.playIndex).toBe(0)
})
it('preserves valid savedPlayIndex', () => {
const state = {
queue: [
{ trackId: 'song-1', musicSrc: 'old-url', uuid: 'a' },
{ trackId: 'song-2', musicSrc: 'old-url', uuid: 'b' },
],
savedPlayIndex: 1,
current: {},
clear: false,
volume: 1,
}
const action = { type: PLAYER_REFRESH_QUEUE, data: {} }
const result = playerReducer(state, action)
expect(result.playIndex).toBe(1)
})
it('uses savedPlayIndex of 0 correctly', () => {
const state = {
queue: [{ trackId: 'song-1', musicSrc: 'old-url', uuid: 'a' }],
savedPlayIndex: 0,
current: {},
clear: false,
volume: 1,
}
const action = { type: PLAYER_REFRESH_QUEUE, data: {} }
const result = playerReducer(state, action)
expect(result.playIndex).toBe(0)
})
})
})