UNPKG

matterbridge-roborock-vacuum-plugin

Version:
403 lines 21.5 kB
import { beforeEach, describe, expect, it, vi } from 'vitest'; import { CleanModeSetting } from '../../../behaviors/roborock.vacuum/core/CleanModeSetting.js'; import { CleanSequenceType } from '../../../behaviors/roborock.vacuum/enums/CleanSequenceType.js'; import { MapInfo, RoomIndexMap } from '../../../core/application/models/index.js'; import { RoborockService } from '../../../services/roborockService.js'; import { asPartial, asType } from '../../testUtils.js'; describe('RoborockService - Complete Coverage', () => { let service; let mockLogger; let mockContainer; let mockAuthCoordinator; let mockDeviceService; let mockAreaService; let mockMessageService; let mockPollingService; let mockConnectionService; let mockPersist; let mockConfigManager; beforeEach(() => { mockLogger = { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn(), notice: vi.fn(), }; mockAuthCoordinator = asPartial({ authenticate: vi.fn(), }); mockDeviceService = asPartial({ listDevices: vi.fn(), getHomeDataForUpdating: vi.fn(), }); mockAreaService = asPartial({ setSelectedAreas: vi.fn(), getSelectedAreas: vi.fn().mockReturnValue([]), setSupportedAreas: vi.fn(), setSupportedAreaIndexMap: vi.fn(), setSupportedRoutines: vi.fn(), getSupportedAreas: vi.fn().mockReturnValue([]), getSupportedAreasIndexMap: vi.fn(), getSupportedRoutines: vi.fn().mockReturnValue([]), getMapInfo: vi.fn(), getRoomMap: vi.fn(), getScenes: vi.fn(), startScene: vi.fn(), }); mockMessageService = asPartial({ getCleanModeData: vi.fn(), getRoomIdFromMap: vi.fn(), changeCleanMode: vi.fn(), startClean: vi.fn(), pauseClean: vi.fn(), stopAndGoHome: vi.fn(), resumeClean: vi.fn(), stopClean: vi.fn(), playSoundToLocate: vi.fn(), customGet: vi.fn(), customSend: vi.fn(), getSerialNumber: vi.fn().mockResolvedValue('SN-1234'), }); mockPollingService = { activateDeviceNotifyOverLocal: vi.fn(), requestStatusOnce: vi.fn().mockResolvedValue(undefined), }; mockConnectionService = asPartial({ initializeMessageClient: vi.fn(), initializeMessageClientForLocal: vi.fn().mockResolvedValue(true), setDeviceNotify: vi.fn(), sendTestEmailNotification: vi.fn().mockResolvedValue(undefined), }); mockContainer = asPartial({ getAuthenticationCoordinator: vi.fn().mockReturnValue(mockAuthCoordinator), getDeviceManagementService: vi.fn().mockReturnValue(mockDeviceService), getAreaManagementService: vi.fn().mockReturnValue(mockAreaService), getMessageRoutingService: vi.fn().mockReturnValue(mockMessageService), getPollingService: vi.fn().mockReturnValue(mockPollingService), getConnectionService: vi.fn().mockReturnValue(mockConnectionService), setUserData: vi.fn(), getIotApi: vi.fn(), synchronizeMessageClients: vi.fn(), destroy: vi.fn(), }); mockPersist = { init: vi.fn().mockResolvedValue(undefined), getItem: vi.fn().mockResolvedValue(undefined), setItem: vi.fn().mockResolvedValue(undefined), }; mockConfigManager = { username: 'testuser', password: 'testpass', verificationCode: undefined, authenticationMethod: 'Password', }; service = new RoborockService({ refreshInterval: 10, baseUrl: 'https://api.roborock.com', persist: mockPersist, configManager: mockConfigManager, container: mockContainer, toastMessage: vi.fn(), }, mockLogger, mockConfigManager); }); describe('Authentication', () => { it('should throw error when configManager is not provided', async () => { const serviceWithoutConfig = new RoborockService({ refreshInterval: 10, baseUrl: 'https://api.roborock.com', persist: mockPersist, configManager: mockConfigManager, container: mockContainer, toastMessage: vi.fn(), }, mockLogger, undefined); await expect(serviceWithoutConfig.authenticate()).rejects.toThrow('PlatformConfigManager not provided. Cannot authenticate.'); }); it('should log password as masked when provided', async () => { vi.mocked(mockAuthCoordinator.authenticate).mockResolvedValue({ nickname: 'Test', username: 'test', }); await service.authenticate(); expect(mockLogger.debug).toHaveBeenCalledWith(expect.stringContaining('******')); }); it('should log verification code as masked when provided', async () => { mockConfigManager.verificationCode = '123456'; vi.mocked(mockAuthCoordinator.authenticate).mockResolvedValue({ nickname: 'Test', username: 'test', }); await service.authenticate(); expect(mockLogger.debug).toHaveBeenCalledWith(expect.stringContaining('******')); }); it('should log success message with user nickname and username', async () => { const userData = { nickname: 'TestUser', username: 'test@example.com' }; vi.mocked(mockAuthCoordinator.authenticate).mockResolvedValue(userData); await service.authenticate(); expect(mockLogger.info).toHaveBeenCalledWith('Authentication successful for user: TestUser (test@example.com)'); }); it('should call setUserData on container when authentication succeeds', async () => { const userData = { nickname: 'Test', username: 'test' }; vi.mocked(mockAuthCoordinator.authenticate).mockResolvedValue(userData); await service.authenticate(); expect(mockContainer.setUserData).toHaveBeenCalledWith(userData); }); }); describe('Device Management', () => { it('should delegate listDevices to deviceService', async () => { const devices = [{ duid: 'test-device' }]; vi.mocked(mockDeviceService.listDevices).mockResolvedValue(devices); const result = await service.listDevices(); expect(result).toEqual(devices); expect(mockDeviceService.listDevices).toHaveBeenCalled(); }); it('should delegate getHomeDataForUpdating to deviceService', async () => { const homeData = { id: 123, name: 'Test Home' }; vi.mocked(mockDeviceService.getHomeDataForUpdating).mockResolvedValue(asPartial(homeData)); const result = await service.getHomeDataForUpdating(123); expect(result).toEqual(homeData); expect(mockDeviceService.getHomeDataForUpdating).toHaveBeenCalledWith(123); }); it('should initialize message client and synchronize', async () => { const device = { duid: 'test' }; const userData = { username: 'test' }; await service.initializeMessageClient(device, userData); expect(mockConnectionService.initializeMessageClient).toHaveBeenCalledWith(device, userData); expect(mockContainer.synchronizeMessageClients).toHaveBeenCalled(); }); it('should initialize local message client and synchronize', async () => { const device = { duid: 'test' }; vi.mocked(mockConnectionService.initializeMessageClientForLocal).mockResolvedValue(true); const result = await service.initializeMessageClientForLocal(device); expect(result).toBe(true); expect(mockConnectionService.initializeMessageClientForLocal).toHaveBeenCalledWith(device); expect(mockContainer.synchronizeMessageClients).toHaveBeenCalled(); }); it('should handle local message client initialization failure', async () => { const device = { duid: 'test' }; vi.mocked(mockConnectionService.initializeMessageClientForLocal).mockResolvedValue(false); const result = await service.initializeMessageClientForLocal(device); expect(result).toBe(false); expect(mockContainer.synchronizeMessageClients).toHaveBeenCalled(); }); it('should set device notify callback on both polling and connection services', () => { const callback = vi.fn(); service.setDeviceNotify(callback); expect(service.deviceNotify).toBe(callback); expect(mockConnectionService.setDeviceNotify).toHaveBeenCalledWith(callback); }); it('should activate device notify for local network', () => { const device = { duid: 'test' }; service.activateDeviceNotify(device); expect(mockPollingService.activateDeviceNotifyOverLocal).toHaveBeenCalledWith(device); }); it('should destroy container when stopping service', () => { service.stopService(); expect(mockContainer.destroy).toHaveBeenCalled(); }); }); describe('Area Management', () => { it('should delegate setSelectedAreas to areaService', () => { service.setSelectedAreas('duid', [1, 2, 3]); expect(mockAreaService.setSelectedAreas).toHaveBeenCalledWith('duid', [1, 2, 3]); }); it('should delegate getSelectedAreas to areaService', () => { vi.mocked(mockAreaService.getSelectedAreas).mockReturnValue([1, 2]); const result = service.getSelectedAreas('duid'); expect(result).toEqual([1, 2]); expect(mockAreaService.getSelectedAreas).toHaveBeenCalledWith('duid'); }); it('should delegate setSupportedAreas to areaService', () => { const areas = [asPartial({ areaId: 1 })]; service.setSupportedAreas('duid', areas); expect(mockAreaService.setSupportedAreas).toHaveBeenCalledWith('duid', areas); }); it('should delegate setSupportedAreaIndexMap to areaService', () => { const indexMap = new RoomIndexMap(new Map(), new Map()); service.setSupportedAreaIndexMap('duid', indexMap); expect(mockAreaService.setSupportedAreaIndexMap).toHaveBeenCalledWith('duid', indexMap); }); it('should delegate setSupportedScenes to areaService', () => { const scenes = [asPartial({ areaId: 1 })]; service.setSupportedRoutines('duid', scenes); expect(mockAreaService.setSupportedRoutines).toHaveBeenCalledWith('duid', scenes); }); it('should delegate getSupportedAreas to areaService', () => { const areas = [asPartial({ areaId: 1 })]; vi.mocked(mockAreaService.getSupportedAreas).mockReturnValue(areas); const result = service.getSupportedAreas('duid'); expect(result).toEqual(areas); expect(mockAreaService.getSupportedAreas).toHaveBeenCalledWith('duid'); }); it('should delegate getSupportedAreasIndexMap to areaService', () => { const indexMap = new RoomIndexMap(new Map(), new Map()); vi.mocked(mockAreaService.getSupportedAreasIndexMap).mockReturnValue(indexMap); const result = service.getSupportedAreasIndexMap('duid'); expect(result).toEqual(indexMap); expect(mockAreaService.getSupportedAreasIndexMap).toHaveBeenCalledWith('duid'); }); it('should return undefined when getSupportedAreasIndexMap has no data', () => { vi.mocked(mockAreaService.getSupportedAreasIndexMap).mockReturnValue(undefined); const result = service.getSupportedAreasIndexMap('duid'); expect(result).toBeUndefined(); }); it('should delegate getMapInfo to areaService', async () => { const mapInfo = MapInfo.empty(); vi.mocked(mockAreaService.getMapInfo).mockResolvedValue(mapInfo); const result = await service.getMapInfo('duid'); expect(result).toEqual(mapInfo); expect(mockAreaService.getMapInfo).toHaveBeenCalledWith('duid'); }); it('should delegate getRoomMap to areaService', async () => { const roomMap = asPartial([]); vi.mocked(mockAreaService.getRoomMap).mockResolvedValue(roomMap); const result = await service.getRoomMap('duid', 1); expect(result).toEqual(roomMap); expect(mockAreaService.getRoomMap).toHaveBeenCalledWith('duid', 1); }); it('should delegate getScenes to areaService', async () => { const scenes = [{ id: 1, name: 'Scene 1' }]; vi.mocked(mockAreaService.getScenes).mockResolvedValue(scenes); const result = await service.getScenes(123); expect(result).toEqual(scenes); expect(mockAreaService.getScenes).toHaveBeenCalledWith(123); }); it('should return undefined when getScenes has no data', async () => { vi.mocked(mockAreaService.getScenes).mockResolvedValue(undefined); const result = await service.getScenes(123); expect(result).toBeUndefined(); }); it('should delegate startScene to areaService', async () => { vi.mocked(mockAreaService.startScene).mockResolvedValue({ success: true }); const result = await service.startScene(1); expect(result).toEqual({ success: true }); expect(mockAreaService.startScene).toHaveBeenCalledWith(1); }); }); describe('Message Routing', () => { it('should delegate getCleanModeData to messageService', async () => { const cleanMode = new CleanModeSetting(100, 200, 25, 300, CleanSequenceType.Persist); vi.mocked(mockMessageService.getCleanModeData).mockResolvedValue(cleanMode); const result = await service.getCleanModeData('duid'); expect(result).toEqual(cleanMode); expect(mockMessageService.getCleanModeData).toHaveBeenCalledWith('duid'); }); it('should delegate getRoomIdFromMap to messageService', async () => { vi.mocked(mockMessageService.getRoomIdFromMap).mockResolvedValue(5); const result = await service.getRoomIdFromMap('duid'); expect(result).toBe(5); expect(mockMessageService.getRoomIdFromMap).toHaveBeenCalledWith('duid'); }); it('should return undefined when getRoomIdFromMap has no data', async () => { vi.mocked(mockMessageService.getRoomIdFromMap).mockResolvedValue(undefined); const result = await service.getRoomIdFromMap('duid'); expect(result).toBeUndefined(); }); it('should delegate changeCleanMode to messageService', async () => { const settings = new CleanModeSetting(102, 203, 25, 300, CleanSequenceType.Persist); await service.changeCleanMode('duid', settings); expect(mockMessageService.changeCleanMode).toHaveBeenCalledWith('duid', settings); }); it('should handle startClean with empty supported areas', async () => { vi.mocked(mockAreaService.getSelectedAreas).mockReturnValue([1]); vi.mocked(mockAreaService.getSupportedAreas).mockReturnValue(asType(undefined)); vi.mocked(mockAreaService.getSupportedRoutines).mockReturnValue(asType(undefined)); await service.startClean('duid'); expect(mockMessageService.startClean).toHaveBeenCalledWith('duid', expect.objectContaining({ type: 'global' })); }); it('should delegate pauseClean to messageService', async () => { await service.pauseClean('duid'); expect(mockMessageService.pauseClean).toHaveBeenCalledWith('duid'); }); it('should delegate stopAndGoHome to messageService', async () => { await service.stopAndGoHome('duid'); expect(mockMessageService.stopAndGoHome).toHaveBeenCalledWith('duid'); }); it('should delegate resumeClean to messageService', async () => { await service.resumeClean('duid'); expect(mockMessageService.resumeClean).toHaveBeenCalledWith('duid'); }); it('should delegate stopClean to messageService', async () => { await service.stopClean('duid'); expect(mockMessageService.stopClean).toHaveBeenCalledWith('duid'); }); it('should delegate playSoundToLocate to messageService', async () => { await service.playSoundToLocate('duid'); expect(mockMessageService.playSoundToLocate).toHaveBeenCalledWith('duid'); }); it('should delegate customGet to messageService', async () => { const request = { method: 'get_status' }; const response = { state: 8 }; vi.mocked(mockMessageService.customGet).mockResolvedValue(response); const result = await service.customGet('duid', request); expect(result).toEqual(response); expect(mockMessageService.customGet).toHaveBeenCalledWith('duid', request); }); it('should delegate customSend to messageService', async () => { const request = { method: 'app_start' }; await service.customSend('duid', request); expect(mockMessageService.customSend).toHaveBeenCalledWith('duid', request); }); }); describe('Custom API', () => { it('should call iotApi.getCustom when initialized', async () => { const mockIotApi = { getCustom: vi.fn().mockResolvedValue({ result: 'success' }) }; vi.mocked(mockContainer.getIotApi).mockReturnValue(asPartial(mockIotApi)); const result = await service.getCustomAPI('/custom/endpoint'); expect(result).toEqual({ result: 'success' }); expect(mockIotApi.getCustom).toHaveBeenCalledWith('/custom/endpoint'); }); }); describe('Delegation methods', () => { it('should delegate listDevices to deviceService', async () => { const devices = [asPartial({ duid: 'd1' })]; vi.mocked(mockDeviceService.listDevices).mockResolvedValue(devices); const result = await service.listDevices(); expect(result).toBe(devices); expect(mockDeviceService.listDevices).toHaveBeenCalled(); }); it('should delegate getSerialNumber to messageRoutingService', async () => { const result = await service.getSerialNumber('d1'); expect(result).toBe('SN-1234'); expect(mockMessageService.getSerialNumber).toHaveBeenCalledWith('d1'); }); it('should delegate getHomeDataForUpdating to deviceService', async () => { const home = asPartial({ id: 1, name: 'Home' }); vi.mocked(mockDeviceService.getHomeDataForUpdating).mockResolvedValue(home); const result = await service.getHomeDataForUpdating(1); expect(result).toBe(home); expect(mockDeviceService.getHomeDataForUpdating).toHaveBeenCalledWith(1); }); it('should delegate initializeMessageClientForLocal to connectionService and synchronize', async () => { const device = asPartial({ duid: 'd1' }); const result = await service.initializeMessageClientForLocal(device); expect(result).toBe(true); expect(mockConnectionService.initializeMessageClientForLocal).toHaveBeenCalledWith(device); expect(mockContainer.synchronizeMessageClients).toHaveBeenCalled(); }); it('should delegate sendTestEmailNotification to connectionService', async () => { await service.sendTestEmailNotification(); expect(mockConnectionService.sendTestEmailNotification).toHaveBeenCalled(); }); it('should delegate setDeviceNotify to pollingService and connectionService', () => { const callback = vi.fn(); service.setDeviceNotify(callback); expect(service.deviceNotify).toBe(callback); expect(mockConnectionService.setDeviceNotify).toHaveBeenCalledWith(callback); }); it('should delegate activateDeviceNotify to pollingService', () => { const device = asPartial({ duid: 'd1' }); service.activateDeviceNotify(device); expect(mockPollingService.activateDeviceNotifyOverLocal).toHaveBeenCalledWith(device); }); it('should delegate requestDeviceStatusOnce to pollingService', async () => { await service.requestDeviceStatusOnce('d1'); expect(mockPollingService.requestStatusOnce).toHaveBeenCalledWith('d1'); }); it('should delegate stopService to container.destroy', () => { service.stopService(); expect(mockContainer.destroy).toHaveBeenCalled(); }); }); }); //# sourceMappingURL=roborockService.coverage.test.js.map