jest + supertest:如何重置模拟依赖

jest + supertest: how to reset the mocked dependency

supertest 使用一次依赖项后,我无法重置依赖项的笑话模拟。感谢任何帮助或提示。

以下是我的api超测测试:

import request from 'supertest';
import router from '../index';
const app = require('express')();
app.use(router);

jest.mock('config', () => ({}));

jest.mock('express-request-proxy', () => data => (req, res, next) =>
  res.json(data),
);

beforeEach(() => {
  jest.resetAllMocks();
});

describe('GET /', () => {
  it('should get all stuff', () =>
    request(app)
      .get('')
      .expect(200)
      .expect('Content-Type', /json/)
      .then(response => {
        expect(response.body).toMatchSnapshot();             // all good here 
      }));

  it('should get all stuff when FOO=bar', async () => {
    jest.mock('config', () => ({
      FOO: 'bar',
      get: key => key,
    }));

    // >> HERE <<
    // config.FOO is still undefined!
    // reseting mocks did not work ...
    await request(app)
      .get('')
      .expect(200)
      .expect('Content-Type', /json/)
      .then(response => {
        expect(response.body.query).toHaveProperty('baz');   // test fails ...
      });
  });
});

express.js api:

const router = require('express').Router({ mergeParams: true });
import config from 'config';
import proxy from 'express-request-proxy';

router.get('', (...args) => {
  let query = {};
  if (config.FOO === 'bar') {
    query.baz = true;
  }
  return proxy({
    url: '/stuff',
    query,
  })(...args);
});

如果你想在测试用例的函数范围内安排模拟,你不能使用jest.mock(moduleName, factory, options) in a function scope, it should be used in the module scope. You should use jest.doMock(moduleName, factory, options)

我们还需要在执行每个测试用例之前使用jest.resetModules()

reset the module registry - the cache of all required modules.

这意味着您的 ./config 模块注册表将被重置,因此当您在 jest.doMock('./config', () => {...}) 语句之后需要它时,它会为每个测试用例 return 不同的模拟值。

{ virtual: true } 选项意味着我没有安装 express-request-proxy 包,因此它不存在于我的 npm_modules 目录中。如果你已经安装了它,你可以去掉这个选项。

这是单元测试解决方案:

index.js:

const router = require('express').Router({ mergeParams: true });

import config from './config';
import proxy from 'express-request-proxy';

router.get('', (...args) => {
  console.log(config);
  let query = {};
  if (config.FOO === 'bar') {
    query.baz = true;
  }
  return proxy({ url: '/stuff', query })(...args);
});

export default router;

config.js:

export default {
  FOO: '',
};

index.test.js:

import request from 'supertest';

jest.mock('express-request-proxy', () => (data) => (req, res, next) => res.json(data), { virtual: true });

beforeEach(() => {
  jest.resetAllMocks();
  jest.resetModules();
});

describe('GET /', () => {
  it('should get all stuff', () => {
    jest.doMock('./config', () => ({}));
    const router = require('./index').default;
    const app = require('express')();
    app.use(router);

    return request(app)
      .get('')
      .expect(200)
      .expect('Content-Type', /json/)
      .then((response) => {
        expect(response.body).toMatchSnapshot();
      });
  });

  it('should get all stuff when FOO=bar', async () => {
    jest.doMock('./config', () => ({
      default: {
        FOO: 'bar',
        get: (key) => key,
      },
      __esModule: true,
    }));
    const router = require('./index').default;
    const app = require('express')();
    app.use(router);

    await request(app)
      .get('')
      .expect(200)
      .expect('Content-Type', /json/)
      .then((response) => {
        expect(response.body.query).toHaveProperty('baz');
      });
  });
});

100% 覆盖率报告的单元测试结果:

 PASS  Whosebug/61828748/index.test.js (11.966s)
  GET /
    ✓ should get all stuff (8710ms)
    ✓ should get all stuff when FOO=bar (24ms)

  console.log
    {}

      at Whosebug/61828748/index.js:7:11

  console.log
    { FOO: 'bar', get: [Function: get] }

      at Whosebug/61828748/index.js:7:11

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |     100 |      100 |     100 |     100 |                   
 index.js |     100 |      100 |     100 |     100 |                   
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   1 passed, 1 total
Time:        13.268s

index.test.js.snap:

// Jest Snapshot v1

exports[`GET / should get all stuff 1`] = `
Object {
  "query": Object {},
  "url": "/stuff",
}
`;

源代码:https://github.com/mrdulin/react-apollo-graphql-starter-kit/tree/master/Whosebug/61828748