mirror of
https://github.com/navidrome/navidrome.git
synced 2026-08-01 07:21:17 +00:00
test(frontend): strengthen useToggleLove assertions and add safety cases
- Tighten 'uses mediaFileId when present' to also assert the original-resource refresh (getOne called twice with both ids) - Add success-path assertion that notify is not called when toggle succeeds - Add error-path assertion that notify is not called when refresh fails after a successful toggle, and that loading still resets - Add 'unmount safety' describe with a case asserting no React state update warnings when the toggle promise resolves after unmount Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
4ce1ef0102
commit
58181cfca3
@ -40,6 +40,8 @@ describe('useToggleLove', () => {
|
||||
await result.current[0]()
|
||||
})
|
||||
expect(subsonic.star).toHaveBeenCalledWith('sg-1')
|
||||
expect(getOne).toHaveBeenCalledTimes(2)
|
||||
expect(getOne).toHaveBeenCalledWith('song', { id: 'pt-1' })
|
||||
expect(getOne).toHaveBeenCalledWith('song', { id: 'sg-1' })
|
||||
})
|
||||
|
||||
@ -62,6 +64,15 @@ describe('useToggleLove', () => {
|
||||
expect(subsonic.unstar).toHaveBeenCalledWith('sg-1')
|
||||
})
|
||||
|
||||
it('does not call notify on a successful toggle', async () => {
|
||||
const record = { id: 'sg-1', starred: false }
|
||||
const { result } = renderHook(() => useToggleLove('song', record))
|
||||
await act(async () => {
|
||||
await result.current[0]()
|
||||
})
|
||||
expect(mockNotify).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
describe('playlist track scenarios', () => {
|
||||
it('refreshes both playlist track and song for playlist tracks', async () => {
|
||||
const record = {
|
||||
@ -159,6 +170,18 @@ describe('useToggleLove', () => {
|
||||
})
|
||||
expect(mockNotify).toHaveBeenCalledWith('ra.page.error', 'warning')
|
||||
})
|
||||
|
||||
it('does not call notify when refresh fails after a successful toggle', async () => {
|
||||
getOne.mockRejectedValue(new Error('refresh failed'))
|
||||
const record = { id: 'sg-1', starred: false }
|
||||
const { result } = renderHook(() => useToggleLove('song', record))
|
||||
await act(async () => {
|
||||
await result.current[0]()
|
||||
})
|
||||
expect(subsonic.star).toHaveBeenCalledWith('sg-1')
|
||||
expect(mockNotify).not.toHaveBeenCalled()
|
||||
expect(result.current[1]).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('loading state', () => {
|
||||
@ -185,4 +208,37 @@ describe('useToggleLove', () => {
|
||||
expect(result.current[1]).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('unmount safety', () => {
|
||||
it('does not warn when the promise resolves after unmount', async () => {
|
||||
let resolveStar
|
||||
subsonic.star.mockReturnValue(
|
||||
new Promise((r) => {
|
||||
resolveStar = r
|
||||
}),
|
||||
)
|
||||
const record = { id: 'sg-1', starred: false }
|
||||
const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
|
||||
|
||||
const { result, unmount } = renderHook(() =>
|
||||
useToggleLove('song', record),
|
||||
)
|
||||
act(() => {
|
||||
result.current[0]()
|
||||
})
|
||||
unmount()
|
||||
await act(async () => {
|
||||
resolveStar()
|
||||
})
|
||||
|
||||
const stateUpdateWarnings = errorSpy.mock.calls.filter(
|
||||
([msg]) =>
|
||||
typeof msg === 'string' &&
|
||||
msg.includes("Can't perform a React state update"),
|
||||
)
|
||||
expect(stateUpdateWarnings).toHaveLength(0)
|
||||
|
||||
errorSpy.mockRestore()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user