Manual snapshots
Besides automatic snapshot, you can capture image snapshot manually.
import { expect } from '@storybook/test'
// `page` and the like are proxies of `@vitest/browser/context` to work within storybookimport { page } from 'storybook-addon-vis'
export const PageSnapshot = { // typically you want to disable automatic snapshot when using manual snapshot // but you can use both at the same time. tags: ['!snapshot'], async play({ canvasElement }) { await expect(canvasElement).toMatchImageSnapshot(/* options */) }}
export const ElementSnapshot = { // typically you want to disable automatic snapshot when using manual snapshot // but you can use both at the same time. tags: ['!snapshot'], async play({ canvas }) { const element = await canvas.getByTestid('subject') await expect(element).toMatchImageSnapshot(/* options */) }}Check if a snapshot exists
Section titled “Check if a snapshot exists”While less common, you can also check if a snapshot exists:
import { hasImageSnapshot } from 'storybook-addon-vis'
export const HasImageSnapshot = { tags: ['!snapshot'], loaders: [async () => ({ hasImageSnapshot: await hasImageSnapshot(/* options */) })], render(_, { loaded: { hasImageSnapshot } }) { return <div data-testid="subject">Has snapshot: {String(hasImageSnapshot)}</div> }, async play({ canvas, loaded: { hasImageSnapshot } }) { const subject = canvas.getByTestId('subject') if (!hasImageSnapshot) { await expect(subject).toMatchImageSnapshot() return }
// This will only execute in Vitest await expect(subject) .toMatchImageSnapshot() .then( () => { throw new Error('Should not reach') }, (error) => { expect(error.message).toMatch(/Expected image to match but was differ by \d+ pixels./) }, ) },}This is useful when you are performing some negative test.
Chrome DevTools Protocol
Section titled “Chrome DevTools Protocol”cdp is a proxy of cdp() from vitest/browser.
Importing vitest/browser directly in a story breaks the story in a plain Storybook preview,
where the module throws on import; the proxy loads it only during a Vitest browser run.
Use it to read what the browser computes, such as the accessible name and description Chromium exposes to screen readers:
import { cdp } from 'storybook-addon-vis'
export const AccessibleName = { async play() { const session = cdp() await session.send('Accessibility.enable') const { nodes } = await session.send('Accessibility.getFullAXTree') // assert on nodes }}CDP is available only with the Playwright provider on Chromium.
Calling cdp() outside a Vitest browser run throws, so keep such tests in Vitest.