Add out-of-the-box Frigate PTZ support.
This commit is contained in:
+53
-50
@@ -4,7 +4,11 @@ import { mock } from 'vitest-mock-extended';
|
||||
import { actionSchema } from '../../src/config/types';
|
||||
import {
|
||||
convertActionToFrigateCardCustomAction,
|
||||
createFrigateCardCustomAction,
|
||||
createFrigateCardCameraAction,
|
||||
createFrigateCardDisplayModeAction,
|
||||
createFrigateCardMediaPlayerAction,
|
||||
createFrigateCardShowPTZAction,
|
||||
createFrigateCardSimpleAction,
|
||||
frigateCardHandleAction,
|
||||
frigateCardHandleActionConfig,
|
||||
frigateCardHasAction,
|
||||
@@ -37,13 +41,24 @@ describe('convertActionToFrigateCardCustomAction', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('createFrigateCardCustomAction', () => {
|
||||
it('should create camera_select', () => {
|
||||
describe('createFrigateCardSimpleAction', () => {
|
||||
it('should create general action', () => {
|
||||
expect(
|
||||
createFrigateCardCustomAction('camera_select', {
|
||||
camera: 'camera',
|
||||
createFrigateCardSimpleAction('clips', {
|
||||
cardID: 'card_id',
|
||||
}),
|
||||
).toEqual({
|
||||
action: 'fire-dom-event',
|
||||
frigate_card_action: 'clips',
|
||||
card_id: 'card_id',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('createFrigateCardCameraAction', () => {
|
||||
it('should create camera_select', () => {
|
||||
expect(
|
||||
createFrigateCardCameraAction('camera_select', 'camera', { cardID: 'card_id' }),
|
||||
).toEqual({
|
||||
action: 'fire-dom-event',
|
||||
camera: 'camera',
|
||||
@@ -51,16 +66,12 @@ describe('createFrigateCardCustomAction', () => {
|
||||
card_id: 'card_id',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should not create camera_select without camera', () => {
|
||||
expect(createFrigateCardCustomAction('camera_select')).toBeNull();
|
||||
});
|
||||
|
||||
describe('createFrigateCardMediaPlayerAction', () => {
|
||||
it('should create media_player', () => {
|
||||
expect(
|
||||
createFrigateCardCustomAction('media_player', {
|
||||
media_player: 'device',
|
||||
media_player_action: 'play',
|
||||
createFrigateCardMediaPlayerAction('device', 'play', {
|
||||
cardID: 'card_id',
|
||||
}),
|
||||
).toEqual({
|
||||
@@ -71,37 +82,12 @@ describe('createFrigateCardCustomAction', () => {
|
||||
card_id: 'card_id',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should not create media_player without player or action', () => {
|
||||
expect(
|
||||
createFrigateCardCustomAction('media_player', {
|
||||
media_player_action: 'play',
|
||||
}),
|
||||
).toBeNull();
|
||||
|
||||
expect(
|
||||
createFrigateCardCustomAction('media_player', {
|
||||
media_player: 'device',
|
||||
}),
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
it('should create general action', () => {
|
||||
expect(
|
||||
createFrigateCardCustomAction('clips', {
|
||||
cardID: 'card_id',
|
||||
}),
|
||||
).toEqual({
|
||||
action: 'fire-dom-event',
|
||||
frigate_card_action: 'clips',
|
||||
card_id: 'card_id',
|
||||
});
|
||||
});
|
||||
|
||||
describe('createFrigateCardDisplayModeAction', () => {
|
||||
it('should create display mode action', () => {
|
||||
expect(
|
||||
createFrigateCardCustomAction('display_mode_select', {
|
||||
display_mode: 'grid',
|
||||
createFrigateCardDisplayModeAction('grid', {
|
||||
cardID: 'card_id',
|
||||
}),
|
||||
).toEqual({
|
||||
@@ -111,9 +97,20 @@ describe('createFrigateCardCustomAction', () => {
|
||||
card_id: 'card_id',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should not create display mode action without display mode', () => {
|
||||
expect(createFrigateCardCustomAction('display_mode_select')).toBeNull();
|
||||
describe('createFrigateCardShowPTZAction', () => {
|
||||
it('should create show PTZ action', () => {
|
||||
expect(
|
||||
createFrigateCardShowPTZAction(true, {
|
||||
cardID: 'card_id',
|
||||
}),
|
||||
).toEqual({
|
||||
action: 'fire-dom-event',
|
||||
frigate_card_action: 'show_ptz',
|
||||
show_ptz: true,
|
||||
card_id: 'card_id',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -124,13 +121,13 @@ describe('getActionConfigGivenAction', () => {
|
||||
});
|
||||
|
||||
it('should not handle undefined arguments', () => {
|
||||
expect(getActionConfigGivenAction()).toBeUndefined();
|
||||
expect(getActionConfigGivenAction()).toBeNull();
|
||||
});
|
||||
|
||||
it('should not handle unknown interactions', () => {
|
||||
expect(
|
||||
getActionConfigGivenAction('triple_poke', { triple_poke_action: action }),
|
||||
).toBeUndefined();
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
it('should handle tap actions', () => {
|
||||
@@ -178,17 +175,23 @@ describe('frigateCardHandleActionConfig', () => {
|
||||
});
|
||||
|
||||
it('should handle simple case', () => {
|
||||
frigateCardHandleActionConfig(element, createHASS(), {}, 'tap', action);
|
||||
const hass = createHASS();
|
||||
frigateCardHandleActionConfig(element, hass, {}, 'tap', action);
|
||||
expect(handleActionConfig).toBeCalled();
|
||||
expect(handleActionConfig).toBeCalledWith(element, hass, {}, action);
|
||||
});
|
||||
|
||||
it('should handle array case', () => {
|
||||
frigateCardHandleActionConfig(element, createHASS(), {}, 'tap', [
|
||||
action,
|
||||
action,
|
||||
action,
|
||||
]);
|
||||
const hass = createHASS();
|
||||
frigateCardHandleActionConfig(element, hass, {}, 'tap', [action, action, action]);
|
||||
expect(handleActionConfig).toBeCalledTimes(3);
|
||||
expect(handleActionConfig).toBeCalledWith(element, hass, {}, action);
|
||||
});
|
||||
|
||||
it('should handle null case', () => {
|
||||
const hass = createHASS();
|
||||
frigateCardHandleActionConfig(element, hass, {}, 'tap', null);
|
||||
expect(handleActionConfig).toBeCalledWith(element, hass, {}, undefined);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
import { CameraManager } from '../../src/camera-manager/manager.js';
|
||||
import { CameraConfigs } from '../../src/camera-manager/types.js';
|
||||
import { getAllDependentCameras, getCameraID } from '../../src/utils/camera.js';
|
||||
import { createCameraConfig, createCameraManager } from '../test-utils.js';
|
||||
|
||||
vi.mock('../../src/camera-manager/manager.js');
|
||||
import { getCameraID } from '../../src/utils/camera.js';
|
||||
import { createCameraConfig } from '../test-utils.js';
|
||||
|
||||
describe('getCameraID', () => {
|
||||
it('should get camera id with id', () => {
|
||||
@@ -25,7 +20,9 @@ describe('getCameraID', () => {
|
||||
expect(getCameraID(config)).toBe('foo');
|
||||
});
|
||||
it('should get camera id with go2rtc url and stream', () => {
|
||||
const config = createCameraConfig({ go2rtc: { url: 'https://foo', stream: 'office' } });
|
||||
const config = createCameraConfig({
|
||||
go2rtc: { url: 'https://foo', stream: 'office' },
|
||||
});
|
||||
expect(getCameraID(config)).toBe('https://foo#office');
|
||||
});
|
||||
it('should get camera id with frigate camera_name', () => {
|
||||
@@ -39,48 +36,3 @@ describe('getCameraID', () => {
|
||||
expect(getCameraID(config)).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getAllDependentCameras', () => {
|
||||
it('should return null without cameraManager', () => {
|
||||
expect(getAllDependentCameras()).toBeNull();
|
||||
});
|
||||
it('should return null without cameraID', () => {
|
||||
expect(getAllDependentCameras(mock<CameraManager>())).toBeNull();
|
||||
});
|
||||
it('should return dependent cameras', () => {
|
||||
const cameraConfigs: CameraConfigs = new Map([
|
||||
[
|
||||
'one',
|
||||
createCameraConfig({
|
||||
dependencies: {
|
||||
cameras: ['two', 'three'],
|
||||
},
|
||||
}),
|
||||
],
|
||||
['two', createCameraConfig({})],
|
||||
]);
|
||||
|
||||
const cameraManager = createCameraManager({ configs: cameraConfigs });
|
||||
expect(getAllDependentCameras(cameraManager, 'one')).toEqual(
|
||||
new Set(['one', 'two']),
|
||||
);
|
||||
});
|
||||
it('should return all cameras', () => {
|
||||
const cameraConfigs: CameraConfigs = new Map([
|
||||
[
|
||||
'one',
|
||||
createCameraConfig({
|
||||
dependencies: {
|
||||
all_cameras: true,
|
||||
},
|
||||
}),
|
||||
],
|
||||
['two', createCameraConfig({})],
|
||||
]);
|
||||
|
||||
const cameraManager = createCameraManager({ configs: cameraConfigs });
|
||||
expect(getAllDependentCameras(cameraManager, 'one')).toEqual(
|
||||
new Set(['one', 'two']),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,7 +13,6 @@ vi.mock('../../package.json', () => ({
|
||||
gitDate: 'Wed, 6 Sep 2023 21:27:28 -0700',
|
||||
},
|
||||
}));
|
||||
vi.mock('../../src/camera-manager/manager.js');
|
||||
vi.mock('../../src/utils/ha');
|
||||
vi.mock('../../src/localize/localize.js');
|
||||
vi.mock('../../src/utils/ha/device-registry');
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
import { CameraManager } from '../../src/camera-manager/manager.js';
|
||||
import { downloadMedia, downloadURL } from '../../src/utils/download';
|
||||
import { homeAssistantSignPath } from '../../src/utils/ha';
|
||||
import { ViewMedia } from '../../src/view/media';
|
||||
import { createCameraManager, createHASS } from '../test-utils';
|
||||
|
||||
vi.mock('../../src/camera-manager/manager.js');
|
||||
vi.mock('../../src/utils/ha');
|
||||
|
||||
const media = new ViewMedia('clip', 'camera-1');
|
||||
@@ -73,7 +71,7 @@ describe('downloadMedia', () => {
|
||||
|
||||
it('should throw error when no media', () => {
|
||||
const cameraManager = createCameraManager();
|
||||
mock<CameraManager>(cameraManager).getMediaDownloadPath.mockResolvedValue(null);
|
||||
vi.mocked(cameraManager.getMediaDownloadPath).mockResolvedValue(null);
|
||||
|
||||
expect(downloadMedia(createHASS(), cameraManager, media)).rejects.toThrow(
|
||||
/No media to download/,
|
||||
@@ -84,7 +82,7 @@ describe('downloadMedia', () => {
|
||||
vi.spyOn(global.console, 'warn').mockReturnValue(undefined);
|
||||
|
||||
const cameraManager = createCameraManager();
|
||||
mock<CameraManager>(cameraManager).getMediaDownloadPath.mockResolvedValue({
|
||||
vi.mocked(cameraManager).getMediaDownloadPath.mockResolvedValue({
|
||||
sign: true,
|
||||
endpoint: 'foo',
|
||||
});
|
||||
@@ -98,7 +96,7 @@ describe('downloadMedia', () => {
|
||||
|
||||
it('should download media', async () => {
|
||||
const cameraManager = createCameraManager();
|
||||
mock<CameraManager>(cameraManager).getMediaDownloadPath.mockResolvedValue({
|
||||
vi.mocked(cameraManager).getMediaDownloadPath.mockResolvedValue({
|
||||
sign: true,
|
||||
endpoint: 'foo',
|
||||
});
|
||||
@@ -111,7 +109,7 @@ describe('downloadMedia', () => {
|
||||
|
||||
it('should download media without signing', async () => {
|
||||
const cameraManager = createCameraManager();
|
||||
mock<CameraManager>(cameraManager).getMediaDownloadPath.mockResolvedValue({
|
||||
vi.mocked(cameraManager).getMediaDownloadPath.mockResolvedValue({
|
||||
sign: false,
|
||||
endpoint: 'https://foo/',
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import add from 'date-fns/add';
|
||||
import sub from 'date-fns/sub';
|
||||
import { beforeEach, describe, expect, it, Mock, vi } from 'vitest';
|
||||
import { CameraConfigs } from '../../src/camera-manager/types';
|
||||
import { QueryType } from '../../src/camera-manager/types';
|
||||
import {
|
||||
changeViewToRecentEventsForCameraAndDependents,
|
||||
changeViewToRecentRecordingForCameraAndDependents,
|
||||
@@ -14,12 +14,11 @@ import { EventMediaQueries } from '../../src/view/media-queries';
|
||||
import {
|
||||
createCameraManager,
|
||||
createPerformanceConfig,
|
||||
createStore,
|
||||
createView,
|
||||
TestViewMedia,
|
||||
} from '../test-utils';
|
||||
|
||||
vi.mock('../../src/camera-manager/manager.js');
|
||||
|
||||
const createElementListenForView = (): {
|
||||
element: HTMLElement;
|
||||
viewHandler: Mock<any, any>;
|
||||
@@ -66,11 +65,10 @@ describe('changeViewToRecentEventsForCameraAndDependents', () => {
|
||||
|
||||
it('should do nothing without camera config for selected camera', async () => {
|
||||
const elementHandler = createElementListenForView();
|
||||
const cameraManager = createCameraManager({ configs: new Map() });
|
||||
|
||||
await changeViewToRecentEventsForCameraAndDependents(
|
||||
elementHandler.element,
|
||||
cameraManager,
|
||||
createCameraManager(),
|
||||
{},
|
||||
createView(),
|
||||
);
|
||||
@@ -79,11 +77,10 @@ describe('changeViewToRecentEventsForCameraAndDependents', () => {
|
||||
|
||||
it('should do nothing without camera configs for all cameras', async () => {
|
||||
const elementHandler = createElementListenForView();
|
||||
const cameraManager = createCameraManager({ configs: new Map() });
|
||||
|
||||
await changeViewToRecentEventsForCameraAndDependents(
|
||||
elementHandler.element,
|
||||
cameraManager,
|
||||
createCameraManager(),
|
||||
{},
|
||||
createView(),
|
||||
{
|
||||
@@ -113,6 +110,19 @@ describe('changeViewToRecentEventsForCameraAndDependents', () => {
|
||||
it('should dispatch new view on success', async () => {
|
||||
const elementHandler = createElementListenForView();
|
||||
const cameraManager = createCameraManager();
|
||||
vi.mocked(cameraManager.getStore).mockReturnValue(
|
||||
createStore([
|
||||
{
|
||||
cameraID: 'camera',
|
||||
},
|
||||
]),
|
||||
);
|
||||
vi.mocked(cameraManager.generateDefaultEventQueries).mockReturnValue([
|
||||
{
|
||||
type: QueryType.Event,
|
||||
cameraIDs: new Set(['camera']),
|
||||
},
|
||||
]);
|
||||
|
||||
const mediaArray = [new ViewMedia('clip', 'camera')];
|
||||
vi.mocked(cameraManager.executeMediaQueries).mockResolvedValue(mediaArray);
|
||||
@@ -136,6 +146,19 @@ describe('changeViewToRecentEventsForCameraAndDependents', () => {
|
||||
|
||||
const elementHandler = createElementListenForView();
|
||||
const cameraManager = createCameraManager();
|
||||
vi.mocked(cameraManager.getStore).mockReturnValue(
|
||||
createStore([
|
||||
{
|
||||
cameraID: 'camera',
|
||||
},
|
||||
]),
|
||||
);
|
||||
vi.mocked(cameraManager.generateDefaultEventQueries).mockReturnValue([
|
||||
{
|
||||
type: QueryType.Event,
|
||||
cameraIDs: new Set(['camera']),
|
||||
},
|
||||
]);
|
||||
vi.mocked(cameraManager.executeMediaQueries).mockRejectedValue(new Error());
|
||||
|
||||
await changeViewToRecentEventsForCameraAndDependents(
|
||||
@@ -150,6 +173,13 @@ describe('changeViewToRecentEventsForCameraAndDependents', () => {
|
||||
|
||||
it('should respect media chunk size', async () => {
|
||||
const cameraManager = createCameraManager();
|
||||
vi.mocked(cameraManager.getStore).mockReturnValue(
|
||||
createStore([
|
||||
{
|
||||
cameraID: 'camera',
|
||||
},
|
||||
]),
|
||||
);
|
||||
|
||||
await changeViewToRecentEventsForCameraAndDependents(
|
||||
createElementListenForView().element,
|
||||
@@ -178,6 +208,13 @@ describe('changeViewToRecentEventsForCameraAndDependents', () => {
|
||||
['clips' as const, 'hasClip'],
|
||||
])('%s', async (mediaType, queryParameter) => {
|
||||
const cameraManager = createCameraManager();
|
||||
vi.mocked(cameraManager.getStore).mockReturnValue(
|
||||
createStore([
|
||||
{
|
||||
cameraID: 'camera',
|
||||
},
|
||||
]),
|
||||
);
|
||||
|
||||
await changeViewToRecentEventsForCameraAndDependents(
|
||||
createElementListenForView().element,
|
||||
@@ -206,12 +243,9 @@ describe('executeMediaQueryForView', () => {
|
||||
});
|
||||
|
||||
it('should not execute empty queries', async () => {
|
||||
const cameraConfigs: CameraConfigs = new Map();
|
||||
const cameraManager = createCameraManager({ configs: cameraConfigs });
|
||||
|
||||
expect(
|
||||
await executeMediaQueryForView(
|
||||
cameraManager,
|
||||
createCameraManager(),
|
||||
createView(),
|
||||
new EventMediaQueries(),
|
||||
),
|
||||
@@ -219,24 +253,25 @@ describe('executeMediaQueryForView', () => {
|
||||
});
|
||||
|
||||
it('should throw on failure', async () => {
|
||||
const cameraConfigs: CameraConfigs = new Map();
|
||||
const cameraManager = createCameraManager({ configs: cameraConfigs });
|
||||
const cameraManager = createCameraManager();
|
||||
vi.mocked(cameraManager.executeMediaQueries).mockRejectedValue(new Error());
|
||||
|
||||
await expect(
|
||||
executeMediaQueryForView(
|
||||
cameraManager,
|
||||
createView(),
|
||||
new EventMediaQueries(
|
||||
cameraManager.generateDefaultEventQueries('camera') ?? undefined,
|
||||
),
|
||||
new EventMediaQueries([
|
||||
{
|
||||
type: QueryType.Event,
|
||||
cameraIDs: new Set('camera'),
|
||||
},
|
||||
]),
|
||||
),
|
||||
).rejects.toThrowError();
|
||||
});
|
||||
|
||||
it('should select time-based result', async () => {
|
||||
const cameraConfigs: CameraConfigs = new Map();
|
||||
const cameraManager = createCameraManager({ configs: cameraConfigs });
|
||||
const cameraManager = createCameraManager();
|
||||
|
||||
const now = new Date();
|
||||
const mediaArray = [
|
||||
@@ -249,9 +284,12 @@ describe('executeMediaQueryForView', () => {
|
||||
const view = await executeMediaQueryForView(
|
||||
cameraManager,
|
||||
createView(),
|
||||
new EventMediaQueries(
|
||||
cameraManager.generateDefaultEventQueries('camera') ?? undefined,
|
||||
),
|
||||
new EventMediaQueries([
|
||||
{
|
||||
type: QueryType.Event,
|
||||
cameraIDs: new Set('camera'),
|
||||
},
|
||||
]),
|
||||
{
|
||||
select: 'time',
|
||||
targetTime: add(now, { seconds: 30 }),
|
||||
@@ -264,8 +302,7 @@ describe('executeMediaQueryForView', () => {
|
||||
});
|
||||
|
||||
it('should select nothing when time-based selection does not match', async () => {
|
||||
const cameraConfigs: CameraConfigs = new Map();
|
||||
const cameraManager = createCameraManager({ configs: cameraConfigs });
|
||||
const cameraManager = createCameraManager();
|
||||
|
||||
const now = new Date();
|
||||
const mediaArray = [
|
||||
@@ -279,9 +316,12 @@ describe('executeMediaQueryForView', () => {
|
||||
const view = await executeMediaQueryForView(
|
||||
cameraManager,
|
||||
createView(),
|
||||
new EventMediaQueries(
|
||||
cameraManager.generateDefaultEventQueries('camera') ?? undefined,
|
||||
),
|
||||
new EventMediaQueries([
|
||||
{
|
||||
type: QueryType.Event,
|
||||
cameraIDs: new Set('camera'),
|
||||
},
|
||||
]),
|
||||
{
|
||||
select: 'time',
|
||||
targetTime: sub(now, { seconds: 30 }),
|
||||
@@ -292,6 +332,24 @@ describe('executeMediaQueryForView', () => {
|
||||
expect(view?.queryResults?.getSelectedIndex()).toBe(2);
|
||||
expect(view?.queryResults?.getResults()).toBe(mediaArray);
|
||||
});
|
||||
|
||||
it('should select nothing when query returns null', async () => {
|
||||
const cameraManager = createCameraManager();
|
||||
vi.mocked(cameraManager.executeMediaQueries).mockResolvedValue(null);
|
||||
|
||||
expect(
|
||||
await executeMediaQueryForView(
|
||||
cameraManager,
|
||||
createView(),
|
||||
new EventMediaQueries([
|
||||
{
|
||||
type: QueryType.Event,
|
||||
cameraIDs: new Set('camera'),
|
||||
},
|
||||
]),
|
||||
),
|
||||
).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
// @vitest-environment jsdom
|
||||
@@ -302,11 +360,10 @@ describe('changeViewToRecentRecordingForCameraAndDependents', () => {
|
||||
|
||||
it('should do nothing without camera config for selected camera', async () => {
|
||||
const elementHandler = createElementListenForView();
|
||||
const cameraManager = createCameraManager({ configs: new Map() });
|
||||
|
||||
await changeViewToRecentRecordingForCameraAndDependents(
|
||||
elementHandler.element,
|
||||
cameraManager,
|
||||
createCameraManager(),
|
||||
{},
|
||||
createView(),
|
||||
);
|
||||
@@ -315,11 +372,10 @@ describe('changeViewToRecentRecordingForCameraAndDependents', () => {
|
||||
|
||||
it('should do nothing without camera configs for all cameras', async () => {
|
||||
const elementHandler = createElementListenForView();
|
||||
const cameraManager = createCameraManager({ configs: new Map() });
|
||||
|
||||
await changeViewToRecentRecordingForCameraAndDependents(
|
||||
elementHandler.element,
|
||||
cameraManager,
|
||||
createCameraManager(),
|
||||
{},
|
||||
createView(),
|
||||
{
|
||||
@@ -346,9 +402,22 @@ describe('changeViewToRecentRecordingForCameraAndDependents', () => {
|
||||
it('should dispatch new view on success', async () => {
|
||||
const elementHandler = createElementListenForView();
|
||||
const cameraManager = createCameraManager();
|
||||
vi.mocked(cameraManager.getStore).mockReturnValue(
|
||||
createStore([
|
||||
{
|
||||
cameraID: 'camera',
|
||||
},
|
||||
]),
|
||||
);
|
||||
|
||||
const mediaArray = [new ViewMedia('recording', 'camera')];
|
||||
vi.mocked(cameraManager.executeMediaQueries).mockResolvedValue(mediaArray);
|
||||
vi.mocked(cameraManager.generateDefaultRecordingQueries).mockReturnValue([
|
||||
{
|
||||
type: QueryType.Recording,
|
||||
cameraIDs: new Set(['camera']),
|
||||
},
|
||||
]);
|
||||
|
||||
await changeViewToRecentRecordingForCameraAndDependents(
|
||||
elementHandler.element,
|
||||
@@ -366,6 +435,13 @@ describe('changeViewToRecentRecordingForCameraAndDependents', () => {
|
||||
|
||||
it('should respect media chunk size', async () => {
|
||||
const cameraManager = createCameraManager();
|
||||
vi.mocked(cameraManager.getStore).mockReturnValue(
|
||||
createStore([
|
||||
{
|
||||
cameraID: 'camera',
|
||||
},
|
||||
]),
|
||||
);
|
||||
|
||||
await changeViewToRecentRecordingForCameraAndDependents(
|
||||
createElementListenForView().element,
|
||||
@@ -402,9 +478,7 @@ describe('executeMediaQueryForViewWithErrorDispatching', () => {
|
||||
elementHandler.element,
|
||||
cameraManager,
|
||||
createView(),
|
||||
new EventMediaQueries(
|
||||
cameraManager.generateDefaultEventQueries('camera') ?? undefined,
|
||||
),
|
||||
new EventMediaQueries([{ type: QueryType.Event, cameraIDs: new Set(['camera']) }]),
|
||||
);
|
||||
|
||||
expect(elementHandler.viewHandler).not.toBeCalled();
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { FrigateCardPTZConfig, frigateCardPTZSchema } from '../../src/config/types';
|
||||
import { hasUsablePTZ } from '../../src/utils/ptz';
|
||||
import { createCameraCapabilities } from '../test-utils';
|
||||
|
||||
const createPTZConfig = (
|
||||
config?: Partial<FrigateCardPTZConfig>,
|
||||
): FrigateCardPTZConfig => {
|
||||
return frigateCardPTZSchema.parse(config ?? {});
|
||||
};
|
||||
|
||||
describe('hasUsablePTZ', () => {
|
||||
it('should return true with manual actions', () => {
|
||||
expect(
|
||||
hasUsablePTZ(
|
||||
createCameraCapabilities(),
|
||||
createPTZConfig({
|
||||
actions_left: {},
|
||||
}),
|
||||
),
|
||||
).toBeTruthy();
|
||||
});
|
||||
it('should return true with capabilities', () => {
|
||||
expect(
|
||||
hasUsablePTZ(
|
||||
createCameraCapabilities({
|
||||
ptz: {},
|
||||
}),
|
||||
createPTZConfig(),
|
||||
),
|
||||
).toBeTruthy();
|
||||
});
|
||||
it('should return false with manual actions or capabilities', () => {
|
||||
expect(hasUsablePTZ(createCameraCapabilities(), createPTZConfig())).toBeFalsy();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user