問題
JS/TSで公開されてない関数(non-exported function)のテストはrewireを使えばできるんですが、その関数内でDOM操作をしてるとき、document
がundefined
でcreateElement()
なんてないぞ!と怒られるんですよね。
解決
はい! jest-environment-jsdom-global〜〜!!
端的に言うと、これを使えばJestが提供するJSDOMインスタンスにアクセスできるので、それをライブラリへ伝えることができるんですよね。
もうちょっと詳しく言うと、jest-environment-jsdom-global
はJestが標準で使っているjest-environment-jsdom
を継承してJSDOMインスタンスを露出させただけのものです。
次の例はnodeToDOM()
というDOM操作する非公開関数をテストしたものです。
import rewire from 'rewire'
import { JSDOM } from 'jsdom'
declare var jsdom: JSDOM
describe('myModule', (): void => {
const myModule = rewire('../dist')
myModule.__set__('document', jsdom.window.document.defaultView.document)
const nodeToDOM = myModule.__get__('nodeToDOM')
it('nodeToDOM()', (): void => {
const node = <meta name="description">Meta</meta>
const el = document.createElement('meta')
el.setAttribute('name', 'description')
el.textContent = 'Meta'
expect(nodeToDOM(node)).toStrictEqual(el)
})
})
ポイントはmyModule.__set__()
ですね。ここでライブラリ内グローバル変数document
にJSDOMの提供するものを当てています。
window
が必要ならばjsdom.window.document.defaultView
を、というように必要なものを適宜割り当ててください。
import { JSDOM } from 'jsdom'
とdeclare var jsdom: JSDOM
はJavaScriptのときは要りません。TypeScriptに「jsdom
なんていうグローバル変数なんて無いぞ!」と怒られないように付けています。
おまけ
サンプルコードはTypeScriptですが、rewire
と@types/rewire
をインストールして、TS→JS変換後のモジュール(dist/index.js
)をrewire()
するだけで動きました!