import { jest } from '@jest/globals'; // Mock dependencies jest.unstable_mockModule('../../config.js', () => ({ loadConfig: jest.fn(() => ({ server: { logLevel: 'info' } })) })); jest.unstable_mockModule('../../auth/auth.js', () => ({ CodeAuth: jest.fn().mockImplementation(() => ({ verifyCode: jest.fn(), verifyOtp: jest.fn() })), createAuthMiddleware: jest.fn(() => (socket, next) => next()) })); jest.unstable_mockModule('../../database/database.js', () => ({ newObject: jest.fn(), editObject: jest.fn(), getObject: jest.fn(), listObjects: jest.fn() })); jest.unstable_mockModule( '../../database/schemas/management/host.schema.js', () => ({ hostModel: { modelName: 'host' } }) ); jest.unstable_mockModule('../../updates/updatemanager.js', () => ({ UpdateManager: jest.fn().mockImplementation(() => ({ subscribeToObjectUpdate: jest.fn(), unsubscribeToObjectUpdate: jest.fn() })) })); jest.unstable_mockModule('../../actions/actionmanager.js', () => ({ ActionManager: jest.fn().mockImplementation(() => ({ subscribeToObjectActions: jest.fn(), removeAllListeners: jest.fn() })) })); jest.unstable_mockModule('../../events/eventmanager.js', () => ({ EventManager: jest.fn().mockImplementation(() => ({ sendObjectEvent: jest.fn(), subscribeToObjectEvent: jest.fn(), removeObjectEventsListener: jest.fn(), removeAllListeners: jest.fn() })) })); jest.unstable_mockModule('../../templates/templatemanager.js', () => ({ TemplateManager: jest.fn().mockImplementation(() => ({ renderPDF: jest.fn() })) })); jest.unstable_mockModule('../../utils.js', () => ({ getModelByName: jest.fn(name => ({ modelName: name })) })); jest.unstable_mockModule('log4js', () => ({ default: { getLogger: () => ({ level: 'info', debug: jest.fn(), error: jest.fn(), warn: jest.fn(), trace: jest.fn(), info: jest.fn() }) } })); const { SocketHost } = await import('../sockethost.js'); const { editObject, newObject, getObject, listObjects } = await import( '../../database/database.js' ); describe('SocketHost', () => { let mockSocket; let mockSocketManager; let socketHost; beforeEach(() => { jest.clearAllMocks(); mockSocket = { id: 'test-socket-id', use: jest.fn(), on: jest.fn(), emit: jest.fn() }; mockSocketManager = {}; socketHost = new SocketHost(mockSocket, mockSocketManager); }); it('should initialize correctly and setup event handlers', () => { expect(mockSocket.use).toHaveBeenCalled(); expect(mockSocket.on).toHaveBeenCalledWith( 'authenticate', expect.any(Function) ); expect(mockSocket.on).toHaveBeenCalledWith( 'disconnect', expect.any(Function) ); }); describe('handleAuthenticate', () => { it('should authenticate with id and authCode', async () => { const data = { id: 'host-1', authCode: 'code-123' }; const callback = jest.fn(); const mockHost = { _id: 'host-id-obj' }; socketHost.codeAuth.verifyCode.mockResolvedValue({ valid: true, host: mockHost }); editObject.mockResolvedValue({}); await socketHost.handleAuthenticate(data, callback); expect(socketHost.codeAuth.verifyCode).toHaveBeenCalledWith( 'host-1', 'code-123' ); expect(editObject).toHaveBeenCalled(); expect(callback).toHaveBeenCalledWith({ valid: true, host: mockHost }); expect(socketHost.authenticated).toBe(true); }); it('should authenticate with otp', async () => { const data = { otp: '123456' }; const callback = jest.fn(); const mockHost = { _id: 'host-id-obj' }; socketHost.codeAuth.verifyOtp.mockResolvedValue({ valid: true, host: mockHost }); editObject.mockResolvedValue({}); await socketHost.handleAuthenticate(data, callback); expect(socketHost.codeAuth.verifyOtp).toHaveBeenCalledWith('123456'); expect(callback).toHaveBeenCalledWith({ valid: true, host: mockHost }); }); it('should return error if params are missing', async () => { const data = {}; const callback = jest.fn(); await socketHost.handleAuthenticate(data, callback); expect(callback).toHaveBeenCalledWith({ valid: false, error: 'Missing params.' }); }); }); describe('database operations handlers', () => { beforeEach(() => { socketHost.host = { _id: 'host-id' }; }); it('handleNewObject should call newObject and callback', async () => { const data = { objectType: 'printer', newData: { name: 'P1' } }; const callback = jest.fn(); newObject.mockResolvedValue({ _id: 'new-id' }); await socketHost.handleNewObject(data, callback); expect(newObject).toHaveBeenCalled(); expect(callback).toHaveBeenCalledWith({ _id: 'new-id' }); }); it('handleEditObject should call editObject and callback', async () => { const data = { objectType: 'printer', _id: 'p1', updateData: { status: 'idle' } }; const callback = jest.fn(); editObject.mockResolvedValue({ success: true }); await socketHost.handleEditObject(data, callback); expect(editObject).toHaveBeenCalled(); expect(callback).toHaveBeenCalledWith({ success: true }); }); }); describe('handleDisconnect', () => { it('should set host offline if authenticated', async () => { socketHost.authenticated = true; socketHost.id = 'host-id'; socketHost.host = { _id: 'host-id' }; listObjects.mockResolvedValue([]); // for setDevicesState await socketHost.handleDisconnect(); expect(editObject).toHaveBeenCalledWith( expect.objectContaining({ id: 'host-id', updateData: expect.objectContaining({ online: false }) }) ); expect(socketHost.actionManager.removeAllListeners).toHaveBeenCalled(); }); }); });