在单元测试中,如何最有效地创建一个用于模拟的伪造HTMLElement?为什么DOMParser/Document.parseHTMLUnsafe无法工作,只返回HTMLDocument?

前端开发 2026-07-10

背景

我有一段代码,它:

  • 想要检查一个元素是否是一个HTML元素,条件是 thing instanceof HTMLElement,然后据此采取相应的行动。 根据 Stack Overflow的说法,这是现代且推荐的做法。

  • 测试这一点时,结果比预期要棘手,因为:

  • 尽管你可以很容易地解析HTML代码——最好通过像 Document.parseHTMLUnsafe 这样的现代方法——但实际并不能这样被接受,也就是说 instanceof HTMLElement 会失败!

  • 原因似乎是返回的“解析后的HTML”并不实际是一个 HTMLElement,而是一个 HTMLDocument,这真的会让人困惑,在我看来,因为细微的差别可能导致许多错误。

  • 在调试时,typeof thing总是 返回 object

  • 你也可以通过在后面使用一个 .getElementById('realHtmlElement') 来绕过它,如下所示。在测试中,这仍然相当奇怪且不易解释清楚。

示例代码

const realHtmlElement = document.getElementById('realHtmlElement');
console.log("realHtmlElement instanceof", typeof realHtmlElement, realHtmlElement instanceof HTMLElement)
// => true

const legacyDomParser = (new DOMParser()).parseFromString('<div id="thing">Text</div>', 'text/html');
console.log("legacyDomParser instanceof", typeof legacyDomParser, legacyDomParser instanceof HTMLElement)
// => will be HTMLDocument instead and false

const legacyDomParserGetElementById = (new DOMParser()).parseFromString('<div id="thing">Text</div>', 'text/html').getElementById('thing');
console.log("legacyDomParserGetElementById instanceof", typeof legacyDomParserGetElementById, legacyDomParserGetElementById instanceof HTMLElement)
// => true

const htmlDoc = Document.parseHTMLUnsafe('<div id="thing">Text</div>');
console.log("htmlDoc instanceof", typeof htmlDoc, htmlDoc instanceof HTMLElement)
// => will be HTMLDocument instead and false

const elementById = Document.parseHTMLUnsafe('<div id="thing">Text</div>').getElementById('thing');
console.log("elementById instanceof", typeof elementById, elementById instanceof HTMLElement)
// => true
<div id="realHtmlElement"></div>

这里的最佳方法是什么?getElementById 是最佳解决方案吗,还是我们也许可以更容易地得到一个HTML元素(即一个“真正的” HTMLElement)?

解决方案

DOMParserDocument.parseHTMLUnsafe 构建了一个完整的 HTMLDocument 上下文。它们不会返回孤立的 HTMLElement 节点。对 HTMLElement 的实例检查会失败,因为根对象是一个文档,而不是一个元素。

<template> 标签会把标记解析成一个 DocumentFragment。从该片段中提取第一个子节点即可得到精确的 HTMLElement,无需进行文档遍历或触发脚本执行。

function createHTMLElement(htmlString) {
  const template = document.createElement('template');
  template.innerHTML = htmlString.trim();
  return template.content.firstElementChild;
}


const inputString = '<div id="thing">Text</div>';
const element = createHTMLElement(inputString);

console.log("Instance check:", element instanceof HTMLElement);
console.log("Specific instance check:", element instanceof HTMLDivElement);
console.log("Tag:", element.tagName);
console.log("ID:", element.id);
console.log("Content:", element.textContent);
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章