From ab67f0b0c13034d09170501d631046be7f8a73cd Mon Sep 17 00:00:00 2001 From: jaaaaavier Date: Tue, 31 Mar 2026 13:15:22 +0200 Subject: [PATCH] add coverage to CircleButton, checkbox, Lists, Menu --- .../__test__/CircleButton.test.tsx | 50 ++++++++++ .../checkbox/__test__/Checkbox.test.tsx | 38 +++++++- .../list/__test__/ListItem.test.tsx | 25 +++++ .../mail/tray/__test__/TrayList.test.tsx | 14 +++ src/components/menu/__test__/Menu.test.tsx | 95 +++++++++++++++++++ 5 files changed, 220 insertions(+), 2 deletions(-) diff --git a/src/components/buttonCircle/__test__/CircleButton.test.tsx b/src/components/buttonCircle/__test__/CircleButton.test.tsx index 998b205..a30ecc5 100644 --- a/src/components/buttonCircle/__test__/CircleButton.test.tsx +++ b/src/components/buttonCircle/__test__/CircleButton.test.tsx @@ -134,4 +134,54 @@ describe('CircleButton component', () => { const button = render(); expect(button).toMatchSnapshot(); }); + + it('should close dropdown when toggle is clicked while open', () => { + const TestComponent = () => { + const [isOpen, setIsOpen] = useState(false); + return ( + Dropdown Content} + isOpen={isOpen} + handleClose={() => setIsOpen(false)} + handleOpen={() => setIsOpen(true)} + /> + ); + }; + render(); + const toggleButton = screen.getAllByRole('button')[1]; + + fireEvent.click(toggleButton); + expect(screen.getByText('Dropdown Content')).toBeInTheDocument(); + + fireEvent.click(toggleButton); + expect(screen.queryByText('Dropdown Content')).not.toBeInTheDocument(); + }); + + it('should render indicator without className correctly', () => { + const indicator = { icon: }; + render(); + expect(screen.getByTestId('indicator-icon')).toBeInTheDocument(); + }); + + it('should not close dropdown when clicking inside the circle button while open', () => { + const TestComponent = () => { + const [isOpen, setIsOpen] = useState(false); + return ( + Dropdown Content} + isOpen={isOpen} + handleClose={() => setIsOpen(false)} + handleOpen={() => setIsOpen(true)} + /> + ); + }; + render(); + const [mainButton, toggleButton] = screen.getAllByRole('button'); + + fireEvent.click(toggleButton); + expect(screen.getByText('Dropdown Content')).toBeInTheDocument(); + + fireEvent.click(mainButton); + expect(screen.getByText('Dropdown Content')).toBeInTheDocument(); + }); }); diff --git a/src/components/checkbox/__test__/Checkbox.test.tsx b/src/components/checkbox/__test__/Checkbox.test.tsx index fa908c4..456a68a 100644 --- a/src/components/checkbox/__test__/Checkbox.test.tsx +++ b/src/components/checkbox/__test__/Checkbox.test.tsx @@ -1,7 +1,7 @@ import React from 'react'; -import { describe, expect, it } from 'vitest'; +import { describe, expect, it, vi } from 'vitest'; import { Checkbox } from '../'; -import { render } from '@testing-library/react'; +import { render, fireEvent } from '@testing-library/react'; describe('Checkbox component', () => { it('Checkbox disabled and not checked should render correctly', () => { @@ -33,4 +33,38 @@ describe('Checkbox component', () => { const button = render(); expect(button).toMatchSnapshot(); }); + + it('calls onClick when label is clicked and not disabled', () => { + const handleClick = vi.fn(); + const { container } = render(); + const label = container.querySelector('label'); + fireEvent.click(label!); + expect(handleClick).toHaveBeenCalled(); + }); + + it('does not call onClick when disabled', () => { + const handleClick = vi.fn(); + const { container } = render(); + const label = container.querySelector('label'); + fireEvent.click(label!); + expect(handleClick).not.toHaveBeenCalled(); + }); + + it('prevents default on inner div click', () => { + const { container } = render(); + const div = container.querySelector('div'); + + const event = new MouseEvent('click', { bubbles: true, cancelable: true }); + event.preventDefault = vi.fn(); + fireEvent(div!, event); + expect(event.preventDefault).toHaveBeenCalled(); + }); + + it('triggers onKeyDown handlers without errors', () => { + const { container } = render(); + const label = container.querySelector('label'); + const div = container.querySelector('div'); + fireEvent.keyDown(label!, { key: 'Enter' }); + fireEvent.keyDown(div!, { key: 'Enter' }); + }); }); diff --git a/src/components/list/__test__/ListItem.test.tsx b/src/components/list/__test__/ListItem.test.tsx index 6b7a425..aa37cfa 100644 --- a/src/components/list/__test__/ListItem.test.tsx +++ b/src/components/list/__test__/ListItem.test.tsx @@ -66,6 +66,31 @@ describe('ListItem', () => { expect(mockOnClickContextMenu).toHaveBeenCalled(); }); + it('updates dimensions when menuItemsRef size changes', () => { + const originalOffsetWidth = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'offsetWidth'); + const originalOffsetHeight = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'offsetHeight'); + + Object.defineProperty(HTMLElement.prototype, 'offsetWidth', { configurable: true, value: 100 }); + Object.defineProperty(HTMLElement.prototype, 'offsetHeight', { configurable: true, value: 100 }); + + renderListItem({ isOpen: true, selected: true }); + + if (originalOffsetWidth) Object.defineProperty(HTMLElement.prototype, 'offsetWidth', originalOffsetWidth); + if (originalOffsetHeight) Object.defineProperty(HTMLElement.prototype, 'offsetHeight', originalOffsetHeight); + }); + + it('handles contextMenu positioning near screen edges', () => { + renderListItem({ isOpen: true, selected: true }); + const listItem = screen.getByText('1').closest('div'); + + fireEvent.contextMenu(listItem!, { + clientX: window.innerWidth + 300, + clientY: Math.max(window.innerHeight, 500) + 300 + }); + + expect(mockOnClickContextMenu).toHaveBeenCalled(); + }); + it('closes the context menu when onClose is called', () => { renderListItem({ isOpen: true }); mockOnClose(); diff --git a/src/components/mail/tray/__test__/TrayList.test.tsx b/src/components/mail/tray/__test__/TrayList.test.tsx index 3735ce5..6408288 100644 --- a/src/components/mail/tray/__test__/TrayList.test.tsx +++ b/src/components/mail/tray/__test__/TrayList.test.tsx @@ -182,4 +182,18 @@ describe('TrayList', () => { expect(screen.getByText('John Doe')).toBeInTheDocument(); }); + + it('should render without onLoadMore and onMailSelected (using defaults)', () => { + render(); + expect(screen.getByText('John Doe')).toBeInTheDocument(); + }); + + it('calls default onMailSelected and onLoadMore functions safely', () => { + const { getAllByRole } = render( + + ); + + const emailButtons = getAllByRole('button'); + expect(() => fireEvent.click(emailButtons[0])).not.toThrow(); + }); }); diff --git a/src/components/menu/__test__/Menu.test.tsx b/src/components/menu/__test__/Menu.test.tsx index 3297be0..8c62fc3 100644 --- a/src/components/menu/__test__/Menu.test.tsx +++ b/src/components/menu/__test__/Menu.test.tsx @@ -126,4 +126,99 @@ describe('Menu Component', () => { expect(option1).toHaveClass('bg-gray-5'); }); + + it('triggers onClick on node item when Enter is pressed', () => { + const nodeClick = vi.fn(); + const menuWithNode: Array> = [ + { node: }, + ]; + render(); + fireEvent.keyDown(document, { key: 'ArrowDown' }); + fireEvent.keyDown(document, { key: 'Enter' }); + expect(nodeClick).toHaveBeenCalled(); + }); + + it('handles node item without onClick on Enter press without errors', () => { + const menuWithNode: Array> = [ + { node: No Click Node }, + ]; + render(); + fireEvent.keyDown(document, { key: 'ArrowDown' }); + fireEvent.keyDown(document, { key: 'Enter' }); + expect(handleMenuClose).toHaveBeenCalled(); + }); + + it('calls onClick handler on item click when defined', () => { + const onClickHandler = vi.fn(); + const menuWithOnClick: Array> = [ + { name: 'Clickable', onClick: onClickHandler }, + ]; + const { getByText } = render(); + fireEvent.click(getByText('Clickable')); + expect(onClickHandler).toHaveBeenCalled(); + }); + + it('renders keyboard shortcut icon when provided', () => { + const menuWithShortcutIcon: Array> = [ + { + name: 'With Icon Shortcut', + action: vi.fn(), + keyboardShortcutOptions: { + keyboardShortcutIcon: MockIcon, + keyboardShortcutText: 'Ctrl+S', + }, + }, + ]; + const { getByText, getAllByTestId } = render(); + expect(getByText('Ctrl+S')).toBeInTheDocument(); + expect(getAllByTestId('mock-icon').length).toBeGreaterThan(0); + }); + + it('renders keyboard shortcut options without text', () => { + const menuWithIconOnly: Array> = [ + { + name: 'Icon Only Shortcut', + action: vi.fn(), + keyboardShortcutOptions: { + keyboardShortcutIcon: MockIcon, + }, + }, + ]; + const { getByText } = render(); + expect(getByText('Icon Only Shortcut')).toBeInTheDocument(); + }); + + it('handles Enter with no selection and no genericEnterKey without errors', () => { + const menuWithItem: Array> = [ + { name: 'Item', action: vi.fn() }, + ]; + render( + , + ); + fireEvent.keyDown(document, { key: 'Enter' }); + expect(handleMenuClose).toHaveBeenCalled(); + }); + + it('returns null from ArrowUp when all items are unclickable', () => { + const allDisabledMenu: Array> = [ + { separator: true }, + { name: 'Disabled', disabled: () => true }, + ]; + render(); + fireEvent.keyDown(document, { key: 'ArrowUp' }); + }); + + it('returns null from ArrowDown when all items are unclickable', () => { + const allDisabledMenu: Array> = [ + { separator: true }, + { name: 'Disabled', disabled: () => true }, + ]; + render(); + fireEvent.keyDown(document, { key: 'ArrowDown' }); + }); });