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 the `toHaveSelection` matcher when the expected-selection argument is defined (not undefined) but is not a string. The matcher reads `selection.toString()` from the DOM and compares it to a string; a non-string expected value cannot be compared meaningfully, so it rejects the call up front. Passing `undefined` is allowed and means 'assert that some selection exists'.
Solutions
- Pass the exact selected text string, e.g. `expect(el).toHaveSelection('hello')`.
- To assert only that a selection exists, omit the argument or pass `undefined`: `expect(el).toHaveSelection()`.
- If you need offset-based assertions, read `element.selectionStart`/`selectionEnd` directly and assert with `toBe`.
Example fix
// before
expect(input).toHaveSelection(5)
// after
expect(input).toHaveSelection('hello') Defensive patterns
Strategy: type-guard
Validate before calling
if (expected !== undefined && typeof expected !== 'string') {
throw new TypeError('expectedSelection must be a string or undefined')
}
expect(el).toHaveSelection(expected) Type guard
function isSelectionArg(v: unknown): v is string | undefined {
return v === undefined || typeof v === 'string'
} Prevention
- Pass the exact selected text, or omit the argument to assert existence.
- Let the `string` TypeScript parameter type catch non-string calls.
- For offset-based checks, assert on `selectionStart`/`selectionEnd` directly.
When it happens
Trigger: Calling `expect(el).toHaveSelection(42)`, `.toHaveSelection(['a','b'])`, or `.toHaveSelection({ start: 0 })`. Also any value whose `typeof` is not `'string'` and not `'undefined'`.
Common situations: Passing a number where the test meant to assert selected text length; passing an array of strings; confusing `toHaveSelection` (text content) with a hypothetical range/offset API; TypeScript callers bypassing types with `as any`.
Related errors
- received value must a Node or a Locator that returns a Node.
- received value must an HTMLElement or an SVGElement or a…
- toHaveFormValues must be called with an object of expected…
- Exact option does not support RegExp expected class names
- input with type=checkbox or type=radio cannot be used with…
AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11).
Data as JSON: /api/errors/2acada4c7fda6269.
Report an issue: GitHub.
Appendix: 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 1fa9837ec2)