| name | uui-unit-testing |
|---|---|
| description | Helps write unit tests for UUI components using Jest, jsdom, and @epam/uui-test-utils. Use when writing unit tests for UUI components, updating snapshots, running Jest tests, or working with test utilities. |
UUI uses Jest with jsdom for unit testing React components. Tests are located in __tests__ folders within each package.
Test files follow the pattern: **/__tests__/**/*.test.{js,ts,tsx}
Examples:
uui/components/buttons/__tests__/Button.test.tsxuui/components/inputs/__tests__/NumericInput.test.tsxuui-core/src/hooks/__tests__/useVirtualList.test.tsx
Run all tests:
yarn testRun tests in watch mode:
yarn test-watchRun a single test file:
yarn test -- --testPathPattern="Button"Use --testPathPattern to match file path, or --testNamePattern="should render" to match test names.
Update snapshots:
yarn test-updateGenerate test coverage report:
yarn test-reportCoverage report saves to .reports/unit-tests folder.
TypeScript type checking:
yarn test-typecheckWindows workaround: If encountering test errors on Windows, use reduced worker count:
yarn test --maxWorkers=2 --testTimeout=10000You can increase maxWorkers up to 4 if needed.
The @epam/uui-test-utils package provides helpers for testing UUI components with proper context.
| Export | Purpose |
|---|---|
renderSnapshotWithContextAsync |
Render with UUI context, returns DocumentFragment for snapshots |
renderWithContextAsync |
Render with UUI context for interaction testing |
renderHookWithContextAsync |
Test custom hooks with UUI context |
setupComponentForTest |
Setup component with mocks and setProps helper |
screen |
Re-exported from @testing-library/react |
userEvent |
Re-exported from @testing-library/user-event |
fireEvent |
Re-exported from @testing-library/react |
SvgMock |
Mock for SVG icon imports in snapshots |
mockReactPortalsForSnapshots |
Mock portals for snapshot tests |
delay, delayAct |
Async timing utilities for tests |
Renders component with UUI context and returns a DocumentFragment (via asFragment()) for snapshot matching:
import { renderSnapshotWithContextAsync } from '@epam/uui-test-utils';
import { NumericInput } from '../NumericInput';
it('should be rendered with minimum props', async () => {
const tree = await renderSnapshotWithContextAsync(
<NumericInput value={null} onValueChange={jest.fn} min={0} max={50} />
);
expect(tree).toMatchSnapshot();
});Use for testing controlled components (e.g. value + onValueChange). Provides setProps to update props without unmounting, and mocks for callback assertions. Call context.current.setProperty(name, value) in callback mocks to simulate controlled updates:
import { setupComponentForTest, screen, fireEvent } from '@epam/uui-test-utils';
import { TextInput } from '@epam/uui';
interface TestComponentProps {
value?: string;
onValueChange?: (value: string) => void;
}
const { mocks, setProps } = await setupComponentForTest<TestComponentProps>(
(context) => ({
value: 'initial',
onValueChange: jest.fn().mockImplementation((newValue) => {
context.current.setProperty('value', newValue);
}),
}),
(props) => <TextInput value={props.value} onValueChange={props.onValueChange} />,
);
const input = screen.queryByRole('textbox');
fireEvent.change(input, { target: { value: 'updated' } });
expect(mocks.onValueChange).toHaveBeenLastCalledWith('updated');
setProps({ value: 'external' }); // Update props without unmountingRenders a hook with UUI context. Returns { result, rerender, unmount, svc }:
- result — current hook return value (use
result.current) - svc — UUI services (api, modals, router, etc.) for mocking or assertions
- rerender, unmount — same as
renderHookfrom Testing Library
import { renderHookWithContextAsync, act } from '@epam/uui-test-utils';
it('should use DataSource view', async () => {
const dataSource = useArrayDataSource({ items: [...], getId: (i) => i.id }, []);
const { result, svc } = await renderHookWithContextAsync(() =>
dataSource.useView({}, () => {}, {})
);
const rows = result.current.getVisibleRows();
expect(rows).toHaveLength(5);
// svc.api, svc.uuiModals, etc. available for mocks
});
it('should test custom hook with services', async () => {
const { result, svc } = await renderHookWithContextAsync(useMyHook);
act(() => result.current.doSomething());
expect(svc.uuiAnalytics.sendEvent).toHaveBeenCalled();
});Renders component with UUI context for interaction testing:
import { renderWithContextAsync, screen, userEvent } from '@epam/uui-test-utils';
import { Tag } from '../Tag';
it('should call onClear callback', async () => {
const onClearMock = jest.fn();
await renderWithContextAsync(
<Tag caption="Test badge" onClear={onClearMock} />
);
const clearButton = await screen.findByRole('button', { name: /remove tag/i });
await userEvent.click(clearButton);
expect(onClearMock).toHaveBeenCalled();
});import React from 'react';
import { ComponentName } from '../ComponentName';
import { renderSnapshotWithContextAsync } from '@epam/uui-test-utils';
describe('ComponentName', () => {
describe('snapshots', () => {
it('should be rendered with minimum props', async () => {
const tree = await renderSnapshotWithContextAsync(<ComponentName />);
expect(tree).toMatchSnapshot();
});
it('should be rendered with maximum props', async () => {
const tree = await renderSnapshotWithContextAsync(
<ComponentName prop1="value1" prop2="value2" />
);
expect(tree).toMatchSnapshot();
});
});
});import { renderWithContextAsync, screen, userEvent } from '@epam/uui-test-utils';
it('should handle user interaction', async () => {
const onActionMock = jest.fn();
await renderWithContextAsync(
<ComponentName onAction={onActionMock} />
);
const button = await screen.findByRole('button');
await userEvent.click(button);
expect(onActionMock).toHaveBeenCalled();
});When UI changes require snapshot updates:
-
Run tests to see which snapshots fail:
yarn test -
Review changes - verify the visual changes are intentional
-
Update snapshots:
yarn test-update
-
Commit updated snapshots along with component changes
Important: Always review snapshot diffs before updating. Snapshots should reflect intentional UI changes, not accidental regressions.
- Test framework: Jest
- Test environment: jsdom (for React components), node (for build scripts)
- Test utilities:
@epam/uui-test-utilsfor component testing helpers
Test coverage is collected from:
uui-coreuui-componentsuuiepam-promoepam-electricloveship
Run yarn test-report to generate coverage reports.
Use the built-in helper instead of manual mocking:
import { mockReactPortalsForSnapshots, renderSnapshotWithContextAsync } from '@epam/uui-test-utils';
describe('ComponentWithPortal', () => {
mockReactPortalsForSnapshots();
it('should render correctly', async () => {
const tree = await renderSnapshotWithContextAsync(<MyModal />);
expect(tree).toMatchSnapshot();
});
});Use SvgMock from test utils for icon props in snapshots:
import { SvgMock, renderSnapshotWithContextAsync } from '@epam/uui-test-utils';
it('should render with icon', async () => {
const tree = await renderSnapshotWithContextAsync(
<Component icon={ SvgMock } />
);
expect(tree).toMatchSnapshot();
});For specific icon imports (when behavior depends on the icon):
// @ts-expect-error
import { ReactComponent as CalendarIcon } from '@epam-assets/icons/action-calendar-fill.svg';- Add tests for bug fixes - Prevent regressions
- Add tests for new functionality - Ensure components work as expected
- Update snapshots when UI changes - Keep snapshots current
- Run full test suite before committing -
yarn test - Use descriptive test names - Make failures easy to understand
- Test user interactions - Not just rendering, but behavior
- Test utilities:
@epam/uui-test-utilspackage - Example snapshot test:
uui/components/inputs/__tests__/NumericInput.test.tsx - Example interaction test:
uui/components/widgets/__tests__/Tag.test.tsx - Example setupComponentForTest:
app/src/docs/_examples/testing/__tests__/testComponent.test.tsx - Example renderHookWithContextAsync:
uui-core/src/data/forms/__tests__/useForm.test.tsx - Testing documentation: https://uui.epam.com/documents?id=testing-getting-started&mode=doc&isSkin=null&category=testing