DOM 操作
另一類通常被認為難以測試的函式是直接操作 DOM 的程式碼。讓我們看看如何測試以下 jQuery 程式碼片段,它會監聽 click 事件、非同步擷取一些資料,並設定 span 的內容。
displayUser.js
'use strict';
const $ = require('jquery');
const fetchCurrentUser = require('./fetchCurrentUser.js');
$('#button').click(() => {
fetchCurrentUser(user => {
const loggedText = 'Logged ' + (user.loggedIn ? 'In' : 'Out');
$('#username').text(user.fullName + ' - ' + loggedText);
});
});
同樣地,我們在 __tests__/
資料夾中建立一個測試檔案
__tests__/displayUser-test.js
'use strict';
jest.mock('../fetchCurrentUser');
test('displays a user after a click', () => {
// Set up our document body
document.body.innerHTML =
'<div>' +
' <span id="username" />' +
' <button id="button" />' +
'</div>';
// This module has a side-effect
require('../displayUser');
const $ = require('jquery');
const fetchCurrentUser = require('../fetchCurrentUser');
// Tell the fetchCurrentUser mock function to automatically invoke
// its callback with some data
fetchCurrentUser.mockImplementation(cb => {
cb({
fullName: 'Johnny Cash',
loggedIn: true,
});
});
// Use jquery to emulate a click on our button
$('#button').click();
// Assert that the fetchCurrentUser function was called, and that the
// #username span's inner text was updated as we'd expect it to.
expect(fetchCurrentUser).toHaveBeenCalled();
expect($('#username').text()).toBe('Johnny Cash - Logged In');
});
我們模擬 fetchCurrentUser.js
,讓我們的測試不會發出真正的網路請求,而是改為解析本機的模擬資料。這可確保我們的測試能在幾毫秒內完成,而不是幾秒,並保證單元測試迭代速度快速。
此外,受測函式會在 #button
DOM 元素上新增事件監聽器,因此我們需要為測試正確設定 DOM。jsdom
和 jest-environment-jsdom
套件會模擬 DOM 環境,就像您在瀏覽器中一樣。這表示我們呼叫的每個 DOM API 都能以在瀏覽器中觀察到的相同方式觀察!
若要開始使用 JSDOM 測試環境,必須先安裝 jest-environment-jsdom
套件(如果尚未安裝的話)
- npm
- Yarn
- pnpm
npm install --save-dev jest-environment-jsdom
yarn add --dev jest-environment-jsdom
pnpm add --save-dev jest-environment-jsdom
此範例的程式碼可在 examples/jquery 取得。