import React from 'react'; import { render, screen, fireEvent, within } from '@testing-library/react'; import { SubjectSidebar } from '../src/components/SubjectSidebar'; const LINES = [ { id: 'a1', name: 'Mouse-A1', group: 'Group A', color: '#111' }, { id: 'a2', name: 'Mouse-A2', group: 'Group A', color: '#222' }, { id: 'b1', name: 'Mouse-B1', group: 'Group B', color: '#333' }, ]; function setup(overrides = {}) { const props = { lines: LINES, hiddenSubjects: new Set(), onToggleSubject: jest.fn(), onToggleGroup: jest.fn(), onShowAll: jest.fn(), onHighlight: jest.fn(), ...overrides, }; render(); return props; } it('renders each group header with its subject count', () => { setup(); expect(screen.getByText('Group A')).toBeInTheDocument(); expect(screen.getByText('Group B')).toBeInTheDocument(); expect(screen.getByText('(2)')).toBeInTheDocument(); expect(screen.getByText('(1)')).toBeInTheDocument(); }); it('renders a subject checkbox per subject, checked when visible', () => { setup({ hiddenSubjects: new Set(['a2']) }); expect(screen.getByLabelText('Mouse-A1').checked).toBe(true); expect(screen.getByLabelText('Mouse-A2').checked).toBe(false); }); it('calls onToggleSubject with the id when a subject checkbox is clicked', () => { const { onToggleSubject } = setup(); fireEvent.click(screen.getByLabelText('Mouse-A1')); expect(onToggleSubject).toHaveBeenCalledWith('a1'); }); it('shows the group checkbox as indeterminate when the group is mixed', () => { setup({ hiddenSubjects: new Set(['a1']) }); const groupCheckbox = screen.getByLabelText(/Group A/); expect(groupCheckbox.indeterminate).toBe(true); expect(groupCheckbox.checked).toBe(false); }); it('checks the group checkbox when all members are visible', () => { setup(); expect(screen.getByLabelText(/Group A/).checked).toBe(true); }); it('calls onToggleGroup with the group ids and hidden=true when an all-visible group is clicked', () => { const { onToggleGroup } = setup(); fireEvent.click(screen.getByLabelText(/Group A/)); expect(onToggleGroup).toHaveBeenCalledWith(['a1', 'a2'], true); }); it('shows the group checkbox unchecked and not indeterminate when all members are hidden', () => { setup({ hiddenSubjects: new Set(['a1', 'a2']) }); const groupCheckbox = screen.getByLabelText(/Group A/); expect(groupCheckbox.checked).toBe(false); expect(groupCheckbox.indeterminate).toBe(false); }); it('calls onToggleGroup with hidden=false when a fully-hidden group is clicked', () => { const { onToggleGroup } = setup({ hiddenSubjects: new Set(['a1', 'a2']) }); fireEvent.click(screen.getByLabelText(/Group A/)); expect(onToggleGroup).toHaveBeenCalledWith(['a1', 'a2'], false); }); it('hides the Show all link when nothing is hidden, shows it otherwise', () => { const { rerender } = render( {}} onToggleGroup={() => {}} onShowAll={() => {}} onHighlight={() => {}} />, ); expect(screen.queryByText('Show all')).toBeNull(); rerender( {}} onToggleGroup={() => {}} onShowAll={() => {}} onHighlight={() => {}} />, ); expect(screen.getByText('Show all')).toBeInTheDocument(); }); it('calls onShowAll when the Show all link is clicked', () => { const { onShowAll } = setup({ hiddenSubjects: new Set(['a1']) }); fireEvent.click(screen.getByText('Show all')); expect(onShowAll).toHaveBeenCalled(); }); it('calls onHighlight on subject row hover enter/leave', () => { const { onHighlight } = setup(); const row = screen.getByLabelText('Mouse-A1').closest('label'); fireEvent.mouseEnter(row); expect(onHighlight).toHaveBeenCalledWith('a1'); fireEvent.mouseLeave(row); expect(onHighlight).toHaveBeenCalledWith(null); });