Refactor views to support dynamic updates.
This commit is contained in:
1 parent
33dee47205
commit
d5c4e56c45
80 files changed
+3714
-4021
No files matched your search
@@ -0,0 +1,360 @@
|
||||
import { add } from 'date-fns';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import { QueryType } from '../../../src/camera-manager/types';
|
||||
import { QueryExecutor } from '../../../src/card-controller/view/query-executor';
|
||||
import { ClipsOrSnapshotsOrAll } from '../../../src/types';
|
||||
import { EventMediaQueries } from '../../../src/view/media-queries';
|
||||
import {
|
||||
TestViewMedia,
|
||||
createCameraManager,
|
||||
createCardAPI,
|
||||
createStore,
|
||||
generateViewMediaArray,
|
||||
} from '../../test-utils';
|
||||
import { createPopulatedAPI } from './test-utils';
|
||||
|
||||
describe('executeDefaultEventQuery', () => {
|
||||
it('should return null without cameras', async () => {
|
||||
const api = createCardAPI();
|
||||
vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager());
|
||||
vi.mocked(api.getCameraManager().getStore).mockReturnValue(createStore());
|
||||
|
||||
const executor = new QueryExecutor(api);
|
||||
expect(
|
||||
await executor.executeDefaultEventQuery({
|
||||
cameraID: 'camera.office',
|
||||
}),
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
it('should return null without queries', async () => {
|
||||
const api = createPopulatedAPI();
|
||||
vi.mocked(api.getCameraManager().generateDefaultEventQueries).mockReturnValue(null);
|
||||
|
||||
const executor = new QueryExecutor(api);
|
||||
expect(
|
||||
await executor.executeDefaultEventQuery({
|
||||
cameraID: 'camera.office',
|
||||
}),
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
describe('should return query results for specified camera', async () => {
|
||||
it.each([['all' as const], ['clips' as const], ['snapshots' as const], [undefined]])(
|
||||
'%s',
|
||||
async (mediaType?: ClipsOrSnapshotsOrAll) => {
|
||||
const api = createPopulatedAPI();
|
||||
const media = generateViewMediaArray();
|
||||
const rawQueries = [
|
||||
{ type: QueryType.Event as const, cameraIDs: new Set(['camera.office']) },
|
||||
];
|
||||
vi.mocked(api.getCameraManager().generateDefaultEventQueries).mockReturnValue(
|
||||
rawQueries,
|
||||
);
|
||||
vi.mocked(api.getCameraManager().executeMediaQueries).mockResolvedValue(media);
|
||||
|
||||
const executor = new QueryExecutor(api);
|
||||
const results = await executor.executeDefaultEventQuery({
|
||||
cameraID: 'camera.office',
|
||||
eventsMediaType: mediaType,
|
||||
});
|
||||
|
||||
expect(results?.query.getQueries()).toEqual(rawQueries);
|
||||
expect(results?.queryResults.getResults()).toEqual(media);
|
||||
expect(api.getCameraManager().generateDefaultEventQueries).toBeCalledWith(
|
||||
new Set(['camera.office']),
|
||||
{
|
||||
limit: 50,
|
||||
...(mediaType === 'clips' && { hasClip: true }),
|
||||
...(mediaType === 'snapshots' && { hasSnapshot: true }),
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it('should return query results for all cameras', async () => {
|
||||
const api = createPopulatedAPI();
|
||||
const media = generateViewMediaArray();
|
||||
const rawQueries = [
|
||||
{
|
||||
type: QueryType.Event as const,
|
||||
cameraIDs: new Set(['camera.office', 'camera.kitchen']),
|
||||
},
|
||||
];
|
||||
vi.mocked(api.getCameraManager().generateDefaultEventQueries).mockReturnValue(
|
||||
rawQueries,
|
||||
);
|
||||
vi.mocked(api.getCameraManager().executeMediaQueries).mockResolvedValue(media);
|
||||
|
||||
const executor = new QueryExecutor(api);
|
||||
const results = await executor.executeDefaultEventQuery();
|
||||
|
||||
expect(results?.query.getQueries()).toEqual(rawQueries);
|
||||
expect(results?.queryResults.getResults()).toEqual(media);
|
||||
expect(api.getCameraManager().generateDefaultEventQueries).toBeCalledWith(
|
||||
new Set(['camera.office', 'camera.kitchen']),
|
||||
{
|
||||
limit: 50,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it('should return null when query returns null', async () => {
|
||||
const api = createPopulatedAPI();
|
||||
const rawQueries = [
|
||||
{
|
||||
type: QueryType.Event as const,
|
||||
cameraIDs: new Set(['camera.office']),
|
||||
},
|
||||
];
|
||||
vi.mocked(api.getCameraManager().generateDefaultEventQueries).mockReturnValue(
|
||||
rawQueries,
|
||||
);
|
||||
vi.mocked(api.getCameraManager().executeMediaQueries).mockResolvedValue(null);
|
||||
|
||||
const executor = new QueryExecutor(api);
|
||||
expect(
|
||||
await executor.executeDefaultEventQuery({ cameraID: 'camera.office' }),
|
||||
).toBeNull();
|
||||
expect(api.getCameraManager().generateDefaultEventQueries).toBeCalledWith(
|
||||
new Set(['camera.office']),
|
||||
{
|
||||
limit: 50,
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('executeDefaultRecordingQuery', () => {
|
||||
it('should return null without cameras', async () => {
|
||||
const api = createCardAPI();
|
||||
vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager());
|
||||
vi.mocked(api.getCameraManager().getStore).mockReturnValue(createStore());
|
||||
|
||||
const executor = new QueryExecutor(api);
|
||||
expect(
|
||||
await executor.executeDefaultRecordingQuery({
|
||||
cameraID: 'camera.office',
|
||||
}),
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
it('should return null without queries', async () => {
|
||||
const api = createPopulatedAPI();
|
||||
vi.mocked(api.getCameraManager().generateDefaultRecordingQueries).mockReturnValue(
|
||||
null,
|
||||
);
|
||||
|
||||
const executor = new QueryExecutor(api);
|
||||
expect(
|
||||
await executor.executeDefaultRecordingQuery({
|
||||
cameraID: 'camera.office',
|
||||
}),
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
it('should return query results for specified camera', async () => {
|
||||
const api = createPopulatedAPI();
|
||||
const media = generateViewMediaArray();
|
||||
const rawQueries = [
|
||||
{ type: QueryType.Recording as const, cameraIDs: new Set(['camera.office']) },
|
||||
];
|
||||
vi.mocked(api.getCameraManager().generateDefaultRecordingQueries).mockReturnValue(
|
||||
rawQueries,
|
||||
);
|
||||
vi.mocked(api.getCameraManager().executeMediaQueries).mockResolvedValue(media);
|
||||
|
||||
const executor = new QueryExecutor(api);
|
||||
const results = await executor.executeDefaultRecordingQuery({
|
||||
cameraID: 'camera.office',
|
||||
});
|
||||
|
||||
expect(results?.query.getQueries()).toEqual(rawQueries);
|
||||
expect(results?.queryResults.getResults()).toEqual(media);
|
||||
expect(api.getCameraManager().generateDefaultRecordingQueries).toBeCalledWith(
|
||||
new Set(['camera.office']),
|
||||
{
|
||||
limit: 50,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it('should return query results for all cameras', async () => {
|
||||
const api = createPopulatedAPI();
|
||||
const media = generateViewMediaArray();
|
||||
const rawQueries = [
|
||||
{
|
||||
type: QueryType.Recording as const,
|
||||
cameraIDs: new Set(['camera.office', 'camera.kitchen']),
|
||||
},
|
||||
];
|
||||
vi.mocked(api.getCameraManager().generateDefaultRecordingQueries).mockReturnValue(
|
||||
rawQueries,
|
||||
);
|
||||
vi.mocked(api.getCameraManager().executeMediaQueries).mockResolvedValue(media);
|
||||
|
||||
const executor = new QueryExecutor(api);
|
||||
const results = await executor.executeDefaultRecordingQuery();
|
||||
|
||||
expect(results?.query.getQueries()).toEqual(rawQueries);
|
||||
expect(results?.queryResults.getResults()).toEqual(media);
|
||||
expect(api.getCameraManager().generateDefaultRecordingQueries).toBeCalledWith(
|
||||
new Set(['camera.office', 'camera.kitchen']),
|
||||
{
|
||||
limit: 50,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it('should return null when query returns null', async () => {
|
||||
const api = createPopulatedAPI();
|
||||
const rawQueries = [
|
||||
{
|
||||
type: QueryType.Recording as const,
|
||||
cameraIDs: new Set(['camera.office']),
|
||||
},
|
||||
];
|
||||
vi.mocked(api.getCameraManager().generateDefaultRecordingQueries).mockReturnValue(
|
||||
rawQueries,
|
||||
);
|
||||
vi.mocked(api.getCameraManager().executeMediaQueries).mockResolvedValue(null);
|
||||
|
||||
const executor = new QueryExecutor(api);
|
||||
expect(
|
||||
await executor.executeDefaultRecordingQuery({ cameraID: 'camera.office' }),
|
||||
).toBeNull();
|
||||
expect(api.getCameraManager().generateDefaultRecordingQueries).toBeCalledWith(
|
||||
new Set(['camera.office']),
|
||||
{
|
||||
limit: 50,
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('execute', () => {
|
||||
it('should return null when query is empty', async () => {
|
||||
const executor = new QueryExecutor(createCardAPI());
|
||||
expect(await executor.execute(new EventMediaQueries())).toBeNull();
|
||||
});
|
||||
|
||||
describe('should handle result rejections', () => {
|
||||
it('rejected', async () => {
|
||||
const api = createPopulatedAPI();
|
||||
const media = generateViewMediaArray();
|
||||
vi.mocked(api.getCameraManager().executeMediaQueries).mockResolvedValue(media);
|
||||
|
||||
const query = new EventMediaQueries([
|
||||
{
|
||||
type: QueryType.Event as const,
|
||||
cameraIDs: new Set(['camera.office']),
|
||||
},
|
||||
]);
|
||||
const executor = new QueryExecutor(api);
|
||||
|
||||
expect(await executor.execute(query, { rejectResults: (_) => true })).toBeNull();
|
||||
});
|
||||
|
||||
it('not rejected', async () => {
|
||||
const api = createPopulatedAPI();
|
||||
const media = generateViewMediaArray();
|
||||
vi.mocked(api.getCameraManager().executeMediaQueries).mockResolvedValue(media);
|
||||
|
||||
const query = new EventMediaQueries([
|
||||
{
|
||||
type: QueryType.Event as const,
|
||||
cameraIDs: new Set(['camera.office']),
|
||||
},
|
||||
]);
|
||||
const executor = new QueryExecutor(api);
|
||||
|
||||
expect(
|
||||
await executor.execute(query, { rejectResults: (_) => false }),
|
||||
).not.toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('should select', () => {
|
||||
it('by id', async () => {
|
||||
const api = createPopulatedAPI();
|
||||
const media = generateViewMediaArray({
|
||||
cameraIDs: ['camera.office'],
|
||||
count: 100,
|
||||
});
|
||||
vi.mocked(api.getCameraManager().executeMediaQueries).mockResolvedValue(media);
|
||||
|
||||
const query = new EventMediaQueries([
|
||||
{
|
||||
type: QueryType.Event as const,
|
||||
cameraIDs: new Set(['camera.office']),
|
||||
},
|
||||
]);
|
||||
const executor = new QueryExecutor(api);
|
||||
|
||||
const results = await executor.execute(query, {
|
||||
selectResult: { id: 'id-camera.office-42' },
|
||||
});
|
||||
expect(results?.getSelectedResult()?.getID()).toBe('id-camera.office-42');
|
||||
});
|
||||
});
|
||||
|
||||
it('by func', async () => {
|
||||
const api = createPopulatedAPI();
|
||||
const media = generateViewMediaArray({
|
||||
cameraIDs: ['camera.office'],
|
||||
count: 100,
|
||||
});
|
||||
vi.mocked(api.getCameraManager().executeMediaQueries).mockResolvedValue(media);
|
||||
|
||||
const query = new EventMediaQueries([
|
||||
{
|
||||
type: QueryType.Event as const,
|
||||
cameraIDs: new Set(['camera.office']),
|
||||
},
|
||||
]);
|
||||
const executor = new QueryExecutor(api);
|
||||
|
||||
const results = await executor.execute(query, {
|
||||
selectResult: { func: (media) => media.getID() === 'id-camera.office-43' },
|
||||
});
|
||||
expect(results?.getSelectedResult()?.getID()).toBe('id-camera.office-43');
|
||||
});
|
||||
|
||||
it('by time', async () => {
|
||||
const now = new Date('2024-07-21T19:09:37Z');
|
||||
|
||||
const api = createPopulatedAPI();
|
||||
const media = [
|
||||
new TestViewMedia({
|
||||
cameraID: 'camera.office',
|
||||
id: 'id-camera.office-0',
|
||||
startTime: now,
|
||||
}),
|
||||
new TestViewMedia({
|
||||
cameraID: 'camera.office',
|
||||
id: 'id-camera.office-1',
|
||||
startTime: add(now, { seconds: 1 }),
|
||||
}),
|
||||
new TestViewMedia({
|
||||
cameraID: 'camera.office',
|
||||
id: 'id-camera.office-2',
|
||||
startTime: add(now, { seconds: 2 }),
|
||||
}),
|
||||
];
|
||||
vi.mocked(api.getCameraManager().executeMediaQueries).mockResolvedValue(media);
|
||||
|
||||
const query = new EventMediaQueries([
|
||||
{
|
||||
type: QueryType.Event as const,
|
||||
cameraIDs: new Set(['camera.office']),
|
||||
},
|
||||
]);
|
||||
const executor = new QueryExecutor(api);
|
||||
|
||||
const results = await executor.execute(query, {
|
||||
selectResult: { time: { time: add(now, { seconds: 1 }) } },
|
||||
});
|
||||
expect(results?.getSelectedResult()?.getID()).toBe('id-camera.office-1');
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user