React组件渲染单元测试

1,802 阅读4分钟

继讨论过“前端写不写单元测试”与“React应用测试:配置Typescript, Jest, ESLint”之后,我们开始进入写测试的环节。

选型:

没有其他附加的断言库和框架。

简单的渲染测试

组件测试第一步,先看看组件是不是能根据提供的属性正常显示。

假设我们有这样一个简单的组件MyComponent.tsx

import * as React from 'react';
export default function MyComponent() {
  return <div>test</div>;
}

在这个组件旁边创建一个 MyComponent.test.tsx测试文件(打包工具如Webpack不会将它打包进去):

import * as React from 'react';
import { render } from '@testing-library/react';
import MyComponent from './MyComponent';

test('test render', () => {
  const { getByText } = render(<MyComponent />);
  expect(getByText('test')).toBeTruthy(); 
});

测试完美通过。这里用了@testing-library/react的两个接口:

  • render()用来渲染React组件
  • render()返回的getByText()是个匹配方法,可以找到有test这个text node的React/DOM元素

这里我将有没有显示test这个词作为测试通过的关键检查点,而不是元素ID或者是CSS Class,因为这样更贴合实际需求的要求。

就这样通过好像有一点不真实。那测试大神 Kent C有个非常有意思的提议——除了让你的测试通过之外,你必须看看是不是不符合要求的时候测试能报错,如果不报错,那说明测试写的不到位。

所以让我们给test随意加一个尾巴变成test1试下:

![](simple render fail.png)

如我们预期的,测试失败了。并且@testing-library/react很贴心地帮我们打印出了实际渲染出的DOM结构,以供我们后续调试。

匹配方法

这个render()除了返回getByText()之外,还有一系列方便使用的其他匹配方法

方法前缀返回特征
getBy匹配的元素无匹配或有多个匹配到的元素会报错
getAllBy匹配的元素组匹配不到会报错
findByPromise,resolve为匹配元素尝试等这个元素出现,默认最多等1秒,过期匹配不到就reject
findAllByPromise,resolve为匹配元素组同上
queryBy第一个匹配到的元素或null匹配到多个元素会报错
queryAllBy匹配的元素组或空数组-

(其实我感觉queryBy和queryAllBy有点多余……)

注意以上只是方法名的前缀,实际使用时需要搭配目标后缀

  • ByLabelText - 匹配表单Label的文字内容
  • ByPlaceholderText - 匹配表单元素的占位(placeholder)文字
  • ByText - 匹配元素文字内容
  • ByAltText - 匹配元素的alt属性
  • ByTitle - 匹配元素的title属性
  • ByDisplayValue - 匹配表单元素的值(value)
  • ByRole - 匹配元素的role属性
  • ByTestId - 匹配元素的data-testid属性,通常为一些特殊的测试要求特意添加的一个ID

上一节使用的getByText()方法就是getByByText的组合。

当然你也完全可以用.querySelectorAll()自己写,这些方法只是提供了一些便捷性。

它们其实是从@testing-library/react的同胞@testing-library/dom继承而来,在render()方法中返回便于使用。

测试渲染的更新

如果一个组件可以接收一些参数,那这时除了能根据初始传入的属性渲染之外,最好再验证一下组件是否能根据参数的变化更新相应的内容。

假设我们的组件MyComponent.tsx现在能够接收一个参数:

import * as React from 'react';
export default function MyComponent({ n }: { n: number }) {
  return <div>test{n}</div>;
}

更新MyComponent.test.tsx测试文件:

import * as React from 'react';
import { render } from '@testing-library/react';
import MyComponent from './MyComponent';

test('test re-render', () => {
  const { getByText, rerender } = render(<MyComponent n={1} />);
  expect(getByText('test1')).toBeTruthy(); 
  
  rerender(<MyComponent n={2} />);
  expect(getByText('test2')).toBeTruthy();
});

以上,我们先尝试用n=1为输入值初始化渲染,然后用rerender()方法将组件的属性改为n=2再重新验证渲染的内容。

小结

以上我们用@testing-library/react对一个异常简单的React组件进行了渲染关键内容的测试。这在实际使用中这些是远远不够的,我们在遇到用CSS Module,第三方组件,复杂依赖的时候需要做一些其他的配置来配合测试,否则Jest会有各种奇怪的抱怨。

好了,我们下次再见👋!

看看其他测试系列文:

加我微信