在等待上下文中模拟带有笑话的导入函数

时间:2019-01-21 22:20:01

标签: javascript node.js jestjs

我们正在基于express创建一个节点应用程序,以从静态本地文件中读取并返回文件中的JSON。

以下是我们的json-file.js和我们的路线方法:

const readFilePromise = require('fs-readfile-promise');

module.exports = {
  readJsonFile: async (req, res) => {
    try {
        const filePath = 'somefile.json';
        const file = await readFilePromise(filePath, 'utf8');

        res.send(file);
      } catch(e) {
        res.status(500).json(e);
      }
  },
};

我们使用第三方模块fs-readfile-promise,该模块基本上将节点readFileSync变成了承诺。

但是我们很难模拟这个第三方的实现,以便能够产生两个测试:一个基于模拟读取文件(已解决承诺),另一个基于拒绝。

这是我们的测试文件:

const { readJsonFile } = require('../routes/json-file');
const readFilePromise = require('fs-readfile-promise');
jest.mock('fs-readfile-promise');

const resJson = jest.fn();
const resStatus = jest.fn();
const resSend = jest.fn();
const res = {
  send: resSend,
  status: resStatus,
  json: resJson,
};
resJson.mockImplementation(() => res);
resStatus.mockImplementation(() => res);
resSend.mockImplementation(() => res);

describe('json routes', () => {
  beforeEach(() => {
    resStatus.mockClear();
    resJson.mockClear();
    resSend.mockClear();
  });

  describe('when there is an error reading file', () => {
    beforeEach(() => {
      readFilePromise.mockImplementation(() => Promise.reject('some error'));
    });

    it('should return given error', () => {
      readJsonFile(null, res);

      expect(readFilePromise).lastCalledWith('somefile.json', 'utf8'); // PASS
      expect(resStatus).lastCalledWith(500); // FAIL : never called
      expect(resSend).lastCalledWith({ "any": "value" }); // FAIL : never called
    });
  });
});

我们试图将readFilePromise.mockImplementation(() => Promise.reject('some error'));放在顶部,紧随jest.mock()之后。

第三方代码基本上类似于:

module.exports = async function fsReadFilePromise(...args) {
  return new Promise(....);
}

我们如何模拟和替换模块的实现,以根据测试设置返回Promise.resolve()Promise.reject(),以使测试用例在res.send()或{{1}中通过}方法?

1 个答案:

答案 0 :(得分:2)

最后2个断言不会通过,因为测试不会等待const file = await readFilePromise(filePath, 'utf8');中的诺言在这种情况下解决或拒绝,因此永远不会调用res.sendres.status

要解决此问题,readJsonFileasync,则应在测试中await

it('should return given error', async () => {
      await readJsonFile(null, res);
      ...
 })
  

我们如何模拟和替换模块的实现以返回   Promise.resolve()或Promise.reject()取决于我们的测试   设置以使我们的测试用例在res.send()或res.status()中通过   方法

确切的操作方式:

readFilePromise.mockImplementation(() => Promise.reject('some error'));

readFilePromise.mockImplementation(() => Promise.resolve('SomeFileContent!'));