Faster testing with Angular and Vitest ⚡️
Tags: angular, vite, testing
Published: 2023-12-08 14:40:37

In the Angular ecosystem, there are a few recommended tools used to run unit tests including Karma, Jasmine, and Jest. Karma and Jasmine have been the recommended tools for Angular projects out of the box, with official support for [Jest](https://blog.angular.io/moving-angular-cli-to-jest-and-web-test-runner-ef85ef69ceca) underway.

In addition to those tools, a new testing framework has emerged named [Vitest](https://vitest.dev). Vitest is built on top of [Vite](https://vitejs.dev) and has many exciting features to keep improving the overall developer experience for writing tests. This post shows you how to set up Vitest in your existing Angular project.

## Vitest Features

Vitest has many modern testing features that make it a great experience to run tests.

- Jest-compatible API 
- Fast 
- ESM ready
- TypeScript support out of the box
- Mocks
- Snapshot testing
- And more ...

Check out the [features](https://vitest.dev/guide/features.html) page to see the full list.

While Jest does have experimental support for ESM, it's not a first-class feature and requires workarounds to support it correctly. Tomas Trajan wrote a very detailed [blog post](https://angularexperts.io/blog/total-guide-to-jest-esm-and-angular) on all the scenarios to get Jest and ESM working for Angular tests.

## Setup for Running tests in a Node environment

As Vitest is built on top of Vite, support for web frameworks can be done through plugins. [AnalogJS](https://analogjs.org)  provides a Vite plugin to enable using Vitest with any Angular application.

Setting up Vitest with an existing Angular project can be done in a couple of steps.

First, install the `@analogjs/platform` package.

```sh
npm install @analogjs/platform --save-dev
```

Next, run the command with the name of your project:

```sh
ng g @analogjs/platform:setup-vitest --project [your-project-name]
```

This is supported in both Angular CLI and [Nx](https://nx.dev) workspaces.

This automates a few steps:

- Installs the necessary packages to run tests with Vitest.
- Adds a `vite.config.ts` file to the project to configure Vitest.
- Adds a `src/test-setup.ts` file to the project for setting up the TestBed environment.
- Updates the `test` target configuration to use `@analogjs/platform:vitest` as the builder.
- Updates the `tsconfig.spec.json` with the appropriate `target` and `files` settings.

You can also see steps for [manual installation](https://analogjs.org/docs/features/testing/vitest#manual-installation) in the documentation.

After the command finishes, you're able to run tests the same way you did before with `ng test`, but now using Vitest as the testing framework.

```sh
ng test
```

With Vitest, by default, tests are run in a node environment with simulated browser APIs using `jsdom`. If you're already using Jest-specific testing APIs, you can [migrate](https://vitest.dev/guide/migration.html#migrating-from-jest) most of them to Vitest with minimal effort.

## Snapshot testing

Vitest also supports snapshot testing with the `toMatchSnapshot()` method.

```ts
import { TestBed } from '@angular/core/testing';

import { MyComponent } from './my.component';

describe('MyComponent', () => {
  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [MyComponent],
    }).compileComponents();
  });

  it('should match the snapshot', () => {
    const fixture = TestBed.createComponent(MyComponent);

    expect(fixture).toMatchSnapshot();
  });
});
```

## Setup for Running tests in the Browser

If you prefer to run your tests in a browser, Vitest also has support for browser testing.

First, follow the steps for running tests in a node environment.

Then, install the necessary packages for running tests in the browser:

```sh
npm install @vitest/browser playwright --save-dev
```

Update the test object in the vite.config.ts.

 - Remove the environment: 'jsdom' property.
 - Add a browser config for Vitest.

```ts
/// <reference types="vitest" />
import { defineConfig } from 'vite';

import angular from '@analogjs/vite-plugin-angular';

export default defineConfig(({ mode }) => ({
  plugins: [angular()],
  test: {
    globals: true,
    setupFiles: ['src/test-setup.ts'],
    // environment: 'jsdom',
    include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
    // Vitest browser config
    browser: {
      enabled: true,
      name: 'chromium',
      headless: false, // set to true in CI
      provider: 'playwright',
    },
  },
  define: {
    'import.meta.vitest': mode !== 'production',
  },
}));
```

Run your tests

```sh
ng test
```

This spins up a Chromium Browser to run your tests and can be run headless in your CI environments.

Vitest is a great addition to the testing frameworks available for Angular developers to use.

If you enjoyed this post, click the :heart: so other people will see it. Follow [me on Twitter/X](https://twitter.com/brandontroberts) and subscribe to my [YouTube Channel](https://youtube.com/brandonrobertsdev?sub_confirmation=1) for more content!