Jestでユニットテストを書くときにrewire.jsで非公開関数をモック化したら出来なかったので、解決策をメモとして残しておきます。
nodejsのバージョン: v9.2.1
ダメな例
テスト対象の実装
api-util.js
const promisify = require('util').promisify
const request = promisify(require('request'))
const cheerio = require('cheerio')
const getPageTitle = async (url) => {
const res = await request(url)
const $ = cheerio.load(res.body)
return $('title').text()
}
module.exports = {
getLowerTitle: async (url) => {
const title = await getPageTitle(url)
return title.toLowerCase()
}
}
テストコード
api-util.test.js
const rewire = require('rewire')
test('ページタイトルが小文字で取得できること', () => {
const apiUtil = rewire('./api-util')
const getPageTitleMock = jest.fn(apiUtil.__get__('getPageTitle')).mockResolvedValue('Google')
apiUtil.__set__({
getPageTitle: getPageTitleMock
})
console.log(apiUtil.getPageTitle)
expect(apiUtil.getLowerTitle('https://xxxxx.co.jp')).resolves.toBe('google')
})
テストを実行したらAssignment to constant variable
のエラーが発生しました。
mocha
では発生しなかったのですが、Jest
だとエラーが発生していまいます。
$ npx jest api-util.test.js
FAIL ./api-util.test.js
✕ ページタイトルが小文字で取得できること (1186ms)
● ページタイトルが小文字で取得できること
TypeError: Assignment to constant variable.
at eval (eval at __set__ (api-util.js:82:5), <anonymous>:1:14)
at Object.__set__ (api-util.js:82:5)
at Object.<anonymous>.test (api-util.test.js:7:13)
解決策
speedskater/babel-plugin-rewire を使うことで解決できました。
$ npm install babel-plugin-rewire
.babelrc
に以下の内容を追記します。
.babelrc
{
"env": {
"test": {
"plugins": ["rewire"]
}
}
}
babel-plugin-rewire
は rewire
と同じ__set__
と__get__
のインターフェースをサポートしているので、同じようにテストコード書くことができます。
またrewire
と比較しても、モジュール読み込みはrequire
で読み込めばよいので、少しだけスッキリします。
api-util.test.js
test('ページタイトルが小文字で取得できること', () => {
const apiUtil = require('./api-util')
const getPageTitleMock = jest.fn(apiUtil.__get__('getPageTitle')).mockResolvedValue('Google')
apiUtil.__set__({
getPageTitle: getPageTitleMock
})
expect(apiUtil.getLowerTitle('https://xxxxx.co.jp')).resolves.toBe('google')
})