変更履歴
-
node-canvas
を追加
やりたいこと
-
mocha
で HTML DOM 操作のあるモジュールのユニットテストをしたい
問題点
- HTML DOM を操作するオブジェクト(
Document
, HTMLCanvasElement etc...)はNode.js
では標準実装されていない為、テストコードを実行すると必ずエラーになる。
エラーになる例
module.exports = {
setup(): () => {
const container = document.querySelector(".container"); // <- この行でエラー
if(!container){
throw new DOMException(`".container" is undefined.`); // <- この行でエラー
}
const canvas = document.querySelector("canvas");
const ctx2d = canvas.getContext("2d"); // <- この行でエラー
// ... 後続処理 ...
}
};
エラーの例 (document が無い)
ReferenceError: document is not defined
エラーの例 (DOMException が無い)
ReferenceError: DOMException is not defined
※ 他にもありそう
結論
jsdom
| Githubを活用する
前提
- Node.js が正しくインストールされていること
- mocha でテストコードが実行可能な事
環境
- Node.js - v16.14.2
- mocha - v10.2.0
- jsdom - v22.1.0
- canvas - v2.11.2
1. jsdom
をインストール
bash
npm install --save-dev jsdom @types/jsdom
2. テストコードに組み込む
想定する構成
-
src
-
sample.js
-
-
test
-
sample.spec.js
-
mocks
-
sample.mock.js
-
-
2.1. 足りないオブジェクトのfake
を作成する
2.1.1. node-canvas
をインストール
別稿を参照
2.1.2. fakeを作成する
./test/mock/sample.mock.js
import jsdom from "jsdom";
const { JSDOM } = jsdom;
const fakedom = new JSDOM();
const { window } = fakedom;
// fake objects
// Node.js の globalThis に宣言がなければ参照を追加
globalThis.DOMException ??= window.DOMException; // Node.js v18 以降では不要
globalThis.document ??= window.document;
globalThis.HTMLCanvasElement ??= window.HTMLCanvasElement;
// ... 他のオブジェクトも、足りないものがあれば参照を追加していく ...
2.3. jsdom
でdocument
のfake
を作成し、テスト対象関数の引数とする
fake object
もimport
しておく
テストコード
/**
* ./test/sample.spec.js
*/
import { assert } from "chai";
// テストの対象モジュール
import {setup} from "@/dom.js";
+ // fake object をインポート
+ import "@/../test/mocks/sample.mock";
+ // @see https://github.com/jsdom/jsdom#basic-usage
+ import jsdom from "jsdom";
+ const { JSDOM } = jsdom;
describe("dom のテスト", () => {
+ const fakedom = new JSDOM(`<!DOCTYPE html>`);
+ const { document } = fakedom.window;
it("setup", () => {
- setup();
+ setup(document);
});
});
2.3. document
を引数で受け取れる様に変更する。
※実環境への影響は最小限にする
テスト対象のモジュール
/**
* ./src/dom.js
*/
module.exports = {
- setup: () => {
- const container = document.querySelector(".container");
+ setup: (document) => {
+ const doc = document || self.document;
+ const container = doc.querySelector(".container");
if(!container){
throw new DOMException(`".container" is undefined`);
}
// ... 後続処理 ...
},
};
2.4. テストを実行
bash
npm run test
... 中略 ...
> mocha test/**/*.spec.ts -R spec
dom のテスト
✔ setup
1 passing (1ms)
了