Manifest

Writing manifests

Test-runner integrations use ManifestWriter:

Test-runner integrations use ManifestWriter: a builder bound to a file that rewrites it atomically on every change. For runs with thousands of screenshots pass { writeDelayMs: 200 } as the third argument to coalesce the rewrites; pending changes are written on flush() and when the process exits (not if it is killed outright, which is why the default is 0). A passed entry never lists .actual or .diff files, even when leftovers of an earlier run sit next to it, and test files are recorded normalised (./a.spec.ts and a.spec.ts are one file).

import {
  ManifestWriter,
  getManifestFileName,
} from 'visual-regression-manifest';

const writer = new ManifestWriter(
  `output/${getManifestFileName('my-runner')}`,
  {
    projectRoot: process.cwd(),
    tool: { name: 'my-visual-plugin', version: '1.0.0' }, // what writes the file
    runner: { name: 'my-runner', version: '2.0.0' }, // what runs the tests; add any runner-specific keys
    options: { threshold: 0.01 }, // your global options, verbatim
    // platform and ci are detected (GitHub Actions, GitLab CI) unless given
  },
);

writer.record({
  actualPath: 'shots/home.actual.png', // also the key: recording it again replaces the entry
  baselinePath: 'shots/home.png',
  // diffPath defaults to the `.diff` sibling; pass `null` when you write none
  testFile: 'e2e/home.spec.ts',
  titlePath: ['home', 'renders'],
  retry: 0, // a retry replaces the entries of the earlier attempts of that test
  status: 'failed',
  diffRatio: 0.02,
  threshold: 0.01,
  baselineWritten: false,
  duration: 840,
  actualSize: { width: 1280, height: 720 },
  platform: {
    osPlatform: process.platform,
    browser: { name: 'chromium', version: '130' },
  },
  attachments: [
    { name: 'trace', contentType: 'application/zip', path: 'trace.zip' },
  ],
  message: '2% of pixels differ',
});
writer.approve({ actualPath: 'shots/home.actual.png' }); // after moving the actual over the baseline
writer.dropTestFile('e2e/home.spec.ts'); // before re-running a file in an interactive runner
writer.reset(); // start of a run: forget everything, delete the file

ManifestBuilder is the same without the file (toJSON() gives the manifest), and writeManifestFile is the atomic write on its own. The writer computes project-relative paths, nulls images that do not exist, hashes the ones that do, derives a native renderer from platform, keeps summary up to date and sorts entries by test file and name.