import React from 'react'; import '@testing-library/jest-dom'; import { act, render, screen, fireEvent, waitFor, } from '@testing-library/react'; import { DropdownMenuItem } from 'react-magma-dom'; import { FullscreenExitIcon, FullscreenIcon, MoreVertIcon, TableChartIcon, } from 'react-magma-icons'; import { ChartDataTable } from './ChartDataTable'; import { ChartFullscreenButton } from './ChartFullscreenButton'; import { ChartMoreOptionsButton } from './ChartMoreOptionsButton'; import { ChartTableButton } from './ChartTableButton'; import { ChartTableModal } from './ChartTableModal'; import { ChartToolbar } from './ChartToolbar'; const dataSet = [ { group: 'High performance', value: 50 }, { group: 'Average performance', value: 30 }, { group: 'Poor performance', value: 15 }, { group: 'Not attempted', value: 5 }, ]; // --------------------------------------------------------------------------- // ChartDataTable // --------------------------------------------------------------------------- describe('ChartDataTable', () => { it('derives column headers from dataset keys when no columns prop is given', () => { render(); expect( screen.getByRole('columnheader', { name: 'Group' }) ).toBeInTheDocument(); expect( screen.getByRole('columnheader', { name: 'Value' }) ).toBeInTheDocument(); }); it('renders all data rows', () => { render(); expect( screen.getByRole('cell', { name: 'High performance' }) ).toBeInTheDocument(); expect(screen.getByRole('cell', { name: '50' })).toBeInTheDocument(); expect( screen.getByRole('cell', { name: 'Not attempted' }) ).toBeInTheDocument(); expect(screen.getByRole('cell', { name: '5' })).toBeInTheDocument(); }); it('accepts custom column definitions', () => { const columns = [ { header: 'Category', key: 'group' }, { header: 'Count', key: 'value' }, ]; render(); expect( screen.getByRole('columnheader', { name: 'Category' }) ).toBeInTheDocument(); expect( screen.getByRole('columnheader', { name: 'Count' }) ).toBeInTheDocument(); }); it('renders with isInverse without error', () => { render(); expect(screen.getByRole('table')).toBeInTheDocument(); }); }); // --------------------------------------------------------------------------- // ChartTableModal // --------------------------------------------------------------------------- describe('ChartTableModal', () => { it('renders a dialog with semantic heading when open', () => { render( ); expect(screen.getByRole('dialog')).toBeInTheDocument(); expect( screen.getByRole('heading', { level: 2, name: 'Tabular representation Overall Performance', }) ).toBeInTheDocument(); }); it('respects custom headerLevel', () => { render( ); expect(screen.getByRole('heading', { level: 1 })).toBeInTheDocument(); }); it('respects custom headerLabel', () => { render( ); expect( screen.getByRole('heading', { name: 'Data table My Chart' }) ).toBeInTheDocument(); }); it('does not render dialog when closed', () => { render( ); expect(screen.queryByRole('dialog')).not.toBeInTheDocument(); }); it('renders the data table inside the modal', () => { render( ); expect( screen.getByRole('columnheader', { name: 'Group' }) ).toBeInTheDocument(); expect( screen.getByRole('cell', { name: 'High performance' }) ).toBeInTheDocument(); }); it('calls onClose when close button is activated', async () => { jest.useFakeTimers(); const onClose = jest.fn(); render( ); fireEvent.click(screen.getByTestId('modal-closebtn')); await act(async () => { jest.runAllTimers(); }); expect(onClose).toHaveBeenCalledTimes(1); jest.useRealTimers(); }); it('renders with isInverse without error', () => { render( ); expect(screen.getByRole('dialog')).toBeInTheDocument(); }); }); // --------------------------------------------------------------------------- // ChartTableButton // --------------------------------------------------------------------------- describe('ChartTableButton', () => { const icon = ; it('renders with aria-haspopup="dialog"', () => { render( ); const button = screen.getByRole('button', { name: 'Overall Performance' }); expect(button).toHaveAttribute('aria-haspopup', 'dialog'); }); it('sets aria-expanded to false when modal is closed', () => { render( ); expect( screen.getByRole('button', { name: 'Overall Performance' }) ).toHaveAttribute('aria-expanded', 'false'); }); it('sets aria-expanded to true when modal is open', () => { render( ); expect( screen.getByRole('button', { name: 'Overall Performance' }) ).toHaveAttribute('aria-expanded', 'true'); }); it('calls onClick when activated', () => { const onClick = jest.fn(); render( ); fireEvent.click( screen.getByRole('button', { name: 'Overall Performance' }) ); expect(onClick).toHaveBeenCalledTimes(1); }); it('renders with custom tooltip content on hover', async () => { render( ); const button = screen.getByRole('button', { name: 'Overall Performance' }); fireEvent.mouseEnter(button); await waitFor(() => { expect(screen.getByText('View data as table')).toBeInTheDocument(); }); }); }); // --------------------------------------------------------------------------- // ChartFullscreenButton // --------------------------------------------------------------------------- describe('ChartFullscreenButton', () => { it('does NOT have aria-haspopup', () => { render( } isFullscreen={false} onClick={jest.fn()} /> ); const button = screen.getByRole('button', { name: 'View chart in full screen', }); expect(button).not.toHaveAttribute('aria-haspopup'); }); it('calls onClick when activated', () => { const onClick = jest.fn(); render( } isFullscreen={false} onClick={onClick} /> ); fireEvent.click( screen.getByRole('button', { name: 'View chart in full screen' }) ); expect(onClick).toHaveBeenCalledTimes(1); }); it('shows "Make full screen" tooltip by default', async () => { render( } isFullscreen={false} onClick={jest.fn()} /> ); fireEvent.mouseEnter(screen.getByRole('button', { name: 'Fullscreen' })); await waitFor(() => { expect(screen.getByText('Make full screen')).toBeInTheDocument(); }); }); it('shows "Exit full screen" tooltip when in fullscreen', async () => { render( } exitIcon={} isFullscreen onClick={jest.fn()} /> ); fireEvent.mouseEnter(screen.getByRole('button', { name: 'Fullscreen' })); await waitFor(() => { expect(screen.getByText('Exit full screen')).toBeInTheDocument(); }); }); }); // --------------------------------------------------------------------------- // ChartMoreOptionsButton // --------------------------------------------------------------------------- describe('ChartMoreOptionsButton', () => { it('renders with default "More options" label', () => { render( }> Download ); expect( screen.getByRole('button', { name: 'More options' }) ).toBeInTheDocument(); }); it('renders with custom aria-label', () => { render( }> Download ); expect( screen.getByRole('button', { name: 'Chart actions' }) ).toBeInTheDocument(); }); it('opens dropdown menu on click', () => { render( }> Download as CSV ); fireEvent.click(screen.getByRole('button', { name: 'More options' })); expect(screen.getByText('Download as CSV')).toBeVisible(); }); }); // --------------------------------------------------------------------------- // ChartToolbar // --------------------------------------------------------------------------- describe('ChartToolbar', () => { it('renders the title as a heading', () => { render( ); expect( screen.getByRole('heading', { level: 3, name: 'Overall Performance' }) ).toBeInTheDocument(); }); it('renders children action buttons', () => { render( ); expect( screen.getByRole('button', { name: 'Show as table' }) ).toBeInTheDocument(); expect( screen.getByRole('button', { name: 'Full screen' }) ).toBeInTheDocument(); }); it('respects custom heading level', () => { render( ); expect( screen.getByRole('heading', { level: 2, name: 'Test' }) ).toBeInTheDocument(); }); });