如何使用Jest为React组件编写快照测试
介绍
快照测试允许您确保您的输出继续按预期运行。 这很有用,因为随着时间的推移,当您重新访问代码以进行更新时,这些更改可能会导致某些东西中断的可能性增加。
与严格的测试驱动开发 (TDD) 不同,标准做法是先编写失败的测试,然后编写代码以使测试通过,快照测试采用不同的方法。
在为 React 组件编写快照测试时,首先需要让代码处于工作状态。 然后,在给定特定数据的情况下生成其预期输出的快照。 快照测试与组件一起提交。 Jest 是一个测试框架,它将快照与测试的渲染输出进行比较。
如果测试失败,这可能意味着两件事。 如果测试结果出乎意料,您可能需要解决组件的问题。 如果测试结果符合预期,则可能意味着需要更新快照测试以支持新输出。
在本教程中,您将探索快照测试以及如何使用它们来确保您的用户界面 (UI) 不会意外更改。
先决条件
要完成本教程,您需要:
本教程还使用 Visual Studio Code 作为代码编辑器,方便运行集成终端。 但是,您可以将其替换为您选择的编辑器和终端。
本教程已使用 Node v14.7.0、npm
v6.14.7、react
v16.13.1 和 jest
v24.9.0 进行了验证。
第 1 步——创建一个 React 组件进行测试
首先,为了测试一些东西,你需要使用 Create React App 创建一个 React App。 对于本教程,项目将被称为 react-snapshot-tests
。
打开终端并运行以下命令:
npx create-react-app@3.4.1 react-snapshot-tests
然后,切换到新创建的 app 目录:
cd react-snapshot-tests
接下来,启动应用程序:
npm start
此时,您现在应该运行了一个 React 应用程序,并且可以在 Web 浏览器中查看它。 接下来,您需要创建一个可以测试的组件。
出于本教程的目的,您将要创建的组件会渲染它接收到的 items
道具。
在您的终端中,在 src
下创建一个 components
子目录:
mkdir src/components
然后,创建一个 Items.js
组件:
nano src/components/Items.js
将以下代码添加到 Items.js
:
src/components/Items.js
import React from 'react'; import PropTypes from 'prop-types'; /** * Render a list of items * * @param {Object} props - List of items */ function Items(props) { const { items = [] } = props; // A single item in the list, render a span. if (items.length === 1) { return <span>{items[0]}</span>; } // Multiple items on the list, render a list. if (items.length > 1) { return ( <ul> {items.map(item => <li key={item}>{item}</li>)} </ul> ); } // No items on the list, render an empty message. return <span>No items in list</span>; } Items.propTypes = { items: PropTypes.array, }; Items.defaultProps = { items: [] }; export default Items;
此代码将根据数量渲染 items
道具:
- 如果有多个项目,项目将显示在无序列表中(
<ul>
)。 - 如果有单个项目,则该项目将显示在
<span>
元素中。 - 如果没有项目,将显示错误消息。
最后,更新 App.js
来渲染我们的组件:
nano src/App.js
将 App.js
的内容替换为以下内容:
src/App.js
import React, { Component } from 'react'; import Items from './components/Items'; class App extends Component { render() { const items = [ 'Shark', 'Dolphin', 'Octopus' ]; return ( <Items items={items} /> ); } } export default App;
如果您在浏览器中访问该应用程序,将会出现一个屏幕,其中列出了您在 App.js
中建立的值:
Output* Shark * Dolphin * Octopus
由于有多个items
,所以显示为无序列表。
接下来,您将添加快照测试。
第 2 步 — 编写快照测试
首先,删除 Create React App 生成的 App.test.js
文件:
rm src/App.test.js
本教程不需要它。
接下来,安装 react-test-renderer,这是一个库,可让您将 React 组件渲染为 JavaScript 对象,而无需 DOM。
npm install react-test-renderer@16.13.1
让我们添加您的第一个测试。 首先,您将创建一个 Items.test.js
文件:
nano src/components/Items.test.js
编写一个渲染 Items
组件的测试,其中没有作为道具传递的项目:
src/components/Items.test.js
import React from 'react'; import renderer from 'react-test-renderer'; import Items from './Items'; it('renders correctly when there are no items', () => { const tree = renderer.create(<Items />).toJSON(); expect(tree).toMatchSnapshot(); });
接下来,让我们运行测试。 Create React App 处理了设置测试的所有初始化:
npm test
您应该通过 "renders correctly when there are no items"
的测试:
当您第一次运行快照测试时,请注意在 __snapshots__
目录中创建了一个新的快照文件。 由于您的测试文件被命名为 Items.test.js
,因此快照文件被适当地命名为 Items.test.js.snap
。
Items.tests.js.snap
的内容应该类似于:
src/components/__snapshots__/Items.test.js.snap
// Jest Snapshot v1, https://goo.gl/fbAQLP exports[`renders correctly when there are no items 1`] = ` <span> No items in list </span> `;
此快照与组件的确切输出相匹配。
Jest 使用 pretty-format 使快照文件易于阅读。
您现在可以为其他两个场景创建测试,其中有一个项目和多个项目。
打开Items.tests.js
:
nano src/components/Items.test.js
添加以下代码行:
src/components/Items.test.js
// ... it('renders correctly when there is a single item', () => { const items = ['one']; const tree = renderer.create(<Items items={items} />).toJSON(); expect(tree).toMatchSnapshot(); }); it('renders correctly when there are multiple items', () => { const items = ['one', 'two', 'three']; const tree = renderer.create(<Items items={items} />).toJSON(); expect(tree).toMatchSnapshot(); });
至此,您已经编写了三个测试:一个针对没有项目,一个针对单个项目,另一个针对多个项目。
重新运行测试:
npm test
所有三个测试都应该成功通过,现在您的 __snapshots__
目录中将拥有三个快照。
接下来,您将通过更新快照测试来解决失败的测试。
第 3 步 — 更新快照测试
为了更好地理解为什么需要快照测试,您将对 Items
组件进行更改并重新运行测试。 这将模拟对开发中的项目进行更改时会发生的情况。
打开Items.js
:
nano src/components/Items.js
将类名添加到 span
和 li
元素:
src/components/Items.js
... /** * Render a list of items * * @param {Object} props - List of items */ function Items(props) { const { items = [] } = props; // A single item in the list, render a span. if (items.length === 1) { return <span className="item-message">{items[0]}</span>; } // Multiple items on the list, render a list. if (items.length > 1) { return ( <ul> {items.map(item => <li key={item} className="item-message">{item}</li>)} </ul> ); } // No items on the list, render an empty message. return <span className="empty-message">No items in list</span>; } Items.propTypes = { items: PropTypes.array, }; Items.defaultProps = { items: [], }; export default Items;
让我们重新运行测试:
npm test
您将观察到失败的测试结果:
Jest 将现有快照与具有更新更改的渲染组件匹配并失败,因为您的组件有一些添加。 然后它显示了引入快照测试的变化的差异。
如果更改不是预期的,您在部署更改之前发现了错误,现在可以解决该错误。 如果更改是预期的,您将需要更新您的快照测试以使它们正确通过。
对于本教程,您可以假设这是预期的更改。 您打算向组件添加类名。 然后,您应该更新快照测试。
当 Jest 处于交互模式时,您可以通过使用提供的选项按 u
来更新快照测试:
注意: 或者,如果你已经全局安装了 Jest [1],你可以运行 jest --updateSnapshot
或 jest -u
。
这将更新快照以匹配您所做的更新,并且您的测试将通过。
这是之前没有项目的快照测试:
src/components/__snapshots__/Items.test.js.snap
// ... exports[`renders correctly when there are no items 1`] = ` <span> No items in list </span> `; // ...
这是新更新的无项目快照测试:
src/components/__snapshots__/Items.test.js.snap
// ... exports[`renders correctly when there are no items 1`] = ` <span className="empty-message" > No items in list </span> `; // ...
更新测试后,它们将通过:
您现在再次通过了测试。 如果这是一个正在开发的项目,您可以部署代码,因为您需要记录您想要的更改以供将来开发使用。
结论
在本教程中,您为 React 组件编写了快照测试。 您还修改了组件以经历失败的测试。 最后,您更新了快照以修复测试。
这是一个现场项目的小型模拟。 这个测试通过、失败和解决失败的循环将成为您的开发工作流程的一部分。
快照测试旨在成为许多不同的测试工具之一。 因此,您可能仍需要为您的操作和减速器编写测试。
当您探索了快照测试的基础知识时,您可以学到很多关于编写更好的快照测试的知识。 请查看 Jest 文档中的 Snapshot 最佳实践 ,以了解有关快照测试的更多信息。
如果您想了解有关 React 的更多信息,请查看 我们的 React 主题页面 以获取练习和编程项目。