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();
});
});