UNPKG

matterbridge-roborock-vacuum-plugin

Version:
244 lines 10.6 kB
import { afterEach, 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 { Q7MessageDispatcher } from '../../../../roborockCommunication/protocol/dispatcher/Q7MessageDispatcher.js'; import { asPartial, asType } from '../../../testUtils.js'; // --- Mock Factories --- function createMockLogger() { return { notice: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn(), }; } function createMockClient() { return { send: vi.fn().mockResolvedValue(undefined), get: vi.fn().mockResolvedValue(undefined), isConnected: vi.fn().mockReturnValue(true), connect: vi.fn(), disconnect: vi.fn(), registerConnectionListener: vi.fn(), registerMessageListener: vi.fn(), }; } // --- Test Suite --- describe('Q7MessageDispatcher', () => { let logger; let client; let dispatcher; const duid = 'test-duid'; beforeEach(() => { logger = createMockLogger(); client = createMockClient(); dispatcher = new Q7MessageDispatcher(asType(logger), asType(client)); }); afterEach(() => { vi.clearAllMocks(); vi.clearAllTimers(); vi.useRealTimers(); }); describe('getNetworkInfo', () => { it('should return undefined', async () => { const result = await dispatcher.getNetworkInfo(duid); expect(result).toBeUndefined(); }); }); describe('getSerialNumber', () => { it('should return the duid as serial number', async () => { const result = await dispatcher.getSerialNumber(duid); expect(result).toBe(duid); }); }); describe('getDeviceStatus', () => { it('should return undefined', async () => { const result = await dispatcher.getDeviceStatus(duid); expect(result).toBeUndefined(); }); }); describe('getHomeMap', () => { it('should return an empty object', async () => { const result = await dispatcher.getHomeMap(duid); expect(result).toEqual({}); }); }); describe('getMapInfo', () => { it('should call client.get and logger.notice, return MapInfo', async () => { client.get.mockResolvedValueOnce({}); const result = await dispatcher.getMapInfo(duid); expect(client.get).toHaveBeenCalled(); expect(logger.notice).toHaveBeenCalled(); expect(result).toBeInstanceOf(Object); // MapInfo, but type is not checked at runtime }); }); describe('getRoomMap', () => { it('should return empty array when response is undefined', async () => { client.get.mockResolvedValueOnce(undefined); const result = await dispatcher.getRoomMap(duid, 1); expect(client.get).toHaveBeenCalled(); expect(result).toEqual([]); }); it('should call client.get and return room mapping data', async () => { const mockRoomData = [ [1, 'Living Room', 0], [2, 'Kitchen', 1], ]; client.get.mockResolvedValueOnce(mockRoomData); const result = await dispatcher.getRoomMap(duid, 1); expect(client.get).toHaveBeenCalled(); expect(result).toEqual(mockRoomData); }); }); describe('goHome', () => { it('should send a charge command', async () => { await dispatcher.goHome(duid); expect(client.send).toHaveBeenCalled(); }); }); describe('startCleaning', () => { it('should call startRoomCleaning with empty roomIds and repeat 1', async () => { const spy = vi.spyOn(dispatcher, 'startRoomCleaning').mockResolvedValue(undefined); await dispatcher.startCleaning(duid); expect(spy).toHaveBeenCalledWith(duid, [], 1); }); }); describe('startRoomCleaning', () => { it('should send a start room cleaning command', async () => { await dispatcher.startRoomCleaning(duid, [1, 2], 2); expect(client.send).toHaveBeenCalled(); }); }); describe('pauseCleaning', () => { it('should send a pause command', async () => { await dispatcher.pauseCleaning(duid); expect(client.send).toHaveBeenCalled(); }); }); describe('resumeCleaning', () => { it('should call startCleaning', async () => { const spy = vi.spyOn(dispatcher, 'startCleaning').mockResolvedValue(undefined); await dispatcher.resumeCleaning(duid); expect(spy).toHaveBeenCalledWith(duid); }); }); describe('resumeRoomCleaning', () => { it('should call startRoomCleaning with empty roomIds and repeat 1', async () => { const spy = vi.spyOn(dispatcher, 'startRoomCleaning').mockResolvedValue(undefined); await dispatcher.resumeRoomCleaning(duid); expect(spy).toHaveBeenCalledWith(duid, [], 1); }); }); describe('stopCleaning', () => { it('should send a stop command', async () => { await dispatcher.stopCleaning(duid); expect(client.send).toHaveBeenCalled(); }); }); describe('findMyRobot', () => { it('should send a find_me command', async () => { await dispatcher.findMyRobot(duid); expect(client.send).toHaveBeenCalled(); }); }); describe('sendCustomMessage', () => { it('should send a custom message', async () => { const def = asPartial({ toLocalRequest: vi.fn(), secure: false, isForProtocol: vi.fn(), version: '1.0', method: 'custom', }); await dispatcher.sendCustomMessage(duid, def); expect(client.send).toHaveBeenCalled(); }); }); describe('getCustomMessage', () => { it('should get a custom message', async () => { const def = asPartial({ dps: { foo: 'bar' } }); await dispatcher.getCustomMessage(duid, def); expect(client.get).toHaveBeenCalled(); }); }); describe('getCleanModeData', () => { it('should return a CleanModeSetting object', async () => { const result = await dispatcher.getCleanModeData(duid); expect(result).toEqual({ suctionPower: 0, waterFlow: 0, mopRoute: 0, distance_off: 0, sequenceType: 0 }); }); }); describe('messageId', () => { it('should return monotonically increasing IDs', () => { const id1 = dispatcher['messageId']; const id2 = dispatcher['messageId']; expect(id2).toBeGreaterThan(id1); }); it('should increment when Date.now returns same value', () => { const fixedTime = Date.now(); vi.spyOn(Date, 'now').mockReturnValue(fixedTime); dispatcher['lastB01Id'] = fixedTime; const id = dispatcher['messageId']; expect(id).toBe(fixedTime + 1); vi.restoreAllMocks(); }); }); describe('changeCleanMode', () => { it('should call setCleanMode, setVacuumMode, setMopMode as needed', async () => { const setCleanMode = vi.fn(); const setVacuumMode = vi.fn(); const setMopMode = vi.fn(); dispatcher['setCleanMode'] = setCleanMode; dispatcher['setVacuumMode'] = setVacuumMode; dispatcher['setMopMode'] = setMopMode; const setting = new CleanModeSetting(1, 2, 4, 3, CleanSequenceType.Persist); await dispatcher.changeCleanMode(duid, setting); expect(setCleanMode).toHaveBeenCalledWith(duid, 1, 2); expect(setVacuumMode).toHaveBeenCalledWith(duid, 1); expect(setMopMode).toHaveBeenCalledWith(duid, 2); }); it('should not call setVacuumMode if suctionPower is 0', async () => { const setCleanMode = vi.fn(); const setVacuumMode = vi.fn(); const setMopMode = vi.fn(); dispatcher['setCleanMode'] = setCleanMode; dispatcher['setVacuumMode'] = setVacuumMode; dispatcher['setMopMode'] = setMopMode; const setting = new CleanModeSetting(0, 2, 4, 3, CleanSequenceType.Persist); await dispatcher.changeCleanMode(duid, setting); expect(setVacuumMode).not.toHaveBeenCalled(); expect(setMopMode).toHaveBeenCalledWith(duid, 2); }); it('should not call setMopMode if waterFlow is 0', async () => { const setCleanMode = vi.fn(); const setVacuumMode = vi.fn(); const setMopMode = vi.fn(); dispatcher['setCleanMode'] = setCleanMode; dispatcher['setVacuumMode'] = setVacuumMode; dispatcher['setMopMode'] = setMopMode; const setting = new CleanModeSetting(1, 0, 4, 3, CleanSequenceType.Persist); await dispatcher.changeCleanMode(duid, setting); expect(setVacuumMode).toHaveBeenCalledWith(duid, 1); expect(setMopMode).not.toHaveBeenCalled(); }); it('should call real private helpers and send commands via client', async () => { const setting = new CleanModeSetting(2, 3, 4, 1, CleanSequenceType.Persist); await dispatcher.changeCleanMode(duid, setting); // setCleanMode + setVacuumMode + setMopMode = 3 sends expect(client.send).toHaveBeenCalledTimes(3); expect(logger.notice).toHaveBeenCalledWith(expect.stringContaining('Change clean mode')); }); it('should only call setCleanMode when both suctionPower and waterFlow are 0', async () => { const setting = new CleanModeSetting(0, 0, 4, 1, CleanSequenceType.Persist); await dispatcher.changeCleanMode(duid, setting); expect(client.send).toHaveBeenCalledTimes(1); }); }); describe('setCleanRoute', () => { it('should send a set_prop command for clean_path_preference', async () => { await dispatcher.setCleanRoute(duid, 1); expect(client.send).toHaveBeenCalled(); }); }); }); //# sourceMappingURL=Q7MessageDispatcher.test.js.map