DEV Community

Cristian Sifuentes
Cristian Sifuentes

Posted on

5 Things to Know About Migrating Angular Tests to Vitest (After Moving 20+ Repositories)

5 Things to Know About Migrating Angular Tests to Vitest (After Moving 10+ Repositories)

5 Things to Know About Migrating Angular Tests to Vitest (After Moving 20+ Repositories)

Cristian Sifuentes\
4 min read · Feb 24, 2026


I recently completed migrating the unit tests of more than 40
repositories
that power a large Angular certification ecosystem to
Vitest.

This wasn't a toy migration.\
It involved real-world test suites, legacy Jasmine patterns, async RxJS
flows, DOM-heavy component tests, and CI pipelines.

What follows is not a tutorial.

It's what actually changes --- and what doesn't --- when you move from
Jasmine/Karma (or Jest) to Vitest in Angular 21+.


Vitest Is 99% the Same Syntax --- And That's the Point

Consider this test:

it('should create', () => {
  expect(component).toBeTruthy();
});

it('should display four tabs', () => {
  const tabs = fixture.debugElement.queryAll(By.css('button'));
  expect(tabs.length).toBe(4);
});
Enter fullscreen mode Exit fullscreen mode

What framework is this?

  • Jasmine\
  • Jest\
  • Vitest

Answer: All of them.

Modern JS testing ecosystems converged toward:

  • describe
  • it
  • expect
  • matchers like toBe, toEqual, toBeTruthy

The migration is therefore not conceptual.

It's mechanical.


Angular CLI Migration Handles the Boring Part

Here's the mapping that matters:

Jasmine Vitest


fit it.only
fdescribe describe.only
xit it.skip
xdescribe describe.skip
spyOn vi.spyOn
jasmine.createSpy vi.fn()
fail() vi.fail()
jasmine.objectContaining expect.objectContaining
jasmine.any expect.any

Automate it:

ng g @schematics/angular:refactor-jasmine-vitest
Enter fullscreen mode Exit fullscreen mode

This removes most manual friction instantly.


Async Tests Are Where Real Migration Happens

Jasmine-style async test:

it("should return all movies by default", (done) => {
  service.filterMovieList().subscribe(movies => {
    expect(movies.length).toBe(2);
    done();
  });
});
Enter fullscreen mode Exit fullscreen mode

Vitest version:

it("should return all movies by default", async () => {
  vi.useFakeTimers();

  let moviesReceived = [];

  service.filterMovieList()
    .subscribe(movies => moviesReceived = movies);

  await vi.runAllTimersAsync();

  expect(moviesReceived.length).toBe(2);
});
Enter fullscreen mode Exit fullscreen mode

Key differences:

  • Explicit timer control\
  • No done() callbacks\
  • Deterministic execution

Under heavy CI parallelization, this matters.


Browser Mode Is Explicit

Vitest can run in a browser like Karma --- but not by default.

If your tests rely on:

  • window
  • localStorage
  • real layout calculations

You must enable browser mode in config.

Flexibility is power --- but it requires awareness.


Component Testing Becomes Ergonomic

Traditional Angular unit test setup:

beforeEach(async () => {
  await TestBed.configureTestingModule({
    declarations: [BasketComponent]
  }).compileComponents();

  fixture = TestBed.createComponent(BasketComponent);
  component = fixture.componentInstance;
  fixture.detectChanges();
});
Enter fullscreen mode Exit fullscreen mode

Vitest-style component testing:

test('should render clear basket button', async ({ page, mount }) => {
  await mount(Basket);
  await expect(
    page.getByRole('button', { name: 'Clear' })
  ).toBeVisible();
});
Enter fullscreen mode Exit fullscreen mode

This reduces boilerplate and increases readability.

It feels closer to real user interaction.


What Actually Required Manual Fixes

  • Async RxJS tests\
  • Custom Jasmine matchers\
  • Implicit zone timing assumptions\
  • Legacy global spy patterns\
  • CI adjustments

What didn't break:

  • Pure function tests\
  • Basic component logic tests\
  • Snapshot-style DOM assertions

Strategic Takeaways

Vitest improves:

  • Startup speed\
  • Parallel execution\
  • Async determinism\
  • Mocking ergonomics\
  • Component testing experience

But test quality still depends on:

  • Lifecycle awareness\
  • Isolation discipline\
  • Architectural clarity

No runner fixes bad test design.


Final Thoughts

The ecosystem is converging.

Syntax differences are fading.

What matters now:

  • Determinism\
  • Speed\
  • Developer ergonomics\
  • Scalability

Vitest delivers on those fronts in Angular 21+.

---\
Cristian Sifuentes\
Angular Architect · Performance & Testing Specialist

Top comments (0)