如何使用 Jest 测试 React 组件?
React 是一个前端开源 JavaScript 库,用于构建交互式用户界面。 React 专注于单页应用程序,更普遍地称为 SPA。
测试是开发的一个重要方面。它检查应用程序是否按预期运行,并在对应用程序进行任何不需要的更改时保护它。有各种测试库,例如 chai、mocha 等。在本教程中,我们将使用 jest 库和反应测试库来测试 React 组件。
先决条件:
- React 简介
- React 中的函数式组件
所需模块:
- npm
- 反应
创建 React 应用程序并设置:
第 1 步:您将使用 create-react-app 启动一个新项目,因此打开您的终端并输入。
npx create-react-app jest-testing
第 2 步:使用以下命令切换到 jest-testing 文件夹。
cd tic-tac-toe-react
第 3 步:切换到 src 文件夹并使用以下命令删除不必要的东西
cd src
rm*
第四步:在 src 文件夹中创建 components 文件夹
mkdir components
第 5 步:创建一个 Button 文件夹和一个 Text 文件夹
mkdir Button,Text
第 6 步:在 Button 文件夹中创建一个 Button.js 文件和 Button.test.js 文件。
touch Button.js Button.test.js
注意:测试文件的名称应与组件的名称相同,并应后跟 .test.js 扩展名,因为当使用npm test命令运行测试时,React 会自动检查所有带有 .test 的文件名扩展并运行测试。
第 7 步:在 Text 文件夹中创建一个 Text.js 文件和 Text.test.js 文件。
touch Text.js Text.test.js
第 8 步:在 src 文件夹中,创建 App.js、index.js 和 App.test.js 文件。
touch App.js index.js App.test.js
项目结构:项目中的文件结构将如下所示。
示例:使用基本代码设置所有文件,以在单击按钮时切换文本 GeeksForGeeks。
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
,
document.getElementById('root')
);
Button.js
const Button = ({ setToggle, btnTxt }) => {
// data-testid is a testing id
// which is used only during tests
return
}
export default Button;
Text.js
const Text = ({toggle, displayTxt}) => {
// data-testid is a testing id
// which is used only during tests
return {toggle? displayTxt : ""}
}
export default Text;
App.js
import Button from "./components/Button/Button";
import Text from "./components/Text/Text";
import { useState } from "react";
const App = () => {
const [toggle, setToggle] = useState(true);
return (
);
}
export default App;
Button.test.js
import { render, screen, cleanup } from "@testing-library/react";
// Importing the jest testing library
import '@testing-library/jest-dom'
import Button from "./Button";
// afterEach function runs after each test suite is executed
afterEach(() => {
cleanup(); // Resets the DOM after each test suite
})
describe("Button Component" ,() => {
const setToggle= jest.fn();
render();
const button = screen.getByTestId("button");
// Test 1
test("Button Rendering", () => {
expect(button).toBeInTheDocument();
})
// Test 2
test("Button Text", () => {
expect(button).toHaveTextContent("Click Me!");
})
})
Text.test.js
import { render, screen, cleanup } from "@testing-library/react";
// Importing the jest testing library
import '@testing-library/jest-dom'
import Text from "./Text";
// afterEach function runs after each test suite is executed
afterEach(() => {
cleanup();
})
describe("Text Component" ,() => {
// Test 1
test("Text Rendering", () => {
render();
const text = screen.getByTestId("text");
expect(text).toBeInTheDocument();
})
// Test 2
test("Displayed Text when toggle is set to true", () => {
render()
const text = screen.getByTestId("text");
expect(text).toHaveTextContent("GeeksForGeeks");
})
// Test 3
test("Displayed Text when toggle is set to false", () => {
render();
const text = screen.getByTestId("text");
expect(text).toBeEmptyDOMElement();
})
})
App.js
import { render, screen, cleanup, fireEvent } from "@testing-library/react";
// Importing the jest testing library
import '@testing-library/jest-dom'
import App from "./App";
// afterEach function runs after each test suite is executed
afterEach(() => {
cleanup();
})
describe("App Component" ,() => {
// Test 1
test("App Rendering", () => {
render( ); // Rendering the App
const text = screen.getByTestId("text");
const button = screen.getByTestId("button");
expect(button).toBeInTheDocument();
expect(text).toBeInTheDocument();
})
// Test 2
test("Default Text", () => {
render( );
const text = screen.getByTestId("text");
expect(text).toHaveTextContent("GeeksForGeeks");
})
// Test 3
test("Toggling Text", () => {
render( );
const text = screen.getByTestId("text");
const button = screen.getByTestId("button");
expect(text).toHaveTextContent("GeeksForGeeks");
fireEvent.click(button);
expect(text).toBeEmptyDOMElement();
fireEvent.click(button);
expect(text).toHaveTextContent("GeeksForGeeks");
})
})
按钮.js
const Button = ({ setToggle, btnTxt }) => {
// data-testid is a testing id
// which is used only during tests
return
}
export default Button;
文本.js
const Text = ({toggle, displayTxt}) => {
// data-testid is a testing id
// which is used only during tests
return {toggle? displayTxt : ""}
}
export default Text;
应用程序.js
import Button from "./components/Button/Button";
import Text from "./components/Text/Text";
import { useState } from "react";
const App = () => {
const [toggle, setToggle] = useState(true);
return (
);
}
export default App;
输出:
运行以下命令来启动应用程序:
npm start
创建了一个简单的应用程序,它在按下按钮时切换文本 GeeksForGeeks。
现在基本的应用程序已经设置好了,我们可以开始测试它了。在测试应用程序之前,让我们了解一些重要的测试方法。
- render(Component):在模拟屏幕上渲染给定的组件。
- screen:对具有各种有用测试功能的模拟屏幕的引用。
- cleanup():重置 DOM。
- afterEach(callback 函数):在运行每个测试套件后运行作为参数给出的回调函数。
- beforeEach(callback 函数):在运行每个测试套件之前运行作为参数给出的回调函数。
- describe(nameOfTestSuite, callback 函数):定义一个包含许多单元测试的测试套件(Callback 函数包含单元测试)。
- test(nameOfTest, callback 函数):定义要执行的测试。
- fireEvent:模拟指定事件。
测试按钮组件:我们将对按钮组件执行两个测试。
- 测试 1:测试按钮是否正确呈现到 DOM。
- 测试 2:测试按钮是否显示作为道具传递的文本。
Button.test.js
import { render, screen, cleanup } from "@testing-library/react";
// Importing the jest testing library
import '@testing-library/jest-dom'
import Button from "./Button";
// afterEach function runs after each test suite is executed
afterEach(() => {
cleanup(); // Resets the DOM after each test suite
})
describe("Button Component" ,() => {
const setToggle= jest.fn();
render();
const button = screen.getByTestId("button");
// Test 1
test("Button Rendering", () => {
expect(button).toBeInTheDocument();
})
// Test 2
test("Button Text", () => {
expect(button).toHaveTextContent("Click Me!");
})
})
输出:
使用以下命令运行测试:
npm test
我们可以看到有两个测试套件失败,一个通过了。原因是没有为 Text 组件和 App 组件设计测试。所以唯一通过的测试套件是按钮组件。
测试文本组件:我们将对文本组件执行三个测试。
- 测试 1:测试文本元素是否正确呈现到 DOM。
- 测试 2:在切换设置为 true 时测试文本元素的内容。
- 测试 3:在切换设置为 false 时测试文本元素的内容。
文本.test.js
import { render, screen, cleanup } from "@testing-library/react";
// Importing the jest testing library
import '@testing-library/jest-dom'
import Text from "./Text";
// afterEach function runs after each test suite is executed
afterEach(() => {
cleanup();
})
describe("Text Component" ,() => {
// Test 1
test("Text Rendering", () => {
render();
const text = screen.getByTestId("text");
expect(text).toBeInTheDocument();
})
// Test 2
test("Displayed Text when toggle is set to true", () => {
render()
const text = screen.getByTestId("text");
expect(text).toHaveTextContent("GeeksForGeeks");
})
// Test 3
test("Displayed Text when toggle is set to false", () => {
render();
const text = screen.getByTestId("text");
expect(text).toBeEmptyDOMElement();
})
})
输出:
使用以下命令运行测试:
npm test
测试应用程序组件:测试应用程序组件也称为集成测试,因为我们在集成按钮和文本组件时测试应用程序。我们将对 App 组件执行三个测试。
- 测试一:测试是否所有组件都已渲染
- 测试2:测试文本元素的默认值
- 测试3:测试按钮的切换能力
应用程序.js
import { render, screen, cleanup, fireEvent } from "@testing-library/react";
// Importing the jest testing library
import '@testing-library/jest-dom'
import App from "./App";
// afterEach function runs after each test suite is executed
afterEach(() => {
cleanup();
})
describe("App Component" ,() => {
// Test 1
test("App Rendering", () => {
render( ); // Rendering the App
const text = screen.getByTestId("text");
const button = screen.getByTestId("button");
expect(button).toBeInTheDocument();
expect(text).toBeInTheDocument();
})
// Test 2
test("Default Text", () => {
render( );
const text = screen.getByTestId("text");
expect(text).toHaveTextContent("GeeksForGeeks");
})
// Test 3
test("Toggling Text", () => {
render( );
const text = screen.getByTestId("text");
const button = screen.getByTestId("button");
expect(text).toHaveTextContent("GeeksForGeeks");
fireEvent.click(button);
expect(text).toBeEmptyDOMElement();
fireEvent.click(button);
expect(text).toHaveTextContent("GeeksForGeeks");
})
})
输出:使用以下命令运行测试:
npm test