// @vitest-environment jsdom import { fireEvent, render, screen, within } from '@testing-library/react'; import { afterEach, describe, expect, it, vi } from 'vitest'; import { ChartInsertPicker, EDITING_UI_STYLES, InsertToolbar, TableInsertPicker, } from '../../src/ui'; describe('InsertToolbar', () => { afterEach(() => { vi.restoreAllMocks(); }); it('invokes a configured insert action', () => { const onInsertText = vi.fn(); render( T, onInvoke: onInsertText, }, ]} />, ); expect(screen.getByRole('button', { name: 'Text box' }).getAttribute('data-tooltip')).toBe( 'Insert text box', ); fireEvent.click(screen.getByRole('button', { name: 'Text box' })); expect(onInsertText).toHaveBeenCalledTimes(1); }); it('renders injected table content and returns the selected dimensions', () => { const onInsertTable = vi.fn(); render( Table, renderPopover: ({ close }) => ( `${rows} x ${columns} table`} onPick={(rows, columns) => { onInsertTable(rows, columns); close(); }} /> ), }, ]} />, ); fireEvent.click(screen.getByRole('button', { name: 'Table' })); fireEvent.mouseEnter(screen.getByRole('button', { name: '3 x 4 table' })); expect(screen.getByTestId('table-insert-dimensions').textContent).toBe('3 x 4 table'); fireEvent.click(screen.getByRole('button', { name: '3 x 4 table' })); expect(onInsertTable).toHaveBeenCalledWith(3, 4); expect(screen.queryByTestId('table-insert-dimensions')).toBeNull(); }); it('renders injected chart content and returns the selected chart type', () => { const onInsertChart = vi.fn(); render( Chart, renderPopover: ({ close }) => ( { onInsertChart(type); close(); }} /> ), }, ]} />, ); fireEvent.click(screen.getByRole('button', { name: 'Chart' })); const pieButton = screen.getByRole('button', { name: 'Pie chart' }); expect(pieButton.textContent).toBe(''); expect(pieButton.getAttribute('data-tooltip')).toBe('Pie chart'); expect(pieButton.querySelector('svg')).not.toBeNull(); fireEvent.click(pieButton); expect(onInsertChart).toHaveBeenCalledWith('pie'); expect(screen.queryByRole('dialog', { name: 'Chart' })).toBeNull(); }); it('lays chart choices out as icon buttons with hover labels', () => { expect(EDITING_UI_STYLES).toContain('flex-direction: row;'); expect(EDITING_UI_STYLES).toContain('content: attr(data-tooltip);'); expect(EDITING_UI_STYLES).toContain('width: 32px;'); expect(EDITING_UI_STYLES).toContain('overflow-y: hidden;'); expect(EDITING_UI_STYLES).toMatch( /\.maic-editing-ui-chart-picker-option \{[\s\S]*?align-items: center;/, ); }); it('shows toolbar button labels with the shared renderer tooltip treatment', () => { expect(EDITING_UI_STYLES).toContain('.maic-editing-ui-tooltip-button::after'); expect(EDITING_UI_STYLES).toContain("[data-tooltip-placement='right']::after"); }); it('anchors a popover beside the triggering insert button instead of the toolbar top', () => { const { container } = render( T }, { id: 'image', label: 'Image', icon: I }, { id: 'table', label: 'Table', icon: Table }, { id: 'chart', label: 'Chart', icon: Chart, renderPopover: () => Chart options, }, ]} />, ); const toolbar = within(container); fireEvent.click(toolbar.getByRole('button', { name: 'Chart' })); expect(toolbar.getByRole('dialog', { name: 'Chart' }).style.top).toBe('102px'); }); it('docks across the top and anchors popovers under the triggering button', () => { const { container } = render( T }, { id: 'table', label: 'Table', icon: Table, renderPopover: () => Table options, }, ]} />, ); const toolbar = within(container); fireEvent.click(toolbar.getByRole('button', { name: 'Table' })); expect(toolbar.getByTestId('renderer-insert-toolbar').getAttribute('data-placement')).toBe( 'top', ); expect( toolbar.getByRole('button', { name: 'Table' }).getAttribute('data-tooltip-placement'), ).toBe('bottom'); expect(toolbar.getByRole('dialog', { name: 'Table' }).style.left).toBe('34px'); expect(toolbar.getByRole('dialog', { name: 'Table' }).style.top).toBe(''); }); it('keeps the canvas rail fixed while a tall popover is open', () => { const onRailSizeChange = vi.fn(); vi.spyOn(HTMLElement.prototype, 'getBoundingClientRect').mockReturnValue( new DOMRect(0, 0, 240, 320), ); render( Video, renderPopover: () => Video options, }, ]} />, ); fireEvent.click(screen.getByRole('button', { name: 'Video' })); expect(onRailSizeChange).toHaveBeenLastCalledWith(48); }); });