vitest-dev/vitest · error · Error

Cannot compare screenshots without a test path

Error message

Cannot compare screenshots without a test path

What it means

The `screenshotMatcher` browser command requires `context.testPath` to resolve where reference/diff images are written relative to the test file. If the command is invoked with a context whose `testPath` is falsy, screenshot paths cannot be computed and the command refuses to run rather than writing files to an arbitrary location.

Source

Thrown at packages/browser/src/node/commands/screenshotMatcher/index.ts:84

/**
 * Browser command that compares a screenshot against a stored reference.
 *
 * The comparison workflow is organized as follows:
 *
 * 1. Load existing reference (if any)
 * 2. Capture a stable screenshot (retrying until the page stops changing)
 * 3. Determine the outcome based on capture results and update settings
 * 4. Write any necessary files (new references, diffs)
 * 5. Return result for the test runner
 */
export const screenshotMatcher: BrowserCommand<ScreenshotMatcherArguments> = async (
  context,
  name,
  testName,
  options,
): ScreenshotMatcherOutput => {
  if (!context.testPath) {
    throw new Error('Cannot compare screenshots without a test path')
  }

  const { element, target } = options
  const {
    codec,
    comparator,
    paths,
    resolvedOptions: { comparatorName, comparatorOptions, screenshotOptions, timeout },
  } = resolveOptions({ context, name, testName, options })

  const screenshotName = `${Date.now()}-${basename(paths.reference)}`
  const screenshotCaptureOptions = {
    context,
    element,
    name: screenshotName,
    screenshotOptions,
    target,
  } satisfies Parameters<typeof takeScreenshotBuffer>[0]

View on GitHub (pinned to d568f8ce37)

Solutions

  1. Run `toMatchScreenshot()` only inside an actual `it`/`test` block running under the Vitest browser runner, not from a plain script or outside a test task.
  2. If invoking `triggerCommand` manually, construct the `BrowserCommandContext` with a valid `testPath` pointing at the test file.
  3. Update Vitest and `@vitest/browser` to the same version; mismatches can cause the context to be missing fields like `testPath`.

Example fix

// before
await page.screenshotMatcher()

// after — inside a Vitest browser test
import { test, expect } from 'vitest/browser'
test('visual', async ({ page }) => {
  await expect(page.getByRole('main')).toMatchScreenshot()
})
Defensive patterns

Strategy: validation

Validate before calling

import type { BrowserCommandContext } from 'vitest/node'

function assertScreenshotContext(ctx: BrowserCommandContext): void {
  if (!ctx.testPath) {
    throw new Error('toMatchScreenshot must run inside a browser test; context.testPath is missing')
  }
}
// call before invoking screenshotMatcher:
assertScreenshotContext(context)

Type guard

const hasTestPath = (c: BrowserCommandContext): c is BrowserCommandContext & { testPath: string } =>
  typeof c.testPath === 'string' && c.testPath.length > 0

Prevention

When it happens

Trigger: Calling `expect(...).toMatchScreenshot()` (which routes to `screenshotMatcher`) from a context where `BrowserCommandContext.testPath` is undefined — e.g. invoking the command outside a registered Vitest test, from a custom runner that doesn't populate `testPath`, or before the test task is bound to the command context.

Common situations: Custom test runners or plugins that call `project.browser.triggerCommand('screenshotMatcher', ...)` directly without forwarding `testPath`; running the screenshot assertion from setup/teardown hooks in some configurations; bugs in third-party frameworks that wrap Vitest's browser command API.

Related errors


AI-assisted analysis of vitest-dev/vitest@d568f8ce37 (2026-08-03). Data as JSON: /data/errors/7956e77a5d9c29c9.json. Report an issue: GitHub.