import { describe, expect, it, vi } from 'vitest' import { fireEvent, renderWithProviders, screen } from '../../test/utils' import { triggerDownload } from './_shared/triggerDownload' import { bubbleVariantForState, bubbleGroupPositionFromStream } from './types' import MessageAttachment from '.' vi.mock('./_shared/triggerDownload', () => ({ triggerDownload: vi.fn(() => Promise.resolve()), })) const mockedDownload = vi.mocked(triggerDownload) describe('MessageAttachment behavior', () => { it('renders file rows with precedence, fallback names, and cancellation', () => { const onClick = vi.fn(() => false) const { rerender } = renderWithProviders( ) expect(screen.getByText('first.pdf')).toBeInTheDocument() expect(screen.getByText('second.pdf')).toBeInTheDocument() fireEvent.click(screen.getByRole('button', { name: 'Download first.pdf' })) expect(onClick).toHaveBeenCalledWith(0) expect(mockedDownload).not.toHaveBeenCalled() rerender( ) fireEvent.click( screen.getByRole('button', { name: 'Download fallback.txt' }) ) expect(mockedDownload).toHaveBeenCalledWith( 'https://cdn.example.com/fallback.txt', 'fallback.txt' ) }) it('renders no file when inputs are absent and supports composer dismissal', () => { const { container } = renderWithProviders( ) expect(container.firstChild).toBeNull() const onDismiss = vi.fn() renderWithProviders( ) fireEvent.click(screen.getByRole('button', { name: 'Dismiss attachment' })) expect(onDismiss).toHaveBeenCalledOnce() }) it('renders image stacks, forwards loading, and supports click cancellation', () => { const onClick = vi.fn(() => false) renderWithProviders( ) expect(screen.getAllByRole('img')[0]).toHaveAttribute('loading', 'lazy') expect(screen.getAllByRole('img')).toHaveLength(2) fireEvent.click(screen.getByRole('button', { name: 'Open image 2 of 2' })) expect(onClick).toHaveBeenCalledWith(1) expect(screen.queryByTestId('image-viewer')).not.toHaveAttribute('open') }) it('opens images at the clicked index and suffixes a shared filename', () => { renderWithProviders( ) fireEvent.click(screen.getByRole('button', { name: 'Open image 2 of 2' })) expect(screen.getByTestId('image-viewer')).toHaveAttribute( 'aria-label', 'photos.jpg (2)' ) expect(screen.getByRole('img', { name: 'photos.jpg (2)' })).toHaveAttribute( 'src', 'https://cdn.example.com/two.jpg' ) }) it('renders video poster and fallback, and wires viewer attributes', () => { const onDismiss = vi.fn() const { rerender } = renderWithProviders( ) expect( screen.getByRole('img', { name: 'Video 1 thumbnail' }) ).toHaveAttribute('src', '/poster.jpg') fireEvent.click(screen.getByRole('button', { name: 'Dismiss attachment' })) expect(onDismiss).toHaveBeenCalledOnce() rerender( ) expect(screen.getByLabelText('Play video 1 of 1')).toBeInTheDocument() }) it('supports PDF titles, download actions, dismiss, and viewer index', () => { const onDismiss = vi.fn() renderWithProviders( ) expect(screen.getByText('Quarterly report')).toBeInTheDocument() fireEvent.click(screen.getByRole('button', { name: 'Dismiss attachment' })) expect(onDismiss).toHaveBeenCalledOnce() renderWithProviders( ) fireEvent.click(screen.getByRole('button', { name: 'Open two.pdf' })) expect(screen.getAllByTestId('pdf-viewer').at(-1)).toHaveAttribute( 'aria-label', 'two.pdf' ) }) it('maps state and stream grouping contracts', () => { expect(bubbleVariantForState('composer')).toBe('dark') expect(bubbleVariantForState('sent')).toBe('dark') expect(bubbleVariantForState('received')).toBe('light') expect(bubbleGroupPositionFromStream({})).toBe('single') expect( bubbleGroupPositionFromStream({ groupedByUser: true, firstOfGroup: true, endOfGroup: true, }) ).toBe('single') expect( bubbleGroupPositionFromStream({ groupedByUser: true, firstOfGroup: true }) ).toBe('first') expect( bubbleGroupPositionFromStream({ groupedByUser: true, endOfGroup: true }) ).toBe('end') expect(bubbleGroupPositionFromStream({ groupedByUser: true })).toBe( 'middle' ) }) })