使用Jest spyOn启动的模块

时间:2018-04-05 20:32:12

标签: javascript node.js unit-testing jestjs

在ExpresS API中,我使用邮戳库发送电子邮件,发送方式如下:

var postmark = require("postmark");
var client = new postmark.Client("aaaa-bbbbb-cccc");

然后用于发送密码重置邮件:

client.sendEmailWithTemplate(
    // Options here
);

现在,我想测试这个函数已被调用,但我很难找到如何模拟/监视这个。

我尝试过以下(简化):

const request = require("supertest");
const app = require("../server/app");

const postmark = require("postmark");
jest.mock("postmark");

describe("API Tests", () => {
    test("it should give a reset link when requesting with existing e-mail address", () => {
        return request(app)
        .post("/api/auth/passwordreset")
        .send({
            email: "user1@test.test"
        })
        .then(response => {
            expect(postmark.Client).toHaveBeenCalled();
        });
    });

});

这样做有效,但它只测试是否使用了邮戳,因为我无法弄清楚如何实际测试client.sendEmailWithTemplate方法

有关如何完成此任务的任何建议?

编辑:跟进@samanime回答我创建了一个回购来说明挑战'

https://github.com/Hyra/jest_test_example

1 个答案:

答案 0 :(得分:1)

您可以专门模拟被模拟的Client返回的postmark函数,以返回具有模拟函数的对象。

在Jest中,您可以通过创建与node_modules相同级别的__mocks__文件夹,为node_modules提供特定的模拟代码,即

/project-root
  /node_modules
  /__mocks__

注意,这是两侧的两个下划线。

在那里,创建一个名为<package_name>.js的函数(在您的情况下为postmark.js)。然后,当您使用mock时,它将加载由此导出的任何内容。

在该文件中,您可以根据需要进行模拟。这样的事可能会奏效:

// global jest
module.exports = {
  Client: jest.fn(() => ({
      sendEmailWithTemplate: jest.fn(() => {})
  }))
};

它不必像这样紧凑,但基本上它使postmark有一个名为Client的函数,它返回一个具有一个名为sendEmailWithTemplate的函数的对象,两者都是模拟/间谍。

然后你可以检查是否调用postmark.Client.sendEmailWithTemplate

一个问题是你需要确保在两次测试之间重置所有这些。您可以在beforeEach()中手动执行此操作,但如果您要重复使用它,我想添加一个名为__reset()的额外函数,它将重置代码并调用它:

// global jest
const mockedPostmark = {
  Client: jest.fn(() => ({
      sendEmailWithTemplate: jest.fn(() => {})
  }))
};

mockedPostmark.__reset = () => {
  mockedPostmark.Client.mockClear();
  mockedPostmark.Client.sendEmailWithTemplate.mockClear();
};

module.exports = mockedPostmark;

您也可以根据需要添加其他功能。