I am not able to reset jest mocks of a dependency after it's being used once by supertest. I appreciate any help or hint.
The following is my api test with supertest:
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);
});
You can't use 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) if you want to arrange the mocks in function scope of test cases.
We also need to use jest.resetModules() before executing each test case to
reset the module registry - the cache of all required modules.
It means your ./config
module registry will be reset so that it will return different mocked values for each test case when you require it after jest.doMock('./config', () => {...})
statement.
{ virtual: true }
option means I don't install the express-request-proxy
package so it doesn't exist in my npm_modules
directory. If you had already installed it, you can remove this option.
Here is the unit test solution:
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');
});
});
});
unit test results with 100% coverage report:
PASS stackoverflow/61828748/index.test.js (11.966s)
GET /
✓ should get all stuff (8710ms)
✓ should get all stuff when FOO=bar (24ms)
console.log
{}
at stackoverflow/61828748/index.js:7:11
console.log
{ FOO: 'bar', get: [Function: get] }
at stackoverflow/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",
}
`;
source code: https://github.com/mrdulin/react-apollo-graphql-starter-kit/tree/master/stackoverflow/61828748