[英]Mocking node_modules which return a function with Jest?
I am writing a typeScript program which hits an external API.我正在编写一个打到外部 API 的 typeScript 程序。 In the process of writing tests for this program, I have been unable to correctly mock-out the dependency on the external API in a way that allows me to inspect the values passed to the API itself.在为这个程序编写测试的过程中,我一直无法正确模拟对外部 API 的依赖,以允许我检查传递给 API 本身的值。
A simplified version of my code that hits the API is as follows:命中 API 的我的代码的简化版本如下:
const api = require("api-name")();
export class DataManager {
setup_api = async () => {
const email = "email@website.ext";
const password = "password";
try {
return api.login(email, password);
} catch (err) {
throw new Error("Failure to log in: " + err);
}
};
My test logic is as follows:我的测试逻辑如下:
jest.mock("api-name", () => () => {
return {
login: jest.fn().mockImplementation(() => {
return "200 - OK. Log in successful.";
}),
};
});
import { DataManager } from "../../core/dataManager";
const api = require("api-name")();
describe("DataManager.setup_api", () => {
it("should login to API with correct parameters", async () => {
//Arrange
let manager: DataManager = new DataManager();
//Act
const result = await manager.setup_api();
//Assert
expect(result).toEqual("200 - OK. Log in successful.");
expect(api.login).toHaveBeenCalledTimes(1);
});
});
What I find perplexing is that the test assertion which fails is only expect(api.login).toHaveBeenCalledTimes(1)
.我发现令人困惑的是,失败的测试断言只是expect(api.login).toHaveBeenCalledTimes(1)
。 Which means the API is being mocked, but I don't have access to the original mock.这意味着 API 正在被模拟,但我无权访问原始模拟。 I think this is because the opening line of my test logic is replacing login
with a NEW jest.fn()
when called.我认为这是因为我的测试逻辑的开头行在调用时用 NEW jest.fn()
替换了login
。 Whether or not that's true, I don't know how to prevent it or to get access to the mock function-which I want to do because I am more concerned with the function being called with the correct values than it returning something specific.无论这是否属实,我不知道如何阻止它或访问模拟函数——我想这样做是因为我更关心使用正确值调用的函数,而不是它返回特定的东西。
I think my difficulty in mocking this library has to do with the way it's imported: const api = require("api-name")();
我认为我嘲笑这个库的困难与它的导入方式有关: const api = require("api-name")();
where I have to include an opening and closing parenthesis after the require statement.我必须在 require 语句之后包含一个左括号和右括号。 But I don't entirely know what that means, or what the implications of it are re:testing.但我不完全知道这意味着什么,或者它的含义是什么:重新测试。
I came across an answer in this issue thread for ts-jest.我在这个问题线程中找到了 ts-jest 的答案。 Apparently, ts-jest does NOT "hoist" variables which follow the naming pattern mock*
, as regular jest does.显然, ts-jest 不会像常规 jest 那样“提升”遵循命名模式mock*
变量。 As a result, when you try to instantiate a named mock variable before using the factory
parameter for jest.mock()
, you get an error that you cannot access the mock variable before initialization.因此,当您在使用jest.mock()
的factory
参数之前尝试实例化一个命名的模拟变量时,您会收到一个错误,提示您在初始化之前无法访问模拟变量。
Per the previously mentioned thread, the jest.doMock()
method works in the same way as jest.mock()
, save for the fact that it is not "hoisted" to the top of the file.根据前面提到的线程, jest.doMock()
方法的工作方式与jest.mock()
相同,除了它没有“提升”到文件顶部的事实。 Thus, you can create variables prior to mocking out the library.因此,您可以在模拟库之前创建变量。
Thus, a working solution is as follows:因此,一个有效的解决方案如下:
const mockLogin = jest.fn().mockImplementation(() => {
return "Mock Login Method Called";
});
jest.doMock("api-name", () => () => {
return {
login: mockLogin,
};
});
import { DataManager } from "../../core/dataManager";
describe("DataManager.setup_api", () => {
it("should login to API with correct parameters", async () => {
//Arrange
let manager: DataManager = new DataManager();
//Act
const result = await manager.setup_api();
//Assert
expect(result).toEqual("Mock Login Method Called");
expect(mockLogin).toHaveBeenCalledWith("email@website.ext", "password");
});
});
Again, this is really only relevant when using ts-jest
, as using babel
to transform your jest typescript tests WILL support the correct hoisting behavior.同样,这仅在使用ts-jest
时才相关,因为使用babel
转换您的 jest 打字稿测试将支持正确的提升行为。 This is subject to change in the future, with updates to ts-jest
, but the jest.doMock()
workaround seems good enough for the time being.这在未来可能会发生变化,更新ts-jest
,但jest.doMock()
解决方法jest.doMock()
似乎已经足够了。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.