238 lines
7.2 KiB
JavaScript
238 lines
7.2 KiB
JavaScript
import { jest } from '@jest/globals';
|
|
|
|
// Mock dependencies
|
|
jest.unstable_mockModule('../../config.js', () => ({
|
|
loadConfig: jest.fn(() => ({
|
|
server: { logLevel: 'info' }
|
|
}))
|
|
}));
|
|
|
|
jest.unstable_mockModule('../../auth/auth.js', () => ({
|
|
KeycloakAuth: jest.fn().mockImplementation(() => ({
|
|
verifyToken: jest.fn()
|
|
})),
|
|
createAuthMiddleware: jest.fn(() => (socket, next) => next())
|
|
}));
|
|
|
|
jest.unstable_mockModule('../../utils.js', () => ({
|
|
generateHostOTP: jest.fn()
|
|
}));
|
|
|
|
jest.unstable_mockModule('../../lock/lockmanager.js', () => ({
|
|
LockManager: jest.fn().mockImplementation(() => ({
|
|
lockObject: jest.fn(),
|
|
unlockObject: jest.fn(),
|
|
getObjectLock: jest.fn()
|
|
}))
|
|
}));
|
|
|
|
jest.unstable_mockModule('../../updates/updatemanager.js', () => ({
|
|
UpdateManager: jest.fn().mockImplementation(() => ({
|
|
subscribeToObjectNew: jest.fn(),
|
|
subscribeToObjectDelete: jest.fn(),
|
|
subscribeToObjectUpdate: jest.fn(),
|
|
removeObjectNewListener: jest.fn(),
|
|
removeObjectDeleteListener: jest.fn(),
|
|
removeObjectUpdateListener: jest.fn()
|
|
}))
|
|
}));
|
|
|
|
jest.unstable_mockModule('../../actions/actionmanager.js', () => ({
|
|
ActionManager: jest.fn().mockImplementation(() => ({
|
|
sendObjectAction: jest.fn(),
|
|
removeAllListeners: jest.fn()
|
|
}))
|
|
}));
|
|
|
|
jest.unstable_mockModule('../../events/eventmanager.js', () => ({
|
|
EventManager: jest.fn().mockImplementation(() => ({
|
|
subscribeToObjectEvent: jest.fn(),
|
|
removeObjectEventsListener: jest.fn(),
|
|
removeAllListeners: jest.fn()
|
|
}))
|
|
}));
|
|
|
|
jest.unstable_mockModule('../../stats/statsmanager.js', () => ({
|
|
StatsManager: jest.fn().mockImplementation(() => ({
|
|
subscribeToStats: jest.fn(),
|
|
removeStatsListener: jest.fn(),
|
|
removeAllListeners: jest.fn()
|
|
}))
|
|
}));
|
|
|
|
jest.unstable_mockModule('../../notification/notificationmanager.js', () => ({
|
|
NotificationManager: jest.fn().mockImplementation(() => ({
|
|
subscribe: jest.fn().mockResolvedValue({ success: true }),
|
|
removeAllListeners: jest.fn().mockResolvedValue({ success: true })
|
|
}))
|
|
}));
|
|
|
|
jest.unstable_mockModule('log4js', () => ({
|
|
default: {
|
|
getLogger: () => ({
|
|
level: 'info',
|
|
debug: jest.fn(),
|
|
error: jest.fn(),
|
|
warn: jest.fn(),
|
|
trace: jest.fn(),
|
|
info: jest.fn()
|
|
})
|
|
}
|
|
}));
|
|
|
|
const { SocketUser } = await import('../socketuser.js');
|
|
const { generateHostOTP } = await import('../../utils.js');
|
|
|
|
describe('SocketUser', () => {
|
|
let mockSocket;
|
|
let mockSocketManager;
|
|
let socketUser;
|
|
|
|
beforeEach(() => {
|
|
jest.clearAllMocks();
|
|
mockSocket = {
|
|
id: 'test-user-socket-id',
|
|
use: jest.fn(),
|
|
on: jest.fn(),
|
|
emit: jest.fn()
|
|
};
|
|
mockSocketManager = {
|
|
templateManager: {
|
|
renderTemplate: jest.fn(),
|
|
renderPDF: jest.fn()
|
|
}
|
|
};
|
|
socketUser = new SocketUser(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('lock', expect.any(Function));
|
|
expect(mockSocket.on).toHaveBeenCalledWith(
|
|
'disconnect',
|
|
expect.any(Function)
|
|
);
|
|
});
|
|
|
|
describe('handleAuthenticateEvent', () => {
|
|
it('should authenticate user with valid token', async () => {
|
|
const data = { token: 'valid-token' };
|
|
const callback = jest.fn();
|
|
const mockUser = { _id: 'user-id-obj', username: 'testuser' };
|
|
|
|
socketUser.keycloakAuth.verifyToken.mockResolvedValue({
|
|
valid: true,
|
|
user: mockUser
|
|
});
|
|
|
|
await socketUser.handleAuthenticateEvent(data, callback);
|
|
|
|
expect(socketUser.keycloakAuth.verifyToken).toHaveBeenCalledWith(
|
|
'valid-token'
|
|
);
|
|
expect(socketUser.authenticated).toBe(true);
|
|
expect(socketUser.user).toEqual(mockUser);
|
|
expect(socketUser.id).toBe('user-id-obj');
|
|
expect(socketUser.notificationManager.subscribe).toHaveBeenCalled();
|
|
expect(callback).toHaveBeenCalledWith({ valid: true, user: mockUser });
|
|
});
|
|
|
|
it('should not authenticate user with invalid token', async () => {
|
|
const data = { token: 'invalid-token' };
|
|
const callback = jest.fn();
|
|
|
|
socketUser.keycloakAuth.verifyToken.mockResolvedValue({ valid: false });
|
|
|
|
await socketUser.handleAuthenticateEvent(data, callback);
|
|
|
|
expect(socketUser.authenticated).toBe(false);
|
|
expect(callback).toHaveBeenCalledWith({ valid: false });
|
|
});
|
|
});
|
|
|
|
describe('lock event handlers', () => {
|
|
beforeEach(() => {
|
|
socketUser.user = { _id: 'user-id' };
|
|
});
|
|
|
|
it('handleLockEvent should call lockManager.lockObject', async () => {
|
|
const data = { _id: 'obj-1', type: 'printer' };
|
|
await socketUser.handleLockEvent(data);
|
|
|
|
expect(socketUser.lockManager.lockObject).toHaveBeenCalledWith({
|
|
...data,
|
|
user: 'user-id'
|
|
});
|
|
});
|
|
|
|
it('handleUnlockEvent should call lockManager.unlockObject', async () => {
|
|
const data = { _id: 'obj-1' };
|
|
await socketUser.handleUnlockEvent(data);
|
|
|
|
expect(socketUser.lockManager.unlockObject).toHaveBeenCalledWith({
|
|
...data,
|
|
user: 'user-id'
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('object type subscription handlers', () => {
|
|
it('should pass filters to type subscription methods', async () => {
|
|
const data = { objectType: 'note', filter: { 'parent._id': 'parent-id' } };
|
|
const callback = jest.fn();
|
|
|
|
await socketUser.handleSubscribeToObjectTypeUpdateEvent(data, callback);
|
|
|
|
expect(socketUser.updateManager.subscribeToObjectNew).toHaveBeenCalledWith(
|
|
'note',
|
|
data.filter
|
|
);
|
|
expect(
|
|
socketUser.updateManager.subscribeToObjectDelete
|
|
).toHaveBeenCalledWith('note', data.filter);
|
|
expect(callback).toHaveBeenCalledWith({ success: true });
|
|
});
|
|
|
|
it('should pass filters to type unsubscribe methods', async () => {
|
|
const data = { objectType: 'note', filter: { 'parent._id': 'parent-id' } };
|
|
|
|
await socketUser.handleUnsubscribeToObjectTypeUpdateEvent(data);
|
|
|
|
expect(
|
|
socketUser.updateManager.removeObjectNewListener
|
|
).toHaveBeenCalledWith('note', data.filter);
|
|
expect(
|
|
socketUser.updateManager.removeObjectDeleteListener
|
|
).toHaveBeenCalledWith('note', data.filter);
|
|
});
|
|
});
|
|
|
|
describe('handleGenerateHostOtpEvent', () => {
|
|
it('should call generateHostOTP and callback', async () => {
|
|
const data = { _id: 'host-id' };
|
|
const callback = jest.fn();
|
|
generateHostOTP.mockResolvedValue('otp-123');
|
|
|
|
await socketUser.handleGenerateHostOtpEvent(data, callback);
|
|
|
|
expect(generateHostOTP).toHaveBeenCalledWith('host-id');
|
|
expect(callback).toHaveBeenCalledWith('otp-123');
|
|
});
|
|
});
|
|
|
|
describe('handleDisconnect', () => {
|
|
it('should remove all listeners', async () => {
|
|
await socketUser.handleDisconnect();
|
|
|
|
expect(socketUser.actionManager.removeAllListeners).toHaveBeenCalled();
|
|
expect(socketUser.eventManager.removeAllListeners).toHaveBeenCalled();
|
|
expect(socketUser.statsManager.removeAllListeners).toHaveBeenCalled();
|
|
expect(socketUser.notificationManager.removeAllListeners).toHaveBeenCalled();
|
|
});
|
|
});
|
|
});
|