在单元测试中,如何最有效地创建一个用于模拟的伪造HTMLElement?为什么DOMParser/Document.parseHTMLUnsafe无法工作,只返回HTMLDocument?
背景
我有一段代码,它:
-
想要检查一个元素是否是一个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)?
解决方案
DOMParser 和 Document.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导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。