LoginSignup
16
7

More than 5 years have passed since last update.

Node.jsのテストでJestを使ってfetchをモックするのは意外に大変

Last updated at Posted at 2018-11-27

opengraph.png

Jestを使ってfetch()をモックしたかったです。
いくつかのハマりポイントでハマってしまったのですが解決できました。

Jestの初期化

Jest本体とBabel、今回テストを行いたいnode-fechのモジュールを入れます。

リポジトリを初期化しておきます。

$ yarn init

BabelはJestのテストファイルでimport文などのES6記法を使うために入れています。

$ yarn add --dev jest babel-core babel-jest babel-plugin-transform-es2015-modules-commonjs node-fetch
.babelrc
{
  "env": {
    "test": {
      "plugins": [
        "transform-es2015-modules-commonjs"
      ]
    }
  }
}

テストファイルを置く

テストコードを先に書いてしまいます。

index.test.js
import fetch from 'node-fetch'

jest.mock('node-fetch', () => jest.fn())

describe('fetch-mock test', () => {
    it('check fetch mock test', async () => {
        const dummyResponse = Promise.resolve({
            ok: true,
            status: 200,
            json: () => {
                return {};
            },
        });

        fetch.mockImplementation(() => dummyResponse)
        await dummyResponse;

        console.log(dummyResponse);
    });
});

動かしてみます。

image.png

テスト対象コード

index.js
'use strict'
var fetch = require('node-fetch');

const makeRequest = async () => {
	const res = await fetch("http://httpbin.org/get");
	const resJson = await res.json();
	return resJson;
};

module.exports = makeRequest;

index.test.js
import fetch from 'node-fetch'

jest.mock('node-fetch', () => jest.fn())

describe('fetch-mock test', () => {
    it('check fetch mock test', async () => {
        const dummyResponse = Promise.resolve({
            ok: true,
            status: 200,
            json: () => {
                return {};
            },
        });
        fetch.mockImplementation(() => dummyResponse)
        await dummyResponse;

        var makeRequest = require('./index'); // テストしたいモジュールを読み込む

        makeRequest().then(function (data) { // success
            console.log('got data', data); // ダミーレスポンスが帰ってきている
        }).catch((e) => { // error
            console.log(e.message)
        });
    });
});

jest.mock('node-fetch', () => jest.fn())をすることで、本体コード側でnode-fetchjestのモックモジュールに置き換える宣言をしています。
fetch.mockImplementation(() => dummyResponse)で実際にどんなレスポンスを返すかの実装を行っています。

うまく動きました!

ハマったポイント

proxyquire

JavaScriptのモック用ライブラリにproxyquireがあります。
テストするときには非常に協力なモックライブラリで、具体的にはrequireを良い感じに乗っ取ってモックされた関数などを返します。
proxyquireでDI もっとモックテストしよう

ただJestとの相性がよくないらしく、Jestではproxyquireが動かない、という報告がありました。
Does not work with proxyquire
実際に今回は動きませんでした。このIssueではjest.mockを使え、となっていますね。

proxyquire自体も古い1ようで、Jestではjest.mockを使っていくほうが良いようです。

nock

fetchのモックするためのライブラリにnockがあります。こちらも良く出来たライブラリなのですが、うまく動きませんでした。
【Node.js】nockでtest!

jest-fetch-mock

Jest用のfetchをモックする専用のライブラリ jest-fetch-mock があります。
jest.mock()汎用のモックシステムなのですが、fetchレスポンスにフォーカスしたライブラリのようです。
こちらもうまく動かせませんでした。

謝辞

今回の件でうまく動かせず色々ヘルプをもらいました。
@say3no @ketch123 @ur0n @naname
ありがとうございました!

StackOverFlowで回答してくれたAndreas Köberleありがとう!
How can I mock fetch function in Node.js by Jest?

  1. 2018年現在では2015年ぐらいの記事が多かったです。

16
7
2

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
16
7