Skip to main content

How to Progressively Migrate to Vitest Browser Mode

In this recipe, you will find a step-by-step guide to progressively migrate your Angular tests to Vitest Browser Mode.

info

Vitest & Browser Mode are officially supported by Angular CLI starting from Angular v21.0.0 (Nov. 2025).

For older Angular versions or more advanced scenarios, you can use Angular Vite plugin by Analog.

Note that Nx added Angular Vitest support in Nx v20.1.0 (Nov. 28th 2024).

๐Ÿฝ๏ธ Before You Startโ€‹

๐Ÿ“„๏ธ Browser Mode

The evolution of Angular browser testing and how to configure Vitest Browser Mode for both partial and full Playwright-powered testing.

1. Migrate to "Partial" Browser Modeโ€‹

When using Vitest with the Angular CLI, the default behavior is to use an emulated environment. Either JSDOM or Happy DOM depending on the first dependency that is available.

To enable browser mode in Angular CLI, you have to update the browsers option to use the browser you want to use:

angular.json | project.json
{
"test": {
"builder": "@angular/build:unit-test",
"options": {
"runner": "vitest",
"browsers": ["Chromium"]
}
}
}

You will then also have to add the required dependencies to your project.

npm install -D playwright vitest @vitest/browser-playwright

After enabling this, the tests will run in the browser. Angular CLI will automatically either use Playwright or WebdriverIO as the Vitest browser provider depending on which package is installed in your workspace.

At this stage, the tests are running in the browser but you are not leveraging the full power of the browser provider yet.
Cf. "Partial" Browser Mode.

2. [Optional] Migrate to "Full" Browser Mode with userEvent adapterโ€‹

If you are already using the @testing-library/user-event library, you can easily enable the "Full" Browser Mode and features such as actionability checks.

Vitest provides a userEvent adapter that has the same API as @testing-library/user-event but is actually using the browser provider under the hood.

This adapter is meant to simplify the migration to "Full" Browser Mode. To enable it, you just have to replace the import of @testing-library/user-event with vitest/browser and your tests will start interacting with the DOM through the browser provider:

import { expect, test } from 'vitest';
- import userEvent from '@testing-library/user-event';
+ import { userEvent } from 'vitest/browser';

test('turn on the stove', async () => {
TestBed.createComponent(Stove);
await userEvent.click(await screen.findByRole('button', { name: 'TURN ON' }));
await expect.poll(() => screen.getByRole('paragraph')).toHaveText('๐Ÿ”ฅ');
});

3. Migrate to "Full" Browser Mode with page APIโ€‹

For a better testing experience, Vitest provides a page API that aligns with the Playwright API.\

You can switch to the page API by replacing DOM queries with the page API, and assertions with the expect.element API.

import { expect, test } from 'vitest';
import { userEvent } from 'vitest/browser';

test('turn on the stove', async () => {
TestBed.createComponent(Stove);

- await userEvent.click(await screen.findByRole('button', { name: 'TURN ON' }));
+ await page.getByRole('button', { name: 'TURN ON' }).click();

- await expect.poll(() => screen.getByRole('paragraph')).toHaveText('๐Ÿ”ฅ');
+ await expect.element(page.getByRole('paragraph')).toHaveText('๐Ÿ”ฅ');
});

The page API methods return a Locator object that does not need to be awaited.

The locator is not querying the DOM, it is the "recipe" of how to find that element in the DOM.

info

The DOM queries are only performed when:

  • an action such as click is performed on the locator
  • an assertion is performed using expect.element on the locator

Thanks to this auto-waiting behavior, you will rarely have to worry about Angular testing APIs such as ComponentFixture#whenStable, nor the differences between Testing Library's getBy vs. queryBy vs. findBy etc... anymore.

warning

Once you opt-in to Browser Mode by importing vitest/browsers, you will not be able to run these tests in an emulated environment.

Otherwise, you will get an error like this:

Error: vitest/browser can be imported only inside the Browser Mode.

4. Extending the Locator API with provider-specific featuresโ€‹

Usually, when using a simple Vitest config file with plugins such as Analog's Vite plugin approach, Vitest automatically augments the Locator API with provider-specific features and options.

When using the Angular CLI, you will have to manually augment the types yourself. Cf. https://github.com/angular/angular-cli/issues/31656.

You can augment the Locator API by adding the provider's ambient typings in the types array of the tsconfig.spec.json file as such:

tsconfig.spec.json
{
"compilerOptions": {
"types": [
...,
+ "@vitest/browser-playwright"
]
}
}

Want to go deeper? Join a full live workshopโ€‹

๐Ÿ‘‰SEE THE FULL PROGRAM๐Ÿ‘ˆ

Source Codeโ€‹

๐Ÿ’ปย Angular Testing using a Fake

Additional Resourcesโ€‹