Test Tools · Unit & Integration Testing

Jest & Vitest

JavaScript unit testing: Jest for React and Node.js, Vitest for Vite projects. Fast, modern, and developer-friendly.

Overview

Jest, created by Meta (Facebook) in 2014, is the most popular JavaScript testing framework. It provides a zero-config testing experience with built-in mocking, coverage reporting, and snapshot testing. Jest is the default choice for React applications and widely used for Node.js backend testing.

Vitest, created in 2021 by the Vite team, is a next-generation testing framework designed for Vite-based projects. It is API-compatible with Jest but significantly faster thanks to Vite's native ESM andesbuild-based bundling. Vitest is becoming the default for new Vue, Svelte, and Vite-based projects.

What it's used for

Jest/Vitest are essential for:

  • JavaScript/TypeScript unit testing: The standard frameworks for testing JS/TS code.
  • React component testing: Jest + React Testing Library is the industry standard.
  • Node.js API testing: Test Express, Fastify, and NestJS endpoints.
  • Snapshot testing: Catch unexpected UI changes in component output.

Pros & Cons

Pros

  • Zero-config setup for most projects
  • Built-in mocking, coverage, and snapshot testing
  • Fast parallel execution
  • Excellent TypeScript support
  • Massive ecosystem and community

Cons

  • JavaScript/TypeScript only
  • Jest can be slow for very large projects (Vitest fixes this)
  • ESM support in Jest has been historically problematic (improving in Jest 30)
  • Snapshot testing can create large, noisy diffs
  • Configuration can be complex for non-standard setups

Platforms & Integrations

Jest and Vitest run on Windows, macOS, and Linux via Node.js. They integrate with all JavaScript build tools and CI platforms.

Windows macOS Linux JavaScript TypeScript Node.js React Vue Svelte Angular Vite Webpack GitHub Actions GitLab CI Jenkins Azure DevOps

Pricing

TierCostIncludes
Open SourceFreeFull framework, all features, community support

NZ Context

Jest is ubiquitous in NZ JavaScript and React teams. Every frontend developer and full-stack JS developer in NZ knows Jest. Vitest is rapidly gaining adoption among NZ teams using Vite, particularly Vue and Svelte projects. For NZ testers working in JavaScript environments, Jest proficiency is essential; Vitest is a valuable addition for Vite-based projects.

Alternatives

  • Mocha — More flexible but requires more configuration.
  • AVA — Minimalist test runner with parallel execution by default.
  • Node.js Test Runner — Built-in since Node.js 18. Zero dependencies for simple cases.

When to choose Jest / Vitest

A quick decision guide for NZ teams evaluating unit testing options.

Choose Jest / Vitest when… Choose something else when… Combine with…
Your project is JavaScript or TypeScript — React, Vue, Svelte, Node.js, or a Vite-based SPA Your stack is Python, .NET, Java, or Go — use pytest, xUnit, JUnit, or Go's built-in test package instead MSW (Mock Service Worker) — intercepts HTTP at the network layer so components under test behave exactly as in production
You need fast CI feedback on a large JS codebase — Vitest's esbuild pipeline can cut Jest's build time by 40–70% on TypeScript-heavy projects You need full browser rendering, accessibility checks, or multi-tab session testing — Jest/Vitest run in jsdom, not a real browser; use Playwright instead React Testing Library — encourages testing what the user sees rather than implementation details; pairs with both Jest and Vitest
Your team is greenfield on Vite (Nuxt 3, SvelteKit, Astro, or modern React) — Vitest reuses the Vite config with zero extra transformation setup Your project uses Create React App or Angular's default Jest config and you'd need to eject or reconfigure CI — the migration overhead outweighs the gains Playwright — covers E2E and cross-browser journeys that Jest/Vitest cannot; the two layers are complementary, not competing
You are testing pure logic: date formatters, currency converters, input validators, reducers, or business-rule functions with no DOM or network dependencies You are writing API contract tests against a live service — use Pact for consumer-driven contract testing; Jest/Vitest handle the unit layer within each service Istanbul / v8 coverage — built into both Jest and Vitest; pipe output to Codecov or SonarQube for team-wide coverage visibility in CI

What I would do

Practitioner judgment on tool adoption, team onboarding, and when to swap.

If…
I were joining a CloudBooks squad that had no unit tests at all — just Cypress E2E suites that took 25 minutes to run — and I needed to make the case for introducing Jest
I would…
Pick the three most-changed utility functions from the last sprint — the ones devs keep breaking by accident — and write a Jest test file for each. Run them in a CI step that completes in under 10 seconds. Once the team sees red-to-green feedback in the same terminal as their local build, they self-convert. Never pitch unit testing as a philosophy; pitch it as "you'll stop breaking the date formatter."
If…
I were a QA engineer at ListRight migrating a large React codebase from webpack to Vite — the kind of project where Jest's Babel pipeline suddenly breaks because modules that worked before no longer resolve the same way
I would…
Treat the webpack-to-Vite migration as the natural trigger to switch to Vitest at the same time. The two migrations share the same root cause — module resolution — so fixing both in one PR reduces overall disruption compared to two separate changes weeks apart. I'd run jest --listTests to get the full test inventory, migrate files directory by directory (starting with pure utility tests, leaving component tests for last), and keep a running count of passing tests as a migration health metric. I would not migrate everything at once; parallel running Jest and Vitest on different directories is a valid intermediate state for 1–2 weeks.
If…
I were working on a government digital transformation project at TransitNZ where a junior developer had written 80 test files using jest.mock() for every dependency — including mocking React components that are simply wrappers around a heading tag — and the suite was passing but a production bug had slipped through anyway
I would…
Run a coverage diff against the actual bug: find the code path the bug lived on, check which test was supposed to cover it, and show the team exactly why the mock meant the test never exercised real behaviour. Then introduce MSW for the 10–15 component tests that interact with the API — not all 80 at once. Use those as the template: "this is what an integration test looks like when you don't mock the component's children." Refactoring 80 test files in a sprint is a way to destroy team morale; replacing the worst 10 and letting the pattern spread organically is how it actually sticks.

The bottom line: A Jest/Vitest test suite that mocks everything is a liability disguised as confidence. The right signal is not how many tests pass — it is how many times your test suite has caught a real bug before a user did. If the answer is "rarely," your mock boundaries are in the wrong place.

Interview questions

Questions you are likely to get if you list Jest or Vitest on your CV — with what interviewers are really testing for.

What is the difference between a unit test and an integration test, and where do Jest and Vitest sit in that picture?

What they’re really testing: Whether you understand the purpose and boundaries of each test layer, not just that you can recite a definition.

Strong answer covers: Unit tests exercise pure logic in isolation (no network, no DOM, no shared state); integration tests wire real components together and intercept at the network layer using something like MSW; Jest/Vitest operate at both layers. Mention a concrete NZ workplace example — e.g. unit-testing a GST calculation function at a NZ payroll company vs. integration-testing the form that submits it.

When would you choose Vitest over Jest for a new project, and when would you stick with Jest?

What they’re really testing: Whether you make tool decisions based on project context rather than hype or personal preference.

Strong answer covers: Vitest is the natural choice for Vite-based stacks (SvelteKit, Nuxt 3, modern React with Vite) because it reuses the same config and transformation pipeline with no extra Babel overhead; Jest is the right call when the project is already on webpack or CRA, or when the team has deep Jest muscle memory and tooling. For NZ government or enterprise projects still on Angular or older React, switching for its own sake carries real risk with little reward.

You’re a QA engineer at a Wellington SaaS company. Your Jest suite passes on every developer’s machine but fails intermittently in GitHub Actions CI. How do you approach diagnosing this?

What they’re really testing: Whether you can systematically investigate environment differences rather than guessing or blaming the CI platform.

Strong answer covers: Check Node.js version parity between local and CI; look for tests relying on timing (fake timers with jest.useFakeTimers() / vi.useFakeTimers() are a common fix); check for shared state between test files that passes in serial locally but breaks in Jest’s parallel workers; inspect the CI logs for the specific error message rather than re-running blind. Mention --runInBand as a diagnostic step to isolate parallelism as the cause.

A developer on your team has written 60 test files where jest.mock() is used to mock almost every dependency, including simple utility functions. The suite shows 90% coverage and all tests pass, but a production bug still slipped through. How do you explain what went wrong and what you’d change?

What they’re really testing: Whether you understand the difference between test coverage as a metric and test coverage as genuine confidence in the software.

Strong answer covers: Over-mocking means tests are verifying that mocks behave like mocks, not that real code works; coverage numbers count executed lines, not meaningful assertions. Fix approach: trace the production bug back to the code path, show which mock hid it, introduce MSW to intercept at the network layer for the component tests that touch the API, and let that pattern replace the worst offenders gradually rather than rewriting all 60 files at once. Reference that this pattern commonly surfaces in NZ fintech or health-sector projects where test suites look mature but real incidents still occur.

How would you structure a Jest or Vitest test suite for a React application that handles personally identifiable information — for example, a patient portal at a NZ health provider?

What they’re really testing: Whether you think about data privacy and test safety at an architectural level, not just whether you can write a describe block.

Strong answer covers: Never use real PII in test fixtures — generate synthetic data with a library like @faker-js/faker seeded for repeatability; use MSW to return controlled fake responses at the network layer so no real API or database is touched; store no PII in __snapshots__ files that get committed to git. Mention the NZ Privacy Act 2020 obligation to minimise data collection and that test data seeded with real names or NHI numbers could constitute a data breach if the repo is ever leaked.

Learn more

Unit vs Integration: The Architecture Decision

The Testing Pyramid

The testing pyramid is not just a metaphor — it describes cost and speed. Unit tests sit at the base: they are fast (milliseconds each), cheap to write, and run in complete isolation. Integration tests sit in the middle: they are slower because they wire real components together, but they catch bugs that unit tests cannot. End-to-end tests sit at the top: they are the slowest and most expensive, but they verify real user journeys against a real browser. Jest and Vitest operate at the bottom two layers.

The Critical Architectural Mistake

The most common mistake teams make is unit-testing UI components by mocking everything around them. Consider a test that mocks fetch, mocks the React component's child components, and mocks the state store — then asserts that the mocked state was called with the mocked data. That test is not testing your software. It is testing that your mocks behave like mocks. When a real bug appears — a mismatched API field, a missing loading state, an uncaught error — those tests will stay green while users see broken screens.

The warning sign: if your test file has more lines of jest.mock() / vi.mock() than actual assertions, you are over-mocking.

The Right Boundary

Draw the boundary at the network layer, not at the component boundary. Use Mock Service Worker (MSW) to intercept HTTP requests at the network level and return controlled responses. This lets your component, your state management, your error handlers, and your rendering logic all run as they would in production — only the actual HTTP call is intercepted. The component does not know it is in a test. That is the right level of isolation.

What to Test at Each Layer

Layer What to Test Tool
Unit Pure logic with no side effects: date formatters, currency converters, input validators, reducers, state machines, business logic functions Jest / Vitest (no mocks needed)
Integration React/Vue components with real API calls, form submission flows, loading and error states, error boundary behaviour Jest / Vitest + MSW (intercept at network)
E2E Complete user journeys, cross-page flows, real authentication, payment flows, file uploads Playwright / Cypress (real browser)

A practical rule: if the function you are testing takes inputs and returns an output with no network calls, no DOM, and no shared state, unit test it with no mocks. If it touches a component that calls an API, integration-test it with MSW. If it spans multiple pages or requires a logged-in session, E2E-test it with Playwright.

Vitest vs Jest in 2026

When to Choose Vitest

Choose Vitest when your project is Vite-based: Nuxt 3, SvelteKit, Astro, or a modern React setup using Vite instead of webpack. The key advantage is that Vitest reuses your existing Vite config and transformation pipeline. There is no separate Babel config to maintain, no separate TypeScript transformer to configure, and no version mismatch between how your dev server handles imports and how your tests handle imports. What runs in the browser runs in tests — the same plugins, the same path aliases, the same environment variables.

Vitest is also meaningfully faster on large codebases. Because it uses esbuild for transformation (like Vite), it avoids the Babel overhead that slows Jest down on TypeScript-heavy projects.

When to Choose Jest

Choose Jest when your project uses webpack or Create React App, when your team has deep Jest ecosystem knowledge and tooling already built around it, or when you rely on complex mocking patterns with jest.mock(). Jest's ecosystem is larger — more third-party matchers, more integrations, more Stack Overflow answers. For teams on legacy Angular or older React setups, Jest is already embedded in the CI pipeline and developer muscle memory. Switching for its own sake is rarely worth the disruption.

Migrating from Jest to Vitest

The migration is mostly mechanical: replace import { describe, it, expect } from '@jest/globals' with import { describe, it, expect } from 'vitest', replace jest.fn() with vi.fn(), replace jest.mock() with vi.mock(). The API surface is intentionally compatible.

The one gotcha that trips teams up: mock hoisting. Jest automatically hoists jest.mock() calls to the top of the file so they run before imports. Vitest hoists vi.mock() too, but the behaviour differs slightly in edge cases — particularly when your mock factory references variables defined in the test file. If you have tests that rely on mock hoisting in non-obvious ways, test those files individually before declaring the migration complete.

The NZ Landscape in 2026

On greenfield projects — new SaaS products, government digital transformation projects, startup MVPs — Vitest is increasingly the default choice. Teams starting fresh with Vite have no reason to pull in Jest's additional configuration overhead. On legacy projects — existing Angular codebases, older React setups that pre-date Vite, enterprise Node.js APIs — Jest is usually already embedded and switching carries real risk with little reward. The practical advice for NZ testers: be comfortable with both. Know which config file to look for (jest.config.ts vs vitest.config.ts), know how to run a single test file, and know how to read the coverage report. The syntax inside test files is nearly identical either way.