Skip to content

Commit 36afafe

Browse files
authored
Merge pull request #97 from internxt/feat/update-test-coverage-4
[PB-3528]:feat/update coverage for components
2 parents f9c0887 + 09997cf commit 36afafe

6 files changed

Lines changed: 160 additions & 0 deletions

File tree

src/components/modalTransparent/__test__/TransparentModal.test.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,4 +130,11 @@ describe('TransparentModal Component', () => {
130130
const container = document.querySelector('.fixed.inset-0.z-50');
131131
expect(container).toHaveClass('pointer-events-none');
132132
});
133+
134+
it('should not call onClose when clicking inside the modal content', () => {
135+
renderTransparentModal();
136+
const modalContent = screen.getByText('Modal Content');
137+
fireEvent.mouseDown(modalContent);
138+
expect(onCloseMock).not.toHaveBeenCalled();
139+
});
133140
});

src/components/popover/__test__/Popover.test.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,4 +151,12 @@ describe('Popover', () => {
151151
fireEvent.mouseDown(button);
152152
expect(stopPropagationSpy).toHaveBeenCalled();
153153
});
154+
155+
it('aligns panel to the left when align is left', async () => {
156+
const { getByText, container } = renderPopover({ align: 'left' });
157+
fireEvent.click(getByText('Open Popover'));
158+
await waitFor(() => expect(getByText('Popover Content')).toBeInTheDocument());
159+
const panel = container.querySelector('.left-0.origin-top-left');
160+
expect(panel).toBeInTheDocument();
161+
});
154162
});

src/components/sidenav/__test__/Sidenav.test.tsx

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,4 +287,45 @@ describe('Sidenav Component', () => {
287287
expect(onToggleCollapse).toHaveBeenCalled();
288288
});
289289
});
290+
291+
it('renders storage without upgradeLabel', () => {
292+
const { queryByText } = renderSidenav({
293+
storage: {
294+
usage: '1 GB',
295+
limit: '5 GB',
296+
percentage: 20,
297+
onUpgradeClick: vi.fn(),
298+
isLoading: false,
299+
},
300+
});
301+
expect(queryByText('1 GB')).toBeInTheDocument();
302+
expect(queryByText('Upgrade')).not.toBeInTheDocument();
303+
});
304+
305+
it('renders storage with default isLoading (shows skeleton)', () => {
306+
const { container, queryByText } = renderSidenav({
307+
storage: {
308+
usage: '1 GB',
309+
limit: '5 GB',
310+
percentage: 20,
311+
onUpgradeClick: vi.fn(),
312+
},
313+
});
314+
expect(queryByText('1 GB')).not.toBeInTheDocument();
315+
const skeletons = container.querySelectorAll('.animate-pulse');
316+
expect(skeletons.length).toBeGreaterThan(0);
317+
});
318+
319+
it('renders header with suiteLauncher', () => {
320+
const MockIcon = React.forwardRef<SVGSVGElement, { size?: number | string }>(({ size = 20 }, ref) => (
321+
<svg ref={ref} width={size} height={size} />
322+
));
323+
const { getByTestId } = renderSidenav({
324+
suiteLauncher: {
325+
suiteArray: [{ icon: <MockIcon />, title: 'Drive', onClick: vi.fn() }],
326+
soonText: 'Soon',
327+
},
328+
});
329+
expect(getByTestId('popover-button')).toBeInTheDocument();
330+
});
290331
});
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import React from 'react';
2+
import { render } from '@testing-library/react';
3+
import { describe, it, expect } from 'vitest';
4+
import SidenavItem from '../SidenavItem';
5+
6+
const MockIcon = React.forwardRef<SVGSVGElement, { size?: number | string; weight?: string }>(({ size = 20 }, ref) => (
7+
<svg ref={ref} data-testid="mock-icon" width={size} height={size} />
8+
));
9+
MockIcon.displayName = 'MockIcon';
10+
11+
describe('SidenavItem Component', () => {
12+
it('renders correctly with default optional props', () => {
13+
const { getByText, getByTestId } = render(<SidenavItem label="Dashboard" Icon={MockIcon} />);
14+
15+
expect(getByText('Dashboard')).toBeInTheDocument();
16+
expect(getByTestId('mock-icon')).toBeInTheDocument();
17+
18+
// Default inactive state includes text-gray-80
19+
expect(getByText('Dashboard').parentElement).toHaveClass('text-gray-80');
20+
});
21+
22+
it('renders subsection with correct styling', () => {
23+
const { getByRole } = render(<SidenavItem label="Settings" Icon={MockIcon} subsection={true} />);
24+
const button = getByRole('button');
25+
expect(button).toHaveClass('pl-5');
26+
});
27+
});

src/components/suiteLauncher/__test__/SuiteLauncher.test.tsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,27 @@ describe('SuiteLauncher', () => {
5959
fireEvent.click(screen.getByText('App 3'));
6060
expect(onClick3).toHaveBeenCalled();
6161
});
62+
63+
it('shows default "Soon" text when soonText is not provided', () => {
64+
const suiteArray = [
65+
{ icon: <span />, title: 'App Soon', onClick: vi.fn(), availableSoon: true },
66+
];
67+
render(<SuiteLauncher suiteArray={suiteArray} />);
68+
fireEvent.click(screen.getByTestId('popover-button'));
69+
expect(screen.getByText('Soon')).toBeInTheDocument();
70+
});
71+
72+
it('renders non-JSX icon as-is when it is not a valid React element', () => {
73+
const suiteArray = [
74+
{ icon: 'not-an-element' as any, title: 'App Raw', onClick: vi.fn() },
75+
];
76+
render(<SuiteLauncher suiteArray={suiteArray} />);
77+
fireEvent.click(screen.getByTestId('popover-button'));
78+
expect(screen.getByText('App Raw')).toBeInTheDocument();
79+
});
80+
81+
it('renders with align left', () => {
82+
render(<SuiteLauncher suiteArray={[]} align="left" />);
83+
expect(screen.getByTestId('popover-button')).toBeInTheDocument();
84+
});
6285
});

src/hooks/__test__/useHotKeys.test.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,58 @@ describe('useHotkeys', () => {
6969
unmount();
7070
expect(removeEventListenerSpy).toHaveBeenCalledWith('keydown', expect.any(Function));
7171
});
72+
73+
it('should not call handler when key is pressed in an input element', () => {
74+
const callback = vi.fn();
75+
renderHook(() => useHotkeys({ a: callback }));
76+
77+
const input = document.createElement('input');
78+
document.body.appendChild(input);
79+
input.focus();
80+
81+
fireKeyDown('a');
82+
expect(callback).not.toHaveBeenCalled();
83+
84+
document.body.removeChild(input);
85+
});
86+
87+
it('should call handler for Escape even when focus is in an input element', () => {
88+
const escapeCallback = vi.fn();
89+
renderHook(() => useHotkeys({ escape: escapeCallback }));
90+
91+
const input = document.createElement('input');
92+
document.body.appendChild(input);
93+
input.focus();
94+
95+
fireKeyDown('Escape');
96+
expect(escapeCallback).toHaveBeenCalledOnce();
97+
98+
document.body.removeChild(input);
99+
});
100+
101+
it('should not call handler when key is pressed in a textarea element', () => {
102+
const callback = vi.fn();
103+
renderHook(() => useHotkeys({ r: callback }));
104+
105+
const textarea = document.createElement('textarea');
106+
document.body.appendChild(textarea);
107+
textarea.focus();
108+
109+
fireKeyDown('r');
110+
expect(callback).not.toHaveBeenCalled();
111+
112+
document.body.removeChild(textarea);
113+
});
114+
115+
it('should handle null activeElement gracefully and still trigger handler', () => {
116+
const callback = vi.fn();
117+
renderHook(() => useHotkeys({ a: callback }));
118+
119+
const activeElementSpy = vi.spyOn(document, 'activeElement', 'get').mockReturnValue(null);
120+
121+
fireKeyDown('a');
122+
expect(callback).toHaveBeenCalledOnce();
123+
124+
activeElementSpy.mockRestore();
125+
});
72126
});

0 commit comments

Comments
 (0)