kenju's blog

About Programming, Mathematics, Security and Blockchain

Reactをテストするenzymeを導入した際の知見メモ

JavaScript Testing utilities for React"である"enzyme"を導入した際の知見。

github.com

要件

  • Testing Frameworkはmocha
  • Full DOM Rendering(mount API)を利用

ポイント

  • mochaでmount APIを使うときは--requireで最初に擬似DOM環境をセットする必要がある
  • 擬似DOM環境はpseudo_window.jsファイルで分離して管理
  • あとはmount APIを用いてReact Componentsをテストするだけ

実装

まず、mocha --requireを用いて、initialize処理時に擬似DOM環境をセットさせる。

mocha.opts:

--require spec/javascripts/client/support/setup.js

このsetup.jsでは、後述する擬似DOM環境ファイルを読み込んで、セットアップしているだけ。

setup.js:

/*
 * This file is supposed to be required from mocha.opts.
 * It is because a 'document' should be loaded into the 'global' scope
 * before requiring React for the first time to use Enzyme `mount` API.
 * @see http://airbnb.io/enzyme/docs/guides/jsdom.html
 */
import * as PseudoWindow from './pseudo_window';
PseudoWindow.setup();

これが今回のキモ。JSDOMを用いて、擬似DOM環境をセットアップしている。

pseudo_window.js:

const { JSDOM } = require('jsdom');

const jsdom = new JSDOM(`
  <!doctype html>
  <html>
    <head><meta name="csrf-token" content="dummy-token" /></head>
    <body></body>
  </html>`);

function setup() {
  // "__jsdom_global_keys"で特有のプロパティは管理。ハードコーディングなのがどうにかしたいが一旦これで
  global.__jsdom_global_keys = [
    'window',
    'jQuery',
    '$',
    'XMLHttpRequest',
  ];

  global.window = global;

  // globalにJSDOMライブラリに用意してあるプロパティをごっそりコピー
  for (const name of Object.getOwnPropertyNames(jsdom.window)) {
    if (!global[name]) {
      const descriptor = Object.getOwnPropertyDescriptor(jsdom.window, name);
      Object.defineProperty(global, name, descriptor);
      global.__jsdom_global_keys.push(name);
    }
  }

  // jQueryは"$"でも使えるように`global.$`に参照渡し
  global.jQuery = require('jquery');
  global.$ = global.jQuery;
}

function cleanup() {
  for (const name of global.__jsdom_global_keys) {
    delete global[name];
  }

  delete global['__jsdom_global_keys'];
}

ここまできたら、後はテストするだけ。

追記

enzymeについては↓の記事を書いている:

itiskj.hatenablog.com