import { describe, expect, it, vi } from 'vitest'
import { fireEvent, renderWithProviders, screen } from '../../../test/utils'
import MediaStackGrid from './MediaStackGrid'
const tiles = (count: number) =>
Array.from({ length: count }, (_, index) => ({
content: tile {index + 1},
ariaLabel: index === 1 ? 'Second tile' : undefined,
}))
describe('MediaStackGrid', () => {
it('renders nothing for empty tiles', () => {
const { container } = renderWithProviders()
expect(container.firstChild).toBeNull()
})
it.each([
[1, 'aspect-square'],
[2, 'aspect-[16/9]'],
[3, 'aspect-[4/3]'],
[4, 'aspect-[379/286]'],
])('renders the %s-tile layout', (count, layoutClass) => {
const { container } = renderWithProviders(
)
expect(container.firstElementChild).toHaveClass(layoutClass, 'custom-grid')
expect(screen.getAllByText(/tile/)).toHaveLength(count)
})
it('clamps visible tiles and places overflow on the last tile', () => {
const { container, rerender } = renderWithProviders(
)
expect(container.querySelectorAll('span')).toHaveLength(4)
expect(screen.getByText('+2')).toBeInTheDocument()
expect(screen.getByText('+2').parentElement).toHaveTextContent('tile 4')
rerender()
expect(container.querySelectorAll('span')).toHaveLength(2)
expect(screen.queryByText(/^\+/)).toBeNull()
rerender()
expect(
screen.getByText('tile 1').closest('div')?.parentElement
).toHaveStyle({
aspectRatio: '0.5',
})
})
it.each([
[2, '+3', 'tile 2'],
[3, '+2', 'tile 3'],
])(
'shows overflow on the last visible tile when maxVisible is %s',
(maxVisible, badge, lastTile) => {
const { container } = renderWithProviders(
)
expect(container.querySelectorAll('span')).toHaveLength(maxVisible)
expect(screen.getByText(badge)).toBeInTheDocument()
expect(screen.getByText(badge).parentElement).toHaveTextContent(lastTile)
}
)
it('shows overflow on the single visible tile', () => {
const { container } = renderWithProviders(
)
expect(container.querySelectorAll('span')).toHaveLength(1)
expect(screen.getByText('+2').parentElement).toHaveTextContent('tile 1')
})
it('does not show overflow when all tiles are visible', () => {
renderWithProviders()
expect(screen.queryByText(/^\+/)).toBeNull()
})
it('renders activatable buttons with labels and indexes', () => {
const onActivate = vi.fn()
renderWithProviders(
)
const buttons = screen.getAllByRole('button')
expect(buttons).toHaveLength(3)
expect(buttons[0]).toHaveAttribute('aria-label', 'Open media 1')
expect(buttons[1]).toHaveAttribute('aria-label', 'Second tile')
fireEvent.click(buttons[0])
fireEvent.click(buttons[2])
expect(onActivate).toHaveBeenNthCalledWith(1, 0)
expect(onActivate).toHaveBeenNthCalledWith(2, 2)
})
it('uses non-interactive shells when no activation handler is supplied', () => {
renderWithProviders()
expect(screen.queryAllByRole('button')).toHaveLength(0)
})
})