Как правильно замокать метод updateOne mongoose в Nest.js используя Jest

Я хочу замокать метод updateOne в приложении Nest.js используя библиотеку для тестов Jest.

У меня есть метод сервиса

public async update(
        newDto: UpdateUserFieldsDTO,
        userName: string,
    ): Promise<UserDocument> {
        const updatedUser = await this.findUserByUserName(userName);

        await this.userModel.updateOne({ userName }, { $set: { ...newDto } });
        return updatedUser;
    }

В нем я обращаюсь к другому методу класса чтоб найти юзера, вот его код

public async findUserByUserName(
        userName: string,
    ): Promise<UserDocument | null> {
        return await this.userModel.findOne({ userName, deletedAt: null });
    }

Я написал тесты для методов и вот что у меня вышло

import { Test, TestingModule } from "@nestjs/testing";
import { UserService } from "./user.service";

import { User, UserRole } from "./models/user.model";
import { getModelToken } from "@nestjs/mongoose";
import { JwtService } from "@nestjs/jwt";
import { AuthService } from "../auth/auth.service";
import { ConfigService } from "@nestjs/config";
import { CreateUserDTO } from "./dto/createUser.dto";
import { UpdateUserFieldsDTO } from "./dto/updateUser.dto";

const mockUser: CreateUserDTO = {
    email: "[email protected]",
    firstName: "str",
    lastName: "str",
    password: "str",
    userName: "userName",
};

const mockUserObject = {
    _id: "12345",
    email: mockUser.email,
    firstName: mockUser.firstName,
    lastName: mockUser.lastName,
    password: mockUser.password,
    userName: mockUser.userName,
    role: UserRole.USER,
    salt: "salt",
    rating: 0,
    lastVoteAt: null,
    createdAt: new Date(),
    updatedAt: new Date(),
    deletedAt: null,
};

class MockedMongoModel {
    constructor(private user: CreateUserDTO) {}

    static readonly findOne = jest.fn(
        async (query: { userName?: string; _id?: string; email?: string }) => {
            if (query._id) {
                return query._id === mockUserObject._id ? mockUserObject : null;
            } else if (query.email)
                return query.email === mockUserObject.email
                    ? mockUserObject
                    : null;
            return query.userName === mockUser.userName ? mockUserObject : null;
        },
    );
    static readonly updateOne = jest.fn(
        async (userName: string, newUserData: UpdateUserFieldsDTO) => {
            const user = await this.findOne({ userName });
            if (newUserData.userName) {
                user.userName = newUserData.userName;
                return user;
            }
        },
    );
}

const MockedAuthModel = {
    generateRandomStr: jest.fn().mockReturnValue("randomStr"),
    hashPassword: jest.fn().mockReturnValue("str"),
};

describe("UserService", () => {
    let service: UserService;

    beforeEach(async () => {
        const module: TestingModule = await Test.createTestingModule({
            providers: [
                UserService,
                {
                    provide: getModelToken(User.name),
                    useValue: MockedMongoModel,
                },
                {
                    provide: AuthService,
                    useValue: MockedAuthModel,
                },
                JwtService,
                ConfigService,
            ],
        }).compile();

        service = module.get<UserService>(UserService);

        jest.clearAllMocks();
    });

    afterEach(() => {
        jest.clearAllMocks();
    });

    it("should be defined", () => {
        expect(service).toBeDefined();
    });

    it.only("should update user's userName", async () => {
        const updatedUser = {
            ...mockUserObject,
            userName: "user",
        };
        const expectedOutput = await service.update(
            { userName: "user" },
            mockUser.userName,
        );

        expect(MockedMongoModel.updateOne).toHaveBeenCalledTimes(1);
        expect(expectedOutput).toEqual(updatedUser);
    });
});

И тут я в замоканном методе обращаюсь к методу класса await this.findOne({ userName }) чтоб получить пользователя. После запуска тестов я вижу картинку такую ошибка запуска теста

В ошибке я вижу что я ожидаю измененного пользователя с "userName": "user" но получаю "userName": "userName", что говорит о том что код

if (newUserData.userName) {
                user.userName = newUserData.userName;
                return user;
            }

не выполняется.

Кто может подсказать что я сделал не так? И как исправить мой код чтоб я получил все таки измененного пользователя и прошел данный тест?


Ответы (0 шт):