How to use Jest matchers with Vitest

A while ago I migrated a test suite from Jest to Vitest. Every thing went fine except that I needed to find out how we could continue to use jest-dom with Vitest. Jest-dom is useful when writing tests for DOM elements with testing-library. It provides handy assertions like for example expect(someButton).toBeDisabled().

Luckily Vitest is largely compatible with Jest and so Jest matchers can be used as is.

First we need to create a setup file. I use the name vitest-setup.mjs but it can be anything you like. Just make sure it matches the configuration below.

// vitest-setup.mjs

import { expect } from "vitest";
import * as matchers from "@testing-library/jest-dom/matchers";

expect.extend(matchers);

Next we add the setup file to the configuration.

// vitest.config.mjs

import { defineConfig } from "vitest/dist/config";

export default defineConfig({
  test: {
    setupFiles: ["./vitest-setup.mjs"],
  },
});

In case we are using TypeScript we need to add the additional matchers to Vitest’s types.

// vitest-testing-library-matchers.d.ts

import "vitest";
import type { TestingLibraryMatchers } from "@testing-library/jest-dom/types/matchers";

declare module "vitest" {
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  interface Assertion<T = any> extends TestingLibraryMatchers<T, void> {}
}

Ensure that TypeScript picks up this declaration file.

// tsconfig.json

{
  "include": ["*.d.ts",],

}

Now we can write tests that make use of Jest-dom. 🎉

// greeting.spec.tsx

import { describe, expect, it } from "vitest";
import { render, screen } from "@testing-library/react";
import { Greeting } from "./greeting";

describe("<Greeting>", () => {
  it("should say Hello", () => {
    render(<Greeting name="Vitest" />);
    const heading = screen.getByRole("heading");
    expect(heading).toHaveTextContent("Hello, Vitest!");
  });
});