iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 23
1
Modern Web

循序漸進學習 Javascript 測試系列 第 23

Day 23 測試 React 元件:使用 React Testing Library 體驗 Test Driven Development (TDD) - 3

用 TDD 實作表單開發

我們現在試著用 TDD 的方式來開發一個表單。

這個表單主要功能是發表文章,它接收標題 (title) 、內容 (content)、標籤 (tag),並且有一個按鈕可以點擊送出表單,並發出 HTTP  request。

我們會經歷以下步驟,一步一步先寫測試再寫程式,重複亮紅燈再亮綠燈的循環過程:

  • 步驟一:開發表單元件結構
  • 步驟二:開發 submit button 功能
  • 步驟三:表單 API Call
  • 步驟四:submit 後的 Redirect

步驟四:submit 後的 Redirect

發送資料到 API 後,要將使用者導回首頁。我們將用 react-router 的 <Redirect /> component 來實作導頁功能。

首先,一樣從寫測試開始,先到 __tests__/post-editor.js 檔案加上測試:

  • import 'react-router' 裡的 Redirect ,並給它一個 alias MockRedirect ,方便維護測試檔案時清楚辨識這是 mock 版本的 Redirect
  • mock 'react-router' 。使用 jest.fn() mock Redirect ,因為 Redirect 的 mock function 是什麼對這個測試本身來說並不重要,所以傳入 () => null 作為 mock function 即可。

tests/post-editor.js

import {Redirect as MockRedirect} from 'react-router'
import {Editor} from '../post-editor'

jest.mock('react-router', () => {
  return {
    Redirect: jest.fn(() => null),
  }
})
  • 加上 assertions,驗證 Redirect 是否傳入正確的參數,以及是否被呼叫一次。
expect(MockRedirect).toHaveBeenCalledWith({to: '/'}, {}))
expect(MockRedirect).toHaveBeenCalledTimes(1)

這時候,測試是 fail ❌。

回到 post-editor.js 補上功能:

  • import 'react-router' 裡的 <Redirect />
  • 新增一個 redirect state,初始值為 false 。當 savePost() 完成之後 setRedirect(true)redirect 如果為 true ,則 return <Redirect to="/" />

post-editor.js

import {Redirect} from 'react-router'

function Editor({user}) {
  const [isSaving, setIsSaving] = React.useState(false)
  const [redirect, setRedirect] = React.useState(false)
  function handleSubmit(e) {
    e.preventDefault()
    const {title, content, tags} = e.target.elements
    const newPost = {
      ...
    }
    setIsSaving(true)
    savePost(newPost).then(() => setRedirect(true))
  }
  if (redirect) {
    return <Redirect to="/" />
  }
  return (
    ...
  )
}

預期此時測試應該要亮綠燈 ✅,但卻是 fail ❌?

console output 顯示 MockRedirect 並沒有被預期的參數呼叫。

這是因為 savePost() 是非同步的,當 promise resolve 之後才呼叫 <Redirect /> 。但我們剛剛寫的 assertions 都是同步的,才造成錯誤。現在,我們必須等到 MockRedirect 確實被呼叫:

  • 使用 wait() 等待

tests/post-editor.js

test('renders a form with title, content, tags, and a submit button', async () => {
  ...

  await wait(() => expect(MockRedirect).toHaveBeenCalledWith({to: '/'}, {}))
  expect(MockRedirect).toHaveBeenCalledTimes(1)
})

測試 pass 亮綠燈 ✅。

...未完


上一篇
Day 22 測試 React 元件:使用 React Testing Library 體驗 Test Driven Development (TDD) - 2
下一篇
Day 24 測試 React 元件:使用 React Testing Library 體驗 Test Driven Development (TDD) - 4
系列文
循序漸進學習 Javascript 測試30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言