{"record":{"id":"0e782de344636d3d","repo":"vitest-dev/vitest","slug":"tester-html-file-testerhtmlpath-doesn-t-exist","errorCode":null,"errorMessage":"Tester HTML file \"${testerHtmlPath}\" doesn't exist.","messagePattern":"Tester HTML file \"(.+?)\" doesn't exist\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"packages/browser/src/node/project.ts","lineNumber":52,"sourceCode":"\n  public state: BrowserServerState = new BrowserServerState()\n\n  constructor(\n    public parent: ParentBrowserProject,\n    public project: TestProject,\n    public base: string,\n  ) {\n    this.vitest = project.vitest\n    this.config = project.config\n    this.vite = parent.vite\n\n    // instances can override testerHtmlPath\n    const testerHtmlPath = project.config.browser.testerHtmlPath\n      ? resolve(project.config.root, project.config.browser.testerHtmlPath)\n      : resolve(distRoot, 'client/tester/tester.html')\n    // TODO: when config resolution is rewritten, project and parentProject should be created before the vite server is started\n    if (!existsSync(testerHtmlPath)) {\n      throw new Error(`Tester HTML file \"${testerHtmlPath}\" doesn't exist.`)\n    }\n    this.testerFilepath = testerHtmlPath\n    this.testerHtml = readFile(\n      this.testerFilepath,\n      'utf8',\n    ).then(html => (this.testerHtml = html))\n  }\n\n  private commands = {} as Record<string, BrowserCommand<any, any>>\n\n  public registerCommand<K extends keyof BrowserCommands>(\n    name: K,\n    cb: BrowserCommand<\n      Parameters<BrowserCommands[K]>,\n      ReturnType<BrowserCommands[K]>\n    >,\n  ): void {\n    if (!/^[a-z_$][\\w$]*$/i.test(name)) {","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/vitest-dev/vitest/blob/1fa9837ec26533512fdcad8baebf249771bd340a/packages/browser/src/node/project.ts#L34-L70","documentation":"The ProjectBrowser constructor resolves the tester HTML file: either the user-supplied config.browser.testerHtmlPath (resolved against config.root) or the built-in client/tester/tester.html under distRoot. If that file is absent on disk, the tester iframe cannot be served, so construction aborts.","triggerScenarios":"Setting browser.testerHtmlPath to a path that does not exist; running @vitest/browser from source/CI without having built the client (so distRoot/client/tester/tester.html is missing); a packaging defect where the published tarball omits the tester html.","commonSituations":"Custom testerHtmlPath with a typo or relative path that resolves outside the project root; running against a linked, un-built @vitest/browser in a monorepo; an npm publish that excluded the dist/client/tester directory.","solutions":["If you set browser.testerHtmlPath, verify the file exists with `fs.existsSync(path.resolve(config.root, testerHtmlPath))`.","If using the default, rebuild the browser package (`pnpm build --filter @vitest/browser`) or reinstall from npm to restore dist/client/tester/tester.html.","Check that @vitest/browser is not being resolved from a src directory due to a faulty `exports` map or a yarn link.","Confirm the published package version is intact; downgrade or upgrade if the tarball is known-broken."],"exampleFix":"// before\nbrowser: { testerHtmlPath: './custom-tester.html' } // missing file\n// after\nbrowser: { testerHtmlPath: './test/custom-tester.html' } // verified to exist","handlingStrategy":"validation","validationCode":"import { existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\nfunction testerHtmlExists(root: string, custom?: string, distRoot = ''): boolean {\n  const p = custom ? resolve(root, custom) : resolve(distRoot, 'client/tester/tester.html')\n  return existsSync(p)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run `pnpm build` for @vitest/browser before running tests against a linked build.","Verify custom testerHtmlPath values with existsSync at config load.","Reinstall from npm if the published tarball appears to be missing dist files."],"tags":["browser","tester","html","config","build"],"backgroundTag":null,"analyzedSha":"1fa9837ec26533512fdcad8baebf249771bd340a","analyzedAt":"2026-08-11T16:11:39.638Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}