Skip to main content

How This App Is Tested

Unit tests here run on Jest with React Testing Library, and the philosophy is RTL's own: test what the operator sees and does, not the component's internals. This lesson gives you the lay of the land — where tests live, what's already mocked for you, and the configuration quirks that will otherwise cost you an afternoon.

Running them

npm run test        # watch mode, for development
npm run test:ci # single pass with coverage — what the pipeline runs

Every PR targeting development runs the suite; results and coverage land in the Azure DevOps PR tabs (details).

Where tests live

Co-located, always: MeasurementToggle.tsx sits next to MeasurementToggle.test.tsx in the same component folder. There is no parallel tests/ tree to keep in sync. Shared mocks live in __mocks__/ at the repo root — ArcGIS modules, Zustand stores, context providers — and the Mocking Playbook catalogs all of them.

What's already set up for you

jest.setup.js runs before every test file and pre-mocks the things almost every component touches: the Next.js router, a signed-in next-auth session, cameraOptionsStore, and Swiper's CSS imports. Your test starts from "a logged-in user on the home route" for free.

For components that need real providers — MUI theme, React Query, session, date pickers — use the shared helper instead of hand-rolling wrappers:

import { renderWithProviders } from 'util/renderWithProviders';

test('renders', () => {
renderWithProviders(<MyComponent />);
});

It builds a fresh QueryClient per test (retries off, cache disabled) so no state leaks between tests.

The config, and its two traps

jest.config.js wraps Next.js's next/jest preset with a few custom entries: jest.polyfills.js runs first (so server-side imports find Request/Response), transformIgnorePatterns lets @arcgis/core and swiper be transformed, and moduleNameMapper routes @/ paths and CSS to stubs.

Trap 1: the ignore patterns that ignore nothing (verified)

testPathIgnorePatterns lists five Notification test files, commented "skip to reduce memory usage." All five paths are stale — the components moved under Notifications/NotificationSettingsForm/, so the patterns match nothing and those tests run in every suite. If a "skipped" Notification test fails your run, that's why. Fix the paths or delete the entries; don't trust the comment.

Trap 2: CSS mapping order matters

^swiper/css.*$ must be mapped before the generic ^.+\.(css)$ rule — both point at scripts/fileTransform.js today, but the specific rule exists because Swiper's CSS imports aren't real files on disk. If you touch moduleNameMapper, keep the specific entry first.

Wrapping up

Watch mode locally, coverage in CI, tests beside their components, a setup file that fakes the world's boring parts, and one shared provider-wrapper. Mind the stale ignore patterns. Now write one: Writing Tests.