Testing with Vitest

This guide will help you set up Vitest and React Testing Library for your project. Note that this guide is intended for projects that use Vite as a bundler. If you're using other frameworks/bundlers, we recommend using Jest instead.

Installation

Install Vitest and React Testing Library:

yarn add --dev vitest jsdom @testing-library/dom @testing-library/jest-dom @testing-library/react @testing-library/user-event

If you want to run tests from your IDE, install one of the extensions.

Configuration

Add Vitest configuration to your Vite config file:

import { defineConfig } from 'vite';

export default defineConfig({
  // ... rest of your config
  test: {
    globals: true,
    environment: 'jsdom',
    setupFiles: './vitest.setup.mjs',
  },
});

Then create a vitest.setup.mjs file in your project root and add the following code to it:

import '@testing-library/jest-dom/vitest';

import { vi } from 'vitest';

const { getComputedStyle } = window;
window.getComputedStyle = (elt) => getComputedStyle(elt);
window.HTMLElement.prototype.scrollIntoView = () => {};

Object.defineProperty(window, 'matchMedia', {
  writable: true,
  value: vi.fn().mockImplementation((query) => ({
    matches: false,
    media: query,
    onchange: null,
    addListener: vi.fn(),
    removeListener: vi.fn(),
    addEventListener: vi.fn(),
    removeEventListener: vi.fn(),
    dispatchEvent: vi.fn(),
  })),
});

class ResizeObserver {
  observe() {}
  unobserve() {}
  disconnect() {}
}

window.ResizeObserver = ResizeObserver;

The code above mocks the window.matchMedia and ResizeObserver APIs that aren't available in the jsdom environment but are required by some Mantine components.

Optionally, you can add Vitest scripts to your package.json:

{
  "scripts": {
    "vitest": "vitest run",
    "vitest:watch": "vitest"
  }
}

Custom render

All Mantine components require MantineProvider to be present in the component tree. To add MantineProvider to the component tree in your tests, create a custom render function:

// ./test-utils/render.tsx
import { render as testingLibraryRender } from '@testing-library/react';
import { MantineProvider } from '@mantine/core';
// Import your theme object
import { theme } from '../src/theme';

export function render(ui: React.ReactNode) {
  return testingLibraryRender(<>{ui}</>, {
    wrapper: ({ children }: { children: React.ReactNode }) => (
      <MantineProvider theme={theme} env="test">{children}</MantineProvider>
    ),
  });
}

It's usually more convenient to export all @testing-library/* functions that you're planning to use from a ./testing-utils/index.ts file:

import userEvent from '@testing-library/user-event';

export * from '@testing-library/react';
export { render } from './render';
export { userEvent };

Then you should import all testing utilities from ./testing-utils instead of @testing-library/react:

import { render, screen } from '../test-utils';
import { Welcome } from './Welcome';

describe('Welcome component', () => {
  it('has correct Next.js theming section link', () => {
    render(<Welcome />);
    expect(screen.getByText('this guide')).toHaveAttribute(
      'href',
      'https://mantine.dev/guides/next/'
    );
  });
});

Example of a full setup

You can find an example with a full Vitest setup in mantine-vite-template.