Skip to main content

uui-unit-testing

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.

Aller à l'installation

Informations de source

Dépôt
epam/UUI
Dernière activité de la source
4 mars 2026 à 09:47
Langue détectée de SKILL.md
anglais
Étoiles
248
Forks
78

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
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 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:** ```bash yarn test ``` **Run tests in watch mode:** ```bash yarn test-watch ``` **Run a single test file:** ```bash yarn test -- --testPathPattern="Button" ``` Use `--testPathPattern` to match file path, or `--testNamePattern="should render"` to match test names. **Update snapshots:** ```bash yarn test-update ``` **Generate test coverage report:** ```bash yarn test-report ``` Coverage report saves to `.reports/unit-tests` folder. **TypeScript type checking:** ```bash yarn test-typecheck ``` **Windows workaround:** If encountering test errors on Windows, use reduced worker count: ```bash 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 | 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 | ### renderSnapshotWithContextAsync Renders component with UUI context and returns a `DocumentFragment` (via `asFragment()`) for snapshot matching: ```typescript 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: ```typescript 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 ```typescript 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: ```typescript 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 ```typescript 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 ```typescript 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: ```bash yarn test ``` 2. **Review changes** - verify the visual changes are intentional 3. **Update snapshots**: ```bash 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: ```typescript 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: ```typescript 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): ```typescript // @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
Voir sur GitHub