Files
matrix-backend/tests/services/db/UserService.test.ts
T
StarAppeal 7b38ec1660 fix
2025-09-26 00:01:19 +02:00

223 lines
8.7 KiB
TypeScript

import { describe, it, expect, vi, beforeEach } from "vitest";
import { UserModel } from "../../../src/db/models/user";
import { UserService } from "../../../src/services/db/UserService";
import { connectToDatabase } from "../../../src/services/db/database.service";
vi.mock("../../../src/services/db/database.service", () => ({
connectToDatabase: vi.fn(),
}));
vi.mock("../../../src/db/models/user");
const mockedUserModel = vi.mocked(UserModel);
const mockedConnectToDatabase = vi.mocked(connectToDatabase);
const createMockMongooseQuery = (resolveValue: any) => {
const exec = vi.fn().mockResolvedValue(resolveValue);
const select = vi.fn().mockReturnValue({ exec });
const collation = vi.fn().mockReturnValue({ select, exec });
return { exec, select, collation };
};
describe("UserService", () => {
let userService: UserService;
beforeEach(async () => {
vi.clearAllMocks();
mockedConnectToDatabase.mockResolvedValue(undefined);
(UserService as any)._instance = undefined;
userService = await UserService.create();
});
describe("create (singleton)", () => {
it("should create a singleton instance", async () => {
const instance1 = userService;
const instance2 = await UserService.create();
expect(instance1).toBe(instance2);
});
});
describe("updateUserById", () => {
it("should update user by id and return updated user without password", async () => {
const userId = "507f1f77bcf86cd799439011";
const updateData = { name: "Updated Name" };
const updatedUser = { _id: userId, name: "Updated Name", email: "test@example.com" };
mockedUserModel.findByIdAndUpdate.mockReturnValue(createMockMongooseQuery(updatedUser) as any);
const result = await userService.updateUserById(userId, updateData);
expect(mockedUserModel.findByIdAndUpdate).toHaveBeenCalledWith(userId, updateData, { new: true });
expect(result).toEqual(updatedUser);
});
it("should return null if user not found", async () => {
mockedUserModel.findByIdAndUpdate.mockReturnValue(createMockMongooseQuery(null) as any);
const result = await userService.updateUserById("some-id", { name: "Updated Name" });
expect(result).toBeNull();
});
});
describe("getAllUsers", () => {
it("should return all users without sensitive fields", async () => {
const users = [{ name: "User1" }, { name: "User2" }];
mockedUserModel.find.mockReturnValue(createMockMongooseQuery(users) as any);
const result = await userService.getAllUsers();
expect(mockedUserModel.find).toHaveBeenCalledWith({}, { spotifyConfig: 0, lastState: 0 });
expect(result).toEqual(users);
});
});
describe("getUserById", () => {
it("should return user by id", async () => {
const user = { _id: "user1", name: "Test User" };
mockedUserModel.findById.mockReturnValue(createMockMongooseQuery(user) as any);
const result = await userService.getUserById("user1");
expect(mockedUserModel.findById).toHaveBeenCalledWith("user1");
expect(result).toEqual(user);
});
it("should return null if user not found", async () => {
mockedUserModel.findById.mockReturnValue(createMockMongooseQuery(null) as any);
const result = await userService.getUserById("non-existent-id");
expect(result).toBeNull();
});
});
describe("getUserByUUID", () => {
it("should return user by UUID", async () => {
const user = { uuid: "uuid-123", name: "Test User" };
mockedUserModel.findOne.mockReturnValue(createMockMongooseQuery(user) as any);
const result = await userService.getUserByUUID("uuid-123");
expect(mockedUserModel.findOne).toHaveBeenCalledWith({ uuid: "uuid-123" });
expect(result).toEqual(user);
});
});
describe("getUserByName", () => {
it("should return user by name with case-insensitive search", async () => {
const user = { name: "TestUser" };
const mockQuery = createMockMongooseQuery(user);
mockedUserModel.findOne.mockReturnValue(mockQuery as any);
const result = await userService.getUserByName("TestUser");
expect(mockedUserModel.findOne).toHaveBeenCalledWith({ name: "TestUser" });
expect(mockQuery.collation).toHaveBeenCalledWith({ locale: "en", strength: 2 });
expect(result).toEqual(user);
});
});
describe("getUserAuthByName", () => {
it("should return user with password for authentication", async () => {
const user = { name: "TestUser", password: "hashedPassword" };
const mockQuery = createMockMongooseQuery(user);
mockedUserModel.findOne.mockReturnValue(mockQuery as any);
const result = await userService.getUserAuthByName("TestUser");
expect(mockedUserModel.findOne).toHaveBeenCalledWith({ name: "TestUser" });
expect(mockQuery.collation).toHaveBeenCalledWith({ locale: "en", strength: 2 });
expect(mockQuery.select).toHaveBeenCalledWith("+password");
expect(result).toEqual(user);
});
});
describe("getSpotifyConfigByUUID", () => {
it("should return spotify config for user", async () => {
const spotifyConfig = { accessToken: "access-token" };
mockedUserModel.findOne.mockReturnValue(createMockMongooseQuery({ spotifyConfig }) as any);
const result = await userService.getSpotifyConfigByUUID("uuid-123");
expect(mockedUserModel.findOne).toHaveBeenCalledWith({ uuid: "uuid-123" }, { spotifyConfig: 1 });
expect(result).toEqual(spotifyConfig);
});
it("should return undefined if user has no spotify config", async () => {
mockedUserModel.findOne.mockReturnValue(createMockMongooseQuery(null) as any);
const result = await userService.getSpotifyConfigByUUID("uuid-123");
expect(result).toBeUndefined();
});
});
describe("createUser", () => {
it("should create user and return without password", async () => {
const userData = { name: "New User", password: "hashedPassword", uuid: "new-uuid" };
const createdUserWithPassword = { ...userData, _id: "newUser1" };
const createdUserDocument = {
...createdUserWithPassword,
toObject: () => createdUserWithPassword,
};
mockedUserModel.create.mockResolvedValue(createdUserDocument as any);
const result = await userService.createUser(userData as any);
expect(mockedUserModel.create).toHaveBeenCalledWith(userData);
expect(result).not.toHaveProperty("password");
expect(result.name).toBe("New User");
// @ts-ignore
expect(result._id).toBe("newUser1");
});
});
describe("existsUserByName", () => {
it("should return true if user exists", async () => {
// @ts-ignore
mockedUserModel.countDocuments.mockReturnValue(1);
const result = await userService.existsUserByName("ExistingUser");
expect(mockedUserModel.countDocuments).toHaveBeenCalledWith({ name: "ExistingUser" });
expect(result).toBe(true);
});
it("should return false if user does not exist", async () => {
// @ts-ignore
mockedUserModel.countDocuments.mockReturnValue(0);
const result = await userService.existsUserByName("NonExistentUser");
expect(result).toBe(false);
});
});
describe("clearSpotifyConfigByUUID", () => {
it("should clear spotify config and return updated user", async () => {
const updatedUser = { uuid: "uuid-123", name: "Test User" };
mockedUserModel.findOneAndUpdate.mockReturnValue(createMockMongooseQuery(updatedUser) as any);
const result = await userService.clearSpotifyConfigByUUID("uuid-123");
expect(mockedUserModel.findOneAndUpdate).toHaveBeenCalledWith(
{ uuid: "uuid-123" },
{ $unset: { spotifyConfig: 1 } },
{ new: true }
);
expect(result).toEqual(updatedUser);
});
it("should return null if user not found", async () => {
mockedUserModel.findOneAndUpdate.mockReturnValue(createMockMongooseQuery(null) as any);
const result = await userService.clearSpotifyConfigByUUID("non-existent-uuid");
expect(result).toBeNull();
});
});
});