React Unit Test | React 的 Route 單元測試 feat. Jest, react-testing-library

神Q超人
Enjoy life enjoy coding
6 min readNov 27, 2019
Photo by Siora Photography on Unsplash

前言

Hi!大家好,我是神 Q 超人!本文要講解 react 中的 router 單元測試,在閱讀這篇前可以先簡單看「Jest | 再一次測試你的 Component — feat.react-testing-library 基本用法」,裡面說明了 component 和 redux 如何測試和 react-testing-library 測試庫的基本用法,算是這篇的上集,服用完後再往下讀剛剛好哦 😃

測試 Router

測試方向

只要能夠融會一些單元測試的觀念(測試觀念可以看 這裡),要來測試 router 其實一點都不難,

因為你已經能夠明白什麼才是重要的!

就 router 執行的過程來說,當使用者點擊頁面中的連結時,router 會改變,然後 render 出符合 path 的 component,流程簡單說大概是這樣子,那問題來囉!在上述幾個部分,使用者會在乎的是什麼呢?

是點下連結後!有沒有出現對應的 component!

就是這樣而已,關於 router 的測試,還真的不需要去管 router,因為使用者(包括我們自己去瀏覽其他人的網站)也不會在乎 router 是什麼,只會想說:

「我點了回首頁就要給我回首頁!」

希望這簡潔有力的解說能 touch 到大家的心 😆,那接下來實作看看吧!

測試情境

接下來的例子都會用 這個專案 的內容下去實作,而專案裡的 router 是用直接用 react-router-dom 處理,裡面的頁面很簡單,只有一個首頁和最新消息,然後內容上方有選單可以變更 router 切換內容:

點選上方的選單能夠變更 router,render 對應的 component

程式碼內容:

測試前置準備

首先我們替一些測試會斷言到的 component 做「測試特徵」,也就是 data-testid,會加到的地方分別是需要點擊的連結和期望會 render 出來的 component。

首先是選單的連結:

再來是根據 router,期望能夠 render 的 component(HomeNews):

接著除了 Jest 和 react-testing-library 外,還需要 jest-dom,它是 Jest 的擴充斷言庫,可以用來確認 DOM 的狀態:

npm install jest-dom --save-dev

開始測試

一切準備就緒後,就能在根目錄上建立一個 __test__ 的資料夾,然後加入 component/Main.test.jsx,來撰寫測試案例:

|-__test__
|-component
|-Main.test.jsx
|-src

首先是把需要的東西 import 進來,完成測試 component 的起手式:

我們第一個測試案例是 ClickNewsLink_RenderNewsPage,想確認點擊 「最新消息」後會不會 render 出 News 這個 component。

Router 的測試就像 redux 需要 Provider,router 也需要 HashRouterBrowserRouter,但測試並不是跑在瀏覽器上,所以我們需要有人替我們紀錄 router 的變化,剛好 react-router-dom 就有提供這麼一個 MemoryRouter 能夠做到!

MemoryRouter 它有個 props 叫做 initialEntries,能夠指定 router!用法大概像這樣子:

<MemoryRouter initialEntries={['/']}>// 初始 router 不一定要 /,也可以從某個 component 開始
<MemoryRouter initialEntries={['/']}>

因此只要透過 MemoryRouter 加上 Main,再用 react-testing-library 做 render,最後搭配 jest-dom 擴充的 toBeInTheDocument 就能輕鬆做斷言測試了。總合以上操作,測試案例會變成:

測試案例中的斷言部分應該非常清楚,就是在點下 newsLink 後確認 newsPage 有沒有正確出現在 DOM 裡,有的話代表使用者看見的畫面是符合預期的!完成測試案例後就能執行指令看結果:

測試案例成功!

重構測試

但還沒結束!雖然上方我們替 Nav 的兩個連結都加上 data-testid,讓測試案例能夠運行,且不會被 UI 的變化影響(連結換位置或移除 CSS),但是 react-testing-library 作者曾說過:

it’s recommended to use data-testid (though you'll want to make sure that you're not forgetting to use a proper role attribute or something first).

引用自:https://kentcdodds.com/blog/making-your-ui-tests-resilient-to-change

意思是雖然是推薦使用 data-testid ,但是你也必須想想,在我們要取用的 element 身上是不是有更適合的 attribute 能夠代表它。

而我們正好有!就是連結按鈕上面顯示的 text 文字!只要透過 text 獲取連結的 element,就不再需要另外設定 data-testid 了!

所以可以將 Nav 上的 data-testid 移除,然後測試案例重構成這樣子:

看起來是不是更清楚 Main 裡面在做什麼事情!如果測試案例夠貼近使用者操作的過程,不只容易寫(因為你也不用思考太多),讀起來也像在看 spec!

最後大家也可以從 專案 fork 或 clone,繼續加上其他測試,像是確認在其他 router 下點 homeLink 後,homePage 會不會正常顯示,或是亂修改一波後再來玩完測試,裡面的環境非常足夠,如果有任何問題可以留言告訴我 🙌

--

--