{"post":{"slug":"how-to-set-up-vitest-2026","title":"How to set up Vitest in 2026","excerpt":"Vitest is the default unit-test runner for Vite-based projects in 2026 — fast, zero-config, and Jest-compatible. This guide wires it up from scratch to CI-ready in minutes.","category":"code","date":"February 27, 2026","author":"ByteLedger Team","content":"<span class=\"dropcap\">V</span>itest took over as the default unit-test runner for Vite-based projects by 2025, and in 2026 it is the obvious choice for any TypeScript/JavaScript project — not just Vite apps. It reuses your existing Vite config, runs tests in native ESM without Babel, and is measurably faster than Jest on medium-to-large test suites. This guide goes from zero to CI-ready coverage in one sitting.\n\n## What changed in 2026\n\n- **Vitest 2.x stabilized** the browser mode and workspace feature, making it possible to test Node code and browser code in one `vitest.config.ts`.\n- **V8 coverage is the default** — the Istanbul provider still exists but V8 is faster and requires no instrumentation.\n- **`@vitest/ui` matured** into a proper debugging UI — filterable test tree, inline source, re-run on save.\n- **Vite 6 perf improvements** cut cold-start time significantly; large monorepos feel genuinely fast.\n- **Jest compat layer** still exists but is no longer needed for most projects — Vitest's own APIs are cleaner.\n\n## Install\n\n```bash\nnpm install -D vitest @vitest/coverage-v8\n# For React component testing add:\nnpm install -D @testing-library/react @testing-library/jest-dom jsdom\n```\n\n## Configure\n\nAdd a `test` block to your existing `vite.config.ts` — Vitest reads the same file.\n\n```ts\n// vite.config.ts\nimport { defineConfig } from 'vite'\nimport react from '@vitejs/plugin-react'\n\nexport default defineConfig({\n  plugins: [react()],\n  test: {\n    environment: 'jsdom',        // 'node' for back-end code\n    globals: true,               // describe/it/expect without imports\n    setupFiles: ['./src/test-setup.ts'],\n    coverage: {\n      provider: 'v8',\n      reporter: ['text', 'lcov'],\n      include: ['src/**/*.{ts,tsx}'],\n      exclude: ['src/**/*.stories.*'],\n    },\n  },\n})\n```\n\n```ts\n// src/test-setup.ts\nimport '@testing-library/jest-dom'\n```\n\nAdd scripts to `package.json`:\n\n```json\n\"scripts\": {\n  \"test\": \"vitest run\",\n  \"test:watch\": \"vitest\",\n  \"test:ui\": \"vitest --ui\",\n  \"test:coverage\": \"vitest run --coverage\"\n}\n```\n\n## Write your first test\n\n```ts\n// src/utils/format.test.ts\nimport { describe, it, expect } from 'vitest'\nimport { formatCurrency } from './format'\n\ndescribe('formatCurrency', () => {\n  it('formats USD', () => {\n    expect(formatCurrency(1234.5, 'USD')).toBe('$1,234.50')\n  })\n\n  it('handles zero', () => {\n    expect(formatCurrency(0, 'USD')).toBe('$0.00')\n  })\n})\n```\n\n## Test a React component\n\n```tsx\n// src/components/Button.test.tsx\nimport { render, screen, fireEvent } from '@testing-library/react'\nimport { Button } from './Button'\n\nit('calls onClick when clicked', () => {\n  const handler = vi.fn()\n  render(<Button onClick={handler}>Save</Button>)\n  fireEvent.click(screen.getByRole('button', { name: /save/i }))\n  expect(handler).toHaveBeenCalledOnce()\n})\n```\n\n## The comparison table\n\n| Feature | Vitest 2.x | Jest 29 |\n| --- | --- | --- |\n| Native ESM | Yes | Partial (experimental) |\n| TypeScript | Zero-config | Needs ts-jest or Babel |\n| Cold start (1k tests) | ~1 s | ~5–8 s |\n| Watch mode HMR | Yes (Vite) | Polling |\n| Browser mode | Built-in | Separate runner needed |\n| Jest API compat | Yes | — |\n\n## How to pick an environment\n\n| Code under test | `environment` setting |\n| --- | --- |\n| DOM / React / Vue | `jsdom` or `happy-dom` |\n| Node.js / API routes | `node` (default) |\n| Real browser APIs | `browser` (Vitest browser mode) |\n\nUse workspaces when a monorepo has both back-end and front-end packages with different environments.\n\n## CI setup\n\n```yaml\n# .github/workflows/test.yml\n- name: Run tests\n  run: npm run test:coverage\n\n- name: Upload coverage\n  uses: codecov/codecov-action@v4\n  with:\n    files: ./coverage/lcov.info\n```\n\n## Common mistakes\n\n**Forgetting `globals: true`** — without it, every test file needs explicit `import { describe, it, expect } from 'vitest'`. Add the global once in config.\n\n**Mixing `jsdom` and `node`** — if a test imports a browser-only API in a `node` environment it will throw at runtime. Match the environment to the code.\n\n**Not excluding stories/fixtures from coverage** — coverage dips look alarming but are usually untested fixture files. Use the `exclude` array in coverage config.\n\n**Running `vitest run` in watch mode** — `vitest run` is the one-shot CI mode; plain `vitest` is watch mode. Don't confuse them in scripts.\n\n## What to skip\n\n- **`babel-jest` or `ts-jest`** — you don't need a transpilation layer with Vitest's native TypeScript support.\n- **Separate `jest.config.js`** when you already have `vite.config.ts` — one config file is cleaner.\n- **`happy-dom` by default** — jsdom has broader coverage of web APIs; switch to happy-dom only if you have a specific performance problem.\n\n## FAQ\n\n**Can I migrate from Jest without rewriting tests?**\nMostly yes. Vitest's `globals: true` mode mirrors Jest's API. Mocks (`vi.fn()`, `vi.spyOn()`, `vi.mock()`) map 1-to-1. Edge cases: timer mocks and some module-level mock patterns may need small tweaks.\n\n**Does Vitest work outside Vite projects?**\nYes. Create a standalone `vitest.config.ts` without a Vite `plugins` section and it works for any TypeScript/JavaScript project.\n\n**How fast is it really?**\nOn a 500-test React suite cold start is typically under 2 seconds. Incremental re-runs with HMR are near-instant.\n\n**What about snapshot testing?**\nVitest supports `expect(x).toMatchSnapshot()` and inline snapshots identically to Jest. Snapshot files live in `__snapshots__` by default.\n\n## Where to go next\n\n- [How to write e2e tests in 2026](/blog/how-to-write-e2e-tests-2026)\n- [How to set up Storybook in 2026](/blog/how-to-set-up-storybook-2026)\n- [How to configure Vite in 2026](/blog/how-to-configure-vite-2026)","hue":315,"metaTitle":"How to Set Up Vitest in 2026 (Fast Unit Testing)","metaDescription":"Step-by-step guide to setting up Vitest in 2026. Install, configure, write tests, add coverage, and run in CI — with real code examples.","keywords":["how to set up vitest 2026","vitest tutorial 2026","vitest vs jest 2026","vitest configuration","vite unit testing 2026","vitest coverage setup","vitest typescript setup","javascript unit testing 2026","vitest ci setup","vitest react testing"],"tldr":["**Install once, run instantly** — `vitest` reads your existing `vite.config.ts` so there is almost no extra config.","**Native ESM and TypeScript** — no Babel transpilation step; tests run as close to your actual module graph as possible.","**UI mode** — `vitest --ui` gives a browser dashboard for debugging slow or flaky tests interactively.","**Coverage via V8 or Istanbul** — add `@vitest/coverage-v8` for zero-config coverage reports.","**Skip:** using Jest in a Vite project just for familiarity — the migration cost is an afternoon; the speed gains are immediate."],"readTime":"4 min read","wordCount":823},"related":[{"slug":"best-test-frameworks-javascript-2026","title":"Best test frameworks for JavaScript in 2026: Vitest, Playwright, Jest","excerpt":"Pick the right test framework for the right layer in 2026. Vitest for units, Playwright for end-to-end, and when Jest still wins.","category":"code","date":"January 26, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":310},{"slug":"how-to-set-up-storybook-2026","title":"How to set up Storybook in 2026","excerpt":"Storybook 8 is faster, Vite-native, and ships a built-in test runner. This guide covers installation, story writing, interaction testing, and plugging Storybook into CI.","category":"code","date":"April 3, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":317},{"slug":"jest-vs-vitest-2026","title":"Jest vs Vitest in 2026: which JavaScript test runner should you use?","excerpt":"Vitest has become the default choice in Vite-based projects and is now challenging Jest even in non-Vite stacks. Here is the honest 2026 comparison.","category":"code","date":"April 6, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":321}],"sameCategory":[{"slug":"bazel-build-explained-2026","title":"Bazel Explained: What Hermetic Builds Actually Cost","excerpt":"Bazel delivers reproducible, precisely cached builds and demands that you describe everything. Here is what you get, what it costs, and who should say no.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":145},{"slug":"graphql-federation-2026","title":"GraphQL Federation: One Graph, Many Teams","excerpt":"Federation composes independently-owned subgraphs into a single API. Here is what it solves, the operational cost it adds, and when a simpler gateway is enough.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":300},{"slug":"hermetic-builds-explained-2026","title":"Hermetic Builds Explained: Same Inputs, Same Output","excerpt":"A hermetic build depends only on declared inputs. Here is what that property gives you, the common leaks that break it, and how to move toward it incrementally.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":130},{"slug":"monorepo-tooling-compared-2026","title":"Monorepo Tooling Compared: What You Actually Need","excerpt":"Monorepo tools solve task orchestration and caching, not repository layout. Here is what each tier provides and how to tell when you have outgrown the simple option.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":150}],"newer":{"slug":"how-to-set-up-plex-2026","title":"How to set up Plex in 2026: the complete guide","excerpt":"Plex is still the best way to stream your personal media library anywhere. This guide walks through installation, library setup, and remote access in 2026.","category":"tech","date":"February 27, 2026","author":"ByteLedger Team","readTime":"5 min read","hue":240},"older":{"slug":"how-to-set-up-vpn-on-iphone-2026","title":"How to set up a VPN on iPhone in 2026: step-by-step guide","excerpt":"Setting up a VPN on iPhone takes under five minutes. This 2026 guide covers the best methods, which services are worth paying for, and what to avoid.","category":"tech","date":"February 27, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":242}}