vitest-dev/vitest · error · Error
Cannot take a screenshot without a test path
Error message
Cannot take a screenshot without a test path
What it means
Vitest's browser screenshot command (takeScreenshot) resolves the output path from the running test file. It requires context.testPath to compute where to save the screenshot. Without a bound test file there is no deterministic location, so the command refuses to run. This is the entry behind page.screenshot(), expect(element).toMatchScreenshot(), and the expect(page).toMatchSnapshot() flow when targeting the browser.
Solutions
- Move the screenshot call inside an `it('...', async () => { ... })` body so a testPath is bound.
- Verify `test.browser` project is using `pool: 'browser'` and the file matches `test.include` for the browser project, not a node project.
- If invoking from a custom browser command, only call it when `context.testPath` is defined; guard with `if (!context.testPath) return`.
- Ensure the test file is not imported by a non-browser runner (e.g. eslint, typecheck, or a node test config) that would execute it without testPath.
Example fix
// before
import { page } from 'vitest/browser'
page.screenshot() // at module top-level -> throws
// after
import { test, expect } from 'vitest'
import { page } from 'vitest/browser'
test('renders', async () => {
await expect(page).toHaveScreenshot()
}) Defensive patterns
Strategy: validation
Validate before calling
import type { BrowserCommandContext } from 'vitest/node'
function assertInTest(ctx: BrowserCommandContext): asserts ctx is BrowserCommandContext & { testPath: string } {
if (!ctx.testPath) {
throw new Error('page.screenshot() must be called inside an it()/test() block')
}
}
// before screenshotting:
assertInTest(context) Type guard
function hasTestPath(ctx: { testPath?: string }): ctx is { testPath: string } {
return typeof ctx.testPath === 'string' && ctx.testPath.length > 0
} Prevention
- Only call page.screenshot()/toMatchScreenshot() inside an `it`/`test` body.
- Keep browser specs in a dedicated project with `pool: 'browser'` so testPath is always set.
- Do not import screenshot helpers from setup files that may run without a test.
When it happens
Trigger: Calling page.screenshot() / expect(locator).toMatchScreenshot() from outside an `it`/`test` callback (e.g. module top-level, beforeAll/beforeEach that runs without testPath, a plain script importing vitest/browser, or a custom browser command invoked without a test in scope). Also when a screenshot is triggered during global teardown where BrowserCommandContext.testPath is undefined.
Common situations: Running browser tests with a pool that does not set testPath; invoking screenshot logic from a helper imported by both browser and non-browser specs; misconfigured project where browser tests accidentally run under the `forks`/`threads` pool; calling takeScreenshot via a registered browser command at a time vitest has not yet entered a test.
Related errors
- Page " " not found in browser.
- [vitest] The provider was closed.
- Browser is not initialized
- Browser provider is not defined for the project
- Cannot compare screenshots without a test path
AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11).
Data as JSON: /api/errors/2fec3b4ccbe5cee8.
Report an issue: GitHub.
Appendix: source
Thrown at packages/browser-playwright/src/commands/screenshot.ts:38
transform: none !important;
}
`
/**
* Takes a screenshot using the provided browser context and returns a buffer and the expected screenshot path.
*
* **Note**: the returned `path` indicates where the screenshot *might* be found.
* It is not guaranteed to exist, especially if `options.save` is `false`.
*
* @throws {Error} If the function is not called within a test or if the browser provider does not support screenshots.
*/
export async function takeScreenshot(
context: BrowserCommandContext,
name: string,
options: Omit<ScreenshotCommandOptions, 'base64'>,
): Promise<{ buffer: Buffer<ArrayBufferLike>; path: string }> {
if (!context.testPath) {
throw new Error(`Cannot take a screenshot without a test path`)
}
const path = resolveScreenshotPath(
context.testPath,
name,
context.project.config,
options.path,
)
// playwright does not need a screenshot path if we don't intend to save it
let savePath: string | undefined
if (options.save) {
savePath = normalize(path)
assertBrowserApiWrite(context.project, savePath)
assertBrowserFileAccess(context.project, savePath)
View on GitHub (pinned to 1fa9837ec2)