使用React测试库进行交互测试

我的旅途 (My Journey)

Testing is complicated. I’ve certainly never been good at it. For the longest time, I’ve only been focused on basic function input-output unit tests. Why? Because they were easy — you didn’t need to render HTML, you didn’t need to query DOM elements, you didn’t need to interact with said DOM elements. But of course, React component testing is a necessity for any mature codebase. And it finally came time for me to sit down and figure it out.

测试很复杂。 我当然从来都不擅长。 最长的时间里,我只专注于基本功能输入输出单元测试。 为什么? 因为它们很简单-不需要呈现HTML,所以不需要查询DOM元素,也不需要与所述DOM元素进行交互。 但是,当然,对于任何成熟的代码库,React组件测试都是必需的。 终于到了我坐下来解决问题的时候了。

That’s when I discovered React Testing Library. And suddenly, everything seemingly became much simpler. All the complexities that I’ve encountered, but not understood, that made me put off React component testing disappeared. Hopefully, the same will happen for you.

那就是我发现React Testing Library的时候 。 突然之间,一切似乎变得简单多了。 我遇到但不了解的所有复杂性使我推迟了React组件测试,这一切消失了。 希望您也会遇到同样的情况。

互动测试 (Interaction Testing)

As the name suggests, interaction testing tests interactions with React components. It can be thought of as unit testing for React components. Your tests will pretend to be the user — interacting with the component by typing stuff, clicking buttons, etc — and check that whatever should happen, happens.

顾名思义,交互测试用于测试与React组件的交互。 可以将其视为React组件的单元测试。 您的测试将冒充用户-通过键入内容,单击按钮等与组件进行交互-并检查应发生的一切。

Take this simple Counter component as an example.

以这个简单的Counter组件为例。

function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
{
count > 0 && (
<button onClick={() => setCount(0)}>
Decrement
</button>
)
}
</div>
);
}

The user can perform two interactions with this component — increment the counter or decrement the counter (if count is greater than 0). Once the respective buttons are clicked, the component will display the new value.

用户可以与此组件执行两次交互-递增计数器或递减计数器(如果count大于0)。 单击相应按钮后,组件将显示新值。

We’ll use this example component to go through how you can use React Testing Library for interaction testing.

我们将使用这个示例组件来介绍如何使用React Testing Library进行交互测试。

渲染图 (Rendering)

So, let’s begin understanding the tools that React Testing Library provides. The first fundamental to React component testing is rendering. This is as simple as calling the render function included in React Testing Library.

因此,让我们开始了解React Testing Library提供的工具。 React组件测试的第一个基础是渲染。 这就像调用React Testing Library中包含的render函数一样简单。

import { render } from '@testing-library/react';test('render', () => {
render(<Counter />);
});

And voilà! That’s literally it. Seriously. Who knew?

和瞧! 就是这样。 说真的 谁知道?

查询方式 (Querying)

Okay, the first hurdle is over. Now that we have rendered our component, we have to get the HTML element(s) to interact with. Fortunately for us, React Testing Library provides a lot of simple and neat queries via the render function response. In our test, getByText will help query the button for us to click.

好的,第一关已经结束。 现在,我们已经渲染了组件,我们必须获取与之交互HTML元素。 对我们来说幸运的是, React Testing库通过render函数响应提供了许多简单明了的查询 。 在我们的测试中, getByText将帮助查询按钮以供我们单击。

test('queries existence', () => {
const { getByText } = render(<Counter />);
const increment = getByText('Increment');
});

A similar thing can be done to get the decrement button if rendered. If the not (when the count is 0),getByText('Decrement') will throw an error causing the test to automatically fail, even though we’re not testing anything yet! When this is the case, we can use queryByText to try and query the button. If the element can’t be found, queryByText will return null.

如果渲染了递减按钮,可以做类似的事情。 如果不是(当count为0时),即使我们尚未测试任何内容, getByText('Decrement')也会引发错误,导致测试自动失败! 在这种情况下,我们可以使用queryByText尝试查询按钮。 如果找不到该元素,则queryByText将返回null

test('queries non-existence', () => {
const { queryByText } = render(<Counter />);
const decrement = queryByText('Decrement');
});

射击事件 (Firing Events)

Time to interact! React Testing Library provides a fireEvent function that includes support for almost all DOM events — keyboard, mouse, animation, etc. Since we have defined onClick for our increment and decrement buttons, we’ll use the click event.

时间互动! React Testing库提供了一个fireEvent函数,其中包括对几乎所有DOM事件的支持 -键盘,鼠标,动画等。由于我们已经为增量和减量按钮定义了onClick ,因此我们将使用click事件。

import { fireEvent, render} from '@testing-library/react';test('fireEvent', () => {
const { getByText } = render(<Counter />);
const increment = getByText('Increment');
fireEvent.click(increment);
});

It’s important to fire the correct event — otherwise, your expected interaction will not happen. The event fired must be the same type as the event listener attached to the element. If not, the event listener will not be triggered. In our Counter component, the buttons have the onClick event listener attached and therefore will only be triggered with click events. This is different from browser implementations where click events also trigger mousedown, mouseup, and other events.

触发正确的事件很重要-否则,您期望的交互将不会发生。 触发的事件必须与附加到元素的事件侦听器具有相同的类型。 否则,将不会触发事件侦听器。 在我们的Counter组件中,按钮附加了onClick事件侦听器,因此只能通过click事件触发。 这与浏览器实现不同,在浏览器实现中, click事件还会触发mousedownmouseup和其他事件。

证实 (Validating)

Congratulations, you’re now an expert in React Testing Library! Rendering, querying, and firing events is pretty much all the specific React Testing Library tooling that you really need to know.

恭喜,您现在是React Testing Library的专家! 渲染,查询和触发事件几乎是您真正需要知道的所有特定的React Testing Library工具。

Wait but our test is not done! Yes, but now you have learned all the tools you need to complete our test.

等待,但我们的测试未完成! 是的,但是现在您已经了解了完成测试所需的所有工具。

Let’s revisit the interactions that we need to handle:

让我们回顾一下我们需要处理的交互:

  • Click the increment button and our counter will increase

    点击增加按钮,我们的计数器将增加
  • Click the decrement button and our counter will decrease

    单击减量按钮,我们的计数器将减少

We now know how to fire the click event on the buttons but how do we validate whether our counterchanged as expected? More queries!

现在,我们知道如何在按钮上触发click事件,但是如何验证我们是否按预期进行了更改? 更多查询!

test('validation existence', () => {
const { getByText } = render(<Counter />);
const increment = getByText('Increment');
fireEvent.click(increment);
expect(getByText('Count: 1')).toBeTruthy();
const decrement = getByText('Decrement');
fireEvent.click(decrement);
expect(getByText('Count: 0')).toBeTruthy();
});

Just like how we queried for the button, we can query the component to see whether our expected update occurred. After we click the increment button, our component is updated to display the new count. By querying for what we expect the new count value to be, we can check its existence to determine whether the Counter behaves as expected.

就像我们查询按钮的方式一样,我们可以查询组件以查看是否发生了预期的更新。 单击增加按钮后,我们的组件将更新以显示新的count 。 通过查询新计数值的期望值,我们可以检查其存在以确定Counter是否按预期运行。

Great! We just tested to make sure the buttons work as expected. But, for full test coverage of our Counter component, we also need to make sure that the decrement button is rendered only when count is greater than 0. Using the same technique but with queryByText, we can test for this.

大! 我们只是进行了测试,以确保按钮可以正常工作。 但是,为了完全覆盖我们的Counter组件,我们还需要确保仅在count大于0时才显示递减按钮。使用相同的技术但使用queryByText ,我们可以对此进行测试。

test('validation non-existence', () => {
const { getByText, queryByText } = render(<Counter />);
expect(queryByText('Decrement')).toBeNull()
const increment = getByText('Increment');
fireEvent.click(increment);
expect(queryByText('Decrement')).toBeTruthy()
});

We first make sure the decrement button doesn’t exist by validating that the queryByText response is null. Then we increment the counter and validate that the decrement button exists.

我们首先通过验证queryByText响应是否为null来确保减量按钮不存在。 然后,我们递增计数器并验证递减按钮的存在。

And that’s it! Our Counter component is fully tested and we can be very confident that it works exactly as expected.

就是这样! 我们的Counter组件已经过全面测试,我们可以非常有信心地按预期工作。

屏幕记录 (Screen Logging)

Oh wait! There’s still one more valuable tool that React Testing Library provides: screen.debug. This function will log the DOM structure. By default, it will log document.body.

等一下! React Testing Library仍然提供了另一个更有价值的工具: screen.debug 。 该函数将记录DOM结构。 默认情况下,它将记录document.body

import { render, screen } from '@testing-library/react';test('debug default', () => {
render(<Counter />);
screen.debug();
// output:
// <body>
// <div>
// <div>
// <p>
// Count:
// 0
// </p>
// <button>
// Increment
// </button>
// </div>
// </div>
// </body>
});

You can also pass in a DOM element to specifically log that.

您也可以传入DOM元素以专门记录该元素。

import { fireEvent, render, screen } from '@testing-library/react';test('debug element', () => {
const { getByText } = render(<Counter />);
const increment = getByText('Increment');
screen.debug(increment);
// output:
// <button>
// Increment
// </button>
});

With this tool, you can visually inspect and understand the DOM structure of your component so you can formulate the queries that are needed to test the component.

使用此工具,您可以直观地检查和了解组件的DOM结构,从而可以制定测试组件所需的查询。

最后的想法 (Final Thoughts)

React Testing Library vastly simplifies and, for lack of a better term, dumbs it down to something you and I can understand and work with. The four tools it provides — rendering, querying, firing events, and screen logging — covers the basics of interaction testing. Now that you’ve learned this, go out and make sure your React components are bug-free!

React Testing Library大大简化了,并且由于缺少更好的术语,所以将其简化为您和我可以理解并使用的内容。 它提供的四个工具-渲染,查询,触发事件和屏幕记录-涵盖了交互测试的基础。 现在,您已经了解了这一点,请确保您的React组件没有错误!

翻译自: https://medium.com/weekly-webtips/interaction-testing-with-react-testing-library-d824f74ce48a

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值