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.