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` when the matcher's `this` context lacks `this.task` or `this.currentTestName`. The screenshot command needs the running test's identity (to name reference files, attach artifacts, and compute a per-test counter) and the test path; without them it cannot place the captured image. This typically means the matcher was called outside a live Vitest browser test.
Solutions
- Ensure the project uses the browser environment: set `// @vitest-environment browser` at the top of the test file or configure `environment: 'browser'`.
- Call `toMatchScreenshot` directly inside an `it(...)`/`test(...)` body, not in `beforeAll` or detached callbacks.
- If testing the matcher in isolation, construct a full `MatcherState` with `task`, `currentTestName`, and `testPath`, or refactor to invoke it through the real runner.
Example fix
// before (called outside a test, e.g. in a helper module)
expect(page).toMatchScreenshot('home')
// after
import { test, expect } from 'vitest'
test('home renders', () => {
expect(page).toMatchScreenshot('home')
}) Defensive patterns
Strategy: validation
Validate before calling
// ensure the matcher runs inside a live browser test
import { test, expect } from 'vitest'
test('visual', () => {
expect(page).toMatchScreenshot('home')
}) Prevention
- Use `// @vitest-environment browser` or set `environment: 'browser'` in config.
- Call screenshot matchers only inside `test()`/`it()` bodies.
- Avoid invoking matchers from detached promises or setup hooks.
When it happens
Trigger: Calling `toMatchScreenshot` from a plain script, a Vitest `beforeAll`/global setup that runs outside the test scope, a manually constructed expect context, or any environment where the matcher is invoked without Vitest binding its `MatcherState`.
Common situations: Unit-testing the matcher itself in isolation; importing the browser tester entry in Node; calling the matcher inside a `setTimeout`/detached promise after the test finished; running browser matchers under the default Node environment instead of `@vitest/browser`.
Related errors
- Cannot compare screenshots without a test path
- 'toMatchScreenshot' cannot be used with "not"
- Cannot take a screenshot in a concurrent test because…
- Cannot take a screenshot outside of a test.
- Cannot take a screenshot without a test path
AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11).
Data as JSON: /api/errors/5e63c7f6985c22a4.
Report an issue: GitHub.
Appendix: 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 1fa9837ec2)