简体   繁体   English

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

[英]Mock imported function with jest in an await context

We are creating a node app, based on express, to read from a static local file and return the JSON within the file. 我们正在基于express创建一个节点应用程序,以从静态本地文件中读取并返回文件中的JSON。

Here is our json-file.js with our route method: 这是我们的json-file.js和我们的route方法:

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);
      }
  },
};

we use a third party module, fs-readfile-promise which basically turns node readFileSync into a promise. 我们使用第三方模块fs-readfile-promise ,该模块基本上将节点readFileSync变成了承诺。

But we struggle to mock implementation of this third party, to be able to produce two tests: one based on simulated read file (promise resolved) and one based on rejection. 但是我们很难模拟这个第三方的实现,以便能够产生两个测试:一个基于模拟读取文件(已解决承诺),另一个基于拒绝。

Here is our test file: 这是我们的测试文件:

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
    });
  });
});

We tried to place readFilePromise.mockImplementation(() => Promise.reject('some error')); 我们试图放置readFilePromise.mockImplementation(() => Promise.reject('some error')); at the top, just after the jest.mock() without more success. 在顶部, jest.mock()之后,没有更多的成功。

The third party code is basically something like: 第三方代码基本上是这样的:

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

How can we mock and replace implementation of the module to return either a Promise.resolve() or Promise.reject() depending on our test setup to make our test case pass within res.send() or res.status() method? 我们如何模拟和替换模块的实现,以根据我们的测试设置返回Promise.resolve()Promise.reject() ,以使测试用例在res.send()res.status()方法中通过?

The last 2 assertions never pass because the test doesn't wait for the promise in: const file = await readFilePromise(filePath, 'utf8'); 最后两个断言永远不会通过,因为测试不会等待以下承诺: const file = await readFilePromise(filePath, 'utf8'); to resolve or reject in this case, therefore res.send or res.status never get called. 在这种情况下解决或拒绝,因此从不调用res.sendres.status

To fix it, readJsonFile is async , you should await it in the test: 要修复它, readJsonFileasync ,您应该在测试中await它:

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

How can we mock and replace implementation of the module to return either a Promise.resolve() or Promise.reject() depending on our test setup to make our test case pass within res.send() or res.status() method 我们如何模拟和替换模块的实现以根据我们的测试设置返回Promise.resolve()或Promise.reject(),以使测试用例在res.send()或res.status()方法中通过

Exactly how you're doing it: 确切的做法是:

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

or 要么

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM