{"id":"d9c03e3a82c597a3","repo":"vitest-dev/vitest","slug":"tocontainhtml-expects-a-string-value-got-htm","errorCode":null,"errorMessage":".toContainHTML() expects a string value, got ${htmlText}","messagePattern":"\\.toContainHTML\\(\\) expects a string value, got (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/browser/src/client/tester/expect/toContainHTML.ts","lineNumber":34,"sourceCode":"import type { MatcherResult, MatcherState } from 'vitest'\nimport type { Locator } from '../locators'\nimport { getElementFromUserInput } from './utils'\n\nfunction getNormalizedHtml(container: HTMLElement | SVGElement, htmlText: string) {\n  const div = container.ownerDocument.createElement('div')\n  div.innerHTML = htmlText\n  return div.innerHTML\n}\n\nexport default function toContainHTML(\n  this: MatcherState,\n  actual: Element | Locator,\n  htmlText: string,\n): MatcherResult {\n  const htmlElement = getElementFromUserInput(actual, toContainHTML, this)\n\n  if (typeof htmlText !== 'string') {\n    throw new TypeError(`.toContainHTML() expects a string value, got ${htmlText}`)\n  }\n\n  return {\n    pass: htmlElement.outerHTML.includes(getNormalizedHtml(htmlElement, htmlText)),\n    message: () => {\n      return [\n        this.utils.matcherHint(\n          `${this.isNot ? '.not' : ''}.toContainHTML`,\n          'element',\n          '',\n        ),\n        'Expected:',\n        `  ${this.utils.EXPECTED_COLOR(htmlText)}`,\n        'Received:',\n        `  ${this.utils.printReceived(htmlElement.cloneNode(true))}`,\n      ].join('\\n')\n    },\n  }","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/vitest-dev/vitest/blob/d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09/packages/browser/src/client/tester/expect/toContainHTML.ts#L16-L52","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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))."],"exampleFix":"// before\nexpect(container).toContainHTML(childElement)\n// after\nexpect(container).toContainHTML(childElement.outerHTML)","handlingStrategy":"type-guard","validationCode":"function ensureHtmlString(v: unknown): string {\n  if (typeof v === 'string') return v\n  if (v instanceof Element) return v.outerHTML\n  throw new TypeError(`toContainHTML expects a string, got ${typeof v}`)\n}\nexpect(container).toContainHTML(ensureHtmlString(maybeNodeOrString))","typeGuard":"function isHtmlSnippet(v: unknown): v is string {\n  return typeof v === 'string'\n}","tryCatchPattern":null,"preventionTips":["Pass only string HTML snippets as the second arg to toContainHTML.","Serialize nodes with .outerHTML before passing them."],"tags":["browser","expect","matcher","tocontainhtml","type-error"],"analyzedSha":"d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09","analyzedAt":"2026-08-03T20:23:56.861Z","schemaVersion":2}