vitest-dev/vitest · error · Error

'toMatchScreenshot' cannot be used without test context

Error message

'toMatchScreenshot' cannot be used without test context

What it means

Thrown by `toMatchScreenshot` at toMatchScreenshot.ts:23-24 when `this.task` or `this.currentTestName` is undefined — i.e. the matcher is invoked outside of an active test scope. The matcher needs the task to record artifacts and the test name to build a stable screenshot filename.

Source

Thrown at packages/browser/src/client/tester/expect/toMatchScreenshot.ts:24

import { getBrowserState } from '../../utils'
import { serializeElement } from '../tester-utils'

const counters = new Map<string, { current: number }>([])

export default async function toMatchScreenshot(
  this: MatcherState,
  actual: BrowserPage | Element | Locator,
  nameOrOptions?: ScreenshotMatcherOptions | string,
  options: ScreenshotMatcherOptions = typeof nameOrOptions === 'object'
    ? nameOrOptions
    : {},
): AsyncMatcherResult {
  if (this.isNot) {
    throw new Error('\'toMatchScreenshot\' cannot be used with "not"')
  }

  if (this.task === undefined || this.currentTestName === undefined) {
    throw new Error('\'toMatchScreenshot\' cannot be used without test context')
  }

  const counterName = `${this.task.result?.repeatCount ?? 0}${this.testPath}${this.currentTestName}`
  let counter = counters.get(counterName)

  if (counter === undefined) {
    counter = { current: 0 }

    counters.set(counterName, counter)
  }

  counter.current += 1

  const name = typeof nameOrOptions === 'string'
    ? nameOrOptions
    : `${this.currentTestName} ${counter.current}`

  const isPageTarget = isBrowserPage(actual)

View on GitHub (pinned to d568f8ce37)

Solutions

  1. Move the `toMatchScreenshot` call inside an `it()`/`test()` body so the matcher state is populated.
  2. If in a helper, ensure the helper is only called from within a test and that the matcher `this` binding is preserved.
  3. For setup-time screenshots use Playwright/Vitest browser APIs (`page.screenshot()`) instead of the matcher.

Example fix

// before
beforeAll(async () => {
  await page.goto('/')
  expect(page).toMatchScreenshot('home.png') // no test context
})

// after
it('renders home', async () => {
  await page.goto('/')
  expect(page).toMatchScreenshot('home.png')
})
Defensive patterns

Strategy: validation

Validate before calling

function inTestScope(ctx: { task?: unknown; currentTestName?: string }): boolean {
  return ctx.task !== undefined && ctx.currentTestName !== undefined
}
if (!inTestScope({ task, currentTestName })) throw new Error('toMatchScreenshot must run inside it()/test()')

Prevention

When it happens

Trigger: Calling `toMatchScreenshot` from a plain function, inside `beforeAll`/`setup`, at module top level, or inside a Vitest utility invoked outside a test body. Also happens when the matcher is called inside a worker/preview context that never received the test task from the runner.

Common situations: Trying to take a baseline screenshot during page setup before any `it()` runs. Calling the matcher inside a custom command helper that is also invoked outside tests. Running the matcher via a manual `expect` invocation in a script.

Related errors


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