昨天我們學習了如何在測試裡 render 元件,並使用 testing library 家族的 jest-dom
及 dom-testing-library
來強化 assertions,寫出更易讀、易維護的測試。
昨天完成的測試如下:
test/react-dom.js
import React from 'react'
import ReactDOM from 'react-dom'
import {getQueriesForElement} from '@testing-library/dom'
import {FavoriteNumber} from '../favorite-number'
test('renders a number input with a label "Favorite Number"', () => {
const div = document.createElement('div')
ReactDOM.render(<FavoriteNumber />, div)
const {getByLabelText} = getQueriesForElement(div)
const input = getByLabelText(/favorite number/i)
expect(input).toHaveAttribute('type', 'number')
})
現在我們進一步思考,在其他的元件測試中,也都會需要 render 元件,所以可以試著將 render 的部分抽出來,讓它成為一個可以重複使用的 function。
我們希望這個 function 叫做 render
,可以像這樣使用 const {getByLabelText} = render(<FavoriteNumber />)
,傳入 component 後回傳一系列 queries 方法:
test/react-dom.js
// 粗略將原本 test 裡面的程式碼搬進來
// render function 還未完成
function render() {
const div = document.createElement('div')
ReactDOM.render(<FavoriteNumber />, div)
const {getByLabelText} = getQueriesForElement(div)
}
test('renders a number input with a label "Favorite Number"', () => {
const {getByLabelText} = render(<FavoriteNumber />) // render 方法可重複使用
const input = getByLabelText(/favorite number/i)
expect(input).toHaveAttribute('type', 'number')
})
讓我們繼續完成 render function:
test/react-dom.js
function render(ui) {
const container = document.createElement('div')
ReactDOM.render(ui, container)
const queries = getQueriesForElement(container)
return {container, ...queries} // 回傳一系列 queries 方法
}
這個 render function 的功能,其實 testing library 家族的 React Testing Library
已經幫我們做好了,現在將它引入測試中,取代剛剛我們自己實作的 render function:
npm install --save-dev @testing-library/react
或
yarn add --dev @testing-library/react
import @testing-library/react
的 render
進來,現在已不需要 'react-dom'
跟 '@testing-library/dom'
了:
test/react-dom.js
import React from 'react'
// 移除 import ReactDOM from 'react-dom'
// 移除 import {getQueriesForElement} from '@testing-library/dom'
import {render} from '@testing-library/react'
import {FavoriteNumber} from '../favorite-number'
test('renders a number input with a label "Favorite Number"', () => {
const {getByLabelText} = render(<FavoriteNumber />)
const input = getByLabelText(/favorite number/i)
expect(input).toHaveAttribute('type', 'number')
})
在寫元件測試的過程中,我們很需要清楚 DOM 當下的狀態是什麼。React testing library 提供一個 debug Function,它會幫我們在 console 中印出 DOM 的長相。
我們可以從 render
function 回傳得到 debug
method,呼叫 debug
可以印出當下 Jest render 出來的 DOM 狀態:
const {getByLabelText, debug} = render(<FavoriteNumber />)
debug()
如果我們只想印出特定的 DOM,也可以在 debug
裡面傳入那個元素:
test('renders a number input with a label "Favorite Number"', () => {
const {getByLabelText, debug} = render(<FavoriteNumber />)
const input = getByLabelText(/favorite number/i)
debug(input) // 只印出 input 現在的 DOM 長相
})
通常 debug
method 只是幫助我們在撰寫測試階段,快速掌握當下的 DOM 長相,當我們寫完測試後,就會將它刪除,不會留在 code base 裡面。