在本教程中,我們將完成在 Next.js 應用程序中執(zhí)行單元測試所需的所有步驟。我們將使用React 測試庫和Jest來測試我們的應用程序跺撼。
Jest 是一個 JavaScript 測試框架联四,旨在確保任何 JavaScript 代碼庫的正確性,而不是 React鳄梅。另一方面厕怜,React 測試庫構(gòu)建在 DOM 測試庫之上衩匣,通過添加 API 來測試 React 組件。Jest 和 React 測試庫一起用于 React 和 Next.js 應用程序的單元測試粥航。
入門
我們將首先使用以下命令創(chuàng)建一個支持 Typescript 的新 Next.js 應用程序琅捏。
npx create-next-app@latest --ts
為您的項目命名并在您選擇的任何代碼編輯器中打開它。pages/index.tsx
使用下面的代碼設置內(nèi)容递雀。
import type { NextPage } from "next";
import Head from "next/head";
import styles from "../styles/Home.module.css";
const Home: NextPage = () => {
return (
<div className={styles.container}>
<Head>
<title>Testing Next.js</title>
<meta name="description" content="Generated by create next app" />
<link rel="icon" href="/favicon.ico" />
</Head>
<main className={styles.main}>
<h1 className={styles.title}>Testing Next.js Applications </h1>
</main>
</div>
);
};
export default Home;
在pages/index.tsx
頁面中柄延,我們正在導入NextPage
當前頁面的組件類型和默認next/head
組件以設置頁眉。然后缀程,我們使用 Next.js 附帶的默認樣式并設置一個h1
來呈現(xiàn)文本“Testing Next.js Applications”拦焚。
設置 Jest 和 React 測試庫
對于以前版本的 Next.js,我們必須設置 Jest 以支持 Babel杠输,但最新的 Next.js 版本使用內(nèi)置的 Rust 編譯器和 Jest 的內(nèi)置配置赎败,因此我們不需要任何額外的配置。
要設置 Jest蠢甲,請安裝jest
, @testing-library/react
,@testing-library/jest-dom
作為開發(fā)依賴項:
npm install --save-dev jest @testing-library/react @testing-library/jest-dom
安裝庫后僵刮,我們需要設置一個配置文件以使用內(nèi)置的 Jest 配置。jest.config.js
在根目錄下創(chuàng)建一個文件并添加以下內(nèi)容:
// jest.config.js
const nextJest = require("next/jest");
const createJestConfig = nextJest({
dir: "./",
});
const customJestConfig = {
setupFilesAfterEnv: ["<rootDir>/jest.setup.js"],
moduleDirectories: ["node_modules", "<rootDir>/"],
testEnvironment: "jest-environment-jsdom",
};
module.exports = createJestConfig(customJestConfig);
查看Next.js 文檔鹦牛,了解默認 Jest 配置中的幕后情況搞糕。
jest.setup.js
接下來,我們在根目錄下創(chuàng)建一個文件曼追,并添加以下內(nèi)容:
import "@testing-library/jest-dom/extend-expect";
讓我們將 Jest 添加到文件的scripts
部分窍仰,package.json
以在監(jiān)視模式下運行我們的測試,這將重新運行我們所有的文件更改測試:
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"test": "jest --watch"
}
或者礼殊,要為 Jest 啟用 ESLint 支持驹吮,請將以下內(nèi)容添加到.eslintrc.json
默認的create-next-app
.
{
"extends": "next/core-web-vitals",
"env": {
"jest": true
}
}
寫作測試
按照 Jest 的約定,__tests__
在項目的根目錄中添加文件夾晶伦。我們將在此文件夾中存儲所有與測試相關(guān)的文件碟狞。
在編寫測試時,Jest 為您提供了一個describe
婚陪、 atest
和一個it
全局函數(shù)族沃,用于與 Jest 庫進行通信以進行各種測試。該describe
函數(shù)是一個將相關(guān)測試組合在一起的測試套件包裝器。該test
功能是一個測試脆淹,它是套件的一部分并運行單獨的單獨測試常空。
// `describe` and `test` being used to write a test
describe("my function or component", () => {
test("does the following", () => {
..
});
});
讓我們通過編寫一個檢查 Jest 設置是否正確的測試來測試我們的測試運行器。在__tests__
目錄中盖溺,創(chuàng)建一個index.test.js
文件漓糙,添加以下內(nèi)容:
describe("true is true and false is false", () => {
test("true is true", () => {
expect(true).toBe(true);
});
test("false is false", () => {
expect(false).toBe(false);
});
});
有了它,我們可以運行測試npm run test
來運行測試咐柜。正確設置 Jest 將在帶有此輸出的測試上顯示一個綠色復選標記:
PASS __tests__/index.test.js
true is true and false is false
? true is true (7 ms)
? false is false (2 ms)
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 1.854 s, estimated 2 s
Ran all test suites.
Watch Usage: Press w to show more.
測試 React 組件
現(xiàn)在 Jest 已經(jīng)設置好了兼蜈,我們可以開始為 Next.js 應用程序編寫測試了攘残。要開始我們的測試拙友,讓我們components
在根目錄中創(chuàng)建一個文件夾并創(chuàng)建一個新文件components/Heading.tsx
. 現(xiàn)在,讓我們創(chuàng)建一個 React 組件來呈現(xiàn)h1
一個文本歼郭,如下所示:
import styles from "../styles/Home.module.css";
export function Heading() {
return <h1 className={styles.title}>Testing Next.js Applications</h1>;
}
讓我們在文件中導入<Heading />
組件遗契,將標簽替換為以下代碼以呈現(xiàn) Heading 組件:pages/index.tsx``main
<main className={styles.main}>
<Heading />
</main>
檢查您的瀏覽器以查看標題是否正確呈現(xiàn)。現(xiàn)在我們已經(jīng)pages/index.tsx
準備好文件病曾,我們可以開始編寫測試了牍蜂。在該__tests__
目錄中,創(chuàng)建一個__tests__/components.test.tsx
包含以下內(nèi)容的文件:
// components.test.tsx
import { render, screen } from "@testing-library/react";
import Heading from "../components/Heading";
describe("heading component", () => {
test("renders a heading", () => {
render(<Heading />);
const heading = screen.getByRole("heading", {
name: /testing next\.js applications/i,
});
expect(heading).toBeInTheDocument();
});
});
我們剛剛做了什么泰涂?
- 我們正在測試的是
<Heading />
組件呈現(xiàn)h1
帶有 text 的標簽Testing Next.js Applications
鲫竞。 - 在測試之前,我們使用
render
函數(shù) from來渲染組件逼蒙。@testing-library/react
- 我們還使用該
screen.getByRole
函數(shù)來獲取h1
我們想要測試的標簽从绘。 - 然后,我們使用
expect
Jest 中的函數(shù)來測試h1
標簽是否在文檔中是牢。 - 最后僵井,我們使用該
toBeInTheDocument
函數(shù)來測試h1
標簽是否在文檔中。
我們現(xiàn)在可以運行我們的測試驳棱,如果一切正常批什,我們的測試將顯示一個綠色復選標記以表明一切正常。
測試事件
我們已經(jīng)測試了一個組件的渲染社搅。是時候測試組件觸發(fā)的事件了驻债。讓我們從創(chuàng)建一個 Button 組件開始。在您的components/Button.tsx
文件中并添加以下內(nèi)容:
type ButtonType = { text: string; onClick: () => void };
export default function Button(props: ButtonType) {
return <button onClick={props.onClick}>{props.text}</button>;
}
然后我們可以導入Button
組件并將其添加到pages/index.tsx
文件中并將其添加到main
標簽中形葬。
...
import Button from "../components/Button";
...
...
<main className={styles.main}>
<Button text="Click Me" onClick={() => alert("Clicked!")} />
</main>
...
我們現(xiàn)在可以測試新的按鈕組件却汉。在__tests__
目錄中,在__tests__/components.test.tsx
文件中添加以下內(nèi)容:
import Button from "../components/Button";
const defaultButtonProps = {
onClick: jest.fn(),
text: "Submit",
};
在導入 Button 組件并創(chuàng)建一個默認的按鈕 props 對象后荷并,我們可以使用它來測試按鈕組件合砂,然后我們添加一個 describe 塊來測試按鈕組件。在__tests__/components.test.tsx
文件中并添加以下內(nèi)容以測試按鈕:
describe("button component", () => {
it("renders a button", () => {
render(<Button {...defaultButtonProps} />);
const button = screen.getByRole("button");
expect(button).toBeInTheDocument();
});
});
上面的測試將測試按鈕組件是否呈現(xiàn)一個按鈕。如果按鈕在文檔中翩伪,則測試將通過微猖,否則將失敗。我們現(xiàn)在可以運行測試缘屹,看看測試是否通過凛剥。
隨著按鈕組件的渲染,我們可以測試按鈕的onClick
事件轻姿。我們正在運行一個簡單的測試來檢查按鈕是否被點擊犁珠。在__tests__/components.test.tsx
文件中,將以下內(nèi)容添加到describe
用于測試按鈕組件是否呈現(xiàn)的塊中:
it("calls the onClick function when the button is clicked", () => {
render(<Button {...defaultButtonProps} />);
const button = screen.getByRole("button");
fireEvent.click(button);
expect(onClick).toHaveBeenCalledTimes(1);
});
這里發(fā)生了什么互亮?
- 按鈕組件有一個 onClick 屬性犁享。測試是檢查單擊按鈕時是否調(diào)用了 onClick 屬性,它是一個函數(shù)豹休。
-
fireEvent.click
在這樣做的過程中炊昆,我們使用React 測試庫中的函數(shù)模擬單擊按鈕。提供這種開箱即用的功能是 React 測試庫是最佳選擇的原因威根。 - 在點擊模擬之后凤巨,我們使用
expect
Jest 中的函數(shù)來測試該函數(shù)是否被調(diào)用,并toHaveBeenCalledTimes
檢查該函數(shù)是否被調(diào)用過一次洛搀。您可以從Jest和React 測試庫的文檔中了解更多這些功能敢茁。
我們可以從這里運行我們的測試,看看測試是否通過留美,我們可以繼續(xù)進行下一組測試彰檬。
測試 Next.js API 路由
接下來,Next.js API 路由独榴,雙關(guān)語僧叉。Next.js 提供了一種在我們的應用程序中創(chuàng)建 API 路由的方法,在這種情況下棺榔,我們可以測試 API 路由瓶堕。讓我們創(chuàng)建一個新的 API,然后我們可以測試它症歇。創(chuàng)建一個新pages/api
目錄并創(chuàng)建一個新[name].ts
文件郎笆。
使用Next.js 動態(tài)路由,我們希望創(chuàng)建一個 API忘晤,該 API 返回一個 JSON 對象宛蚓,其中 aname
在 URL 中指定。例如设塔,如果我們訪問/api/john
凄吏,我們希望返回一個name
屬性設置為的 JSON 對象john
。
// pages/api/[name].ts
import { NextApiRequest, NextApiResponse } from "next";
export default function handler(req: NextApiRequest, res: NextApiResponse) {
const {
query: { name },
} = req;
res.statusCode = 200;
res.setHeader("Content-Type", "application/json");
res.json({ name: `Your name is ${name}` });
}
我們在這里做什么?
在我們新的 [name].ts 文件中痕钢,我們正在創(chuàng)建一個處理程序來處理所有傳入的 ant 傳出請求图柏。然后我們從請求查詢中解構(gòu)name
,設置狀態(tài)碼和內(nèi)容類型任连,最后返回一個 JSON 對象蚤吹,其name
屬性設置為Your name is [name]
.
有了 API 路由,我們現(xiàn)在為它編寫測試随抠。在__tests__
目錄中裁着,創(chuàng)建一個新__tests__/api.test.ts
文件。這是我們將為 API 路由編寫測試的地方拱她。注意在不同的文件中進行二驰,我們要在組件文件中測試組件,在 api 文件中測試 API椭懊。
我們需要一個庫來向我們的 API 路由發(fā)出請求诸蚕。我們可以使用fetch
它步势,因為它已默認添加到 Node.js氧猬,但如果您的版本較低,我們可以使用外部庫坏瘩。如果它仍然可用isomorphic-fetch
盅抚,您仍然可以使用默認瀏覽器獲取。安裝并@types/isomorphic-fetch
使用以下內(nèi)容向我們的 API 路由發(fā)出請求:
npm install --save isomorphic-fetch @types/isomorphic-fetch
在__tests__/api.test.ts
文件中倔矾,讓我們導入isomorphic-fetch
包妄均。
import fetch from "isomorphic-fetch";
我們現(xiàn)在可以測試我們的 API 路由。在__tests__/api.test.ts
文件中哪自,添加以下內(nèi)容:
describe("api routes", () => {
it("should return the correct data", async () => {
const data = await fetch("http://localhost:3000/api/Duncan");
expect(data.status).toBe(200);
const json = await data.json();
expect(json).toEqual({ name: "Your name is Duncan" });
});
});
我們剛剛做了什么丰包?
- 在上面的代碼中,我們正在測試 API 路由是否使用
fetch
函數(shù)向我們的 API 路由發(fā)出請求返回正確的數(shù)據(jù)壤巷。我們正在使用expect
Jest 中的函數(shù)來測試請求的狀態(tài)代碼是否為 200邑彪,并且我們還在檢查我們期望的響應是否確實是我們從請求中得到的。
這是迄今為止測試 Next.js API 路由最簡單的方法胧华,我將在另一篇文章中介紹另一種方法寄症。您可以運行測試以查看它是否通過。
結(jié)論
我們首先使用 TypeScript 創(chuàng)建了一個新的 Next.js 應用程序矩动,然后設置了 Jest 和 React 測試庫以用于我們的測試有巧。我們測試了三個主要方面;在 Next.js 應用程序中測試組件的呈現(xiàn)悲没、測試組件上的事件和測試 API 端點篮迎。
謝謝你的時間。下一篇文章見。
文章來源:https://blog.astrosaurus.me/testing-nextjs-applications-with-jest-and-react-testing-library