Jestで非公開関数をテストする方法がイマイチだった

前回の続き。

結論:const を上書きできないっぽいのでrewire以外の方法を探すのが良さそう…

(追記に上げたように、Jestで動かす時にできないという条件付き)

前提

検証した時のバージョン

{
  "dependencies": {
    "jest": "^23.6.0",
    "rewire": "^4.0.1"
  }
}

モック前

テスト対象

const fs = require("fs");

const read = cb => {
  return fs.readFile("./text.txt", "utf-8", cb);
};

module.exports = read;

テストコード

const read = require("./read.js");

test("read", done => {
  return read((err, text) => {
    expect(text).toMatch("foobar");
    done();
  });
});

モックしてみる(失敗)

fs.readFile の結果をモックしたいので、こう書いてみる

テストコード2

const rewire = require("rewire");
const read = rewire("./read.js");

test("read", done => {
  read.__set__("fs", {
    readFile: (path, enc, cb) => cb(null, "foobar")
  });

  return read((err, text) => {
    expect(text).toMatch("foobar");
    done();
  });
});

けれど結果はモック前と変わらない…

Issue当たってみると、同じ悩みを抱えてる人がいたよう。「Rewiring const is supported since 3.0.0」って言ってるけどReopenされてる。そしてReopenした人の「TypeError: Assignment to constant variable」とも違う状況なので不思議な気持ち。

github.com

モックしてみる(とりあえず成功)

Issueへの返信にもあった let 使ってみる方法を試す。テストコードは2の状態のまま。

テスト対象2

let fs = require("fs");

const read = cb => {
  return fs.readFile("./text.txt", "utf-8", cb);
};

module.exports = read;

これでテストはPassした。でもテストのために let にするのっておかしいし、そんな制限ある中でコード書きたくないのでrewireは使えないかな…


追記

どうやらJestとの組み合わせが良くないらしい。

github.com

リンク先ではMochaで試してるけどnodeでもMock成功した。

// run.js
const rewire = require("rewire");
const read = rewire("./read.js");

read.__set__("fs", {
  readFile: (path, enc, cb) => cb(null, "foobar")
});

return read((error, text) => {
  console.log({ error, text });
});

node run.js として呼び出したらモック成功した。まあJestとの組み合わせが良くないなら選択できないんだけど、ライブラリ自体は問題ないようだったので訂正。