不同于普通JS测试,组件的测试会更关注 DOM 渲染,以及组件功能正确性,而不是组件内部某些方法调用等的测试
Testing Library 包含 DOM 及 UI 组件测试的一系列工具, 支持 React Vue Angular 等多个框架
组件测试目标
相关
测试 React 组件需要使用的技术
@testing-library/dom
: 一个轻量级的(DOM 查询、交互)测试解决方案,它使用了一种与 ”用户的在页面中查找元素" 类似的DOM 查询方式,以保证准确性@testing-library/user-event
: 提供了更加高级的浏览器交互模拟 – 即事件@testing-library/react
: 在 @testing-library/dom
基础上,将 React 组件渲染为 DOM 便于后边测试@testing-library/jest-dom
追加一系列辅助测试 DOM 的 matchers 匹配器,需要在每个 react test 文件的顶部引用,否则类似 expect(dom).toBeInTheDocument()
这样的断言则没法用由于 react 组件使用jsx 编写,所以要在基础的 babel 配置中加上对 react 的支持,否则 jest 会不认识 react 组件代码
// babel.config.js
module.exports = {
presets: [
['@babel/preset-env', {targets: {node: 'current'}}],
'@babel/preset-react', // 追加
'@babel/preset-typescript',
],
};
查询语句说明:查询语句分为三大类:getBy…\queryBy…\findBy…
查询项说明
getByRole(tagName, {name: '通过 name 过滤'})
这里的 role 指的是浏览器 ARIA 无障碍机制中的属性(可用的 role),name 指的则是 aria-label 属性的值getByText(string)
通过文本内容来查找元素,但是尽量不要用在 div span p 等元素的查找上getByAltText(string)
通过 alt 属性查找 img area input 等元素getByPlaceholderText(string)
通过 placeholder 查询元素getByTestId(string)
通过给元素设置 data-testid 然后可以借助这个查询获得这个元素container.querySelector('')
借助 render 后返回的 container 使用 DOM 的方式查询元素使用
@testing-library/jest-dom
后增加的 matchers 查看
借助
@testing-library/user-event
实现的事件 查看
一个测试案例
import '@testing-library/jest-dom';
import {render, cleanup, } from '@testing-library/react';
import userEvent from "@testing-library/user-event";
import React from 'react';
import Button from "../Button";
/**
* 在每个测试用例完成后执行 react ummount 卸载程序
* 在 jest 中这个行为会默认加上,不需要我们手动加上
* */
// afterEach(cleanup);
describe('测试 React 组件', () => {
test('测试组件渲染', () => {
/**
* 使用 render 将组件渲染到 dom 上,
* 其返回值,包含 DOM Testing Library 中的 queries 查询方法
* */
const result = render(<Button appearance="primary" >TEXT</Button>);
/**
* debug() 用来查看渲染出的 dom 是什么样的结构 (html), 主要用来辅助测试
* 执行 test 可以在控制台看到, 其渲染出的时普通的 html ,复杂的 react 状态等并没有展示
* 由此可见,RTL 不关心组件的编写方式,它只关心最后生成的 DOM 树是否符合要求
*/
result.debug();
/**
* 通过无障碍属性 role='button' 来查找元素,name 则表示 aria-label 属性
* */
expect(result.getByRole('button')).toBeInTheDocument();
/**
* 通过文本内容来查找元素,但是尽量不要用在 div span p 等元素的查找上
* */
expect(result.getByText('TEXT')).toBeInTheDocument();
/**
* 第一个参数也可以写作 正则,用来匹配
* */
expect(result.getByText(/^TEX/)).toBeInTheDocument();
/**
* 可以使用其他的 matchers https://github.com/testing-library/jest-dom#custom-matchers
* */
expect(result.getByText(/^TEX/)).toHaveClass('yufu-btn-primary');
const input = render(
<input type="text" alt="testAlt" placeholder="testPlaceholder" data-testid="TTTT" />
)
/**
* 通过 alt 属性查找 img area input 等元素
* */
expect(input.getByAltText('testAlt')).toBeInTheDocument();
/**
* 通过 placeholder 查询元素
* */
expect(input.getByPlaceholderText('testPlaceholder')).toBeInTheDocument();
/**
* queryBy... 用来断言不存在的"预期"
* */
expect(input.queryByPlaceholderText('test')).not.toBeInTheDocument();
/**
* 通过 testid 查询元素
* */
expect(input.getByTestId('TTTT')).toBeInTheDocument();
/**
* 借助 container 使用DOM 查询元素
* */
expect(input.container.querySelector('input[type="text"]')).toBeInTheDocument();
/**
* 借助 @testing-library/user-event 来测试事件
* */
userEvent.type(input.getByTestId('TTTT'), 'something'); // 触发事件
expect(input.getByTestId('TTTT')).toHaveValue('something'); // 验证事件结果
})
})