LoginSignup
0
0

mocha + jsdom で HTMLElement の単体テストを実行する

Last updated at Posted at 2023-08-17

変更履歴

  • 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. テストコードに組み込む

想定する構成

  • :open_file_folder: src
    • :notebook: sample.js
  • :open_file_folder: test
    • :notebook: sample.spec.js
    • :open_file_folder: mocks
      • :notebook: 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. jsdomdocumentfakeを作成し、テスト対象関数の引数とする

fake objectimportしておく

テストコード
/**
 * ./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)

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0