{"id":"087526821f58d90e","repo":"vitest-dev/vitest","slug":"expected-dom-element-to-be-an-instance-of-element","errorCode":null,"errorMessage":"Expected DOM element to be an instance of Element, received ${typeof element}","messagePattern":"Expected DOM element to be an instance of Element, received (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/browser/src/client/tester/tester-utils.ts","lineNumber":11,"sourceCode":"import type { Locator, SelectorOptions, SerializedLocator, UserEventWheelDeltaOptions, UserEventWheelOptions } from 'vitest/browser'\nimport type { BrowserRPC } from '../client'\nimport type { BrowserTraceEntryStatus } from './trace'\nimport { __INTERNAL } from 'vitest/internal/browser'\nimport { getBrowserState, getWorkerState, now } from '../utils'\nimport { createBrowserTraceRangeId, recordBrowserTraceEntry } from './trace'\n\n/* @__NO_SIDE_EFFECTS__ */\nexport function convertElementToCssSelector(element: Element): string {\n  if (!element || !(element instanceof Element)) {\n    throw new Error(\n      `Expected DOM element to be an instance of Element, received ${typeof element}`,\n    )\n  }\n\n  return getUniqueCssSelector(element)\n}\n\nfunction escapeIdForCSSSelector(id: string) {\n  return id\n    .split('')\n    .map((char) => {\n      const code = char.charCodeAt(0)\n\n      if (char === ' ' || char === '#' || char === '.' || char === ':' || char === '[' || char === ']' || char === '>' || char === '+' || char === '~' || char === '\\\\') {\n        // Escape common special characters with backslashes\n        return `\\\\${char}`\n      }\n      else if (code >= 0x10000) {","sourceCodeStart":1,"sourceCodeEnd":29,"githubUrl":"https://github.com/vitest-dev/vitest/blob/d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09/packages/browser/src/client/tester/tester-utils.ts#L1-L29","documentation":"Thrown by `convertElementToCssSelector` at tester-utils.ts:10-14 when its argument is falsy or not an `instanceof Element`. This helper builds a unique CSS selector for an element so it can be shipped to the browser-driver (Playwright/WebDriver) for interaction; passing anything other than a real DOM Element makes selector generation impossible.","triggerScenarios":"Passing `null`/`undefined`, a text node, a Locator whose `.element()` returned null, a Window, or a serialized element stub. Triggered indirectly by locators and user-event utilities that ultimately call `convertElementToCssSelector`.","commonSituations":"A Locator resolved to nothing because the element wasn't in the DOM yet (timing). Selecting via `querySelector` that returned null and not guarding. Passing a React/Vue ref wrapper object instead of `.current`.","solutions":["Ensure the element exists in the DOM before resolving it; use `await page.locator(...).element()` or wait helpers.","Unwrap refs/holders: pass `ref.current`, not the ref object.","Add a null guard and fail with a clearer message if the element genuinely isn't present."],"exampleFix":"// before\nconst el = document.querySelector('.maybe-gone')\nconvertElementToCssSelector(el) // el is null\n\n// after\nconst el = document.querySelector('.maybe-gone')\nif (!el) throw new Error('element missing')\nconvertElementToCssSelector(el)","handlingStrategy":"type-guard","validationCode":"function isElement(v: unknown): v is Element {\n  return v instanceof Element\n}\nif (!isElement(target)) throw new Error('target is not a DOM Element')","typeGuard":"function isElement(v: unknown): v is Element {\n  return v instanceof Element\n}","tryCatchPattern":null,"preventionTips":["Resolve elements with querySelector/locator.element() and guard for null.","Unwrap framework refs (ref.current) before passing.","Use waitFor/locator waits to ensure presence before resolution."],"tags":["browser","dom","locator","type-validation","tester-utils"],"analyzedSha":"d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09","analyzedAt":"2026-08-03T20:23:56.861Z","schemaVersion":2}