英文:
How to mock a MongoDB query .exec() in Jest?
问题
以下是您要翻译的部分:
// src/helpers/user.ts
import { UserModel } from "../models";
export const getUserByUsername = async (username: string) => {
return UserModel.findOne({ username }).exec()
}
// src/models/index.ts
import { getModelForClass } from "@typegoose/typegoose";
export const UserModel = getModelForClass(User, { schemaOptions: { timestamps: true } });
以下是测试代码的部分:
// src/helpers/user.test.ts
describe("getUserByUsername():", () => {
test('should return a user if username matches', async () => {
const mockUser: User = await userFactory.build("user");
const spy = jest.spyOn(UserModel, "findOne");
spy.mockImplementationOnce(() => Promise.resolve(mockUser))
const userByUsernameResult = usersHelper.getUserByUsername(mockUser.username);
await expect(userByUsernameResult).resolves.toEqual(expect.objectContaining({ username: mockUser.username }));
});
});
在上面的代码中,我已经翻译了您提供的JavaScript代码。如果您需要进一步的帮助,请随时告诉我。
英文:
I would like to mock this async function with Jest in a Typescript Express env.
// src/helpers/user.ts
import { UserModel } from "../models";
export const getUserByUsername = async (username: string) => {
return UserModel.findOne({ username }).exec()
}
// src/models/index.ts
import { getModelForClass } from "@typegoose/typegoose";
export const UserModel = getModelForClass(User, { schemaOptions: { timestamps: true } });
Here is my the test that fails:
// src/helpers/user.test.ts
describe("getUserByUsername():", () => {
test('should return a user if username matches', async () => {
const mockUser: User = await userFactory.build("user");
const spy = jest.spyOn(UserModel, "findOne");
spy.mockImplementationOnce(() => Promise.resolve(mockUser))
const userByUsernameResult = usersHelper.getUserByUsername(mockUser.username);
await expect(userByUsernameResult).resolves.toEqual(expect.objectContaining({ username: mockUser.username }));
});
});
The error message I get:
> expect(received).resolves.toEqual() Received promise rejected instead
> of resolved Rejected to value: [TypeError:
> models_1.UserModel.findOne(...).exec is not a function]
Could you please help me?
UPDATE: I use in some other tests the MongoDB Memory Server
approach that works in this case too (see below). However, I would really like to know how to do it by mocking the .exec()
(see above).
// src/helpers/user.test.ts
beforeAll(async () => {
await mongoose.connect(process.env.MONGO_URL as string, { useNewUrlParser: true, useUnifiedTopology: true } as ConnectOptions, (err) => {
if(err) {
console.error(err);
process.exit(1);
}
})
});
afterAll(async () => {
await mongoose.connection.close();
});
describe("getUserByUsername():", () => {
test('should return a user if username matches', async () => {
const mockUser: User = await userFactory.build("user", {}, { setId: false });
const validUser = new UserModel(mockUser);
await validUser.save();
const userByUsernameResult = usersHelper.getUserByUsername(mockUser.username);
await expect(userByUsernameResult).resolves.toEqual(expect.objectContaining({ username: mockUser.username }));
});
答案1
得分: 1
你的情况似乎与这个问题非常相似。
与那里给出的答案相似,你可以这样做:
UserModel.findOne = jest.fn().mockImplementationOnce(() => ({ exec: jest.fn().mockResolvedValueOnce(() => {/* 这里是你的值。*/})}));
为了详细说明并为答案添加一些价值:exec()
是在调用 UserModel.findOne()
上链接的方法。因此,你必须进行两个级别的模拟:一个是为 UserModel.findOne()
定义一个模拟实现,另一个是将 exec()
模拟为与 UserModel.findOne
链式调用,指定其返回的值。
如果你想在链式调用中继续模拟,你也必须为 exec()
定义一个模拟实现,使用 mockImplementationOnce
提供一个带有所需方法的对象等等。
英文:
Your case seems quite similar with this question.
In similarity to the answer given there, you can do:
UserModel.findOne = jest.fn().mockImplementationOnce(() => ({ exec: jest.fn().mockResolvedValueOnce(() => {/* Your value here.*/})}));
To elaborate and add some value to the answer: exec()
is a method chained with the call on UserModel.findOne()
. Therefore, you have to mock on two levels: one that defines a mock implementation for UserModel.findOne()
, and one that mocks the exec()
as a chain call with UserModel.findOne
, specifying the value returned by it.
If you want continue mocking in the chain, you have to define a mock implementation for exec()
as well using mockImplementationOnce
, providing an object with the methods desired for the chain, etc.
答案2
得分: 0
我认为这个方法应该有效。
const findOneMock = jest.spyOn(UserModel, 'findOne');
findOneMock.mockResolvedValueOnce({ exec: jest.fn().mockResolvedValue(mockUser) } as any)
在类型错误的情况下,显式类型断言在模拟对象方法中的方法。
findOneMock.mockResolvedValueOnce({
exec: jest.fn().mockResolvedValue(mockUser) as unknown as () => Promise<User>,
} as any);
英文:
I think this approach should work.
const findOneMock = jest.spyOn(UserModel, 'findOne');
findOneMock.mockResolvedValueOnce({ exec: jest.fn().mockResolvedValue(mockUser) } as any)
in case of type error explicit type assertions on mock object approach.
findOneMock.mockResolvedValueOnce({
exec: jest.fn().mockResolvedValue(mockUser) as unknown as () => Promise<User>,
} as any);
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论