vitest-dev/vitest · error · TypeError
.toContainHTML() expects a string value, got ${htmlText}
Error message
.toContainHTML() expects a string value, got ${htmlText} What it means
Thrown by the toContainHTML matcher (packages/browser/src/client/tester/expect/toContainHTML.ts:33-35) when the second argument (the expected HTML snippet) is not a string. The matcher normalizes the snippet via a temp div.innerHTML (line 20-23), which requires a string; numbers, objects, or undefined would either coerce wrongly or break normalization, so the matcher rejects them with a TypeError.
Source
Thrown at packages/browser/src/client/tester/expect/toContainHTML.ts:34
import type { MatcherResult, MatcherState } from 'vitest'
import type { Locator } from '../locators'
import { getElementFromUserInput } from './utils'
function getNormalizedHtml(container: HTMLElement | SVGElement, htmlText: string) {
const div = container.ownerDocument.createElement('div')
div.innerHTML = htmlText
return div.innerHTML
}
export default function toContainHTML(
this: MatcherState,
actual: Element | Locator,
htmlText: string,
): MatcherResult {
const htmlElement = getElementFromUserInput(actual, toContainHTML, this)
if (typeof htmlText !== 'string') {
throw new TypeError(`.toContainHTML() expects a string value, got ${htmlText}`)
}
return {
pass: htmlElement.outerHTML.includes(getNormalizedHtml(htmlElement, htmlText)),
message: () => {
return [
this.utils.matcherHint(
`${this.isNot ? '.not' : ''}.toContainHTML`,
'element',
'',
),
'Expected:',
` ${this.utils.EXPECTED_COLOR(htmlText)}`,
'Received:',
` ${this.utils.printReceived(htmlElement.cloneNode(true))}`,
].join('\n')
},
}View on GitHub (pinned to d568f8ce37)
Solutions
- Pass the expected markup as a string literal or string variable: expect(el).toContainHTML('<span>Hi</span>').
- If you have a node, serialize it: expect(el).toContainHTML(otherEl.outerHTML).
- Coerce safely only when meaningful: expect(el).toContainHTML(String(value)).
Example fix
// before expect(container).toContainHTML(childElement) // after expect(container).toContainHTML(childElement.outerHTML)
Defensive patterns
Strategy: type-guard
Validate before calling
function ensureHtmlString(v: unknown): string {
if (typeof v === 'string') return v
if (v instanceof Element) return v.outerHTML
throw new TypeError(`toContainHTML expects a string, got ${typeof v}`)
}
expect(container).toContainHTML(ensureHtmlString(maybeNodeOrString)) Type guard
function isHtmlSnippet(v: unknown): v is string {
return typeof v === 'string'
} Prevention
- Pass only string HTML snippets as the second arg to toContainHTML.
- Serialize nodes with .outerHTML before passing them.
When it happens
Trigger: Calling expect(el).toContainHTML(value) where value is a number, an object, null, or undefined — e.g. passing a DOM node instead of its outerHTML string, or passing a variable that was never assigned.
Common situations: Passing an Element where its HTML string was intended (forgot .outerHTML); passing a number from a computed value; refactor that changed the variable type from string to something else.
Related errors
- Invalid element or locator: ${elementOrLocator}. Expected an
- Exact option does not support RegExp expected class names
- .toHaveDisplayValue() currently supports only input, textare
- .toHaveDisplayValue() currently does not support input[type=
- aria adapter expects an Element
AI-assisted analysis of vitest-dev/vitest@d568f8ce37 (2026-08-03).
Data as JSON: /data/errors/d9c03e3a82c597a3.json.
Report an issue: GitHub.