{"record":{"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/1fa9837ec26533512fdcad8baebf249771bd340a/packages/browser/src/client/tester/expect/toContainHTML.ts#L16-L52","documentation":"The .toContainHTML() matcher requires its second argument (the expected HTML snippet) to be a string so it can be normalized and injected into a detached div for comparison. Passing a non-string (number, object, null, undefined) throws a TypeError before any comparison occurs. This is a strict input-type guard, not a comparison failure.","triggerScenarios":"Calling expect(el).toContainHTML(123) or .toContainHTML({ tag: 'div' }); passing a variable holding null because the expected HTML was never assigned; interpolating a non-string template result.","commonSituations":"Building expected HTML dynamically and accidentally passing a number/object; refactoring that changed a string constant to an object; null defaults from optional config.","solutions":["Ensure the expected argument is always a string literal or a string-typed variable.","Add a typeof check before the assertion if the value comes from dynamic input.","Use String(value) only if a coercion is genuinely intended."],"exampleFix":"// before\nconst html = parts.length\nexpect(el).toContainHTML(html)\n// after\nconst html = parts.join('')\nexpect(el).toContainHTML(html)","handlingStrategy":"validation","validationCode":"if (typeof htmlText !== 'string') {\n  throw new TypeError('expected HTML must be a string')\n}\nexpect(el).toContainHTML(htmlText)","typeGuard":"function isString(v: unknown): v is string {\n  return typeof v === 'string'\n}","tryCatchPattern":null,"preventionTips":["Type expected HTML parameters as string in helper signatures.","Verify dynamic HTML builders return strings before assertion.","Add a typeof check in shared assertion utilities."],"tags":["browser","expect","matcher","type-guard","html"],"backgroundTag":null,"analyzedSha":"1fa9837ec26533512fdcad8baebf249771bd340a","analyzedAt":"2026-08-11T16:11:39.638Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}