@@ -0,0 +1,282 @@
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
import { ViewItemManager } from '../../../src/card-controller/view/item-manager';
|
||||
import { homeAssistantSignPath } from '../../../src/ha/sign-path.js';
|
||||
import { downloadURL } from '../../../src/utils/download';
|
||||
import { ViewFolder, ViewMediaType } from '../../../src/view/item';
|
||||
import {
|
||||
createCardAPI,
|
||||
createFolder,
|
||||
createHASS,
|
||||
TestViewMedia,
|
||||
} from '../../test-utils';
|
||||
|
||||
vi.mock('../../../src/utils/download');
|
||||
vi.mock('../../../src/ha/sign-path.js');
|
||||
|
||||
describe('ViewItemManager', () => {
|
||||
describe('getCapabilities', () => {
|
||||
it('should return null for unsupported item types', () => {
|
||||
const api = createCardAPI();
|
||||
const manager = new ViewItemManager(api);
|
||||
|
||||
expect(manager.getCapabilities(new TestViewMedia({ cameraID: null }))).toBeNull();
|
||||
});
|
||||
|
||||
it('should return capabilities for camera media', () => {
|
||||
const api = createCardAPI();
|
||||
const capabilities = {
|
||||
canDownload: true,
|
||||
canFavorite: true,
|
||||
};
|
||||
vi.mocked(api.getCameraManager().getMediaCapabilities).mockReturnValue(
|
||||
capabilities,
|
||||
);
|
||||
|
||||
const manager = new ViewItemManager(api);
|
||||
const item = new TestViewMedia({ cameraID: 'camera.office' });
|
||||
|
||||
expect(manager.getCapabilities(item)).toEqual(capabilities);
|
||||
});
|
||||
|
||||
it('should return capabilities for folder media', () => {
|
||||
const api = createCardAPI();
|
||||
const capabilities = {
|
||||
canDownload: true,
|
||||
canFavorite: true,
|
||||
};
|
||||
vi.mocked(api.getFoldersManager().getItemCapabilities).mockReturnValue(
|
||||
capabilities,
|
||||
);
|
||||
|
||||
const manager = new ViewItemManager(api);
|
||||
const item = new TestViewMedia({ folder: createFolder() });
|
||||
|
||||
expect(manager.getCapabilities(item)).toEqual(capabilities);
|
||||
});
|
||||
});
|
||||
|
||||
describe('download', () => {
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('should not download without hass', async () => {
|
||||
const api = createCardAPI();
|
||||
const manager = new ViewItemManager(api);
|
||||
const item = new TestViewMedia({ cameraID: 'camera.office' });
|
||||
|
||||
expect(await manager.download(item)).toBe(true);
|
||||
expect(downloadURL).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should throw error when signing fails', async () => {
|
||||
const consoleSpy = vi.spyOn(global.console, 'warn').mockReturnValue(undefined);
|
||||
|
||||
const api = createCardAPI();
|
||||
vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS());
|
||||
|
||||
const manager = new ViewItemManager(api);
|
||||
const item = new TestViewMedia({ cameraID: 'camera.office' });
|
||||
|
||||
vi.mocked(api.getCameraManager().getMediaDownloadPath).mockResolvedValue({
|
||||
sign: true,
|
||||
endpoint: 'foo',
|
||||
});
|
||||
|
||||
const signError = new Error('sign-error');
|
||||
vi.mocked(homeAssistantSignPath).mockRejectedValue(signError);
|
||||
|
||||
expect(await manager.download(item)).toBe(false);
|
||||
expect(api.getMessageManager().setErrorIfHigherPriority).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
message: 'Could not sign media URL for download',
|
||||
}),
|
||||
);
|
||||
expect(consoleSpy).toHaveBeenCalledWith('sign-error');
|
||||
});
|
||||
|
||||
it('should download camera media', async () => {
|
||||
const api = createCardAPI();
|
||||
vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS());
|
||||
|
||||
const manager = new ViewItemManager(api);
|
||||
const item = new TestViewMedia({ cameraID: 'camera.office' });
|
||||
|
||||
vi.mocked(api.getCameraManager().getMediaDownloadPath).mockResolvedValue({
|
||||
sign: true,
|
||||
endpoint: 'foo',
|
||||
});
|
||||
|
||||
vi.mocked(homeAssistantSignPath).mockResolvedValue('http://foo/signed-url');
|
||||
|
||||
expect(await manager.download(item)).toBe(true);
|
||||
expect(downloadURL).toBeCalledWith(
|
||||
'http://foo/signed-url',
|
||||
'camera-office_id.mp4',
|
||||
);
|
||||
});
|
||||
|
||||
it('should download folder media', async () => {
|
||||
const api = createCardAPI();
|
||||
vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS());
|
||||
|
||||
const manager = new ViewItemManager(api);
|
||||
const item = new TestViewMedia({ cameraID: null, folder: createFolder() });
|
||||
|
||||
vi.mocked(api.getFoldersManager().getDownloadPath).mockResolvedValue({
|
||||
sign: true,
|
||||
endpoint: 'foo',
|
||||
});
|
||||
|
||||
vi.mocked(homeAssistantSignPath).mockResolvedValue('http://foo/signed-url');
|
||||
|
||||
expect(await manager.download(item)).toBe(true);
|
||||
expect(downloadURL).toBeCalledWith('http://foo/signed-url', 'media_id.mp4');
|
||||
});
|
||||
|
||||
it('should download media without signing', async () => {
|
||||
const api = createCardAPI();
|
||||
vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS());
|
||||
|
||||
const manager = new ViewItemManager(api);
|
||||
const item = new TestViewMedia({ cameraID: 'camera.office' });
|
||||
|
||||
vi.mocked(api.getCameraManager().getMediaDownloadPath).mockResolvedValue({
|
||||
sign: false,
|
||||
endpoint: 'foo',
|
||||
});
|
||||
|
||||
expect(homeAssistantSignPath).not.toBeCalled();
|
||||
|
||||
expect(await manager.download(item)).toBe(true);
|
||||
expect(downloadURL).toBeCalledWith('foo', 'camera-office_id.mp4');
|
||||
});
|
||||
|
||||
it('should download media without camera or folder', async () => {
|
||||
const api = createCardAPI();
|
||||
vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS());
|
||||
|
||||
const manager = new ViewItemManager(api);
|
||||
const item = new TestViewMedia({ cameraID: null, folder: null });
|
||||
|
||||
expect(await manager.download(item)).toBe(false);
|
||||
expect(api.getMessageManager().setErrorIfHigherPriority).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
message: 'No media to download',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
describe('should generate useful download filenames', () => {
|
||||
it('should generate filename for media without ID', async () => {
|
||||
const api = createCardAPI();
|
||||
vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS());
|
||||
|
||||
const manager = new ViewItemManager(api);
|
||||
const item = new TestViewMedia({ id: null });
|
||||
|
||||
vi.mocked(api.getCameraManager().getMediaDownloadPath).mockResolvedValue({
|
||||
sign: false,
|
||||
endpoint: 'foo',
|
||||
});
|
||||
|
||||
expect(await manager.download(item)).toBe(true);
|
||||
expect(downloadURL).toBeCalledWith('foo', 'camera.mp4');
|
||||
});
|
||||
|
||||
it('should generate filename for media with start time', async () => {
|
||||
const api = createCardAPI();
|
||||
vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS());
|
||||
|
||||
const manager = new ViewItemManager(api);
|
||||
const item = new TestViewMedia({ startTime: new Date('2025-05-03T17:41:00Z') });
|
||||
|
||||
vi.mocked(api.getCameraManager().getMediaDownloadPath).mockResolvedValue({
|
||||
sign: false,
|
||||
endpoint: 'foo',
|
||||
});
|
||||
|
||||
expect(await manager.download(item)).toBe(true);
|
||||
expect(downloadURL).toBeCalledWith('foo', 'camera_id_2025-05-03-17-41-00.mp4');
|
||||
});
|
||||
|
||||
it('should generate filename for snapshot', async () => {
|
||||
const api = createCardAPI();
|
||||
vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS());
|
||||
|
||||
const manager = new ViewItemManager(api);
|
||||
const item = new TestViewMedia({ mediaType: ViewMediaType.Snapshot });
|
||||
|
||||
vi.mocked(api.getCameraManager().getMediaDownloadPath).mockResolvedValue({
|
||||
sign: false,
|
||||
endpoint: 'foo',
|
||||
});
|
||||
|
||||
expect(await manager.download(item)).toBe(true);
|
||||
expect(downloadURL).toBeCalledWith('foo', 'camera_id.jpg');
|
||||
});
|
||||
|
||||
it('should generate filename for folder without title', async () => {
|
||||
const api = createCardAPI();
|
||||
vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS());
|
||||
|
||||
const manager = new ViewItemManager(api);
|
||||
const item = new ViewFolder(createFolder());
|
||||
|
||||
vi.mocked(api.getFoldersManager().getDownloadPath).mockResolvedValue({
|
||||
sign: false,
|
||||
endpoint: 'foo',
|
||||
});
|
||||
|
||||
expect(await manager.download(item)).toBe(true);
|
||||
expect(downloadURL).toBeCalledWith('foo', 'media');
|
||||
});
|
||||
|
||||
it('should generate filename for folder with title', async () => {
|
||||
const api = createCardAPI();
|
||||
vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS());
|
||||
|
||||
const manager = new ViewItemManager(api);
|
||||
const item = new ViewFolder(createFolder(), { title: 'title' });
|
||||
|
||||
vi.mocked(api.getFoldersManager().getDownloadPath).mockResolvedValue({
|
||||
sign: false,
|
||||
endpoint: 'foo',
|
||||
});
|
||||
|
||||
expect(await manager.download(item)).toBe(true);
|
||||
expect(downloadURL).toBeCalledWith('foo', 'title');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('favorite', () => {
|
||||
it('should favorite camera media', async () => {
|
||||
const api = createCardAPI();
|
||||
|
||||
const manager = new ViewItemManager(api);
|
||||
const item = new TestViewMedia({
|
||||
cameraID: 'camera.office',
|
||||
mediaType: ViewMediaType.Snapshot,
|
||||
});
|
||||
|
||||
await manager.favorite(item, true);
|
||||
|
||||
expect(api.getCameraManager().favoriteMedia).toBeCalledWith(item, true);
|
||||
});
|
||||
|
||||
it('should favorite folder media', async () => {
|
||||
const api = createCardAPI();
|
||||
|
||||
const manager = new ViewItemManager(api);
|
||||
const item = new TestViewMedia({
|
||||
folder: createFolder(),
|
||||
mediaType: ViewMediaType.Snapshot,
|
||||
});
|
||||
|
||||
await manager.favorite(item, true);
|
||||
|
||||
expect(api.getFoldersManager().favorite).toBeCalledWith(item, true);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user