refactor to inject userservice

This commit is contained in:
StarAppeal
2025-09-18 21:13:40 +02:00
parent da19a0aaf1
commit c7d4454359
19 changed files with 290 additions and 230 deletions
+21 -11
View File
@@ -1,7 +1,8 @@
import { describe, it, expect, vi, beforeAll, beforeEach } from "vitest";
import { describe, it, expect, vi, beforeAll, afterAll, beforeEach } from "vitest";
import request from "supertest";
import express from "express";
import {authLimiter} from "../src/rest/middleware/rateLimit";
import http from "http";
import { authLimiter } from "../src/rest/middleware/rateLimit";
vi.mock("../src/db/services/db/database.service", () => ({
connectToDatabase: vi.fn().mockResolvedValue(undefined),
@@ -20,7 +21,6 @@ vi.mock("../src/config", () => ({
vi.mock("../src/rest/middleware/rateLimit", async (importOriginal) => {
const original = await importOriginal<typeof import("../src/rest/middleware/rateLimit")>();
return {
...original,
authLimiter: vi.fn((req, res, next) => next()),
@@ -29,12 +29,25 @@ vi.mock("../src/rest/middleware/rateLimit", async (importOriginal) => {
});
let app: express.Application;
let server: http.Server;
beforeAll(async () => {
const indexModule = await import("../src/index");
app = indexModule.default;
const { startServer } = await import("../src/index");
const instances = await startServer();
app = instances.app;
server = instances.server;
});
afterAll(async () => {
await new Promise<void>((resolve) => {
if (server) {
server.close(() => resolve());
} else {
resolve();
}
});
});
describe("Express App Integration Test", () => {
@@ -63,24 +76,21 @@ describe("Express App Integration Test", () => {
expect(response.headers['referrer-policy']).toBe('no-referrer');
});
it("should protect a route with the authenticateJwt middleware", async () => {
const response = await request(app).get("/api/user/me").expect(401);
expect(response.text).toBe("Unauthorized");
it("should protect a route with authentication middleware", async () => {
await request(app).get("/api/user/me").expect(401);
});
it("should apply the auth rate limiter to an auth route", async () => {
await request(app).post("/api/auth/login").send({}).expect(400);
await request(app).post("/api/auth/login").send({});
expect(authLimiter).toHaveBeenCalledOnce();
});
it("should NOT apply the auth rate limiter to a non-auth route", async () => {
await request(app).get("/api/healthz").expect(200);
expect(authLimiter).not.toHaveBeenCalled();
});
it("should return a 404 for an unknown route", async () => {
await request(app).get("/api/this-route-does-not-exist").expect(404);
});
});
+1 -3
View File
@@ -2,7 +2,6 @@ import {describe, it, expect, vi, beforeEach, afterEach} from "vitest";
import request from "supertest";
import express from "express";
import {RestAuth} from "../../src/rest/auth";
import {UserService} from "../../src/db/services/db/UserService";
import {JwtAuthenticator} from "../../src/utils/jwtAuthenticator";
import {PasswordUtils} from "../../src/utils/passwordUtils";
import {createMockJwtAuthenticator, createMockUserService, createPublicTestApp} from "../helpers/testSetup";
@@ -40,7 +39,6 @@ describe("RestAuth", () => {
vi.clearAllMocks();
mockUserService = createMockUserService();
vi.mocked(UserService.create).mockResolvedValue(mockUserService);
mockPasswordUtils = vi.mocked(PasswordUtils);
mockCrypto = vi.mocked(crypto);
@@ -48,7 +46,7 @@ describe("RestAuth", () => {
mockJwtAuthenticator = createMockJwtAuthenticator();
vi.mocked(JwtAuthenticator).mockImplementation(() => mockJwtAuthenticator);
const restAuth = new RestAuth();
const restAuth = new RestAuth(mockUserService);
app = createPublicTestApp(restAuth.createRouter(), "/auth");
process.env.SECRET_KEY = "test-secret-key";
+4 -7
View File
@@ -2,7 +2,6 @@ import { describe, it, expect, vi, beforeEach, afterEach, type Mocked } from "vi
import { Request, Response, NextFunction } from "express";
import { isAdmin } from "../../../src/rest/middleware/isAdmin";
import { createMockUserService } from "../../helpers/testSetup";
import { UserService } from "../../../src/db/services/db/UserService";
import { notFound } from "../../../src/rest/utils/responses";
vi.mock("../../../src/db/services/db/UserService", () => ({
@@ -27,7 +26,6 @@ describe("isAdmin middleware", () => {
vi.clearAllMocks();
mockedUserService = createMockUserService();
vi.mocked(UserService.create).mockResolvedValue(mockedUserService);
req = {
payload: { uuid, username: "username", id: ""}
@@ -50,9 +48,8 @@ describe("isAdmin middleware", () => {
const mockUser = { uuid, config: { isAdmin: true } };
mockedUserService.getUserByUUID.mockResolvedValue(mockUser);
await isAdmin(req as Request, res, next);
await isAdmin(mockedUserService)(req as Request, res, next);
expect(UserService.create).toHaveBeenCalledOnce();
expect(mockedUserService.getUserByUUID).toHaveBeenCalledWith(uuid);
expect(next).toHaveBeenCalledOnce();
expect(res.status).not.toHaveBeenCalled();
@@ -66,7 +63,7 @@ describe("isAdmin middleware", () => {
const mockUser = { uuid, config: { isAdmin: false } };
mockedUserService.getUserByUUID.mockResolvedValue(mockUser);
await isAdmin(req as Request, res, next);
await isAdmin(mockedUserService)(req as Request, res, next);
expect(mockedUserService.getUserByUUID).toHaveBeenCalledWith(uuid);
expect(notFound).toHaveBeenCalledWith(res);
@@ -76,7 +73,7 @@ describe("isAdmin middleware", () => {
it("should call notFound if user does not exist", async () => {
mockedUserService.getUserByUUID.mockResolvedValue(null);
await isAdmin(req as Request, res, next);
await isAdmin(mockedUserService)(req as Request, res, next);
expect(mockedUserService.getUserByUUID).toHaveBeenCalledWith(uuid);
expect(notFound).toHaveBeenCalledWith(res);
@@ -87,7 +84,7 @@ describe("isAdmin middleware", () => {
const dbError = new Error("Database error");
mockedUserService.getUserByUUID.mockRejectedValue(dbError);
await isAdmin(req as Request, res, next);
await isAdmin(mockedUserService)(req as Request, res, next);
expect(next).toHaveBeenCalledWith(expect.objectContaining({ message: 'Database error' }));
});
+35 -34
View File
@@ -2,7 +2,7 @@ import {describe, it, expect, vi, beforeEach, afterEach} from "vitest";
import request from "supertest";
import {RestUser} from "../../src/rest/restUser";
import {setupTestEnvironment, type TestEnvironment} from "../helpers/testSetup";
import {createMockUserService, setupTestEnvironment, type TestEnvironment} from "../helpers/testSetup";
vi.mock("../../src/db/services/db/UserService", () => ({
UserService: {
@@ -24,11 +24,12 @@ describe("RestUser", () => {
const requestingUserUUID = "test-user-uuid";
const adminUser = { uuid: requestingUserUUID, config: { isAdmin: true } };
const nonAdminUser = { uuid: requestingUserUUID, config: { isAdmin: false } };
const mockedUserService = createMockUserService();
beforeEach(() => {
vi.clearAllMocks();
const restUser = new RestUser();
const restUser = new RestUser(mockedUserService);
testEnv = setupTestEnvironment(restUser.createRouter(), "/user");
});
@@ -44,14 +45,14 @@ describe("RestUser", () => {
uuid: "test-user-uuid"
};
testEnv.mockUserService.getUserByUUID.mockResolvedValue(mockUser);
mockedUserService.getUserByUUID.mockResolvedValue(mockUser);
const response = await request(testEnv.app)
.get("/user/me")
.expect(200);
expect(response.body.data).toEqual(mockUser);
expect(testEnv.mockUserService.getUserByUUID).toHaveBeenCalledWith("test-user-uuid");
expect(mockedUserService.getUserByUUID).toHaveBeenCalledWith("test-user-uuid");
});
});
@@ -71,8 +72,8 @@ describe("RestUser", () => {
spotifyConfig: null
};
testEnv.mockUserService.getUserByUUID.mockResolvedValue(mockUser);
testEnv.mockUserService.updateUser.mockResolvedValue(mockUser);
mockedUserService.getUserByUUID.mockResolvedValue(mockUser);
mockedUserService.updateUser.mockResolvedValue(mockUser);
const response = await request(testEnv.app)
.put("/user/me/spotify")
@@ -80,8 +81,8 @@ describe("RestUser", () => {
.expect(200);
expect(response.body.data.message).toBe("Spotify Config erfolgreich geändert");
expect(testEnv.mockUserService.getUserByUUID).toHaveBeenCalledWith("test-user-uuid");
expect(testEnv.mockUserService.updateUser).toHaveBeenCalledWith({
expect(mockedUserService.getUserByUUID).toHaveBeenCalledWith("test-user-uuid");
expect(mockedUserService.updateUser).toHaveBeenCalledWith({
...mockUser,
spotifyConfig: {
accessToken: "access-token-123",
@@ -93,7 +94,7 @@ describe("RestUser", () => {
});
it("should return bad request when user not found", async () => {
testEnv.mockUserService.getUserByUUID.mockResolvedValue(null);
mockedUserService.getUserByUUID.mockResolvedValue(null);
const response = await request(testEnv.app)
.put("/user/me/spotify")
@@ -176,20 +177,20 @@ describe("RestUser", () => {
spotifyConfig: null
};
testEnv.mockUserService.getUserByUUID.mockResolvedValue(mockUser);
testEnv.mockUserService.clearSpotifyConfigByUUID.mockResolvedValue(updatedUser);
mockedUserService.getUserByUUID.mockResolvedValue(mockUser);
mockedUserService.clearSpotifyConfigByUUID.mockResolvedValue(updatedUser);
const response = await request(testEnv.app)
.delete("/user/me/spotify")
.expect(200);
expect(response.body.data.user).toEqual(updatedUser);
expect(testEnv.mockUserService.getUserByUUID).toHaveBeenCalledWith("test-user-uuid");
expect(testEnv.mockUserService.clearSpotifyConfigByUUID).toHaveBeenCalledWith("test-user-uuid");
expect(mockedUserService.getUserByUUID).toHaveBeenCalledWith("test-user-uuid");
expect(mockedUserService.clearSpotifyConfigByUUID).toHaveBeenCalledWith("test-user-uuid");
});
it("should return bad request when user not found", async () => {
testEnv.mockUserService.getUserByUUID.mockResolvedValue(null);
mockedUserService.getUserByUUID.mockResolvedValue(null);
const response = await request(testEnv.app)
.delete("/user/me/spotify")
@@ -215,10 +216,10 @@ describe("RestUser", () => {
password: "old-hashed-password"
};
testEnv.mockUserService.getUserByUUID.mockResolvedValue(mockUser);
mockedUserService.getUserByUUID.mockResolvedValue(mockUser);
vi.mocked(PasswordUtils.validatePassword).mockReturnValue({valid: true});
vi.mocked(PasswordUtils.hashPassword).mockResolvedValue("new-hashed-password");
testEnv.mockUserService.updateUser.mockResolvedValue(mockUser);
mockedUserService.updateUser.mockResolvedValue(mockUser);
const response = await request(testEnv.app)
.put("/user/me/password")
@@ -228,14 +229,14 @@ describe("RestUser", () => {
expect(response.body.data.message).toBe("Passwort erfolgreich geändert");
expect(PasswordUtils.validatePassword).toHaveBeenCalledWith("newpassword123");
expect(PasswordUtils.hashPassword).toHaveBeenCalledWith("newpassword123");
expect(testEnv.mockUserService.updateUser).toHaveBeenCalledWith({
expect(mockedUserService.updateUser).toHaveBeenCalledWith({
...mockUser,
password: "new-hashed-password"
});
});
it("should return bad request when user not found", async () => {
testEnv.mockUserService.getUserByUUID.mockResolvedValue(null);
mockedUserService.getUserByUUID.mockResolvedValue(null);
const response = await request(testEnv.app)
.put("/user/me/password")
@@ -252,7 +253,7 @@ describe("RestUser", () => {
uuid: "test-user-uuid"
};
testEnv.mockUserService.getUserByUUID.mockResolvedValue(mockUser);
mockedUserService.getUserByUUID.mockResolvedValue(mockUser);
const invalidData = {
password: "newpassword123",
@@ -276,7 +277,7 @@ describe("RestUser", () => {
uuid: "test-user-uuid"
};
testEnv.mockUserService.getUserByUUID.mockResolvedValue(mockUser);
mockedUserService.getUserByUUID.mockResolvedValue(mockUser);
vi.mocked(PasswordUtils.validatePassword).mockReturnValue({
valid: false,
message: "Password too weak"
@@ -331,7 +332,7 @@ describe("RestUser", () => {
describe("when user is an admin", () => {
beforeEach(() => {
testEnv.mockUserService.getUserByUUID.mockResolvedValue(adminUser);
mockedUserService.getUserByUUID.mockResolvedValue(adminUser);
});
it("should return all users", async () => {
@@ -339,19 +340,19 @@ describe("RestUser", () => {
{id: "1", name: "user1", uuid: "uuid1"},
{id: "2", name: "user2", uuid: "uuid2"}
];
testEnv.mockUserService.getAllUsers.mockResolvedValue(mockUsers);
mockedUserService.getAllUsers.mockResolvedValue(mockUsers);
const response = await request(testEnv.app)
.get("/user/")
.expect(200);
expect(response.body.data.users).toEqual(mockUsers);
expect(testEnv.mockUserService.getUserByUUID).toHaveBeenCalledWith(requestingUserUUID);
expect(testEnv.mockUserService.getAllUsers).toHaveBeenCalled();
expect(mockedUserService.getUserByUUID).toHaveBeenCalledWith(requestingUserUUID);
expect(mockedUserService.getAllUsers).toHaveBeenCalled();
});
it("should handle empty user list", async () => {
testEnv.mockUserService.getAllUsers.mockResolvedValue([]);
mockedUserService.getAllUsers.mockResolvedValue([]);
const response = await request(testEnv.app)
.get("/user/")
@@ -363,7 +364,7 @@ describe("RestUser", () => {
describe("when user is not an admin", () => {
it("should return 404 Not Found if user is not an admin", async () => {
testEnv.mockUserService.getUserByUUID.mockResolvedValue(nonAdminUser);
mockedUserService.getUserByUUID.mockResolvedValue(nonAdminUser);
await request(testEnv.app)
.get("/user/")
@@ -371,7 +372,7 @@ describe("RestUser", () => {
});
it("should return 404 Not Found if user does not exist", async () => {
testEnv.mockUserService.getUserByUUID.mockResolvedValue(null);
mockedUserService.getUserByUUID.mockResolvedValue(null);
await request(testEnv.app)
.get("/user/")
@@ -390,23 +391,23 @@ describe("RestUser", () => {
describe("when user is an admin", () => {
beforeEach(() => {
testEnv.mockUserService.getUserByUUID.mockResolvedValue(adminUser);
mockedUserService.getUserByUUID.mockResolvedValue(adminUser);
});
it("should return user by id", async () => {
testEnv.mockUserService.getUserById.mockResolvedValue(mockUser);
mockedUserService.getUserById.mockResolvedValue(mockUser);
const response = await request(testEnv.app)
.get(`/user/${specificUserId}`)
.expect(200);
expect(response.body.data).toEqual(mockUser);
expect(testEnv.mockUserService.getUserByUUID).toHaveBeenCalledWith(requestingUserUUID);
expect(testEnv.mockUserService.getUserById).toHaveBeenCalledWith(specificUserId);
expect(mockedUserService.getUserByUUID).toHaveBeenCalledWith(requestingUserUUID);
expect(mockedUserService.getUserById).toHaveBeenCalledWith(specificUserId);
});
it("should return bad request when target user is not found", async () => {
testEnv.mockUserService.getUserById.mockResolvedValue(null);
mockedUserService.getUserById.mockResolvedValue(null);
const response = await request(testEnv.app)
.get(`/user/nonexistent-id`)
@@ -418,7 +419,7 @@ describe("RestUser", () => {
describe("when user is not an admin", () => {
it("should return 404 Not Found if user is not an admin", async () => {
testEnv.mockUserService.getUserByUUID.mockResolvedValue(nonAdminUser);
mockedUserService.getUserByUUID.mockResolvedValue(nonAdminUser);
await request(testEnv.app)
.get(`/user/${specificUserId}`)
@@ -426,7 +427,7 @@ describe("RestUser", () => {
});
it("should return 404 Not Found if user does not exist", async () => {
testEnv.mockUserService.getUserByUUID.mockResolvedValue(null);
mockedUserService.getUserByUUID.mockResolvedValue(null);
await request(testEnv.app)
.get(`/user/${specificUserId}`)
@@ -2,6 +2,10 @@ import { describe, it, expect, vi, beforeEach, type Mocked } from "vitest";
import { getEventListeners } from "../../../../src/utils/websocket/websocketCustomEvents/websocketEventUtils";
import { WebsocketEventType } from "../../../../src/utils/websocket/websocketCustomEvents/websocketEventType";
import { CustomWebsocketEvent } from "../../../../src/utils/websocket/websocketCustomEvents/customWebsocketEvent";
import type { UserService } from "../../../../src/db/services/db/UserService";
import {
CustomWebsocketEventUserService
} from "../../../../src/utils/websocket/websocketCustomEvents/customWebsocketEventUserService";
type MockWs = {
user: {
@@ -9,10 +13,16 @@ type MockWs = {
lastState: { global: { mode: string; brightness: number } };
};
send: Mocked<(data: any, options: { binary: boolean }) => void>;
on: Mocked<(event: string, listener: (...args: any[]) => void) => void>;
emit: Mocked<(event: string, ...args: any[]) => void>;
};
type MockUserService = Mocked<UserService>;
describe("websocketEventUtils.getEventListeners", () => {
let mockWs: MockWs;
let mockUserService: MockUserService;
let listeners: CustomWebsocketEvent[];
beforeEach(() => {
@@ -22,8 +32,16 @@ describe("websocketEventUtils.getEventListeners", () => {
lastState: { global: { mode: "idle", brightness: 42 } },
},
send: vi.fn(),
on: vi.fn(),
emit: vi.fn(),
};
listeners = getEventListeners(mockWs as any);
mockUserService = {
getUserByUUID: vi.fn(),
updateUser: vi.fn(),
} as any;
listeners = getEventListeners(mockWs as any, mockUserService);
});
it("should return an array of event listener objects", () => {
@@ -34,6 +52,9 @@ describe("websocketEventUtils.getEventListeners", () => {
expect(listener).toHaveProperty("event");
expect(listener).toHaveProperty("handler");
expect(typeof listener.handler).toBe("function");
if (typeof listener === typeof CustomWebsocketEventUserService){
expect(listener).toHaveProperty("userService", mockUserService);
}
}
});
@@ -2,10 +2,12 @@ import { describe, it, expect, vi, beforeEach, afterEach, type Mocked } from "vi
import { WebsocketEventHandler } from "../../../src/utils/websocket/websocketEventHandler";
import { ExtendedWebSocket } from "../../../src/interfaces/extendedWebsocket";
import { CustomWebsocketEvent } from "../../../src/utils/websocket/websocketCustomEvents/customWebsocketEvent";
import {UserService} from "../../../src/db/services/db/UserService";
describe("WebsocketEventHandler", () => {
let mockWebSocket: Mocked<ExtendedWebSocket>;
let websocketEventHandler: WebsocketEventHandler;
let mockUserService: Mocked<UserService>;
let registeredHandlers: Map<string, (...args: any[]) => void>;
beforeEach(() => {
@@ -27,7 +29,10 @@ describe("WebsocketEventHandler", () => {
asyncUpdates: new Map([["update1", 123], ["update2", 456]]),
} as unknown as Mocked<ExtendedWebSocket>;
websocketEventHandler = new WebsocketEventHandler(mockWebSocket);
// not used in this test
mockUserService = {} as Mocked<UserService>;
websocketEventHandler = new WebsocketEventHandler(mockWebSocket, mockUserService);
});
afterEach(() => {
@@ -108,6 +113,7 @@ describe("WebsocketEventHandler", () => {
// @ts-ignore
const bindSpy = vi.spyOn(customEvent.handler, "bind");
// @ts-ignore - Access to private method for testing purposes
websocketEventHandler.registerCustomEvent(customEvent);
expect(mockWebSocket.on).toHaveBeenCalledWith("custom_event", expect.any(Function));
@@ -1,16 +1,12 @@
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { describe, it, expect, vi, beforeEach, afterEach, type Mocked } from "vitest";
import { WebsocketServerEventHandler } from "../../../src/utils/websocket/websocketServerEventHandler";
import type { UserService } from "../../../src/db/services/db/UserService";
const { heartbeatSpy, getUserByUUID } = vi.hoisted(() => ({
heartbeatSpy: vi.fn(),
getUserByUUID: vi.fn(),
const heartbeatSpy = vi.fn();
vi.mock("../../../src/utils/websocket/websocketServerHeartbeatInterval", () => ({
heartbeat: () => heartbeatSpy,
}));
vi.mock("../../../src/utils/websocket/websocketServerHeartbeatInterval", () => {
return {
heartbeat: () => heartbeatSpy,
};
});
const userObj = {
name: "tester",
uuid: "uuid-1",
@@ -19,38 +15,27 @@ const userObj = {
lastState: { global: { mode: "idle", brightness: 50 } },
};
vi.mock("../../../src/db/services/db/UserService", () => {
return {
UserService: {
create: vi.fn().mockResolvedValue({
getUserByUUID,
}),
},
};
});
class FakeWSS {
clients = new Set<any>();
handlers = new Map<string, Function>();
on(event: string, handler: Function) {
this.handlers.set(event, handler);
}
emit(event: string, ...args: any[]) {
const h = this.handlers.get(event);
if (h) h(...args);
this.handlers.get(event)?.(...args);
}
}
import { WebsocketServerEventHandler } from "../../../src/utils/websocket/websocketServerEventHandler";
describe("WebsocketServerEventHandler", () => {
let wss: FakeWSS;
let mockUserService: Mocked<UserService>; // Variable für unseren Mock-Service
beforeEach(() => {
wss = new FakeWSS();
heartbeatSpy.mockReset();
getUserByUUID.mockReset();
getUserByUUID.mockResolvedValue(userObj);
heartbeatSpy.mockClear();
mockUserService = {
getUserByUUID: vi.fn().mockResolvedValue(userObj),
} as any;
});
afterEach(() => {
@@ -58,12 +43,10 @@ describe("WebsocketServerEventHandler", () => {
});
it("enableConnectionEvent sets user/payload/isAlive/asyncUpdates and calls callback", async () => {
const handler = new WebsocketServerEventHandler(wss as any);
const handler = new WebsocketServerEventHandler(wss as any, mockUserService);
const cb = vi.fn();
const done = new Promise<void>((resolve) => {
cb.mockImplementation(() => resolve());
});
const done = new Promise<void>((resolve) => cb.mockImplementation(() => resolve()));
handler.enableConnectionEvent(cb);
@@ -74,7 +57,7 @@ describe("WebsocketServerEventHandler", () => {
await done;
expect(getUserByUUID).toHaveBeenCalledWith("uuid-1");
expect(mockUserService.getUserByUUID).toHaveBeenCalledWith("uuid-1");
expect(ws.user).toEqual(userObj);
expect(ws.payload).toEqual(req.payload);
expect(ws.isAlive).toBe(true);
@@ -84,7 +67,7 @@ describe("WebsocketServerEventHandler", () => {
it("enableHeartbeat starts interval and calls heartbeat()", () => {
vi.useFakeTimers();
const handler = new WebsocketServerEventHandler(wss as any);
const handler = new WebsocketServerEventHandler(wss as any, mockUserService);
const id = handler.enableHeartbeat(1000);
expect(["number", "object"]).toContain(typeof id);
@@ -97,16 +80,16 @@ describe("WebsocketServerEventHandler", () => {
});
it("enableCloseEvent registers Listener and calls callback on close", () => {
const handler = new WebsocketServerEventHandler(wss as any);
const handler = new WebsocketServerEventHandler(wss as any, mockUserService);
const cb = vi.fn();
const logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
handler.enableCloseEvent(cb);
handler.enableCloseEvent(cb);
wss.emit("close");
expect(cb).toHaveBeenCalledTimes(1);
expect(logSpy).toHaveBeenCalledWith("WebSocket server closed");
logSpy.mockRestore();
});
});
+15 -8
View File
@@ -5,6 +5,8 @@ import { ExtendedWebSocketServer } from "../src/websocket";
import { WebsocketServerEventHandler } from "../src/utils/websocket/websocketServerEventHandler";
import { WebsocketEventHandler } from "../src/utils/websocket/websocketEventHandler";
import { getEventListeners } from "../src/utils/websocket/websocketCustomEvents/websocketEventUtils";
import {UserService} from "../src/db/services/db/UserService";
import {createMockUserService} from "./helpers/testSetup";
let mockWssInstance: Mocked<WebSocketServer>;
let mockServerEventHandler: Mocked<WebsocketServerEventHandler>;
@@ -24,6 +26,7 @@ vi.mock("../src/utils/websocket/websocketCustomEvents/websocketEventUtils");
describe("ExtendedWebSocketServer", () => {
let mockHttpServer: Mocked<Server>;
let extendedWss: ExtendedWebSocketServer;
let mockUserService: Mocked<UserService>;
beforeEach(() => {
vi.clearAllMocks();
@@ -42,7 +45,9 @@ describe("ExtendedWebSocketServer", () => {
close: vi.fn(),
} as unknown as Mocked<WebSocketServer>;
extendedWss = new ExtendedWebSocketServer(mockHttpServer);
mockUserService = createMockUserService();
extendedWss = new ExtendedWebSocketServer(mockHttpServer, mockUserService);
});
describe("Constructor and Setup", () => {
@@ -53,8 +58,8 @@ describe("ExtendedWebSocketServer", () => {
});
});
it("should create and use a WebsocketServerEventHandler", () => {
expect(WebsocketServerEventHandler).toHaveBeenCalledWith(mockWssInstance);
it("should create and use a WebsocketServerEventHandler with the correct service", () => {
expect(WebsocketServerEventHandler).toHaveBeenCalledWith(mockWssInstance, mockUserService);
});
it("should enable the heartbeat", () => {
@@ -99,9 +104,11 @@ describe("ExtendedWebSocketServer", () => {
emit: vi.fn(), on: vi.fn(), user: { lastState: { global: { mode: "idle" } } },
};
mockClientEventHandler = {
enableErrorEvent: vi.fn(), enablePongEvent: vi.fn(),
enableMessageEvent: vi.fn(), enableDisconnectEvent: vi.fn(),
registerCustomEvent: vi.fn(),
enableErrorEvent: vi.fn(),
enablePongEvent: vi.fn(),
enableMessageEvent: vi.fn(),
enableDisconnectEvent: vi.fn(),
registerCustomEvents: vi.fn(),
} as unknown as Mocked<WebsocketEventHandler>;
vi.mocked(WebsocketEventHandler).mockImplementation(() => mockClientEventHandler);
@@ -110,12 +117,12 @@ describe("ExtendedWebSocketServer", () => {
it("should create and configure a WebsocketEventHandler for new clients", () => {
connectionHandler(mockWsClient, {});
expect(vi.mocked(WebsocketEventHandler)).toHaveBeenCalledWith(mockWsClient);
expect(vi.mocked(WebsocketEventHandler)).toHaveBeenCalledWith(mockWsClient, mockUserService);
expect(mockClientEventHandler.enableErrorEvent).toHaveBeenCalled();
expect(mockClientEventHandler.enablePongEvent).toHaveBeenCalled();
expect(mockClientEventHandler.enableMessageEvent).toHaveBeenCalled();
expect(mockClientEventHandler.enableDisconnectEvent).toHaveBeenCalled();
expect(mockClientEventHandler.registerCustomEvent).toHaveBeenCalled();
expect(mockClientEventHandler.registerCustomEvents).toHaveBeenCalled();
});
it("should emit initial events to the new client", () => {