本篇為 [FE302] React 基礎 - hooks 版本 這門課程的學習筆記。如有錯誤歡迎指正!
這篇會稍微談談有關測試的東西,測試在現今已漸漸成為重要的議題,主要目的就是為了避免產品出現 Bug,藉此提高使用者體驗。
測試簡單來說可分成以下三種:
- 單元測試 Unit testing
- 以程式碼的最小單位進行測試
- 整合測試 Integration testing
- 對不同模組之間的交互作用進行測試
- 端對端測試 End-to-end testing 或 E2E testing
- 從使用者角度出發,對真實系統進行測試
- 主要為「人工測試」
(參考資料:一次搞懂單元測試、整合測試、端對端測試之間的差異)
如果要測試 React Component,可使用 React Testing Library 套件,這在安裝 React 時就有內建。
其原理是把 React 的 Component 給 render 出來,並非真的 render 在瀏覽器上,而是透過 JS DOM 模擬成 JS 來執行,即可針對 render 出來的畫面進行各種測試。
在我們建立專案時,就有個 App.test.js 檔案可用來寫測試內容:
每個測試會用一個 function 包住:
import { render, screen } from '@testing-library/react';
import App from './App';
test('renders learn react link', () => {
// render component
render(<App />);
// 確認是否有出現指定文字
const linkElement = screen.getByText(/learn react/i);
// 確認是否有在 document 裡面
expect(linkElement).toBeInTheDocument();
});
在終端機輸入指令即可執行測試:
$ npm run test
測試預設會找 App.test.js 在上次 commit 時有更動的部分,例如輸入 a 可跑所有測試結果:
由於 App.test.js 是 watch 模式,只要檔案有變動就會自動跑測試,結果會長這樣:
但實際在測試時並不會真的去 call API,因為 mock API 代表要做什麼事,而我們在意的點其實是:
- 會不會發 request 去 back-end
- 拿到 API response 之後,會不會顯示想要的資料
也就是說,測試其實不需要知道 back-end 回覆的內容,而是透過 mock API Point,就可以在打 API 之前回傳一個結構,藉此來測試顯示的資料。
例如以下範例,藉由 mock API 來模擬每次 fetch 會回傳的資料,再使用 await waitfor() 非同步處理進行測試:
這種測試方法其實就類似於 Unit testing 或 Integration testing,再來要介紹的是用於 End-to-end testing 的程式。
End-to-end testing 的特點在於會真的跑一個 Browser 起來,並將手動測試轉變成程式碼執行,因此會更接近使用者實際在使用網站的感受。
我們要介紹的是 cypress 這套 E2E testing 程式,在測試時也有提供錄影功能,能夠記錄錯誤截圖等等。
$ npm install cypress
$ npx cypress open
或是在 package.json 的 scripts 新增 cypress open 指令,即可使用 npm run cypress:open
指令執行:
第一次執行 cypress open 時,會自動在 my-app 資料夾建立 cypress 相關程式,像是 integration 裡的內建測試等等。
執行後會自動開啟 GUI 介面:
預設的測試檔名為 spec.js
,例如我們可在 integration 建立一個 home.spec.js,並在 my-app 底下的 cypress.json 新增 baseUrl:
{
"baseUrl": "http://localhost:3000/react-board-test"
}
然後在 home.spec.js 寫入官網範例:
describe("The Home Page", () => {
it("successfully loads", () => {
// 改成連線到首頁
cy.visit("/");
});
});
點選 cypress 介面中的 home.spec.js 執行:
此時會自動開啟 Chrome 瀏覽器跑測試,結果如下:
但是和先前的例子一樣,我們通常不會真的去 call API,而是會 mock API,在 cypress 可透過 route 來模擬 API,可參考官方文件。
首先要修改 cypress.json 設定檔,加上 experimentalFetchPolyfill
參數:
{
"baseUrl": "http://localhost:3000/react-board-test",
"experimentalFetchPolyfill": true
}
改寫 home.spec.js 範例如下,這樣就是一個簡單的測試:
describe("The Home Page", () => {
it("successfully loads", () => {
cy.server();
// mock API
cy.route(
"https://student-json-api.lidemy.me/posts?_sort=createdAt&_order=desc",
[
{
id: 1,
title: "Hello World!",
createdAt: 20202020,
},
]
);
// 導向首頁
cy.visit("/");
// 測試: 確認頁面是否包含該字串
cy.contains("Hello World!");
});
});
測試結果如下:
查看 Request URL 會發現網址有被 cypress 換成 mock API,藉此來 mock 回傳結果:
以上介紹的兩種測試,差別在於:
- React Testing Library
- 類似於 Unit testing 或 Integration testing
- 利用 JavaScript 模擬環境
- Cypress
- E2E testing
- 實際在瀏覽器載入頁面,透過 mock API 的方式測試行為