Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .storybook/preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import '../src/community/styles/index.scss';
import '../node_modules/@tedi-design-system/core/tedi-storybook-styles.scss';
import '../src/community/styles/storybook.scss';

import { PrintingProvider } from '../src/tedi/providers/printing-provider/printing-provider';
import { ThemeProvider } from '../src/tedi/providers/theme-provider/theme-provider';
import { useEffect } from 'react';

Expand Down Expand Up @@ -59,13 +60,15 @@ export const decorators: Preview['decorators'] = [

return (
<ThemeProvider theme={theme}>
<PrintingProvider>
{context.componentId === 'components-labelprovider' ? (
<Story />
) : (
<StorybookDecorator>
<Story />
</StorybookDecorator>
)}
</PrintingProvider>
</ThemeProvider>
);
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import cn from 'classnames';
import React from 'react';
import AnimateHeight from 'react-animate-height';

import { usePrint } from '../../../../tedi/helpers';
import { usePrint } from '../../../../tedi/providers/printing-provider/printing-provider';
import { CardContent, CardContentProps } from '../../card';
import { AccordionContext } from '../accordion';
import styles from '../accordion.module.scss';
Expand Down
2 changes: 1 addition & 1 deletion src/community/components/table/table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ import {
import cn from 'classnames';
import React from 'react';

import { usePrint } from '../../../tedi/helpers';
import { useLabels } from '../../../tedi/providers/label-provider';
import { usePrint } from '../../../tedi/providers/printing-provider/printing-provider';
import { IntentionalAny } from '../../types';
import { Card, CardContent } from '../card';
import { PlaceholderProps } from '../placeholder/placeholder';
Expand Down
2 changes: 1 addition & 1 deletion src/community/components/tabs/tabs/tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import cn from 'classnames';
import React from 'react';

import Print, { PrintProps } from '../../../../tedi/components/misc/print/print';
import { usePrint } from '../../../../tedi/helpers';
import { usePrint } from '../../../../tedi/providers/printing-provider/printing-provider';
import { TabsContext } from '../tabs-context';
import TabsItem, { TabsItemProps } from '../tabs-item/tabs-item';
import TabsNav from '../tabs-nav/tabs-nav';
Expand Down
27 changes: 17 additions & 10 deletions src/tedi/components/buttons/collapse/collapse.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,34 @@
import { fireEvent, render, screen } from '@testing-library/react';

import { useBreakpointProps, usePrint } from '../../../helpers';
import { useBreakpointProps } from '../../../helpers';
import { PrintingProvider, usePrint } from '../../../providers/printing-provider/printing-provider';
import { Heading } from '../../base/typography/heading/heading';
import Collapse, { CollapseProps } from './collapse';

import '@testing-library/jest-dom';

jest.mock('../../../helpers', () => ({
useBreakpointProps: jest.fn(),
}));

jest.mock('../../../providers/printing-provider/printing-provider', () => ({
PrintingProvider: ({ children }: { children: React.ReactNode }) => <>{children}</>,
usePrint: jest.fn(),
}));

const getComponent = (props?: Partial<CollapseProps>) =>
render(
<Collapse
id="collapse-1"
title={<Heading>Heading</Heading>}
openText="Näita rohkem"
closeText="Näita vähem"
{...props}
>
Collapse content
</Collapse>
<PrintingProvider>
<Collapse
id="collapse-1"
title={<Heading>Heading</Heading>}
openText="Näita rohkem"
closeText="Näita vähem"
{...props}
>
Collapse content
</Collapse>
</PrintingProvider>
);

describe('Collapse component with breakpoint support', () => {
Expand Down
3 changes: 2 additions & 1 deletion src/tedi/components/buttons/collapse/collapse.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import cn from 'classnames';
import React from 'react';
import AnimateHeight from 'react-animate-height';

import { BreakpointSupport, useBreakpointProps, usePrint } from '../../../helpers';
import { BreakpointSupport, useBreakpointProps } from '../../../helpers';
import { useLabels } from '../../../providers/label-provider';
import { usePrint } from '../../../providers/printing-provider/printing-provider';
import { Icon } from '../../base/icon/icon';
import { Text } from '../../base/typography/text/text';
import { Col, Row, RowProps } from '../../layout/grid';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

import { PrintingProvider, usePrint } from '../../../../../providers/printing-provider/printing-provider';
import { SideNavItem } from './sidenav-item';

jest.mock('../../../../../providers/printing-provider/printing-provider', () => ({
PrintingProvider: ({ children }: { children: React.ReactNode }) => <>{children}</>,
usePrint: jest.fn(),
}));

const renderWithProviders = (ui: React.ReactElement) => render(<PrintingProvider>{ui}</PrintingProvider>);

describe('SideNavItem', () => {
const defaultProps = {
children: 'Test Item',
Expand All @@ -15,11 +23,12 @@ describe('SideNavItem', () => {

beforeEach(() => {
jest.clearAllMocks();
(usePrint as jest.Mock).mockReturnValue(false);
});

describe('basic item (no children)', () => {
test('renders correctly', () => {
render(<SideNavItem {...defaultProps} />);
renderWithProviders(<SideNavItem {...defaultProps} />);
expect(screen.getByText('Test Item')).toBeInTheDocument();
expect(screen.getByRole('menuitem')).toBeInTheDocument();
});
Expand All @@ -35,40 +44,42 @@ describe('SideNavItem', () => {
const user = userEvent.setup();
const onItemClick = jest.fn();

render(<SideNavItem {...defaultProps} onItemClick={onItemClick} subItems={[{ children: 'Child' }]} />);
renderWithProviders(
<SideNavItem {...defaultProps} onItemClick={onItemClick} subItems={[{ children: 'Child' }]} />
);

await user.click(screen.getByText('Test Item'));
expect(onItemClick).not.toHaveBeenCalled();
});

test('applies active styles when isActive=true', () => {
render(<SideNavItem {...defaultProps} isActive />);
renderWithProviders(<SideNavItem {...defaultProps} isActive />);
expect(screen.getByRole('menuitem').parentElement).toHaveClass('tedi-sidenav__item--current');
});
});

describe('collapsed mode (isCollapsed = true)', () => {
test('uses aria-label when collapsed', () => {
render(<SideNavItem {...defaultProps} isCollapsed />);
renderWithProviders(<SideNavItem {...defaultProps} isCollapsed />);
expect(screen.getByRole('menuitem')).toHaveAttribute('aria-label', 'Test Item');
});

test('renders SideNavDropdown when has children & collapsed', () => {
render(<SideNavItem {...defaultProps} isCollapsed subItems={[{ children: 'Sub' }]} />);
renderWithProviders(<SideNavItem {...defaultProps} isCollapsed subItems={[{ children: 'Sub' }]} />);
expect(screen.getByText('Test Item')).toBeInTheDocument();
expect(screen.getByText(/expand_more/i)).toBeInTheDocument();
});
});

describe('items with children', () => {
test('opens subitems when isDefaultOpen=true', () => {
render(<SideNavItem {...defaultProps} subItems={[{ children: 'Visible Child' }]} isDefaultOpen />);
renderWithProviders(<SideNavItem {...defaultProps} subItems={[{ children: 'Visible Child' }]} isDefaultOpen />);

expect(screen.getByText('Visible Child')).toBeInTheDocument();
});

test('renders subItemGroups with heading', () => {
render(
renderWithProviders(
<SideNavItem
{...defaultProps}
isDefaultOpen
Expand All @@ -86,7 +97,9 @@ describe('SideNavItem', () => {
});

test('uses clickable Link + separate Collapse when href exists (level 1)', () => {
render(<SideNavItem {...defaultProps} href="/dashboard" subItems={[{ children: 'Dash' }]} isDefaultOpen />);
renderWithProviders(
<SideNavItem {...defaultProps} href="/dashboard" subItems={[{ children: 'Dash' }]} isDefaultOpen />
);

const link = screen.getByRole('menuitem', { name: /Test Item/ });
expect(link).toHaveAttribute('href', '/dashboard');
Expand All @@ -96,7 +109,7 @@ describe('SideNavItem', () => {
test('keyboard toggle works on Collapse button (Enter/Space)', async () => {
const user = userEvent.setup();

render(<SideNavItem {...defaultProps} subItems={[{ children: 'Child' }]} />);
renderWithProviders(<SideNavItem {...defaultProps} subItems={[{ children: 'Child' }]} />);

const collapseButton = screen.getByRole('button', {
name: 'sidenav.toggleSubmenuChildren',
Expand All @@ -112,7 +125,7 @@ describe('SideNavItem', () => {
test('keyboard toggle works with Space key on non-linked parent', async () => {
const user = userEvent.setup();

render(<SideNavItem {...defaultProps} subItems={[{ children: 'Space Child' }]} />);
renderWithProviders(<SideNavItem {...defaultProps} subItems={[{ children: 'Space Child' }]} />);

await user.tab();
await user.keyboard(' ');
Expand All @@ -123,7 +136,7 @@ describe('SideNavItem', () => {

describe('level > 1 (nested)', () => {
test('renders bullet instead of chevron on nested parents', () => {
render(
renderWithProviders(
<SideNavItem {...defaultProps} level={1} isDefaultOpen>
<SideNavItem subItems={[{ children: 'Deep' }]}>Nested Parent</SideNavItem>
</SideNavItem>
Expand All @@ -134,7 +147,7 @@ describe('SideNavItem', () => {
});

test('handles accessibility attributes', () => {
render(
renderWithProviders(
<SideNavItem {...defaultProps} isActive={true} isCollapsed={true}>
Active Item
</SideNavItem>
Expand All @@ -146,7 +159,7 @@ describe('SideNavItem', () => {
});

test('handles accessibility attributes', () => {
render(
renderWithProviders(
<SideNavItem {...defaultProps} isActive={true} isCollapsed={true}>
Active Item
</SideNavItem>
Expand All @@ -165,7 +178,7 @@ describe('SideNavItem', () => {
subItems: [{ children: 'Deep Item', icon: 'deep-icon' }],
},
];
render(<SideNavItem {...defaultProps} subItems={subItems} isDefaultOpen={true} />);
renderWithProviders(<SideNavItem {...defaultProps} subItems={subItems} isDefaultOpen={true} />);
expect(screen.getByText('Deep Item')).toBeInTheDocument();
const nestedItem = screen.getByText('Deep Item').closest('li');
const icon = nestedItem?.querySelector('span[data-name="icon"]');
Expand All @@ -175,7 +188,7 @@ describe('SideNavItem', () => {
test('does not toggle on unrelated keys', async () => {
const user = userEvent.setup();

render(<SideNavItem {...defaultProps} subItems={[{ children: 'Hidden Child' }]} isDefaultOpen />);
renderWithProviders(<SideNavItem {...defaultProps} subItems={[{ children: 'Hidden Child' }]} isDefaultOpen />);
expect(screen.getByText('Hidden Child')).toBeInTheDocument();

await user.tab();
Expand All @@ -185,7 +198,7 @@ describe('SideNavItem', () => {
});

test('sets aria attributes for linked parent with children', () => {
render(<SideNavItem {...defaultProps} href="/parent" subItems={[{ children: 'Child' }]} />);
renderWithProviders(<SideNavItem {...defaultProps} href="/parent" subItems={[{ children: 'Child' }]} />);

const link = screen.getByRole('menuitem', { name: /test item/i });
expect(link).toHaveAttribute('aria-haspopup', 'true');
Expand All @@ -196,7 +209,7 @@ describe('SideNavItem', () => {
test('updates dropdown open state when SideNavDropdown opens', async () => {
const user = userEvent.setup();

render(<SideNavItem {...defaultProps} isCollapsed subItems={[{ children: 'Child' }]} />);
renderWithProviders(<SideNavItem {...defaultProps} isCollapsed subItems={[{ children: 'Child' }]} />);

await user.click(screen.getByText('Test Item'));
});
Expand Down
Loading
Loading