feat: Make cameras optional (#2343)
This commit is contained in:
1 parent
21f9469784
commit
93f1f08e51
61 files changed
+1312
-557
No files matched your search
@@ -1,4 +1,6 @@
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
import { FoldersManager } from '../../../src/card-controller/folders/manager';
|
||||
import { ViewFactory } from '../../../src/card-controller/view/factory';
|
||||
import { ViewModifier } from '../../../src/card-controller/view/types';
|
||||
import { AdvancedCameraCardView } from '../../../src/config/schema/common/const';
|
||||
@@ -9,6 +11,7 @@ import {
|
||||
createCapabilities,
|
||||
createCardAPI,
|
||||
createConfig,
|
||||
createFolder,
|
||||
createStore,
|
||||
createView,
|
||||
} from '../../test-utils';
|
||||
@@ -20,7 +23,7 @@ describe('getViewDefault', () => {
|
||||
expect(factory.getViewDefault()).toBeNull();
|
||||
});
|
||||
|
||||
it('should throw if no cameras support view', () => {
|
||||
it('should throw when no cameras support view', () => {
|
||||
const api = createCardAPI();
|
||||
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig());
|
||||
vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager());
|
||||
@@ -47,6 +50,23 @@ describe('getViewDefault', () => {
|
||||
expect(() => factory.getViewDefault()).toThrowError(/No cameras support this view/);
|
||||
});
|
||||
|
||||
it('should use folders view as default when folders exist without cameras', () => {
|
||||
const api = createCardAPI();
|
||||
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig());
|
||||
vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager());
|
||||
vi.mocked(api.getFoldersManager).mockReturnValue(mock<FoldersManager>());
|
||||
vi.mocked(api.getFoldersManager().hasFolders).mockReturnValue(true);
|
||||
vi.mocked(api.getFoldersManager().getFolder).mockReturnValue(createFolder());
|
||||
|
||||
vi.mocked(api.getCameraManager().getStore).mockReturnValue(createStore([]));
|
||||
|
||||
const factory = new ViewFactory(api);
|
||||
const view = factory.getViewDefault();
|
||||
|
||||
expect(view?.view).toBe('folders');
|
||||
expect(view?.camera).toBeNull();
|
||||
});
|
||||
|
||||
it('should create view', () => {
|
||||
const factory = new ViewFactory(createPopulatedAPI());
|
||||
const view = factory.getViewDefault();
|
||||
@@ -217,8 +237,6 @@ describe('getViewByParameters', () => {
|
||||
const factory = new ViewFactory(api);
|
||||
expect(() =>
|
||||
factory.getViewByParameters({
|
||||
// Since no camera is specified, and no camera supports the capabilities
|
||||
// necessary for this view, the view will be null.
|
||||
params: {
|
||||
view: 'snapshots',
|
||||
},
|
||||
@@ -226,6 +244,56 @@ describe('getViewByParameters', () => {
|
||||
).toThrowError(/No cameras support this view/);
|
||||
});
|
||||
|
||||
describe('should handle no camera for view with failsafe', () => {
|
||||
it('should choose default view when it does not require a camera', () => {
|
||||
const api = createCardAPI();
|
||||
vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager());
|
||||
vi.mocked(api.getCameraManager().getStore).mockReturnValue(createStore([]));
|
||||
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(
|
||||
createConfig({
|
||||
view: {
|
||||
default: 'diagnostics',
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
const factory = new ViewFactory(api);
|
||||
const view = factory.getViewByParameters({
|
||||
params: {
|
||||
view: 'live',
|
||||
},
|
||||
failSafe: true,
|
||||
});
|
||||
expect(view?.is('diagnostics')).toBeTruthy();
|
||||
expect(view?.camera).toBeNull();
|
||||
});
|
||||
|
||||
it('should choose default view and camera when it requires a camera', () => {
|
||||
const api = createCardAPI();
|
||||
vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager());
|
||||
vi.mocked(api.getCameraManager().getStore).mockReturnValue(
|
||||
createStore([{ cameraID: 'camera.one' }]),
|
||||
);
|
||||
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(
|
||||
createConfig({
|
||||
view: {
|
||||
default: 'live',
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
const factory = new ViewFactory(api);
|
||||
const view = factory.getViewByParameters({
|
||||
params: {
|
||||
view: 'snapshots',
|
||||
},
|
||||
failSafe: true,
|
||||
});
|
||||
expect(view?.is('live')).toBeTruthy();
|
||||
expect(view?.camera).toBe('camera.one');
|
||||
});
|
||||
});
|
||||
|
||||
describe('should handle unsupported view', () => {
|
||||
it('should throw without failsafe', () => {
|
||||
const api = createCardAPI();
|
||||
@@ -285,6 +353,24 @@ describe('getViewByParameters', () => {
|
||||
});
|
||||
expect(view?.is('live')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should throw and omit capabilities when camera object is missing from store', () => {
|
||||
const api = createCardAPI();
|
||||
const store = createStore([{ cameraID: 'camera.one' }]);
|
||||
vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager(store));
|
||||
vi.spyOn(store, 'getCamera').mockReturnValue(null);
|
||||
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig());
|
||||
|
||||
const factory = new ViewFactory(api);
|
||||
expect(() =>
|
||||
factory.getViewByParameters({
|
||||
params: {
|
||||
camera: 'camera.one',
|
||||
view: 'snapshots',
|
||||
},
|
||||
}),
|
||||
).toThrowError(/The selected camera or media does not support this view/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should call modifiers', () => {
|
||||
|
||||
@@ -21,29 +21,27 @@ const createAPIWithSubstreams = (
|
||||
config?: RawAdvancedCameraCardConfig,
|
||||
): CardController => {
|
||||
const api = createCardAPI();
|
||||
vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager());
|
||||
vi.mocked(api.getCameraManager().getStore).mockReturnValue(
|
||||
createStore([
|
||||
{
|
||||
cameraID: 'camera.office',
|
||||
capabilities: createCapabilities({
|
||||
live: true,
|
||||
substream: true,
|
||||
}),
|
||||
config: createCameraConfig({
|
||||
dependencies: {
|
||||
all_cameras: true,
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
cameraID: 'camera.kitchen',
|
||||
capabilities: createCapabilities({
|
||||
substream: true,
|
||||
}),
|
||||
},
|
||||
]),
|
||||
);
|
||||
const store = createStore([
|
||||
{
|
||||
cameraID: 'camera.office',
|
||||
capabilities: createCapabilities({
|
||||
live: true,
|
||||
substream: true,
|
||||
}),
|
||||
config: createCameraConfig({
|
||||
dependencies: {
|
||||
all_cameras: true,
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
cameraID: 'camera.kitchen',
|
||||
capabilities: createCapabilities({
|
||||
substream: true,
|
||||
}),
|
||||
},
|
||||
]);
|
||||
vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager(store));
|
||||
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig(config));
|
||||
return api;
|
||||
};
|
||||
@@ -97,11 +95,25 @@ describe('should turn on substream', () => {
|
||||
expect(hasSubstream(view)).toBe(false);
|
||||
|
||||
const api = createCardAPI();
|
||||
vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager());
|
||||
const cameraManager = createCameraManager(createStore([]));
|
||||
vi.mocked(api.getCameraManager).mockReturnValue(cameraManager);
|
||||
|
||||
const modifier = new SubstreamOnViewModifier(api);
|
||||
modifier.modify(view);
|
||||
|
||||
expect(hasSubstream(view)).toBe(false);
|
||||
});
|
||||
|
||||
it('without camera', () => {
|
||||
const view = createView({
|
||||
camera: null,
|
||||
view: 'live',
|
||||
});
|
||||
|
||||
const api = createCardAPI();
|
||||
const modifier = new SubstreamOnViewModifier(api);
|
||||
modifier.modify(view);
|
||||
|
||||
expect(hasSubstream(view)).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -257,7 +257,7 @@ describe('ViewQueryExecutor', () => {
|
||||
const store = createStore([
|
||||
{
|
||||
cameraID: 'camera.office',
|
||||
capabilities: createCapabilities({ [mode]: true }),
|
||||
capabilities: createCapabilities({ live: true, [mode]: true }),
|
||||
config: createCameraConfig({
|
||||
media: {
|
||||
type: mode === 'reviews' ? 'reviews' : 'events',
|
||||
@@ -546,6 +546,34 @@ describe('ViewQueryExecutor', () => {
|
||||
expect(view.query).toBeNull();
|
||||
expect(view.queryResults).toBeNull();
|
||||
});
|
||||
|
||||
it('should handle non-grid view without a camera', async () => {
|
||||
const api = createPopulatedAPI();
|
||||
const viewQueryExecutor = new ViewQueryExecutor(api);
|
||||
const view = createView({
|
||||
view: 'live',
|
||||
camera: null,
|
||||
});
|
||||
|
||||
const modifiers = await viewQueryExecutor.getNewQueryModifiers(view);
|
||||
applyViewModifiers(view, modifiers);
|
||||
|
||||
expect(view.query).toBeNull();
|
||||
});
|
||||
|
||||
it('should handle diagnostics view without a camera', async () => {
|
||||
const api = createPopulatedAPI();
|
||||
const viewQueryExecutor = new ViewQueryExecutor(api);
|
||||
const view = createView({
|
||||
view: 'diagnostics',
|
||||
camera: null,
|
||||
});
|
||||
|
||||
const modifiers = await viewQueryExecutor.getNewQueryModifiers(view);
|
||||
applyViewModifiers(view, modifiers);
|
||||
|
||||
expect(view.query).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('with a timeline view', () => {
|
||||
@@ -799,6 +827,7 @@ describe('ViewQueryExecutor', () => {
|
||||
'should execute default folder query with %s view',
|
||||
async (viewName: AdvancedCameraCardView) => {
|
||||
const api = createPopulatedAPI();
|
||||
vi.mocked(api.getFoldersManager().hasFolders).mockReturnValue(true);
|
||||
vi.mocked(api.getFoldersManager().getFolder).mockReturnValue({
|
||||
type: 'ha',
|
||||
id: 'office',
|
||||
@@ -827,6 +856,7 @@ describe('ViewQueryExecutor', () => {
|
||||
|
||||
it('should execute default folder query with folder view and handle null results', async () => {
|
||||
const api = createPopulatedAPI();
|
||||
vi.mocked(api.getFoldersManager().hasFolders).mockReturnValue(true);
|
||||
vi.mocked(api.getFoldersManager().getFolder).mockReturnValue(null);
|
||||
vi.mocked(api.getFoldersManager().getDefaultQueryParameters).mockReturnValue(
|
||||
null,
|
||||
|
||||
Reference in new issue
Block a user