@@ -0,0 +1,247 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
import { CameraManager } from '../../../../src/camera-manager/manager';
|
||||
import { ThumbnailDetailsController } from '../../../../src/components-lib/thumbnail/details-controller';
|
||||
import { ViewFolder, ViewMediaType } from '../../../../src/view/item';
|
||||
import { createFolder, TestViewMedia } from '../../../test-utils';
|
||||
|
||||
describe('ThumbnailDetailsController', () => {
|
||||
describe('should set heading', () => {
|
||||
it('should set heading on event with what, tags and score', () => {
|
||||
const item = new TestViewMedia({
|
||||
what: ['person', 'car'],
|
||||
tags: ['tag1', 'tag2'],
|
||||
score: 0.5,
|
||||
});
|
||||
|
||||
const controller = new ThumbnailDetailsController();
|
||||
controller.calculate(null, item);
|
||||
expect(controller.getHeading()).toBe('Person, Car: Tag1, Tag2 50.00%');
|
||||
});
|
||||
|
||||
it('should set heading on event with tags', () => {
|
||||
const item = new TestViewMedia({
|
||||
tags: ['tag1', 'tag2'],
|
||||
});
|
||||
|
||||
const controller = new ThumbnailDetailsController();
|
||||
controller.calculate(null, item);
|
||||
expect(controller.getHeading()).toBe('Tag1, Tag2');
|
||||
});
|
||||
|
||||
it('should set heading on event with what', () => {
|
||||
const item = new TestViewMedia({
|
||||
what: ['person', 'car'],
|
||||
});
|
||||
|
||||
const controller = new ThumbnailDetailsController();
|
||||
controller.calculate(null, item);
|
||||
expect(controller.getHeading()).toBe('Person, Car');
|
||||
});
|
||||
|
||||
it('should set null heading on event with no other information', () => {
|
||||
const item = new TestViewMedia({
|
||||
mediaType: ViewMediaType.Snapshot,
|
||||
what: null,
|
||||
tags: null,
|
||||
score: null,
|
||||
});
|
||||
|
||||
const controller = new ThumbnailDetailsController();
|
||||
controller.calculate(null, item);
|
||||
expect(controller.getHeading()).toBeNull();
|
||||
});
|
||||
|
||||
it('should set heading on recording with camera metadata', () => {
|
||||
const cameraManager = mock<CameraManager>();
|
||||
cameraManager.getCameraMetadata.mockReturnValue({
|
||||
title: 'Camera Title',
|
||||
icon: { icon: 'mdi:cow' },
|
||||
});
|
||||
|
||||
const item = new TestViewMedia({
|
||||
mediaType: ViewMediaType.Recording,
|
||||
});
|
||||
|
||||
const controller = new ThumbnailDetailsController();
|
||||
controller.calculate(cameraManager, item);
|
||||
expect(controller.getHeading()).toBe('Camera Title');
|
||||
});
|
||||
|
||||
it('should set heading on recording without camera metadata', () => {
|
||||
const item = new TestViewMedia({
|
||||
mediaType: ViewMediaType.Recording,
|
||||
});
|
||||
|
||||
const controller = new ThumbnailDetailsController();
|
||||
controller.calculate(null, item);
|
||||
expect(controller.getHeading()).toBeNull();
|
||||
});
|
||||
|
||||
it('should set no heading on folder', () => {
|
||||
const item = new ViewFolder(createFolder());
|
||||
|
||||
const controller = new ThumbnailDetailsController();
|
||||
controller.calculate(null, item);
|
||||
expect(controller.getHeading()).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('should set details', () => {
|
||||
describe('should have title in details', () => {
|
||||
it('should have icon with title when there are other details', () => {
|
||||
const item = new TestViewMedia({
|
||||
title: 'Test Event',
|
||||
where: ['where1', 'where2'],
|
||||
});
|
||||
|
||||
const controller = new ThumbnailDetailsController();
|
||||
controller.calculate(null, item);
|
||||
expect(controller.getDetails()).toContainEqual({
|
||||
title: 'Test Event',
|
||||
icon: { icon: 'mdi:rename' },
|
||||
hint: 'Title',
|
||||
});
|
||||
});
|
||||
|
||||
it('should not have icon with title when there are no other details', () => {
|
||||
const item = new TestViewMedia({
|
||||
title: 'Test Event',
|
||||
});
|
||||
|
||||
const controller = new ThumbnailDetailsController();
|
||||
controller.calculate(null, item);
|
||||
expect(controller.getDetails()).toEqual([
|
||||
{
|
||||
title: 'Test Event',
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should have start time in details', () => {
|
||||
const item = new TestViewMedia({
|
||||
startTime: new Date('2025-05-18T17:03:00Z'),
|
||||
});
|
||||
|
||||
const controller = new ThumbnailDetailsController();
|
||||
controller.calculate(null, item);
|
||||
expect(controller.getDetails()).toContainEqual({
|
||||
title: '2025-05-18 17:03:00',
|
||||
hint: 'Start',
|
||||
icon: { icon: 'mdi:calendar-clock-outline' },
|
||||
});
|
||||
});
|
||||
|
||||
describe('should have duration in details', () => {
|
||||
it('should have duration in details', () => {
|
||||
const item = new TestViewMedia({
|
||||
startTime: new Date('2025-05-18T17:03:00Z'),
|
||||
endTime: new Date('2025-05-18T17:04:00Z'),
|
||||
});
|
||||
|
||||
const controller = new ThumbnailDetailsController();
|
||||
controller.calculate(null, item);
|
||||
expect(controller.getDetails()).toContainEqual({
|
||||
title: '1m 0s',
|
||||
hint: 'Duration',
|
||||
icon: { icon: 'mdi:clock-outline' },
|
||||
});
|
||||
});
|
||||
|
||||
it('should have in-progress in details', () => {
|
||||
const item = new TestViewMedia({
|
||||
startTime: new Date('2025-05-18T17:03:00Z'),
|
||||
endTime: null,
|
||||
inProgress: true,
|
||||
});
|
||||
|
||||
const controller = new ThumbnailDetailsController();
|
||||
controller.calculate(null, item);
|
||||
expect(controller.getDetails()).toContainEqual({
|
||||
title: 'In Progress',
|
||||
hint: 'Duration',
|
||||
icon: { icon: 'mdi:clock-outline' },
|
||||
});
|
||||
});
|
||||
|
||||
it('should have duration and in-progress in details', () => {
|
||||
const item = new TestViewMedia({
|
||||
startTime: new Date('2025-05-18T17:03:00Z'),
|
||||
endTime: new Date('2025-05-18T17:04:00Z'),
|
||||
inProgress: true,
|
||||
});
|
||||
|
||||
const controller = new ThumbnailDetailsController();
|
||||
controller.calculate(null, item);
|
||||
expect(controller.getDetails()).toContainEqual({
|
||||
title: '1m 0s In Progress',
|
||||
hint: 'Duration',
|
||||
icon: { icon: 'mdi:clock-outline' },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should have camera title in details', () => {
|
||||
const cameraManager = mock<CameraManager>();
|
||||
cameraManager.getCameraMetadata.mockReturnValue({
|
||||
title: 'Camera Title',
|
||||
icon: { icon: 'mdi:cow' },
|
||||
});
|
||||
|
||||
const item = new TestViewMedia({
|
||||
cameraID: 'camera_1',
|
||||
});
|
||||
|
||||
const controller = new ThumbnailDetailsController();
|
||||
controller.calculate(cameraManager, item);
|
||||
expect(controller.getDetails()).toContainEqual({
|
||||
title: 'Camera Title',
|
||||
hint: 'Camera',
|
||||
icon: { icon: 'mdi:cctv' },
|
||||
});
|
||||
});
|
||||
|
||||
it('should have where in details', () => {
|
||||
const item = new TestViewMedia({
|
||||
cameraID: 'camera_1',
|
||||
where: ['where1', 'where2'],
|
||||
});
|
||||
|
||||
const controller = new ThumbnailDetailsController();
|
||||
controller.calculate(null, item);
|
||||
expect(controller.getDetails()).toContainEqual({
|
||||
title: 'Where1, Where2',
|
||||
hint: 'Where',
|
||||
icon: { icon: 'mdi:map-marker-outline' },
|
||||
});
|
||||
});
|
||||
|
||||
it('should have tags in details', () => {
|
||||
const item = new TestViewMedia({
|
||||
cameraID: 'camera_1',
|
||||
tags: ['tag1', 'tag2'],
|
||||
});
|
||||
|
||||
const controller = new ThumbnailDetailsController();
|
||||
controller.calculate(null, item);
|
||||
expect(controller.getDetails()).toContainEqual({
|
||||
title: 'Tag1, Tag2',
|
||||
hint: 'Tag',
|
||||
icon: { icon: 'mdi:tag' },
|
||||
});
|
||||
});
|
||||
|
||||
it('should have seek in details', () => {
|
||||
const item = new TestViewMedia();
|
||||
|
||||
const controller = new ThumbnailDetailsController();
|
||||
controller.calculate(null, item, new Date('2025-05-20T07:14:57Z'));
|
||||
expect(controller.getDetails()).toContainEqual({
|
||||
title: '07:14:57',
|
||||
hint: 'Seek',
|
||||
icon: { icon: 'mdi:clock-fast' },
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,176 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
import { CameraManager } from '../../../../src/camera-manager/manager';
|
||||
import { ThumbnailFeatureController } from '../../../../src/components-lib/thumbnail/feature/controller';
|
||||
import { ViewFolder } from '../../../../src/view/item';
|
||||
import { createFolder, TestViewMedia } from '../../../test-utils';
|
||||
|
||||
describe('ThumbnailFeatureController', () => {
|
||||
const itemWithTime = new TestViewMedia({
|
||||
startTime: new Date('2025-05-18T17:03:00Z'),
|
||||
title: 'Test Event',
|
||||
cameraID: 'camera_1',
|
||||
});
|
||||
|
||||
describe('should set title', () => {
|
||||
it('should set title with start time ', () => {
|
||||
const controller = new ThumbnailFeatureController();
|
||||
|
||||
controller.calculate(null, itemWithTime, false);
|
||||
|
||||
expect(controller.getTitle()).toBe('17:03');
|
||||
});
|
||||
|
||||
it('should not set title when details are shown ', () => {
|
||||
const controller = new ThumbnailFeatureController();
|
||||
|
||||
controller.calculate(null, itemWithTime, true);
|
||||
|
||||
expect(controller.getTitle()).toBeNull();
|
||||
});
|
||||
|
||||
it('should not set title on media with a thumbnail', () => {
|
||||
const controller = new ThumbnailFeatureController();
|
||||
const itemWithThumbnail = new TestViewMedia({
|
||||
startTime: new Date('2025-05-18T17:03:00Z'),
|
||||
title: 'Test Event',
|
||||
cameraID: 'camera_1',
|
||||
thumbnail: 'thumbnail',
|
||||
});
|
||||
|
||||
controller.calculate(null, itemWithThumbnail, true);
|
||||
|
||||
expect(controller.getTitle()).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('should set subtitles', () => {
|
||||
it('should set subtitle with start date ', () => {
|
||||
const controller = new ThumbnailFeatureController();
|
||||
|
||||
controller.calculate(null, itemWithTime, false);
|
||||
|
||||
expect(controller.getSubtitles()).toContain('May 18th');
|
||||
});
|
||||
|
||||
it('should set subtitle with source from item title ', () => {
|
||||
const controller = new ThumbnailFeatureController();
|
||||
|
||||
controller.calculate(null, itemWithTime, false);
|
||||
|
||||
expect(controller.getSubtitles()).toContain('Test Event');
|
||||
});
|
||||
|
||||
it('should set subtitle with source from camera title ', () => {
|
||||
const controller = new ThumbnailFeatureController();
|
||||
|
||||
const cameraManager = mock<CameraManager>();
|
||||
cameraManager.getCameraMetadata.mockReturnValue({
|
||||
title: 'Camera 1',
|
||||
icon: { icon: 'mdi:camera' },
|
||||
});
|
||||
|
||||
const itemWithoutTitle = new TestViewMedia({
|
||||
startTime: new Date('2025-05-18T17:03:00Z'),
|
||||
title: null,
|
||||
cameraID: 'camera_1',
|
||||
});
|
||||
|
||||
controller.calculate(cameraManager, itemWithoutTitle, false);
|
||||
|
||||
expect(controller.getSubtitles()).toContain('Camera 1');
|
||||
});
|
||||
|
||||
it('should set subtitle falling back to item title when cameraID not found', () => {
|
||||
const controller = new ThumbnailFeatureController();
|
||||
|
||||
const item = new TestViewMedia({
|
||||
title: 'Title',
|
||||
cameraID: null,
|
||||
});
|
||||
|
||||
controller.calculate(null, item, false);
|
||||
|
||||
expect(controller.getSubtitles()).toContain('Title');
|
||||
});
|
||||
|
||||
it('should not set subtitle on media with a thumbnail', () => {
|
||||
const controller = new ThumbnailFeatureController();
|
||||
const itemWithThumbnail = new TestViewMedia({
|
||||
startTime: new Date('2025-05-18T17:03:00Z'),
|
||||
title: 'Test Event',
|
||||
cameraID: 'camera_1',
|
||||
thumbnail: 'thumbnail',
|
||||
});
|
||||
|
||||
controller.calculate(null, itemWithThumbnail, false);
|
||||
|
||||
expect(controller.getSubtitles()).toEqual([]);
|
||||
});
|
||||
|
||||
it('should not set subtitle on folder media', () => {
|
||||
const controller = new ThumbnailFeatureController();
|
||||
const itemWithThumbnail = new ViewFolder(createFolder(), {
|
||||
title: 'Test Folder',
|
||||
});
|
||||
|
||||
controller.calculate(null, itemWithThumbnail, false);
|
||||
|
||||
expect(controller.getSubtitles()).toContain('Test Folder');
|
||||
});
|
||||
});
|
||||
|
||||
describe('should set icon', () => {
|
||||
it('should set icon without a thumbnail', () => {
|
||||
const controller = new ThumbnailFeatureController();
|
||||
const itemWithThumbnail = new TestViewMedia({
|
||||
thumbnail: null,
|
||||
icon: 'mdi:cow',
|
||||
});
|
||||
|
||||
controller.calculate(null, itemWithThumbnail, false);
|
||||
|
||||
expect(controller.getIcon()).toBe('mdi:cow');
|
||||
});
|
||||
|
||||
it('should not set icon when there is a thumbnail', () => {
|
||||
const controller = new ThumbnailFeatureController();
|
||||
const itemWithThumbnail = new TestViewMedia({
|
||||
thumbnail: 'thumbnail',
|
||||
icon: 'mdi:cow',
|
||||
});
|
||||
|
||||
controller.calculate(null, itemWithThumbnail, false);
|
||||
|
||||
expect(controller.getIcon()).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('should set thumbnail', () => {
|
||||
it('should set brand thumbnail', () => {
|
||||
const controller = new ThumbnailFeatureController();
|
||||
const itemWithThumbnail = new TestViewMedia({
|
||||
thumbnail: 'https://brands.home-assistant.io//amcrest/icon.png',
|
||||
});
|
||||
|
||||
controller.calculate(null, itemWithThumbnail, false);
|
||||
|
||||
expect(controller.getThumbnail()).toBe(
|
||||
'https://brands.home-assistant.io/brands/_/amcrest/icon.png',
|
||||
);
|
||||
expect(controller.getThumbnailClass()).toBe('brand');
|
||||
});
|
||||
|
||||
it('should set other thumbnail', () => {
|
||||
const controller = new ThumbnailFeatureController();
|
||||
const itemWithThumbnail = new TestViewMedia({
|
||||
thumbnail: 'https://card.camera/thumbnail.jpg',
|
||||
});
|
||||
|
||||
controller.calculate(null, itemWithThumbnail, false);
|
||||
|
||||
expect(controller.getThumbnail()).toBe('https://card.camera/thumbnail.jpg');
|
||||
expect(controller.getThumbnailClass()).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user