OpenParable
Skip to content
← Back to skills

uui-unit-testing

Testing & Quality

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.

View on GitHub ↗
QUICK START

How to use this skill

Bring this guide into your coding agent with a prompt tailored to the tool you use.

  1. Open your project in Codex.
  2. Copy and paste the prompt below.
  3. Review files and risks before approving any action.
Prompt to paste
Inspect the Agent Skill at https://github.com/epam/UUI/blob/HEAD/.cursor/skills/unit-testing/SKILL.md and all supporting files. Report provenance, permissions, scripts, dependencies, and security risks. Propose an exact installation into .agents/skills/uui-unit-testing, but wait for my approval before writing files or running scripts.

Copying this prompt does not install or run the skill. Review third-party files before use.

UUI Unit Testing

UUI uses Jest with jsdom for unit testing React components. Tests are located in __tests__ folders within each package.

Test File Location

Test files follow the pattern: **/__tests__/**/*.test.{js,ts,tsx}

Examples:

  • uui/components/buttons/__tests__/Button.test.tsx
  • uui/components/inputs/__tests__/NumericInput.test.tsx
  • uui-core/src/hooks/__tests__/useVirtualList.test.tsx

Test Commands

Run all tests:

yarn test

Run tests in watch mode:

yarn test-watch

Run 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-update

Generate test coverage report:

yarn test-report

Coverage report saves to .reports/unit-tests folder.

TypeScript type checking:

yarn test-typecheck

Windows workaround: If encountering test errors on Windows, use reduced worker count:

yarn test --maxWorkers=2 --testTimeout=10000

You can increase maxWorkers up to 4 if needed.

Using @epam/uui-test-utils

The @epam/uui-test-utils package provides helpers for testing UUI components with proper context.

Key Exports

ExportPurpose
renderSnapshotWithContextAsyncRender with UUI context, returns DocumentFragment for snapshots
renderWithContextAsyncRender with UUI context for interaction testing
renderHookWithContextAsyncTest custom hooks with UUI context
setupComponentForTestSetup component with mocks and setProps helper
screenRe-exported from @testing-library/react
userEventRe-exported from @testing-library/user-event
fireEventRe-exported from @testing-library/react
SvgMockMock for SVG icon imports in snapshots
mockReactPortalsForSnapshotsMock portals for snapshot tests
delay, delayActAsync timing utilities for tests

renderSnapshotWithContextAsync

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();
});

setupComponentForTest

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 unmounting

renderHookWithContextAsync

Renders 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 renderHook from 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();
});

renderWithContextAsync

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();
});

Test Structure

Basic Snapshot Test

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();
        });
    });
});

Interaction Test

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();
});

Snapshot Update Workflow

When UI changes require snapshot updates:

  1. Run tests to see which snapshots fail:

    yarn test
    
  2. Review changes - verify the visual changes are intentional

  3. Update snapshots:

    yarn test-update
    
  4. Commit updated snapshots along with component changes

Important: Always review snapshot diffs before updating. Snapshots should reflect intentional UI changes, not accidental regressions.

Test Environment

  • Test framework: Jest
  • Test environment: jsdom (for React components), node (for build scripts)
  • Test utilities: @epam/uui-test-utils for component testing helpers

Test Coverage

Test coverage is collected from:

  • uui-core
  • uui-components
  • uui
  • epam-promo
  • epam-electric
  • loveship

Run yarn test-report to generate coverage reports.

Common Patterns

Mocking Portals for Snapshots

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();
    });
});

Testing with Icons

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';

Best Practices

  1. Add tests for bug fixes - Prevent regressions
  2. Add tests for new functionality - Ensure components work as expected
  3. Update snapshots when UI changes - Keep snapshots current
  4. Run full test suite before committing - yarn test
  5. Use descriptive test names - Make failures easy to understand
  6. Test user interactions - Not just rendering, but behavior

References

  • Test utilities: @epam/uui-test-utils package
  • 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