vitest-dev/vitest · error · UserInputElementTypeError

received value must ${expectedString} or a Locator that retu

Error message

received value must ${expectedString} or a Locator that returns ${expectedString}.

What it means

Thrown via the `UserInputElementTypeError` class (utils.ts:55, 192-200) which subclasses `GenericTypeError` with the expected string `'an HTMLElement or an SVGElement'`. It fires from `getElementFromUserInput` (utils.ts:42-60) when the resolved value is neither an `HTMLElement` nor an `SVGElement` of its owner document's defaultView. The message template lives at utils.ts:184-188.

Source

Thrown at packages/browser/src/client/tester/expect/utils.ts:55

  elementOrLocator: Element | Locator | null,
  // TODO: minifier doesn't keep names, so we need to update this
  matcherFn: (...args: any) => any,
  context: MatcherState,
): HTMLElement | SVGElement {
  if (elementOrLocator instanceof Locator) {
    elementOrLocator = elementOrLocator.element()
  }

  const defaultView = elementOrLocator?.ownerDocument?.defaultView || window

  if (
    elementOrLocator instanceof defaultView.HTMLElement
    || elementOrLocator instanceof defaultView.SVGElement
  ) {
    return elementOrLocator
  }

  throw new UserInputElementTypeError(
    elementOrLocator,
    matcherFn,
    context,
  )
}

export function getNodeFromUserInput(
  elementOrLocator: Element | Locator,
  matcherFn: (...args: any) => any,
  context: MatcherState,
): Node {
  if (elementOrLocator instanceof Locator) {
    elementOrLocator = elementOrLocator.element()
  }

  const defaultView = elementOrLocator.ownerDocument?.defaultView || window

  if (

View on GitHub (pinned to d568f8ce37)

Solutions

  1. Ensure you pass a DOM Element (e.g. `document.querySelector('button')`) or a Vitest Locator that resolves to one.
  2. For iframe contents, resolve the element through that iframe's document so `instanceof` matches the correct realm.
  3. If you hold a Node, walk up to its parentElement/ownerDocument.documentElement to obtain an Element.

Example fix

// before
expect(document).toHaveValue('x')

// after
expect(document.querySelector('input')!).toHaveValue('x')
Defensive patterns

Strategy: type-guard

Validate before calling

function isHtmlOrSvg(el: unknown, view: Window = window): boolean {
  return el instanceof view.HTMLElement || el instanceof view.SVGElement
}
if (!isHtmlOrSvg(target)) throw new Error('expected HTMLElement or SVGElement')

Type guard

function isHtmlOrSvgElement(el: unknown, view: Window = window): el is HTMLElement | SVGElement {
  return el instanceof view.HTMLElement || el instanceof view.SVGElement
}

Prevention

When it happens

Trigger: Passing a text node, a Document, a Window, a plain object, a number, or a Locator whose `element()` resolves to a non-element Node to any matcher that calls `getElementFromUserInput` (e.g. `toBeChecked`, `toHaveValue`, `toHaveSelection`, `toHaveFormValues`). Cross-realm element instances whose constructor differs from the document's `defaultView.HTMLElement` also fail.

Common situations: Passing `document` or `window` by mistake. Grabbing a text node via `element.firstChild`. Element coming from an iframe whose `defaultView` differs. Serializer returning a wrapper object instead of a real Element.

Related errors


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