Capture screenshots for Difora

Render in your CI, keep names stable, and upload PNGs for review.

Version: the helpers below require CLI 0.4.0 or newer. The release is prepared; npm distribution is temporarily unavailable. Pilot users with the supplied release tarball can install it with npm install --save-dev ./difora-0.4.0.tgz. Registry installation will resume after publication.

Playwright

Install the CLI release package as a dev dependency alongside your own Playwright installation. The helper imports no browser package and adds no runtime dependencies.

import { test, expect } from '@playwright/test';
import { diforaScreenshot } from 'difora/playwright';

test('home', async ({ page }) => {
  await page.goto('/'); // configure Playwright's baseURL for your app
  await expect(page.getByRole('main')).toBeVisible();
  await diforaScreenshot(page, 'home', {
    fullPage: true,
    viewportSuffix: true,
    mask: [page.getByTestId('clock')],
  });
});

The output directory is dir, then DIFORA_SCREENSHOT_DIR, then ./screenshots. The promise returns the absolute file path. Set a fixed Playwright viewport to use viewportSuffix; a 1280-pixel viewport produces home@1280.png.

To bind capture to a fixture, pass your own test after adding any custom fixtures:

import { test as base } from '@playwright/test';
import { withDifora } from 'difora/playwright';
const test = withDifora(base);

test('home', async ({ page, diforaScreenshot }) => {
  await page.goto('/');
  await diforaScreenshot('home', { viewportSuffix: true });
});

Options are fullPage, mask (Playwright locators), clip (x/y/width/height), viewportSuffix and dir. Choose full-page capture or clipping. Animations are disabled and the text caret is hidden during capture. Your test still needs to wait for application data, fonts and images to be ready. Keep browser, fonts, viewport and test data stable between runs.

Manual Playwright capture

import { mkdir } from 'node:fs/promises';
await mkdir('screenshots', { recursive: true });
await page.screenshot({
  path: 'screenshots/home.png',
  fullPage: true,
  animations: 'disabled',
  caret: 'hide',
});

Storybook test runner

For projects using @storybook/test-runner, set its post-visit hook in .storybook/test-runner.ts. Start your Storybook first, then run test-storybook.

import type { TestRunnerConfig } from '@storybook/test-runner';
import { createPostVisit } from 'difora/storybook';

export default {
  postVisit: createPostVisit({
    fullPage: true,
    skip: ({ id }) => id === 'components-clock--live',
  }),
} satisfies TestRunnerConfig;

Names follow <title>/<story>. The hook runs after rendering and the story's play function. skip may return a boolean or promise. The helper supports the test-runner hook API; it is not a Storybook Vitest-addon integration.

Cypress recipe

No Difora-specific Cypress plugin is required. Choose a dedicated screenshot directory and avoid uploading automatic failure captures as intended baselines.

// cypress.config.ts
import { defineConfig } from 'cypress';
export default defineConfig({
  screenshotsFolder: 'screenshots',
  screenshotOnRunFailure: false,
  trashAssetsBeforeRuns: true,
});

// Your Cypress test, after the page is ready:
cy.screenshot('home', { capture: 'viewport' });

Upload screenshots after cypress run. Cypress includes the spec path in screenshot names; keep it stable.

Names and clean directories

The helpers preserve slash-separated groups, reject traversal and absolute paths, and sanitise unsupported characters. Changed segments receive a stable hash suffix so different labels do not silently collapse to the same path. A repeated name intentionally overwrites its previous capture. Use distinct names or viewport/browser suffixes for each intended snapshot.

Start each CI capture run with a fresh screenshot directory. Otherwise stale PNGs can remain in the uploaded manifest and conceal removals. The helpers never clear a directory automatically.

Then run npx difora upload ./screenshots with DIFORA_TOKEN set as a CI secret. See CI recipes and exit codes.

Reference APIs: Playwright fixtures, Storybook test-runner hooks, Cypress screenshots.