首页 > 解决方案 > 用玩笑模拟 nodemailer.createTransport.sendMail

问题描述

我有一些使用nodemailer模块的代码。

在路由器(router.js)中,我有

const transporter = nodeMailer.createTransport(emailArgs);

然后在路线(/login)内我有:

...
return transporter.sendMail(mailOptions);

我正在尝试使用jest测试框架测试这条路线。我在模拟对 的调用时遇到了一些麻烦sendMail。我读了这篇关于如何使用 jest mocking 的不错的博文,但我收到了这个错误:

TypeError:无法读取未定义的属性“sendMail”

事实上,当我检查它的值时,transporter它是未定义的。

这是我的测试代码(不起作用):

import request from "supertest";
import router from "./router";

jest.mock("nodemailer");

describe("", () => {
...

    test("", async () => {
        // 1 - 200 status code; 2 - check email was sent
        expect.assertions(2);

        const response = await request(router)
            .post("/login")
            // global variable
            .send({ "email": email })
            .set("Accept", "application/json")
            .expect("Content-Type", /json/);

        // should complete successfully
        expect(response.status).toBe(200);
        // TODO not sure how to express the expect statement here
    });
});

所以我的问题是如何模拟模块返回的类实例的方法

标签: node.jsunit-testingmockingjestjsnodemailer

解决方案


我遇到了同样的问题并找到了解决方案。这是我发现的:

jest.mock("nodemailer");你告诉 jest用nodemailer自动模拟替换。这意味着 的每个属性nodemailer都被一个空的模拟函数替换(类似于jest.fn())。

这就是您收到错误的原因TypeError: Cannot read property 'sendMail' of undefined。为了有一些有用的东西,你必须定义nodemailer.createTransport.

在我们的例子中,我们不希望有一个带有 property 的对象sendMail。我们可以用nodemailer.createTransport.mockReturnValue({"sendMail": jest.fn()});. 由于您可能想测试是否sendMail被调用,因此最好事先创建该模拟函数。

这是您的测试代码的完整示例:

import request from "supertest";
import router from "./router";

const sendMailMock = jest.fn(); // this will return undefined if .sendMail() is called

// In order to return a specific value you can use this instead
// const sendMailMock = jest.fn().mockReturnValue(/* Whatever you would expect as return value */);

jest.mock("nodemailer");

const nodemailer = require("nodemailer"); //doesn't work with import. idk why
nodemailer.createTransport.mockReturnValue({"sendMail": sendMailMock});

beforeEach( () => {
    sendMailMock.mockClear();
    nodemailer.createTransport.mockClear();
});

describe("", () => {
...

    test("", async () => {
        // 1 - 200 status code; 2 - check email was sent
        expect.assertions(2);

        const response = await request(router)
            .post("/login")
            // global variable
            .send({ "email": email })
            .set("Accept", "application/json")
            .expect("Content-Type", /json/);

        // should complete successfully
        expect(response.status).toBe(200);

        // TODO not sure how to express the expect statement here
        expect(sendMailMock).toHaveBeenCalled();
    });
});

推荐阅读