{"id":"2acada4c7fda6269","repo":"vitest-dev/vitest","slug":"expected-selection-must-be-a-string-or-undefined","errorCode":null,"errorMessage":"expected selection must be a string or undefined","messagePattern":"expected selection must be a string or undefined","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/browser/src/client/tester/expect/toHaveSelection.ts","lineNumber":30,"sourceCode":" * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n */\n\nimport type { MatcherResult, MatcherState } from 'vitest'\nimport type { Locator } from '../locators'\nimport { arrayAsSetComparison, getElementFromUserInput, getMessage, getTag } from './utils'\n\nexport default function toHaveSelection(\n  this: MatcherState,\n  element: HTMLElement | SVGElement | Locator,\n  expectedSelection: string,\n): MatcherResult {\n  const htmlElement = getElementFromUserInput(element, toHaveSelection, this)\n\n  const expectsSelection = expectedSelection !== undefined\n\n  if (expectsSelection && typeof expectedSelection !== 'string') {\n    throw new Error(`expected selection must be a string or undefined`)\n  }\n\n  const receivedSelection = getSelection(htmlElement)\n\n  return {\n    pass: expectsSelection\n      ? this.equals(receivedSelection, expectedSelection, [arrayAsSetComparison, ...this.customTesters])\n      : Boolean(receivedSelection),\n    message: () => {\n      const to = this.isNot ? 'not to' : 'to'\n      const matcher = this.utils.matcherHint(\n        `${this.isNot ? '.not' : ''}.toHaveSelection`,\n        'element',\n        expectedSelection,\n      )\n      return getMessage(\n        this,\n        matcher,","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/vitest-dev/vitest/blob/d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09/packages/browser/src/client/tester/expect/toHaveSelection.ts#L12-L48","documentation":"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.","triggerScenarios":"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`.","commonSituations":"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.","solutions":["Pass the literal selected text as a string: `expect(el).toHaveSelection('hello')`.","If you only want to assert *some* selection exists, pass `undefined` or omit the argument: `expect(el).toHaveSelection()`.","Coerce with `String(...)` only if the value really is text; otherwise fix the source of the wrong type."],"exampleFix":"// before\nexpect(el).toHaveSelection(selectionLength) // number\n\n// after\nexpect(el).toHaveSelection('expected substring')","handlingStrategy":"type-guard","validationCode":"function isStringOrUndefined(v: unknown): v is string | undefined {\n  return v === undefined || typeof v === 'string'\n}\nif (!isStringOrUndefined(selection)) throw new Error('selection must be string or undefined')","typeGuard":"function isStringOrUndefined(v: unknown): v is string | undefined {\n  return v === undefined || typeof v === 'string'\n}","tryCatchPattern":null,"preventionTips":["Type the expected selection parameter as string | undefined at call sites.","If you only care that some selection exists, omit the argument entirely.","Avoid passing numeric offsets/range objects; this matcher compares selected text."],"tags":["browser","expect-matcher","tohaveselection","argument-validation"],"analyzedSha":"d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09","analyzedAt":"2026-08-03T20:23:56.861Z","schemaVersion":2}