Allow camera engines to signal events to the card.

This commit is contained in:
Dermot Duffy
2024-03-03 15:40:20 -08:00
parent 305a2db573
commit 88bea0ae7d
61 changed files with 7480 additions and 4213 deletions
+105 -1
View File
@@ -1,8 +1,10 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { describe, expect, it } from 'vitest';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import {
getEntityIcon,
hasHAConnectionStateChanged,
parseStateChangeTrigger,
subscribeToTrigger,
} from '../../../src/utils/ha/index.js';
import { createHASS, createStateEntity } from '../../test-utils.js';
@@ -67,3 +69,105 @@ describe('getEntityIcon', () => {
expect(getEntityIcon(createHASS(), 'camera.test')).toBe('mdi:video');
});
});
describe('should subscribe to trigger', () => {
it('mqtt', async () => {
const hass = createHASS();
const callback = vi.fn();
await subscribeToTrigger(hass, callback, {
platform: 'mqtt',
topic: 'topic',
payload: 'payload',
valueTemplate: 'value_template',
});
expect(hass.connection.subscribeMessage).toBeCalledWith(callback, {
type: 'subscribe_trigger',
trigger: {
platform: 'mqtt',
topic: 'topic',
payload: 'payload',
value_template: 'value_template',
},
});
});
it('state and attributes', async () => {
const hass = createHASS();
const callback = vi.fn();
await subscribeToTrigger(hass, callback, {
platform: 'state',
entityID: 'camera.foo',
});
expect(hass.connection.subscribeMessage).toBeCalledWith(callback, {
type: 'subscribe_trigger',
trigger: {
platform: 'state',
entity_id: 'camera.foo',
},
});
});
it('state only', async () => {
const hass = createHASS();
const callback = vi.fn();
await subscribeToTrigger(hass, callback, {
platform: 'state',
entityID: 'camera.foo',
stateOnly: true,
});
expect(hass.connection.subscribeMessage).toBeCalledWith(callback, {
type: 'subscribe_trigger',
trigger: {
platform: 'state',
entity_id: 'camera.foo',
from: null,
to: null,
},
});
});
});
describe('should parse state change response', () => {
beforeEach(() => {
vi.restoreAllMocks();
});
it('malformed response', async () => {
const consoleSpy = vi.spyOn(global.console, 'warn').mockReturnValue(undefined);
expect(parseStateChangeTrigger('INVALID')).toBeNull();
expect(consoleSpy).toBeCalledWith('Ignoring unparseable HA state change', 'INVALID');
});
it('valid response', async () => {
const consoleSpy = vi.spyOn(global.console, 'warn').mockReturnValue(undefined);
const stateChange = {
from_state: {
entity_id: 'camera.foo',
state: 'off',
},
to_state: {
entity_id: 'camera.foo',
state: 'on',
},
};
expect(
parseStateChangeTrigger({
variables: {
trigger: stateChange,
},
}),
).toEqual(stateChange);
expect(consoleSpy).not.toBeCalled();
});
});
+70
View File
@@ -202,6 +202,40 @@ describe('changeViewToRecentEventsForCameraAndDependents', () => {
);
});
it('should respect useCache', async () => {
const cameraManager = createCameraManager();
vi.mocked(cameraManager.getStore).mockReturnValue(
createStore([
{
cameraID: 'camera',
},
]),
);
vi.mocked(cameraManager.generateDefaultEventQueries).mockReturnValue([
{
type: QueryType.Event,
cameraIDs: new Set(['camera']),
},
]);
await changeViewToRecentEventsForCameraAndDependents(
createElementListenForView().element,
cameraManager,
{},
createView(),
{
useCache: false,
},
);
expect(vi.mocked(cameraManager.executeMediaQueries)).toBeCalledWith(
expect.anything(),
expect.objectContaining({
useCache: false,
}),
);
});
describe('should respect request for media type', () => {
it.each([
['snapshots' as const, 'hasSnapshot'],
@@ -463,6 +497,42 @@ describe('changeViewToRecentRecordingForCameraAndDependents', () => {
}),
);
});
it('should respect useCache', async () => {
const cameraManager = createCameraManager();
vi.mocked(cameraManager.getStore).mockReturnValue(
createStore([
{
cameraID: 'camera',
},
]),
);
vi.mocked(cameraManager.generateDefaultRecordingQueries).mockReturnValue([
{
type: QueryType.Recording,
cameraIDs: new Set(['camera']),
},
]);
await changeViewToRecentRecordingForCameraAndDependents(
createElementListenForView().element,
cameraManager,
{},
createView(),
{
targetView: 'recordings',
select: 'latest',
useCache: false,
},
);
expect(vi.mocked(cameraManager.executeMediaQueries)).toBeCalledWith(
expect.anything(),
expect.objectContaining({
useCache: false,
}),
);
});
});
// @vitest-environment jsdom