用 Jest 模拟 nodemailer
Mocking nodemailer with Jest
我设置了一个允许用户重置密码的端点。一切正常,测试通过,直到我添加了 nodemailer 并包含一行向用户发送电子邮件。
我正在使用 Jest 进行测试。
如果我注释掉发送电子邮件的行,则测试通过,mailer.sendPasswordResetEmail(body.email, token);
如果我保留该行 - 我的测试失败。我已经与 REST 客户端确认一切正常,这让我相信测试是问题所在。
ReferenceError:您正在尝试在 Jest 环境被拆除后导入文件。
test("if a valid user requests a password change, they should be assigned a hash", async () => {
const userBefore = await helper.getUser();
expect(userBefore.passwordResetHash).toBe("");
await api
.post("/api/reset-password")
.send({ email: userBefore.email })
.expect(200);
const userAfter = await helper.getUser();
expect(userAfter.passwordResetHash).not.toBeNull();
});
我认为我没有正确地模拟 nodemailer - 有没有人有将 nodemailer 和 jest 一起使用的经验?或者有更好的方法吗
有问题的文件是 controllers/resetPassword.js
、utils/mailer.js
和 tests/resetPassword.test.js
。
controllers/resetPassword.js
resetPasswordRouter.post("/", async (request, response) => {
// get email from request
const { body } = request;
// get the user with matching email
const user = await User.findOne({ email: body.email });
// if not found return error
if (!user) {
return response.status(400).json({ error: "User not found" });
}
// if user generate a token
const token = helper.generateToken();
// create a new user object with the resetPasswordHash defined
const update = {
passwordResetHash: await bcrypt.hash(token, 10),
};
// update user model with the password hash
const updatedUser = await User.findByIdAndUpdate(user.id, update, {
new: true,
});
mailer.sendPasswordResetEmail(body.email, token);
// setup timer to reset password hash in 30 minutes
setTimeout(async () => {
await User.findByIdAndUpdate(
user.id,
{ passwordResetHash: "" },
{ new: true }
);
}, 30000); // half hour
// return the updated user with the hash set
response.status(200).json(updatedUser);
});
utils/mailer.js
const nodemailer = require("nodemailer");
const config = require("../utils/config");
const mailer = nodemailer.createTransport({
host: "smtp.mailtrap.io",
port: 1111,
auth: {
user: "8b4f30425e75ea",
pass: "8b4f30425e75ea",
},
});
const sendPasswordResetEmail = (email, token) => {
const sitename = config.SITENAME;
const resetPasswordLink = `${sitename}/api/reset-password/verify?email=${email}&token=${token}`;
mailer.sendMail({
to: email,
from: config.FROM_EMAIL,
subject: `Password Reset | ${sitename}`,
html: `<h1>Password Reset</h1>
<p>Hello, you\'ve requested a password reset.</p>
<p><a href="${resetPasswordLink}">Click here to reset your password</a>, if you did not make this request please disregard the email.</p>`,
});
};
module.exports = {
sendPasswordResetEmail,
};
您可以在此处找到存储库:https://github.com/gerrgg/gregpress
您需要模拟函数 mailer.sendPasswordResetEmail
因此当控制器调用它时,它实际上会调用您的模拟实现。
test("if a valid user requests a password change, they should be assigned a hash", async () => {
const userBefore = await helper.getUser();
expect(userBefore.passwordResetHash).toBe("");
// Jest spy to intercept mailer.sendPasswordResetEmail call
let spy = jest.spyOn(mailer, 'sendPasswordResetEmail').mockImplementation(() => return true);
await api
.post("/api/reset-password")
.send({ email: userBefore.email })
.expect(200);
const userAfter = await helper.getUser();
expect(userAfter.passwordResetHash).not.toBeNull();
});
我设置了一个允许用户重置密码的端点。一切正常,测试通过,直到我添加了 nodemailer 并包含一行向用户发送电子邮件。
我正在使用 Jest 进行测试。
如果我注释掉发送电子邮件的行,则测试通过,mailer.sendPasswordResetEmail(body.email, token);
如果我保留该行 - 我的测试失败。我已经与 REST 客户端确认一切正常,这让我相信测试是问题所在。
ReferenceError:您正在尝试在 Jest 环境被拆除后导入文件。
test("if a valid user requests a password change, they should be assigned a hash", async () => {
const userBefore = await helper.getUser();
expect(userBefore.passwordResetHash).toBe("");
await api
.post("/api/reset-password")
.send({ email: userBefore.email })
.expect(200);
const userAfter = await helper.getUser();
expect(userAfter.passwordResetHash).not.toBeNull();
});
我认为我没有正确地模拟 nodemailer - 有没有人有将 nodemailer 和 jest 一起使用的经验?或者有更好的方法吗
有问题的文件是 controllers/resetPassword.js
、utils/mailer.js
和 tests/resetPassword.test.js
。
controllers/resetPassword.js
resetPasswordRouter.post("/", async (request, response) => {
// get email from request
const { body } = request;
// get the user with matching email
const user = await User.findOne({ email: body.email });
// if not found return error
if (!user) {
return response.status(400).json({ error: "User not found" });
}
// if user generate a token
const token = helper.generateToken();
// create a new user object with the resetPasswordHash defined
const update = {
passwordResetHash: await bcrypt.hash(token, 10),
};
// update user model with the password hash
const updatedUser = await User.findByIdAndUpdate(user.id, update, {
new: true,
});
mailer.sendPasswordResetEmail(body.email, token);
// setup timer to reset password hash in 30 minutes
setTimeout(async () => {
await User.findByIdAndUpdate(
user.id,
{ passwordResetHash: "" },
{ new: true }
);
}, 30000); // half hour
// return the updated user with the hash set
response.status(200).json(updatedUser);
});
utils/mailer.js
const nodemailer = require("nodemailer");
const config = require("../utils/config");
const mailer = nodemailer.createTransport({
host: "smtp.mailtrap.io",
port: 1111,
auth: {
user: "8b4f30425e75ea",
pass: "8b4f30425e75ea",
},
});
const sendPasswordResetEmail = (email, token) => {
const sitename = config.SITENAME;
const resetPasswordLink = `${sitename}/api/reset-password/verify?email=${email}&token=${token}`;
mailer.sendMail({
to: email,
from: config.FROM_EMAIL,
subject: `Password Reset | ${sitename}`,
html: `<h1>Password Reset</h1>
<p>Hello, you\'ve requested a password reset.</p>
<p><a href="${resetPasswordLink}">Click here to reset your password</a>, if you did not make this request please disregard the email.</p>`,
});
};
module.exports = {
sendPasswordResetEmail,
};
您可以在此处找到存储库:https://github.com/gerrgg/gregpress
您需要模拟函数 mailer.sendPasswordResetEmail
因此当控制器调用它时,它实际上会调用您的模拟实现。
test("if a valid user requests a password change, they should be assigned a hash", async () => {
const userBefore = await helper.getUser();
expect(userBefore.passwordResetHash).toBe("");
// Jest spy to intercept mailer.sendPasswordResetEmail call
let spy = jest.spyOn(mailer, 'sendPasswordResetEmail').mockImplementation(() => return true);
await api
.post("/api/reset-password")
.send({ email: userBefore.email })
.expect(200);
const userAfter = await helper.getUser();
expect(userAfter.passwordResetHash).not.toBeNull();
});