skip to content

How would you move an existing Angular Karma and Jasmine suite to the unit-test builder with Vitest, and what does the migrate-karma-to-vitest migration leave for you?

level: seniorimportance: should knowfreq 30%

answer

  1. application builder first
  2. an optional v22 update migration
  3. build options move to a configuration
  4. specs are rewritten separately

basics

~10 s

Ensure the build uses @angular/build:application, run the optional migrate-karma-to-vitest migration to switch the test target to @angular/build:unit-test with Vitest, then install jsdom, run refactor-jasmine-vitest on the specs, and port custom Karma config by hand.

solid answer

~40 s

The prerequisite is the `@angular/build:application` build system; the migration skips projects without it, and libraries too. The optional v22 `migrate-karma-to-vitest` migration switches the `test` target to `@angular/build:unit-test` with `runner: "vitest"`, moves build options such as `polyfills`, `styles` and `assets` into a new `testing` build configuration, renames `codeCoverage` to `coverage`, maps a custom `main` to `setupFiles`, swaps `jasmine` for `vitest/globals` in tsconfig types, deletes a plain `karma.conf.js` or flags a customised one, and adds `vitest`. It does not touch spec files: that is the `refactor-jasmine-vitest` schematic. I would still install `jsdom`, port reporters and launchers, handle `fakeAsync` with the Zone.js Vitest patch or fake timers, and compare pass counts before removing Karma.

code

bash · 8 lines
bash
# 1. after the optional migrate-karma-to-vitest migration has rewritten angular.json
npm install --save-dev jsdom

# 2. rewrite Jasmine specs to Vitest APIs, one area at a time
ng g @schematics/angular:refactor-jasmine-vitest --include=src/app/profile

# 3. run the suite on the new builder and compare with the Karma baseline
ng test --watch=false

go deeper

for a junior

Recall the two tools: the optional migrate-karma-to-vitest migration for configuration and the refactor-jasmine-vitest schematic for spec files.

for a middle

Explain what the migration changes in angular.json, the testing build configuration, option renames and setupFiles, and what it leaves undone.

for a senior

Run it as a staged project: baseline counts, application-builder prerequisite, folder-by-folder spec refactoring, isolation and fakeAsync fixes, then removal of Karma.

for a principal

Decide whether and when each project migrates, weighing Karma plugin dependencies, CI time savings and the risk of silently skipped or weakened tests.

## The scenario An application created before v21 runs a few thousand Jasmine specs through a legacy **Karma builder** (`@angular-devkit/build-angular:karma` or `@angular/build:karma`) with a customised `karma.conf.js`. The team wants the **`@angular/build:unit-test`** builder with **Vitest**. The Angular docs still call migrating an existing project experimental, so plan it as a project with checkpoints, not a one-command upgrade. ## Prerequisites 1. The project's `build` target must already use **`@angular/build:application`**. The automated migration skips any project that does not, and the unit-test builder compiles specs through that build system. 2. Only **application** projects are migrated automatically; libraries are skipped and done by hand. 3. The suite should be green on Karma first, so every later failure is attributable to the move. ## What the optional `migrate-karma-to-vitest` migration does Since v22 the CLI ships an **optional** update migration, `migrate-karma-to-vitest`. For each eligible project whose `test` target uses a Karma builder, it: - sets the builder to `@angular/build:unit-test` and `runner` to `"vitest"`; - moves **build options** that the unit-test builder no longer accepts on the test target (`assets`, `styles`, `scripts`, `polyfills`, `inlineStyleLanguage`, `fileReplacements`, `aot` and others) into a new **`testing`** configuration of the `build` target, starting from `aot: false`, `optimization: false` and `extractLicenses: false` to match Karma's behaviour, and points the test target's `buildTarget` at it; - renames options: `codeCoverage` becomes `coverage`, `codeCoverageExclude` becomes `coverageExclude`; `sourceMap` is dropped because source maps are always on; - maps a custom `main` test entry to **`setupFiles`**, with a warning to remove `TestBed.initTestEnvironment` calls, since the builder initialises TestBed itself; - replaces `jasmine` with `vitest/globals` in the spec tsconfig's `types`; - deletes `karma.conf.js` when it holds nothing custom, and **lists it for manual migration** when it does; - adds `vitest` as a dev dependency, plus a coverage provider when coverage was enabled. ## What it does not do | Still your job | How | |---|---| | Rewrite spec files from Jasmine to Vitest APIs | the `refactor-jasmine-vitest` schematic, which the migration suggests at the end | | Install a DOM emulator | add `jsdom` or `happy-dom`; non-browser runs refuse to start without one | | Port custom Karma reporters, plugins and launchers | `reporters` in `angular.json`, a Vitest config via `runnerConfig`, `browsers` plus a browser provider | | Keep `fakeAsync` working | add `zone.js/plugins/vitest-patch` to the test polyfills, or convert to the runner's fake timers | ## A migration plan that holds up 1. **Branch and baseline**: record the Karma pass count and duration. 2. **Run the migration** through the CLI's update flow (or apply the manual steps from the docs), review the `angular.json` diff and the new `testing` build configuration. 3. **Install `jsdom`** and, if some specs truly need a browser, a browser provider with a separate `browsers` configuration. 4. **Refactor the specs** with `ng g @schematics/angular:refactor-jasmine-vitest`, one folder at a time with `--include` on a large suite, then review every TODO it leaves. 5. **Fix what differs**: layout-dependent specs that relied on a real Chrome, tests that leaked state between files (the builder's `isolate` option defaults to `false`, matching Karma's shared-context behaviour), and `fakeAsync` tests. 6. **Compare** pass counts, look for silently skipped specs, and delete the Karma packages only when the numbers match. ## Reading the migration's summary The migration ends by printing a summary, and each line is a to-do: - **Projects migrated**: these now use the unit-test builder; their specs still need refactoring. - **Projects skipped (non-applications)**: libraries, which you configure by hand. - **Projects skipped (missing application builder)**: move their `build` target to `@angular/build:application` first, then migrate their test target. - **Karma configuration files requiring manual migration**: customised `karma.conf.js` files it left in place; port their settings before deleting them. - **The suggested command** for `refactor-jasmine-vitest`, which is the next step for every migrated project. ## Staying on Karma is legitimate Karma remains supported. Keeping it, or switching to the unit-test builder with `"runner": "karma"` as an intermediate step, is reasonable when a suite depends on Karma plugins with no Vitest equivalent or when the migration cost is not yet justified.

  • The migration logs that karma.conf.js requires manual migration. What usually lives there, and where does it go?
    Custom reporters, plugins and browser launchers. Reporters map to the unit-test builder's `reporters` option or a Vitest config file linked through `runnerConfig`; launchers become the `browsers` option plus a browser provider package; coverage is the builder's `coverage` options. Anything without an equivalent needs a Vitest plugin or a decision to drop it.
  • After the move, a spec passes alone but fails in the full run. What builder option is involved?
    `isolate`, which defaults to `false` to match the shared-context behaviour of Karma and Jasmine. State leaking between spec files, such as a module-level variable or a global patched and never restored, therefore survives across files. Fix the leak in the spec, or enable `isolate` to run files separately at some speed cost.

saying these in an interview costs you the question

  • The migration also rewrites spyOn calls in every spec file
  • Projects still on the browser builder are migrated automatically
  • The unit-test builder accepts polyfills and styles on the test target
  • Karma must be removed because v22 no longer supports it
  • jsdom is added by the migration, so nothing else needs installing