ContactSign inSign up
Contact

Take targeted snapshots with Vitest

By default, Chromatic takes a snapshot at the end of every Vitest test, whether it passes or fails. However, you can also choose to programmatically take snapshots at specific points in your tests using the takeSnapshot function inside your test runs.

takeSnapshot is especially useful for capturing a snapshot of your UI’s appearance when your UI reaches a specific state mid-test:

test/accordion.test.tsx
import { test, expect } from 'vitest';
import { page } from 'vitest/browser';
import { render } from 'vitest-browser-react';
import { takeSnapshot } from '@chromatic-com/vitest'; 
import { Accordion } from '../src/components/Accordion';

test('Can open accordion', async () => {
  await render(<Accordion header="Example header">Example content</Accordion>);

  const toggle = page.getByRole('button', { name: 'Example header' });
  const content = page.getByText('Example content');

  // Open accordion, content should become visible
  await toggle.click();
  await expect.element(content).toBeInTheDocument();

  // Call takeSnapshot to take an archive "snapshot"
  // of the component at this point in the test.
  await takeSnapshot(); 

  // Close accordion, content should become hidden
  await toggle.click();
  await expect.element(content).not.toBeInTheDocument();

  // You can call takeSnapshot multiple times if necessary.
  // To help disambiguate, you can give the snapshot a name,
  // which is passed as the first argument to takeSnapshot.
  await takeSnapshot('closed'); 
});

The Chromatic integration provides a waitForIdleNetwork utility function that can be used before you take manual snapshots. It will resolve once the network has been idle for a given time, meaning no new network requests started during that period.

test/accordion.test.tsx
import { test, expect } from 'vitest';
import { page } from 'vitest/browser';
import { render } from 'vitest-browser-react';
import { takeSnapshot, waitForIdleNetwork } from '@chromatic-com/vitest'; 
import { Accordion } from '../src/components/Accordion';

test('image inside accordion', async () => {
  await render(
    <Accordion header="Example header">
      <img alt="Vitest logo" src="https://www.chromatic.com/integrations/vitest.svg" />
    </Accordion>
  );

  const toggle = page.getByRole('button', { name: 'Example header' });
  const image = page.getByRole('image', { name: 'Vitest logo' });

  // Open accordion, image should become visible
  await toggle.click();
  await expect.element(image).toBeInTheDocument();

  // Wait for image to finish loading. If it's not ready in 1000ms, error out.
  await waitForIdleNetwork(1000); 
  await takeSnapshot('accordion open with image inside');
});

Network request state is polled in intervals of idleNetworkInterval in milliseconds. Default value is 100ms. This can be configured on Chromatic plugin’s options:

export default defineConfig({
  plugins: [chromaticPlugin({ idleNetworkInterval: 50 })],
});

Limiting included tests using tags

By default the chromaticPlugin applies its test setup for all test cases that the Vitest project runs. If your Vitest project contains test cases that should not be visually tested, this introduces unnecessary performance overhead.

You can limit test inclusion using the tags option. In your Vitest configuration, define tags: string[] in the plugin options.

vitest.config.ts
import { defineConfig } from 'vitest/config';
import { chromaticPlugin } from '@chromatic-com/vitest/plugin';

export default defineConfig({
  plugins: [
    chromaticPlugin({
      // Apply test setups needed for visual regression only for
      // test cases that have following tag:
      tags: ['visual-regression'], 
    }),
  ],
});

Then use the configured tag in your test cases that should be included in visual regression. See Vitest’s tags documention for more details.

test/accordion.test.tsx
import { test } from "vitest";

// Inlcuded in visual regression ✅
test("accordion rendering", { tags: ["visual-regression"] }, async () => { 
  await render(<Accordion />);
});

// Not included in visual regression ❌
test("accordion public API", () => {
  expect(Accordion.open).toBeFunction();
  expect(Accordion.close).toBeFunction();
  expect(Accordion.toggle).toBeFunction();
});