190 lines
5.4 KiB
TypeScript
190 lines
5.4 KiB
TypeScript
import add from 'date-fns/add';
|
|
import { HassEntities } from 'home-assistant-js-websocket';
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
import { CardController } from '../../src/card-controller/controller';
|
|
import { TriggersManager } from '../../src/card-controller/triggers-manager';
|
|
import { ScanOptions } from '../../src/config/types';
|
|
import {
|
|
createCameraConfig,
|
|
createCameraManager,
|
|
createCardAPI,
|
|
createConfig,
|
|
createHASS,
|
|
createStateEntity,
|
|
createStore,
|
|
createView,
|
|
} from '../test-utils';
|
|
|
|
// Creating and mocking a trigger API is a lot of boilerplate, this convenience
|
|
// function reduces it.
|
|
const createTriggerAPI = (options?: {
|
|
config?: Partial<ScanOptions>;
|
|
hassStates?: HassEntities;
|
|
interaction?: boolean;
|
|
}): CardController => {
|
|
const api = createCardAPI();
|
|
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(
|
|
createConfig({
|
|
view: {
|
|
scan: options?.config ?? {
|
|
enabled: true,
|
|
untrigger_reset: true,
|
|
untrigger_seconds: 10,
|
|
},
|
|
},
|
|
}),
|
|
);
|
|
vi.mocked(api.getHASSManager().getHASS).mockReturnValue(
|
|
createHASS(options?.hassStates),
|
|
);
|
|
vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager());
|
|
vi.mocked(api.getCameraManager().getStore).mockReturnValue(
|
|
createStore([
|
|
{
|
|
cameraID: 'camera_1',
|
|
config: createCameraConfig({
|
|
triggers: {
|
|
entities: ['binary_sensor.motion'],
|
|
},
|
|
}),
|
|
},
|
|
]),
|
|
);
|
|
vi.mocked(api.getInteractionManager().hasInteraction).mockReturnValue(
|
|
options?.interaction ?? false,
|
|
);
|
|
|
|
return api;
|
|
};
|
|
|
|
// @vitest-environment jsdom
|
|
describe('TriggersManager', () => {
|
|
const hassActiveState = {
|
|
'binary_sensor.motion': createStateEntity({ state: 'on' }),
|
|
};
|
|
const hassInactiveState = {
|
|
'binary_sensor.motion': createStateEntity({ state: 'off' }),
|
|
};
|
|
|
|
beforeEach(() => {
|
|
vi.resetAllMocks();
|
|
vi.useFakeTimers();
|
|
});
|
|
|
|
it('should not be triggered by default', () => {
|
|
const manager = new TriggersManager(createCardAPI());
|
|
expect(manager.isTriggered()).toBeFalsy();
|
|
});
|
|
|
|
it('should not trigger when scan mode disabled default', () => {
|
|
const api = createTriggerAPI({
|
|
config: { enabled: false },
|
|
hassStates: hassActiveState,
|
|
});
|
|
const manager = new TriggersManager(api);
|
|
|
|
manager.updateTriggeredCameras(null);
|
|
|
|
expect(manager.isTriggered()).toBeFalsy();
|
|
});
|
|
|
|
it('should trigger and untrigger based on entity state', () => {
|
|
const start = new Date('2023-10-01T17:14');
|
|
vi.setSystemTime(start);
|
|
const api = createTriggerAPI({
|
|
hassStates: hassActiveState,
|
|
});
|
|
const manager = new TriggersManager(api);
|
|
|
|
manager.updateTriggeredCameras(createHASS(hassInactiveState));
|
|
|
|
expect(manager.isTriggered()).toBeTruthy();
|
|
expect(api.getViewManager().setViewByParameters).toBeCalledWith({
|
|
viewName: 'live',
|
|
cameraID: 'camera_1',
|
|
});
|
|
|
|
vi.mocked(api.getHASSManager().getHASS).mockReturnValue(
|
|
createHASS(hassInactiveState),
|
|
);
|
|
|
|
manager.updateTriggeredCameras(createHASS(hassActiveState));
|
|
|
|
// Intentional state update with no change.
|
|
manager.updateTriggeredCameras(createHASS(hassActiveState));
|
|
|
|
// Will still be triggered, but untrigger timer will be running.
|
|
expect(manager.isTriggered()).toBeTruthy();
|
|
|
|
vi.setSystemTime(add(start, { seconds: 10 }));
|
|
vi.runOnlyPendingTimers();
|
|
|
|
expect(manager.isTriggered()).toBeFalsy();
|
|
expect(api.getViewManager().setViewDefault).toBeCalled();
|
|
});
|
|
|
|
it('should trigger and set view if current view is wrong', () => {
|
|
const api = createTriggerAPI({
|
|
hassStates: hassActiveState,
|
|
});
|
|
vi.mocked(api.getViewManager().getView).mockReturnValue(
|
|
createView({
|
|
// Correct camera, but wrong view.
|
|
view: 'clips',
|
|
camera: 'camera_1',
|
|
}),
|
|
);
|
|
const manager = new TriggersManager(api);
|
|
manager.updateTriggeredCameras(null);
|
|
|
|
expect(api.getViewManager().setViewByParameters).toBeCalledWith({
|
|
viewName: 'live',
|
|
cameraID: 'camera_1',
|
|
});
|
|
});
|
|
|
|
it('should trigger when entity state is active on startup', () => {
|
|
const api = createTriggerAPI({
|
|
hassStates: hassActiveState,
|
|
});
|
|
const manager = new TriggersManager(api);
|
|
expect(manager.isTriggered()).toBeFalsy();
|
|
|
|
manager.updateTriggeredCameras(null);
|
|
expect(manager.isTriggered()).toBeTruthy();
|
|
});
|
|
|
|
it('should untrigger manually', () => {
|
|
const api = createTriggerAPI({
|
|
hassStates: hassActiveState,
|
|
});
|
|
const manager = new TriggersManager(api);
|
|
|
|
// Untriggering when not triggered.
|
|
manager.untrigger();
|
|
expect(api.getViewManager().setViewDefault).not.toBeCalled();
|
|
|
|
manager.updateTriggeredCameras(null);
|
|
expect(manager.isTriggered()).toBeTruthy();
|
|
|
|
manager.untrigger();
|
|
expect(manager.isTriggered()).toBeFalsy();
|
|
expect(api.getViewManager().setViewDefault).toBeCalled();
|
|
});
|
|
|
|
it('should take no actions when automated actions are not allowed', () => {
|
|
const api = createTriggerAPI({
|
|
hassStates: hassActiveState,
|
|
// Interaction present.
|
|
interaction: true,
|
|
});
|
|
const manager = new TriggersManager(api);
|
|
manager.updateTriggeredCameras(null);
|
|
expect(manager.isTriggered()).toBeTruthy();
|
|
expect(api.getViewManager().setViewByParameters).not.toBeCalled();
|
|
|
|
manager.untrigger();
|
|
expect(api.getViewManager().setViewDefault).not.toBeCalled();
|
|
});
|
|
});
|