vitest-dev/vitest · error · Error

expected selection must be a string or undefined

Error message

expected selection must be a string or undefined

What it means

Thrown by `toHaveSelection` at toHaveSelection.ts:29-30 when the second argument is defined and not a string. The matcher accepts either an expected selection string or `undefined` (meaning 'any non-empty selection'); numbers, objects, booleans, or arrays are rejected.

Source

Thrown at packages/browser/src/client/tester/expect/toHaveSelection.ts:30

 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 */

import type { MatcherResult, MatcherState } from 'vitest'
import type { Locator } from '../locators'
import { arrayAsSetComparison, getElementFromUserInput, getMessage, getTag } from './utils'

export default function toHaveSelection(
  this: MatcherState,
  element: HTMLElement | SVGElement | Locator,
  expectedSelection: string,
): MatcherResult {
  const htmlElement = getElementFromUserInput(element, toHaveSelection, this)

  const expectsSelection = expectedSelection !== undefined

  if (expectsSelection && typeof expectedSelection !== 'string') {
    throw new Error(`expected selection must be a string or undefined`)
  }

  const receivedSelection = getSelection(htmlElement)

  return {
    pass: expectsSelection
      ? this.equals(receivedSelection, expectedSelection, [arrayAsSetComparison, ...this.customTesters])
      : Boolean(receivedSelection),
    message: () => {
      const to = this.isNot ? 'not to' : 'to'
      const matcher = this.utils.matcherHint(
        `${this.isNot ? '.not' : ''}.toHaveSelection`,
        'element',
        expectedSelection,
      )
      return getMessage(
        this,
        matcher,

View on GitHub (pinned to d568f8ce37)

Solutions

  1. Pass the literal selected text as a string: `expect(el).toHaveSelection('hello')`.
  2. If you only want to assert *some* selection exists, pass `undefined` or omit the argument: `expect(el).toHaveSelection()`.
  3. Coerce with `String(...)` only if the value really is text; otherwise fix the source of the wrong type.

Example fix

// before
expect(el).toHaveSelection(selectionLength) // number

// after
expect(el).toHaveSelection('expected substring')
Defensive patterns

Strategy: type-guard

Validate before calling

function isStringOrUndefined(v: unknown): v is string | undefined {
  return v === undefined || typeof v === 'string'
}
if (!isStringOrUndefined(selection)) throw new Error('selection must be string or undefined')

Type guard

function isStringOrUndefined(v: unknown): v is string | undefined {
  return v === undefined || typeof v === 'string'
}

Prevention

When it happens

Trigger: Calling `expect(el).toHaveSelection(123)`, `expect(el).toHaveSelection(['a','b'])`, `expect(el).toHaveSelection({ start: 0 })`, or passing a number-typed value. The guard runs only when `expectedSelection !== undefined`.

Common situations: Passing a character offset or range object by mistake. Migrating from a different selection API and assuming an index is accepted. Building the expected value from `JSON.parse` of user input that yields a non-string.

Related errors


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