测试
编辑此页面测试 Solid 应用程序非常重要,它可以通过防止出现错误导致倒退,进而激发对代码库的信心。
开始
测试包说明
vitest
- 测试框架,包括运行器、断言引擎和 mock 设施jsdom
- 虚拟 DOM,用于模拟在 node 中运行的无头浏览器环境@solidjs/testing-library
- 一个用于简化测试组件、指令和原语的库,具有自动清理功能@testing-library/user-event
- 用于模拟更接近现实的用户事件@testing-library/jest-dom
- 提供了有用的 matchers,加强了断言功能
添加测试包
Solid 应用程序的推荐测试框架是 vitest 。
要开始使用 vitest,请安装以下开发依赖项:
测试配置
在您的 package.json
中添加一个 test
脚本调用 vitest
:
无需将 @testing-library/jest-dom
添加到 vite.config
中的测试选项,因为 vite-plugin-solid
会自动检测并加载它(如果存在)。
TypeScript 配置
如果使用 TypeScript,请将 @testing-library/jest-dom
添加到 tsconfig.json#compilerOptions.types
:
SolidStart 配置
使用 SolidStart 时,创建一个 vitest.config.ts
文件:
编写测试
组件测试
组件测试包含三个主要内容:
- 渲染组件
- 与组件交互
- 验证断言
要为组件编写测试,请创建一个 [name].test.tsx
文件。该文件的目的是以单元测试的形式从用户的角度描述预期的行为:
在 test.jsx
文件中,来自 @solidjs/testing-library
的 render 函数用于渲染组件并提供 props 和上下文。
为了模拟用户交互,使用 @testing-library/user-event
。
vitest
提供的 expect 函数使用 @testing-library/jest-dom
中的 .ToHaveTextContent("content")
匹配器,提供该组件的预期行为是什么。
要运行此测试,请使用以下命令:
如果运行命令成功,您将得到以下结果,显示测试是否通过或失败:
渲染组件
@solidjs/testing-library
中的 render
函数在 test.tsx
文件中创建测试环境。它设置容器,在其中渲染组件,并自动注册它,测试成功后自动清理。此外,它还将组件包装在上下文中以及设置路由。
使用正确的查询
查询是用于查找页面内元素:
前缀(get
、query
和 find
)和中间部分(By
和 AllBy
)取决于查询是否应该等待元素出现(或不出现)、如果元素没有找到是否应该抛出错误,以及如何处理多个匹配:
- getBy: 同步,如果未找到或超过 1 个匹配则抛出异常
- getAllBy: 同步,如果未找到则抛出异常,返回匹配数组
- queryBy: 同步,如果未找到则为 null,如果超过 1 个匹配则出错
- queryAllBy: 同步,返回零个或多个匹配项的数组
- findBy: 异步,如果在 1000 毫秒内未找到或超过 1 个匹配项则 rejected,如果找到则解析元素
- findAllBy: 异步,如果在 1000 毫秒内未找到则 rejected,解析为包含一个或多个元素的数组
默认情况下,查询应以 get...
开头。如果有多个元素匹配同一查询,则应使用 getAllBy...
,否则使用 getBy...
。
有两种例外情况不应以 get...
开头:
- 如果使用
location
选项或者组件是基于 resources 的,则路由将延迟加载;在这种情况下,渲染后的第一个查询需要是find...
。 - 当测试未渲染的内容时,您需要找到同时渲染的内容;之后,使用
queryAllBy...
测试结果是否为空数组 ([]
)。
查询的后缀(Role
、LabelText
...)取决于您要选择的元素的特征。如果可能,尝试选择可访问的属性(大致按以下顺序):
- Role: WAI ARIA 由语义元素自动设置,像
<button>
或其他使用role
属性 - LabelText: 由标签包裹或
aria-label
属性描述的元素,或者与for
- 或aria-labelledby
属性链接的元素 - PlaceholderText: 具有
placeholder
属性的 input 元素 - Text: 搜索元素中所有文本节点内的文本,即使拆分为多个节点
- DisplayValue: 显示给定值的表单元素(例如选择元素)
- AltText: 带有 alt 文本的图像
- Title: 具有
title
属性的 HTML 元素或具有包含给定文本的<title>
标记的 SVG - TestId: 通过
data-testid
属性查询;可以通过configure({testIdAttribute: 'data-my-test-attribute'})
设置不同的数据属性; TestId-queries 不可访问,因此仅将它们用作最后的手段。
有关更多信息,请查看测试库文档。
测试 Portal
Solid 允许组件使用 <Portal>
突破 DOM 树结构。该机制在测试中仍然有效,因此 portals 的内容将脱离测试容器。为了测试此内容,请确保使用 screen
导出来查询内容:
在上下文中进行测试
如果组件依赖于某些上下文,请使用 wrapper
选项来包装它:
如果包装器是外部创建的,可以重复使用。对于具有不同值的包装器,创建所需包装器的高阶组件可以使测试更加简洁:
如果使用多个 providers,solid-primitives 有 <MultiProvider>
避免嵌套多级 providers
测试路由
为了方便起见,render
函数支持 location
选项,该选项将渲染的组件包装在指向给定位置的路由中。由于 <Router>
组件是延迟加载的,因此渲染后的第一个查询需要异步,即 findBy...
:
与组件交互
许多组件不是静态的,而是根据用户交互而变化。为了测试这些变化,需要模拟这些交互。为了模拟用户交互,可以使用 @testing-library/user-event
库。它负责处理实际用户交互中发生的事件的通常顺序。例如,来自用户的 click
事件将伴随 mousemove
、 hover
、 keydown
、 focus
、 keyup
和 keypress
。
最方便测试的事件通常是 click
、 keyboard
和 pointer
(模拟触摸事件)。要更深入地了解这些事件,您可以在 user-event 文档中学习。
使用定时器
如果您需要一个假计时器并希望在测试中使用 vi.useFakeTimers()
,则必须使用 advanceTimers
选项对其进行设置:
验证断言
vitest
附带 expect
函数来增强断言,其工作原理如下:
该命令支持开箱即用的断言,例如 toBe
(引用比较)和 toEqual
(值比较)。为了在 DOM 内部进行测试,@testing-library/jest-dom
通过一些有用的附加断言对其进行了增强:
.toBeInTheDocument()
- 检查元素是否确实存在于 DOM 中.toBeVisible()
- 检查是否隐藏该元素.toHaveTextContent(content)
- 检查文本内容是否匹配.toHaveFocus()
- 检查这是否是当前聚焦的元素.toHaveAccessibleDescription(description)
- 检查可访问的描述- 等等.
指令测试
指令是元素的可复用行为。它们接收绑定的 HTML 元素作为第一个参数,接收指令 prop 访问器作为第二个参数。为了使测试更加简洁,@solidjs/testing-library
有一个 renderDirective
函数:
在 ...renderResults
中,容器将包含 targetElement
,默认为 <div>
。这与修改 arg
信号的能力一起,在测试指令时非常有用。
例如,如果您有一个处理 Fullscreen API 的指令,您可以像这样测试它:
原语测试
当不需要对元素的引用时,可以将部分状态和逻辑放入可复用的 hooks 或原语中。由于这些不需要元素,因此不需要 render
来测试它们,因为它需要一个没有其他用途的组件。为了避免这种情况,有一个 renderHook
工具函数可以模拟组件而不实际渲染任何内容。
一个管理计数器状态的原语可以这样测试:
测试 effects
由于 effects 可能异步发生,因此测试它们可能很困难。 @solidjs/testing-library
提供了一个 testEffect 函数,该函数接受另一个函数,该函数接收 done
函数,在测试结束后调用该函数并返回一个 promise。一旦 done 被调用,返回的 promise 就被 resolve。任何会触及下一个边界的错误都会被用来 reject 返回的 promise。
使用 testEffect
的示例测试可能如下所示:
基准测试
虽然 Solid 提供了优化的性能,但最好验证一下是否可以兑现这一承诺。 Vitest 提供了一个实验性的 bench
函数来运行基准测试并比较同一 describe
块内的结果;
例如,如果您有一个类似于 <For>
的 <List>
流组件,您可以像这样对它进行基准测试:
运行 [npm|pnpm|yarn] test bench
将执行基准测试函数:
请记住,创建有意义的基准非常困难。对于这些数字应该持保留态度,但如果在版本之间进行比较,仍然可以表明性能下降。
测试覆盖率
虽然覆盖率数字可能会产生误导,但许多项目都使用它们作为代码质量的粗略衡量标准。
Vitest支持覆盖率收集。要使用它,需要额外的包:
另外,还需要设置 vitest 的覆盖率功能。
集成/端到端测试
有些问题只有在代码在其应该运行的环境中运行后才能发现。由于集成和端到端测试与框架无关,因此所有经过验证的方法都适用于 Solid。