From 2b9e950f02ac873d27c48a1a075d591a4cfaa1bc Mon Sep 17 00:00:00 2001 From: jaaaaavier Date: Tue, 31 Mar 2026 12:52:44 +0200 Subject: [PATCH 1/3] feat: update coverage for components --- .../avatar/__test__/Avatar.test.tsx | 22 +++++ .../contextMenu/__test__/ContextMenu.test.tsx | 18 +++++ .../dialog/__test__/Dialog.test.tsx | 21 +++++ .../dropdown/__test__/Dropdown.test.tsx | 81 +++++++++++++++++++ .../infiniteScroll/InfiniteScroll.tsx | 2 - .../__test__/InfiniteScroll.test.tsx | 21 +++++ src/components/input/__test__/Input.test.tsx | 10 +++ src/components/list/__test__/List.test.tsx | 9 +++ .../list/__test__/ListHeader.test.tsx | 39 +++++++++ 9 files changed, 221 insertions(+), 2 deletions(-) diff --git a/src/components/avatar/__test__/Avatar.test.tsx b/src/components/avatar/__test__/Avatar.test.tsx index 1bd8722..64c9f0c 100644 --- a/src/components/avatar/__test__/Avatar.test.tsx +++ b/src/components/avatar/__test__/Avatar.test.tsx @@ -1,6 +1,8 @@ import { render } from '@testing-library/react'; import { describe, expect, it } from 'vitest'; import { Avatar } from '../'; +import DefaultAvatar from '../components/DefaultAvatar'; +import PictureAvatar from '../components/PictureAvatar'; const FULL_NAME = 'My Internxt'; const IMAGE_SRC = 'https://internxt.com/favicon.ico'; @@ -11,6 +13,16 @@ describe('Avatar component', () => { expect(avatarComponent).toMatchSnapshot(); }); + it('Avatar with single word name should render correctly', () => { + const avatarComponent = render(); + expect(avatarComponent).toMatchSnapshot(); + }); + + it('Avatar with empty spaces name should return empty content', () => { + const avatarComponent = render(); + expect(avatarComponent).toMatchSnapshot(); + }); + it('Avatar with fullname as null should render correctly with empty letters', () => { const avatarComponent = render(); expect(avatarComponent).toMatchSnapshot(); @@ -47,4 +59,14 @@ describe('Avatar component', () => { const avatarComponent = render(); expect(avatarComponent).toMatchSnapshot(); }); + + it('DefaultAvatar handles default parameters', () => { + const avatarComponent = render(); + expect(avatarComponent).toMatchSnapshot(); + }); + + it('PictureAvatar handles default parameters', () => { + const avatarComponent = render(); + expect(avatarComponent).toMatchSnapshot(); + }); }); diff --git a/src/components/contextMenu/__test__/ContextMenu.test.tsx b/src/components/contextMenu/__test__/ContextMenu.test.tsx index 03f0524..b485503 100644 --- a/src/components/contextMenu/__test__/ContextMenu.test.tsx +++ b/src/components/contextMenu/__test__/ContextMenu.test.tsx @@ -96,4 +96,22 @@ describe('ContextMenu Component', () => { if (menuItem && 'action' in menuItem) expect(menuItem?.action).toHaveBeenCalledWith(props.item); expect(props.handleMenuClose).toHaveBeenCalled(); }); + + it('positions menu at bottom when isContextMenuCutOff is true and not from right click', () => { + const { container } = render( + , + ); + const outerDiv = container.firstChild as HTMLElement; + expect(outerDiv.style.bottom).toBe('40px'); + expect(outerDiv.style.top).toBe(''); + }); + + it('positions menu at top when isContextMenuCutOff is false and not from right click', () => { + const { container } = render( + , + ); + const outerDiv = container.firstChild as HTMLElement; + expect(outerDiv.style.top).toBe('40px'); + expect(outerDiv.style.bottom).toBe(''); + }); }); diff --git a/src/components/dialog/__test__/Dialog.test.tsx b/src/components/dialog/__test__/Dialog.test.tsx index 29a017c..0901048 100644 --- a/src/components/dialog/__test__/Dialog.test.tsx +++ b/src/components/dialog/__test__/Dialog.test.tsx @@ -51,6 +51,27 @@ describe('Dialog', () => { expect(defaultProps.onClose).toHaveBeenCalled(); }); + it('does not call onClose when pressing other keys', () => { + renderDialog(); + fireEvent.keyDown(window, { key: 'Enter' }); + expect(defaultProps.onClose).not.toHaveBeenCalled(); + }); + + it('handles timeouts correctly on active transition states', () => { + vi.useFakeTimers(); + const { rerender } = renderDialog({ isOpen: false }); + + vi.runAllTimers(); + + rerender(); + vi.runAllTimers(); + + rerender(); + vi.runAllTimers(); + + vi.useRealTimers(); + }); + it('calls onPrimaryAction when clicking the primary button', () => { const { getByText } = renderDialog(); fireEvent.click(getByText(defaultProps.primaryAction)); diff --git a/src/components/dropdown/__test__/Dropdown.test.tsx b/src/components/dropdown/__test__/Dropdown.test.tsx index bfb64ad..f8ad83c 100644 --- a/src/components/dropdown/__test__/Dropdown.test.tsx +++ b/src/components/dropdown/__test__/Dropdown.test.tsx @@ -155,4 +155,85 @@ describe('Dropdown component', () => { const menu = getByTestId('menu-dropdown'); expect(menu).toHaveClass('scale-95 opacity-0'); }); + + it('should extract padding values and open to the right', () => { + const { getByTestId } = render( + + Dropdown + , + ); + const menu = getByTestId('menu-dropdown'); + expect(menu).toHaveClass('right-0'); + }); + + it('should handle undefined options and dropdownActionsContext, and render menuItems', () => { + const { getByRole, getByText } = render( + Custom Item]}> + Dropdown + , + ); + + fireEvent.click(getByRole('button')); + expect(getByText('Custom Item')).toBeInTheDocument(); + }); + + it('should handle children as a function', () => { + const { getByRole, getByText } = render( + + {({ open }) => {open ? 'Close' : 'Open'}} + , + ); + + expect(getByText('Open')).toBeInTheDocument(); + fireEvent.click(getByRole('button')); + expect(getByText('Close')).toBeInTheDocument(); + }); + + it('should close when clicking outside', () => { + const { getByRole, getByTestId } = renderDropdown(); + const button = getByRole('button'); + const menu = getByTestId('menu-dropdown'); + + fireEvent.click(button); + expect(menu).toHaveClass('opacity-100'); + + fireEvent.mouseDown(document.body); + expect(menu).toHaveClass('opacity-0'); + }); + + it('should not close when mousedown fires inside the dropdown container', () => { + const { getByRole, getByTestId } = renderDropdown(); + const button = getByRole('button'); + const menu = getByTestId('menu-dropdown'); + + fireEvent.click(button); + expect(menu).toHaveClass('opacity-100'); + + fireEvent.mouseDown(button); + expect(menu).toHaveClass('opacity-100'); + }); + + it('should close when right-clicking outside the dropdown', async () => { + const { getByRole, getByTestId } = renderDropdown(); + const button = getByRole('button'); + const menu = getByTestId('menu-dropdown'); + + fireEvent.click(button); + expect(menu).toHaveClass('opacity-100'); + + fireEvent.contextMenu(document.body); + await waitFor(() => expect(menu).toHaveClass('opacity-0')); + }); + + it('should render correctly when options, menuItems, and dropdownActionsContext are all undefined', () => { + const { getByRole, getByTestId } = render( + + Dropdown + , + ); + + fireEvent.click(getByRole('button')); + const menu = getByTestId('menu-dropdown'); + expect(menu).toHaveClass('scale-100'); + }); }); diff --git a/src/components/infiniteScroll/InfiniteScroll.tsx b/src/components/infiniteScroll/InfiniteScroll.tsx index b474a92..6c75f6f 100644 --- a/src/components/infiniteScroll/InfiniteScroll.tsx +++ b/src/components/infiniteScroll/InfiniteScroll.tsx @@ -66,8 +66,6 @@ const InfiniteScroll = ({ if (hasMoreItems) { handleNextPage(); setShowLoader(true); - } else { - setShowLoader(false); } } }, diff --git a/src/components/infiniteScroll/__test__/InfiniteScroll.test.tsx b/src/components/infiniteScroll/__test__/InfiniteScroll.test.tsx index 601982e..8389998 100644 --- a/src/components/infiniteScroll/__test__/InfiniteScroll.test.tsx +++ b/src/components/infiniteScroll/__test__/InfiniteScroll.test.tsx @@ -76,6 +76,27 @@ describe('InfiniteScroll Component', () => { await waitFor(() => expect(screen.queryByTestId('loader')).not.toBeInTheDocument()); }); + it('does not show loader when isIntersecting is true but hasMoreItems is false', async () => { + vi.stubGlobal( + 'IntersectionObserver', + vi.fn((callback) => ({ + observe: () => { + callback([{ isIntersecting: true }]); + }, + unobserve: vi.fn(), + disconnect: vi.fn(), + })), + ); + + render( + +
Item 1
+
+ ); + + await waitFor(() => expect(screen.queryByTestId('loader')).not.toBeInTheDocument()); + }); + it('should call handleNextPage when scrolled to the bottom', async () => { renderInfiniteScroll(); diff --git a/src/components/input/__test__/Input.test.tsx b/src/components/input/__test__/Input.test.tsx index b459a81..b1a4877 100644 --- a/src/components/input/__test__/Input.test.tsx +++ b/src/components/input/__test__/Input.test.tsx @@ -209,4 +209,14 @@ describe('Input component', () => { const { getByText } = renderInput({ disabled: true }); expect(getByText('Test Label')).toHaveClass('text-gray-40'); }); + + it('should focus email input without setting selectionStart/End', () => { + const { getByRole } = renderInput({ variant: 'email', autofocus: true }); + expect(getByRole('textbox')).toHaveFocus(); + }); + + it('should show 0 count when maxLength is set and value is undefined', () => { + const { getByText } = renderInput({ maxLength: 20, value: undefined }); + expect(getByText('0/20')).toBeInTheDocument(); + }); }); diff --git a/src/components/list/__test__/List.test.tsx b/src/components/list/__test__/List.test.tsx index c1f4f61..d155910 100644 --- a/src/components/list/__test__/List.test.tsx +++ b/src/components/list/__test__/List.test.tsx @@ -306,6 +306,15 @@ describe('List component', () => { expect(mockOnSelectedItemsChanged).toHaveBeenCalled(); }); + it('closes the item context menu when clicking outside the list container', () => { + const { getByText } = renderList(); + + const itemElement = getByText('Item 2'); + fireEvent.contextMenu(itemElement); + + fireEvent.mouseDown(document.body); + }); + it('should toggle selection when Ctrl or Meta key is pressed', () => { const { getByText } = renderList(); diff --git a/src/components/list/__test__/ListHeader.test.tsx b/src/components/list/__test__/ListHeader.test.tsx index 9162b26..2a6c3c1 100644 --- a/src/components/list/__test__/ListHeader.test.tsx +++ b/src/components/list/__test__/ListHeader.test.tsx @@ -85,4 +85,43 @@ describe('ListHeader', () => { expect(mockOnOrderableColumnClicked).not.toHaveBeenCalled(); }); + + it('renders ArrowDown when orderBy direction is DESC', () => { + const { container } = renderListHeader({ + orderBy: { field: 'id', direction: 'DESC' }, + }); + expect(container.querySelector('svg')).toBeInTheDocument(); + }); + + it('renders ArrowUp when orderBy direction is ASC', () => { + const { container } = renderListHeader({ + orderBy: { field: 'id', direction: 'ASC' }, + }); + expect(container.querySelector('svg')).toBeInTheDocument(); + }); + + it('renders columns with buttonDataCy and textDataCy attributes', () => { + const { container } = render( + , + ); + expect(container.querySelector('[data-cy="btn-data-cy"]')).toBeInTheDocument(); + expect(container.querySelector('[data-cy="text-data-cy"]')).toBeInTheDocument(); + }); }); From 036fa76627f4ac7b4c0ae475bf71dc2d40cfe0ec Mon Sep 17 00:00:00 2001 From: jaaaaavier Date: Tue, 31 Mar 2026 13:03:52 +0200 Subject: [PATCH 2/3] Update Avatar.test.tsx.snap --- .../__snapshots__/Avatar.test.tsx.snap | 308 ++++++++++++++++++ 1 file changed, 308 insertions(+) diff --git a/src/components/avatar/__test__/__snapshots__/Avatar.test.tsx.snap b/src/components/avatar/__test__/__snapshots__/Avatar.test.tsx.snap index 876ffa2..ede2e30 100644 --- a/src/components/avatar/__test__/__snapshots__/Avatar.test.tsx.snap +++ b/src/components/avatar/__test__/__snapshots__/Avatar.test.tsx.snap @@ -75,6 +75,81 @@ exports[`Avatar component > Avatar with avatar (user image profile) should rende } `; +exports[`Avatar component > Avatar with empty spaces name should return empty content 1`] = ` +{ + "asFragment": [Function], + "baseElement": +
+
+

+

+
+ , + "container":
+
+

+

+
, + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; + exports[`Avatar component > Avatar with full name (first letters) should render correctly 1`] = ` { "asFragment": [Function], @@ -229,6 +304,85 @@ exports[`Avatar component > Avatar with fullname as null should render correctly } `; +exports[`Avatar component > Avatar with single word name should render correctly 1`] = ` +{ + "asFragment": [Function], + "baseElement": +
+
+

+ J +

+
+
+ , + "container":
+
+

+ J +

+
+
, + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; + exports[`Avatar component > Base Avatar should render correctly 1`] = ` { "asFragment": [Function], @@ -304,6 +458,85 @@ exports[`Avatar component > Base Avatar should render correctly 1`] = ` } `; +exports[`Avatar component > DefaultAvatar handles default parameters 1`] = ` +{ + "asFragment": [Function], + "baseElement": +
+
+

+ JD +

+
+
+ , + "container":
+
+

+ JD +

+
+
, + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; + exports[`Avatar component > LG Avatar should render correctly 1`] = ` { "asFragment": [Function], @@ -379,6 +612,81 @@ exports[`Avatar component > LG Avatar should render correctly 1`] = ` } `; +exports[`Avatar component > PictureAvatar handles default parameters 1`] = ` +{ + "asFragment": [Function], + "baseElement": +
+ +
+ , + "container":
+ +
, + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; + exports[`Avatar component > SM Avatar should render correctly 1`] = ` { "asFragment": [Function], From c414f30d30ccf3d941f21a99245eb78c05e66ac1 Mon Sep 17 00:00:00 2001 From: jaaaaavier Date: Wed, 1 Apr 2026 09:31:19 +0200 Subject: [PATCH 3/3] Update Avatar.test.tsx --- .../avatar/__test__/Avatar.test.tsx | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/components/avatar/__test__/Avatar.test.tsx b/src/components/avatar/__test__/Avatar.test.tsx index 64c9f0c..f0accdb 100644 --- a/src/components/avatar/__test__/Avatar.test.tsx +++ b/src/components/avatar/__test__/Avatar.test.tsx @@ -1,5 +1,5 @@ import { render } from '@testing-library/react'; -import { describe, expect, it } from 'vitest'; +import { describe, expect, it, test } from 'vitest'; import { Avatar } from '../'; import DefaultAvatar from '../components/DefaultAvatar'; import PictureAvatar from '../components/PictureAvatar'; @@ -8,64 +8,64 @@ const FULL_NAME = 'My Internxt'; const IMAGE_SRC = 'https://internxt.com/favicon.ico'; describe('Avatar component', () => { - it('Avatar with full name (first letters) should render correctly', () => { + test('Avatar with full name (first letters) should render correctly', () => { const avatarComponent = render(); expect(avatarComponent).toMatchSnapshot(); }); - it('Avatar with single word name should render correctly', () => { + test('Avatar with single word name should render correctly', () => { const avatarComponent = render(); expect(avatarComponent).toMatchSnapshot(); }); - it('Avatar with empty spaces name should return empty content', () => { + test('Avatar with empty spaces name should return empty content', () => { const avatarComponent = render(); expect(avatarComponent).toMatchSnapshot(); }); - it('Avatar with fullname as null should render correctly with empty letters', () => { + test('Avatar with fullname as null should render correctly with empty letters', () => { const avatarComponent = render(); expect(avatarComponent).toMatchSnapshot(); }); - it('Avatar with avatar (user image profile) should render correctly', () => { + test('Avatar with avatar (user image profile) should render correctly', () => { const avatarComponent = render(); expect(avatarComponent).toMatchSnapshot(); }); - it('XXS Avatar should render correctly', () => { + test('XXS Avatar should render correctly', () => { const avatarComponent = render(); expect(avatarComponent).toMatchSnapshot(); }); - it('XS Avatar should render correctly', () => { + test('XS Avatar should render correctly', () => { const avatarComponent = render(); expect(avatarComponent).toMatchSnapshot(); }); - it('SM Avatar should render correctly', () => { + test('SM Avatar should render correctly', () => { const avatarComponent = render(); expect(avatarComponent).toMatchSnapshot(); }); - it('Base Avatar should render correctly', () => { + test('Base Avatar should render correctly', () => { const avatarComponent = render(); expect(avatarComponent).toMatchSnapshot(); }); - it('LG Avatar should render correctly', () => { + test('LG Avatar should render correctly', () => { const avatarComponent = render(); expect(avatarComponent).toMatchSnapshot(); }); - it('XL Avatar should render correctly', () => { + test('XL Avatar should render correctly', () => { const avatarComponent = render(); expect(avatarComponent).toMatchSnapshot(); }); - it('DefaultAvatar handles default parameters', () => { + test('DefaultAvatar handles default parameters', () => { const avatarComponent = render(); expect(avatarComponent).toMatchSnapshot(); }); - it('PictureAvatar handles default parameters', () => { + test('PictureAvatar handles default parameters', () => { const avatarComponent = render(); expect(avatarComponent).toMatchSnapshot(); });