jest.setTimeout.Error: Mocking Express middleware with Jest and Supertest
jest.setTimeout.Error: Mocking Express middleware with Jest and Supertest
我想模拟 auth 中间件函数总是只调用 next()
。为了尝试实现这一点,在将身份验证中间件功能添加到 app.js
.
中的应用程序之前,我将以下内容添加到测试文件的开头
jest.mock('../../middleware/auth.js', () =>
// ensure func is mocked before being attached to the app instance
jest.fn((req, res, next) => next()) // seems to only work for first request that hits this middleware
); // Mock authentication
然后我在 auth 中间件中添加了一些调试,但没有为任何测试命中它们。
目前我正在使用下面的,当beforeEach()
函数没有被注释掉时测试全部通过:
role.test.js
jest.mock('../../middleware/auth.js', () =>
// ensure func is mocked before being attached to the app instance
jest.fn((req, res, next) => next()) // seems to only work for first request that hits this middleware
); // Mock authentication
const request = require('supertest');
const app = require('../../app.js');
const Role = require('../../../db/models/index.js').Role;
// const auth = require('../../middleware/auth.js');
/**
* Test role API routes
*/
describe('role-router', () => {
let res;
const token = 'valid-token';
const baseUrl = '/private/api/roles';
// Without the `beforeEach()` only the first request sent using supertest will use the mocked functionality
// With the `beforeEach()` everything functions as expected, but why?
// beforeEach(() => {
// auth.mockImplementation((req, res, next) => next());
// });
describe(`Create new role | post ${baseUrl}`, () => {
describe('When successful', () => {
beforeAll(async () => {
// this will use the proper mocked functionality
res = await request(app)
.post(baseUrl)
.set('Authorization', token)
.send({
roleName: 'Secret Agent',
roleDesc: "World's best secret agent",
...
});
});
// passes
it('Should return 201', () => {
expect(res.status).toBe(201);
});
}); // When successful
}); // Create new role
describe(`Delete role by id | delete ${baseUrl}/:id`, () => {
describe('When successful', () => {
beforeAll(async () => {
const role = await Role.create({
roleName: 'Secret Agent',
roleDesc: "World's best secret agent",
...
});
// fails does not get response, res remains the same as res from previous test
res = await request(app)
.delete(`${baseUrl}/${role.id}`)
.set('Authorization', token)
.send();
});
// fails with 201
it('Should return 204', () => {
expect(res.status).toBe(204);
});
}); // When successful
}); // Delete role
});
收到错误:
● role-router › Delete role by id | delete /private/api/roles/:id › When successful › Should return 204
Timeout - Async callback was not invoked within the 5000 ms timeout specified by jest.setTimeout.Error: Timeout - Async callback was not invoked within the 5000 ms timeout specified by jest.setTimeout.
at mapper (node_modules/jest-jasmine2/build/queueRunner.js:29:45)
app.js
// Dependencies
const express = require('express');
const auth = require('./middleware/auth.js');
...
/**
* Express application
*/
const app = express();
// Middleware
app.use(express.json());
...
// Private routes are secured with jwt authentication middleware
app.all('/private/*', (req, res, next) => auth(req, res, next));
// Public routes
...
// Private routes
app.use('/private/api/roles/', require('./components/role/role-router.js'));
...
module.exports = app;
知道为什么在每次测试前不使用 beforeEach()
函数模拟中间件功能就无法工作吗?也许我错过了更严重的事情?
出现这种行为的原因是存在 spy.mockReset()
、jest.resetAllMocks()
或启用的 resetMocks
配置选项。使用 restoreMocks
选项代替合理的默认配置。
jest.fn(() => ...)
和 jest.fn().mockImplementation(() => ...)
的区别在于他们对 jest.restoreAllMocks()
的反应。 restoreAllMocks
恢复原始实现,在 jest.fn()
的情况下是无操作,而 () => ...
在 jest.fn(...)
的情况下被认为是原始实现。所以通常 jest.fn(() => ...)
实现不会被重置。
jest.resetAllMocks
和 jest.restoreAllMocks
之间的区别在于前者可以使 jest.fn(...)
成为一个 noop 但不会将间谍恢复到原始实现。这特别影响在每个测试套件中使用 jest.mock
在模拟模块中提供一次的间谍,但仍然不会恢复全局间谍。由于很少需要这种行为,因此 jest.restoreAllMocks()
或 restoreMocks
配置选项通常更可取。如果需要重置 jest.fn(...)
实现,可以专门为此间谍完成 mockReset
或 mockImplementation
。
我想模拟 auth 中间件函数总是只调用 next()
。为了尝试实现这一点,在将身份验证中间件功能添加到 app.js
.
jest.mock('../../middleware/auth.js', () =>
// ensure func is mocked before being attached to the app instance
jest.fn((req, res, next) => next()) // seems to only work for first request that hits this middleware
); // Mock authentication
然后我在 auth 中间件中添加了一些调试,但没有为任何测试命中它们。
目前我正在使用下面的,当beforeEach()
函数没有被注释掉时测试全部通过:
role.test.js
jest.mock('../../middleware/auth.js', () =>
// ensure func is mocked before being attached to the app instance
jest.fn((req, res, next) => next()) // seems to only work for first request that hits this middleware
); // Mock authentication
const request = require('supertest');
const app = require('../../app.js');
const Role = require('../../../db/models/index.js').Role;
// const auth = require('../../middleware/auth.js');
/**
* Test role API routes
*/
describe('role-router', () => {
let res;
const token = 'valid-token';
const baseUrl = '/private/api/roles';
// Without the `beforeEach()` only the first request sent using supertest will use the mocked functionality
// With the `beforeEach()` everything functions as expected, but why?
// beforeEach(() => {
// auth.mockImplementation((req, res, next) => next());
// });
describe(`Create new role | post ${baseUrl}`, () => {
describe('When successful', () => {
beforeAll(async () => {
// this will use the proper mocked functionality
res = await request(app)
.post(baseUrl)
.set('Authorization', token)
.send({
roleName: 'Secret Agent',
roleDesc: "World's best secret agent",
...
});
});
// passes
it('Should return 201', () => {
expect(res.status).toBe(201);
});
}); // When successful
}); // Create new role
describe(`Delete role by id | delete ${baseUrl}/:id`, () => {
describe('When successful', () => {
beforeAll(async () => {
const role = await Role.create({
roleName: 'Secret Agent',
roleDesc: "World's best secret agent",
...
});
// fails does not get response, res remains the same as res from previous test
res = await request(app)
.delete(`${baseUrl}/${role.id}`)
.set('Authorization', token)
.send();
});
// fails with 201
it('Should return 204', () => {
expect(res.status).toBe(204);
});
}); // When successful
}); // Delete role
});
收到错误:
● role-router › Delete role by id | delete /private/api/roles/:id › When successful › Should return 204
Timeout - Async callback was not invoked within the 5000 ms timeout specified by jest.setTimeout.Error: Timeout - Async callback was not invoked within the 5000 ms timeout specified by jest.setTimeout.
at mapper (node_modules/jest-jasmine2/build/queueRunner.js:29:45)
app.js
// Dependencies
const express = require('express');
const auth = require('./middleware/auth.js');
...
/**
* Express application
*/
const app = express();
// Middleware
app.use(express.json());
...
// Private routes are secured with jwt authentication middleware
app.all('/private/*', (req, res, next) => auth(req, res, next));
// Public routes
...
// Private routes
app.use('/private/api/roles/', require('./components/role/role-router.js'));
...
module.exports = app;
知道为什么在每次测试前不使用 beforeEach()
函数模拟中间件功能就无法工作吗?也许我错过了更严重的事情?
出现这种行为的原因是存在 spy.mockReset()
、jest.resetAllMocks()
或启用的 resetMocks
配置选项。使用 restoreMocks
选项代替合理的默认配置。
jest.fn(() => ...)
和 jest.fn().mockImplementation(() => ...)
的区别在于他们对 jest.restoreAllMocks()
的反应。 restoreAllMocks
恢复原始实现,在 jest.fn()
的情况下是无操作,而 () => ...
在 jest.fn(...)
的情况下被认为是原始实现。所以通常 jest.fn(() => ...)
实现不会被重置。
jest.resetAllMocks
和 jest.restoreAllMocks
之间的区别在于前者可以使 jest.fn(...)
成为一个 noop 但不会将间谍恢复到原始实现。这特别影响在每个测试套件中使用 jest.mock
在模拟模块中提供一次的间谍,但仍然不会恢复全局间谍。由于很少需要这种行为,因此 jest.restoreAllMocks()
或 restoreMocks
配置选项通常更可取。如果需要重置 jest.fn(...)
实现,可以专门为此间谍完成 mockReset
或 mockImplementation
。