mirror of
https://github.com/navidrome/navidrome.git
synced 2026-04-28 11:29:38 +00:00
* Update song playlist menu and endpoint * feat(ui): show submenu on click, not on hover Signed-off-by: Deluan <deluan@navidrome.org> * feat(ui): integrate dataProvider for fetching playlists in song context menu Signed-off-by: Deluan <deluan@navidrome.org> * feat(ui): update song context menu to use dataProvider for fetching playlists and inspecting songs Signed-off-by: Deluan <deluan@navidrome.org> * feat(ui): stop event propagation when closing playlist submenu Signed-off-by: Deluan <deluan@navidrome.org> * feat(ui): add 'show in playlist' option to options object Signed-off-by: Deluan <deluan@navidrome.org> --------- Signed-off-by: Deluan <deluan@navidrome.org>
82 lines
2.3 KiB
JavaScript
82 lines
2.3 KiB
JavaScript
import React from 'react'
|
|
import { render, fireEvent, screen, waitFor } from '@testing-library/react'
|
|
import { TestContext } from 'ra-test'
|
|
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
import { SongContextMenu } from './SongContextMenu'
|
|
|
|
vi.mock('../dataProvider', () => ({
|
|
httpClient: vi.fn(),
|
|
}))
|
|
|
|
vi.mock('react-redux', () => ({ useDispatch: () => vi.fn() }))
|
|
|
|
vi.mock('react-admin', async (importOriginal) => {
|
|
const actual = await importOriginal()
|
|
return {
|
|
...actual,
|
|
useRedirect: () => (url) => {
|
|
window.location.hash = `#${url}`
|
|
},
|
|
useDataProvider: () => ({
|
|
getPlaylists: vi.fn().mockResolvedValue({
|
|
data: [{ id: 'pl1', name: 'Pl 1' }],
|
|
}),
|
|
inspect: vi.fn().mockResolvedValue({
|
|
data: { rawTags: {} },
|
|
}),
|
|
}),
|
|
}
|
|
})
|
|
|
|
describe('SongContextMenu', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
window.location.hash = ''
|
|
})
|
|
|
|
it('navigates to playlist when selected', async () => {
|
|
render(
|
|
<TestContext>
|
|
<SongContextMenu record={{ id: 'song1', size: 1 }} resource="song" />
|
|
</TestContext>,
|
|
)
|
|
fireEvent.click(screen.getAllByRole('button')[1])
|
|
await waitFor(() =>
|
|
screen.getByText(/resources\.song\.actions\.showInPlaylist/),
|
|
)
|
|
fireEvent.click(
|
|
screen.getByText(/resources\.song\.actions\.showInPlaylist/),
|
|
)
|
|
await waitFor(() => screen.getByText('Pl 1'))
|
|
fireEvent.click(screen.getByText('Pl 1'))
|
|
expect(window.location.hash).toBe('#/playlist/pl1/show')
|
|
})
|
|
|
|
it('stops event propagation when playlist submenu is closed', async () => {
|
|
const mockOnClick = vi.fn()
|
|
render(
|
|
<TestContext>
|
|
<div onClick={mockOnClick}>
|
|
<SongContextMenu record={{ id: 'song1', size: 1 }} resource="song" />
|
|
</div>
|
|
</TestContext>,
|
|
)
|
|
|
|
// Open main menu
|
|
fireEvent.click(screen.getAllByRole('button')[1])
|
|
await waitFor(() =>
|
|
screen.getByText(/resources\.song\.actions\.showInPlaylist/),
|
|
)
|
|
|
|
// Open playlist submenu
|
|
fireEvent.click(
|
|
screen.getByText(/resources\.song\.actions\.showInPlaylist/),
|
|
)
|
|
await waitFor(() => screen.getByText('Pl 1'))
|
|
|
|
// Click outside the playlist submenu (should close it without triggering parent click)
|
|
fireEvent.click(document.body)
|
|
|
|
expect(mockOnClick).not.toHaveBeenCalled()
|
|
})
|
|
})
|