javascript - 开玩笑测试nodejs控制器
问题描述
我有以下控制器
import bcrypt from 'bcrypt';
import jwt from 'jsonwebtoken';
import { UserModel, isPasswordAllowed } from '../../models/User';
const saltRounds = 10;
function userController() {
function add(req, res) {
try {
if (req.body.administrator) {
res.status(400).json({
error: {
message: 'Bad Request',
},
});
return;
}
if (!isPasswordAllowed(req.body.password)) {
res.status(400).json({
error: {
message: 'La contraseña no cumple con los requisitos minimos',
},
});
return;
}
bcrypt.hash(req.body.password, saltRounds, async (err, hash) => {
if (err) {
res.status(500).json({ error: { code: '500', message: err.errmsg } });
return;
}
const user = new UserModel();
user.email = req.body.email.toLowerCase();
user.password = hash;
await user
.save()
.then(() => {
const token = jwt.sign(
{
username: user.email,
userId: user.id,
},
process.env.JWT_KEY,
{
expiresIn: '7d',
},
);
res.status(200).json({
message: 'Usuario Creado',
token,
email: user.email,
});
})
.catch((error) => {
if (error.code === 11000) {
res.status(400).json({
error: { code: '500', message: 'El correo ya existe' },
});
} else {
console.log(error);
res.status(500).json({ error: { code: '500', message: error.message } });
}
});
});
} catch (error) {
res.status(503).json({ error });
}
}
return {
add,
};
}
export default userController();
正如您所料,这个控制器工作得很好,用户是在数据库中创建的,但我有以下测试:
import UserController from './UserController';
import { connect, closeDatabase, clearDatabase } from '../../__test__/db-handler';
describe('test UserController', () => {
const res = {};
beforeEach(async () => {
await connect();
res.send = jest.fn().mockReturnValue(res);
res.status = jest.fn().mockReturnValue(res);
res.json = jest.fn().mockReturnValue(res);
});
afterEach(async () => {
await clearDatabase();
});
afterAll(async () => {
await closeDatabase();
});
test('should return the expect api method', () => {
const userControllerApi = {
add: expect.any(Function),
};
expect(UserController).toMatchObject(userControllerApi);
});
test('should return 400 error bad request is body contains administrator: true', async () => {
const req = {
body: {
administrator: true,
},
};
await UserController.add(req, res);
expect(res.status).toHaveBeenCalledWith(400);
expect(res.json).toHaveBeenCalledTimes(1);
expect(res.json).toHaveBeenCalledWith({
error: {
message: 'Bad Request',
},
});
});
test('should return 400 error bad request is password is not allow', async () => {
const req = {
body: {
password: '123456',
},
};
await UserController.add(req, res);
expect(res.status).toHaveBeenCalledWith(400);
expect(res.json).toHaveBeenCalledTimes(1);
expect(res.json).toHaveBeenCalledWith({
error: {
message: 'La contraseña no cumple con los requisitos minimos',
},
});
});
// this test is not passing
test('should create an user and return a token', async () => {
const req = {
body: {
email: 'test@test.com',
password: 'Abc123456',
},
};
const expectObject = {
message: 'Usuario Creado',
email: 'test@test.com',
};
await UserController.add(req, res);
jest.useFakeTimers();
expect(res.status).toHaveBeenCalledWith(200);
expect(res.json).toHaveBeenCalledTimes(1);
expect(res.json).toMatchObject(expectObject);
});
});
但最后一个测试“应该创建一个用户并返回一个令牌”从未通过,我得到以下信息:
● test UserController › should create an user and return a token
expect(jest.fn()).toHaveBeenCalledWith(...expected)
Expected: 200
Number of calls: 0
78 | jest.useFakeTimers();
79 |
> 80 | expect(res.status).toHaveBeenCalledWith(200);
| ^
81 | expect(res.json).toHaveBeenCalledTimes(1);
82 | expect(res.json).toMatchObject(expectObject);
83 | });
我还在测试模式下调试了这段代码,如下图所示,代码输入在 中res.status(200).json({ .... })
,所以我不明白这里发生了什么。
解决方案
问题是您将回调与 async/await 混合在一起,这意味着执行add()
将在回调完成之前bcrypt.hash
完成。这导致res.status
在您的测试中尚未调用。
你可以通过等待bcrypt.hash
调用来解决这个问题(它默认支持返回一个承诺):
// await hashing function instead of using callback
const hash = await bcrypt.hash(req.body.password, saltRounds);
const user = new UserModel();
user.email = req.body.email.toLowerCase();
user.password = hash;
// rest of the code ...
推荐阅读
- java - SQLite Java:连接到加密数据库
- xml - xslt - 向所有匹配的 xml 子元素添加属性(不移动它们)
- node.js - Facebook 图形 API 批处理请求
- c++ - 在 MacOS 上写入串行端口时出现问题
- reflection - Kotlin 和使用 kotlin-reflect 对属性进行反射
- batch-file - 检查文件名是否包含子字符串
- javascript - 格式化文本使条件介于 2 个单词之间
- algorithm - 找到具有特定总和的数字对
- c++ - 位设置为浮点值或双精度值 C++
- javascript - 用于浏览网站的 JavaScript 脚本?