首先我们以一个基本的 HTML 作为例子,这是我们的目标:
<html>
<body>
<div id="root">
<h1 class="title">Test Titleh1>
<p>Test Paragraph <a href="https://blog.crimx.com">Test Linka> Endp>
div>
body>
html>
DOM APIs
创建 DOM 元素最直接的方式是通过 DOM APIs。
const root = document.createElement('div')
root.id = 'root'
const title = document.createElement('h1')
title.textContent = 'Test Title'
root.appendChild(title)
const p = document.createElement('p')
root.appendChild(p)
p.appendChild(document.createTextNode('Test Paragraph '))
const a = document.createElement('a')
a.href = 'https://blog.crimx.com'
a.textContent = 'Test Link'
p.appendChild(a)
p.appendChild(document.createTextNode(' End'))
document.body.appendChild(root)
优点
- 速度快。
缺点
- 编写较繁琐。
- 不直观。即便使用 document fragment 可以方便离线操作 DOM,光看代码还是不容易看出目标 HTML 是什么样子。
HTML 字符串
另一个最常见的方式是编写 HTML 字符串,通过 innerHTML
解析生成 DOM 元素。
const root = document.createElement('div')
root.id = 'root'
root.innerHTML = `Test Title
Test Paragraph Test Link End
`
document.body.appendChild(root)
优点
- 容易编写。
- 直观。
缺点
- 需要解析字符串,所以会有性能损失,但这个差别非常小(一般最多只有几毫秒),对于测试来说完全可以接受。
- 不好查错。字符串不容易 lint,出现错误需要人眼排查。
JSX
这个问题其实正是 React 团队创造 JSX 语法糖的原因。利用 JSX 我们可以在 JS 文件中编写 Markup,然后转换成相应的 JavaScript 代码。
默认情况下,JSX 生成的渲染函数是 React.createElement(component, props, ...children)
。然而 JSX 只是语法糖,各种 JSX(TSX) 编译器都提供了选项来自定义生成的函数名。我们完全可以换成直接生成 DOM 的库。
如 @babel/plugin-transform-react-jsx 提供了 pragma
等选项;TypeScript 可以在 tsconfig.json 中配置 jsxFactory
。
Babel 例子中配合了 deku 生成 DOM,这个库有点老,写测试也不需要虚拟 DOM 来操作,建议使用更轻量的 tsx-dom(也支持 JSX)。
document.body.appendChild(
<div id='root'><h1 class='title'>Test Titleh1><p>Test Paragraph<a href='https://blog.crimx.com'>Test Linka>Endp>div>
)
优点
- 容易编写。
- 直观。
- 可以使用 JSX 相关的 lint 规则。
缺点
- 需要搭建编译器。虽然如今项目十个有九个都是打包的,但有的脚手架需要 eject 才让配置,这点需要考虑。
总结
如果测试需要大量编写 DOM 元素,使用 JSX 的方式无疑是最方便可靠的;如果只是少量几个测试,可以用 innerHTML
的方式凑合用;一遍不建议使用 DOM APIs ,因为测试首要考虑的应该是直观。
评论