417 lines
14 KiB
TypeScript
417 lines
14 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
import { FrigateCardView } from '../../src/config/types';
|
|
import { StyleManager } from '../../src/card-controller/style-manager';
|
|
import { createCardAPI, createConfig, createHASS, createView } from '../test-utils';
|
|
|
|
// @vitest-environment jsdom
|
|
describe('StyleManager', () => {
|
|
beforeEach(() => {
|
|
vi.resetAllMocks();
|
|
});
|
|
|
|
describe('setLightOrDarkMode', () => {
|
|
it('dark mode unspecified', () => {
|
|
const api = createCardAPI();
|
|
const element = document.createElement('div');
|
|
vi.mocked(api.getCardElementManager().getElement).mockReturnValue(element);
|
|
const manager = new StyleManager(api);
|
|
|
|
manager.setLightOrDarkMode();
|
|
|
|
expect(element.getAttribute('dark')).toBeNull();
|
|
});
|
|
|
|
it('dark mode explicitly off', () => {
|
|
const api = createCardAPI();
|
|
const element = document.createElement('div');
|
|
vi.mocked(api.getCardElementManager().getElement).mockReturnValue(element);
|
|
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(
|
|
createConfig({
|
|
view: {
|
|
dark_mode: 'off',
|
|
},
|
|
}),
|
|
);
|
|
const manager = new StyleManager(api);
|
|
|
|
manager.setLightOrDarkMode();
|
|
|
|
expect(element.getAttribute('dark')).toBeNull();
|
|
});
|
|
|
|
it('dark mode explicitly set', () => {
|
|
const api = createCardAPI();
|
|
const element = document.createElement('div');
|
|
vi.mocked(api.getCardElementManager().getElement).mockReturnValue(element);
|
|
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(
|
|
createConfig({
|
|
view: {
|
|
dark_mode: 'on',
|
|
},
|
|
}),
|
|
);
|
|
const manager = new StyleManager(api);
|
|
|
|
manager.setLightOrDarkMode();
|
|
|
|
expect(element.getAttribute('dark')).not.toBeNull();
|
|
});
|
|
|
|
it('dark mode auto without interaction', () => {
|
|
const api = createCardAPI();
|
|
const element = document.createElement('div');
|
|
vi.mocked(api.getCardElementManager().getElement).mockReturnValue(element);
|
|
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(
|
|
createConfig({
|
|
view: {
|
|
dark_mode: 'auto',
|
|
},
|
|
}),
|
|
);
|
|
vi.mocked(api.getInteractionManager().hasInteraction).mockReturnValue(false);
|
|
const manager = new StyleManager(api);
|
|
|
|
manager.setLightOrDarkMode();
|
|
|
|
expect(element.getAttribute('dark')).not.toBeNull();
|
|
});
|
|
|
|
it('dark mode auto with HA dark mode', () => {
|
|
const api = createCardAPI();
|
|
const element = document.createElement('div');
|
|
vi.mocked(api.getCardElementManager().getElement).mockReturnValue(element);
|
|
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(
|
|
createConfig({
|
|
view: {
|
|
dark_mode: 'auto',
|
|
},
|
|
}),
|
|
);
|
|
vi.mocked(api.getInteractionManager().hasInteraction).mockReturnValue(true);
|
|
const hass = createHASS();
|
|
hass.themes.darkMode = true;
|
|
vi.mocked(api.getHASSManager().getHASS).mockReturnValue(hass);
|
|
const manager = new StyleManager(api);
|
|
|
|
manager.setLightOrDarkMode();
|
|
|
|
expect(element.getAttribute('dark')).not.toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('setExpandedMode', () => {
|
|
it('with no view or known media', () => {
|
|
const api = createCardAPI();
|
|
const element = document.createElement('div');
|
|
vi.mocked(api.getCardElementManager().getElement).mockReturnValue(element);
|
|
vi.mocked(api.getMediaLoadedInfoManager().getLastKnown).mockReturnValue(null);
|
|
const manager = new StyleManager(api);
|
|
|
|
manager.setExpandedMode();
|
|
|
|
expect(element.style.getPropertyValue('--frigate-card-expand-aspect-ratio')).toBe(
|
|
'unset',
|
|
);
|
|
expect(element.style.getPropertyValue('--frigate-card-expand-width')).toBe(
|
|
'var(--frigate-card-expand-max-width)',
|
|
);
|
|
expect(element.style.getPropertyValue('--frigate-card-expand-height')).toBe(
|
|
'var(--frigate-card-expand-max-height)',
|
|
);
|
|
});
|
|
|
|
it('with view but without media', () => {
|
|
const api = createCardAPI();
|
|
const element = document.createElement('div');
|
|
vi.mocked(api.getCardElementManager().getElement).mockReturnValue(element);
|
|
const view = createView({ view: 'media', displayMode: 'single' });
|
|
vi.mocked(api.getViewManager().getView).mockReturnValue(view);
|
|
vi.mocked(api.getMediaLoadedInfoManager().getLastKnown).mockReturnValue(null);
|
|
const manager = new StyleManager(api);
|
|
|
|
manager.setExpandedMode();
|
|
|
|
expect(element.style.getPropertyValue('--frigate-card-expand-aspect-ratio')).toBe(
|
|
'unset',
|
|
);
|
|
expect(element.style.getPropertyValue('--frigate-card-expand-width')).toBe('none');
|
|
expect(element.style.getPropertyValue('--frigate-card-expand-height')).toBe(
|
|
'none',
|
|
);
|
|
});
|
|
|
|
it('with view and media', () => {
|
|
const api = createCardAPI();
|
|
const element = document.createElement('div');
|
|
vi.mocked(api.getCardElementManager().getElement).mockReturnValue(element);
|
|
const view = createView({ view: 'media', displayMode: 'single' });
|
|
vi.mocked(api.getViewManager().getView).mockReturnValue(view);
|
|
vi.mocked(api.getMediaLoadedInfoManager().getLastKnown).mockReturnValue({
|
|
width: 800,
|
|
height: 600,
|
|
});
|
|
const manager = new StyleManager(api);
|
|
|
|
manager.setExpandedMode();
|
|
|
|
expect(element.style.getPropertyValue('--frigate-card-expand-aspect-ratio')).toBe(
|
|
'800 / 600',
|
|
);
|
|
expect(element.style.getPropertyValue('--frigate-card-expand-width')).toBe('none');
|
|
expect(element.style.getPropertyValue('--frigate-card-expand-height')).toBe(
|
|
'none',
|
|
);
|
|
});
|
|
|
|
it('with view and grid display mode', () => {
|
|
const api = createCardAPI();
|
|
const element = document.createElement('div');
|
|
vi.mocked(api.getCardElementManager().getElement).mockReturnValue(element);
|
|
const view = createView({ view: 'media', displayMode: 'grid' });
|
|
vi.mocked(api.getViewManager().getView).mockReturnValue(view);
|
|
vi.mocked(api.getMediaLoadedInfoManager().getLastKnown).mockReturnValue({
|
|
width: 800,
|
|
height: 600,
|
|
});
|
|
const manager = new StyleManager(api);
|
|
|
|
manager.setExpandedMode();
|
|
|
|
expect(element.style.getPropertyValue('--frigate-card-expand-aspect-ratio')).toBe(
|
|
'800 / 600',
|
|
);
|
|
expect(element.style.getPropertyValue('--frigate-card-expand-width')).toBe(
|
|
'var(--frigate-card-expand-max-width)',
|
|
);
|
|
expect(element.style.getPropertyValue('--frigate-card-expand-height')).toBe(
|
|
'var(--frigate-card-expand-max-height)',
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('setMinMaxHeight', () => {
|
|
it('without a config', () => {
|
|
const api = createCardAPI();
|
|
const element = document.createElement('div');
|
|
vi.mocked(api.getCardElementManager().getElement).mockReturnValue(element);
|
|
const manager = new StyleManager(api);
|
|
|
|
manager.setMinMaxHeight();
|
|
|
|
expect(element.style.getPropertyValue('--frigate-card-max-height')).toBeFalsy();
|
|
expect(element.style.getPropertyValue('--frigate-card-expand-height')).toBeFalsy();
|
|
});
|
|
|
|
it('with a config', () => {
|
|
const api = createCardAPI();
|
|
const element = document.createElement('div');
|
|
vi.mocked(api.getCardElementManager().getElement).mockReturnValue(element);
|
|
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(
|
|
createConfig({
|
|
dimensions: {
|
|
max_height: '800px',
|
|
min_height: '400px',
|
|
},
|
|
}),
|
|
);
|
|
const manager = new StyleManager(api);
|
|
|
|
manager.setMinMaxHeight();
|
|
|
|
expect(element.style.getPropertyValue('--frigate-card-min-height')).toBe('400px');
|
|
expect(element.style.getPropertyValue('--frigate-card-max-height')).toBe('800px');
|
|
});
|
|
});
|
|
|
|
describe('setPerformance', () => {
|
|
it('no styles set', () => {
|
|
const api = createCardAPI();
|
|
const element = document.createElement('div');
|
|
vi.mocked(api.getCardElementManager().getElement).mockReturnValue(element);
|
|
vi.mocked(api.getConfigManager().getCardWideConfig).mockReturnValue({});
|
|
const manager = new StyleManager(api);
|
|
|
|
manager.setPerformance();
|
|
|
|
expect(
|
|
element.style.getPropertyValue('--frigate-card-css-box-shadow'),
|
|
).toBeFalsy();
|
|
expect(
|
|
element.style.getPropertyValue('--frigate-card-css-border-radius'),
|
|
).toBeFalsy();
|
|
});
|
|
|
|
it('valid styles set', () => {
|
|
const api = createCardAPI();
|
|
const element = document.createElement('div');
|
|
vi.mocked(api.getCardElementManager().getElement).mockReturnValue(element);
|
|
vi.mocked(api.getConfigManager().getCardWideConfig).mockReturnValue(
|
|
createConfig({
|
|
performance: {
|
|
style: {
|
|
box_shadow: false,
|
|
border_radius: true,
|
|
},
|
|
},
|
|
}),
|
|
);
|
|
const manager = new StyleManager(api);
|
|
|
|
manager.setPerformance();
|
|
|
|
expect(element.style.getPropertyValue('--frigate-card-css-box-shadow')).toEqual(
|
|
'none',
|
|
);
|
|
expect(
|
|
element.style.getPropertyValue('--frigate-card-css-border-radius'),
|
|
).toBeFalsy();
|
|
});
|
|
});
|
|
|
|
describe('getAspectRatioStyle', () => {
|
|
it('without config or view', () => {
|
|
const api = createCardAPI();
|
|
const manager = new StyleManager(api);
|
|
expect(manager.getAspectRatioStyle()).toEqual({ 'aspect-ratio': '16 / 9' });
|
|
});
|
|
|
|
it('should be auto with unconstrained aspect ratio', () => {
|
|
const api = createCardAPI();
|
|
const view = createView({ view: 'media' });
|
|
vi.mocked(api.getViewManager().getView).mockReturnValue(view);
|
|
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(
|
|
createConfig({
|
|
dimensions: {
|
|
aspect_ratio_mode: 'unconstrained',
|
|
},
|
|
}),
|
|
);
|
|
const manager = new StyleManager(api);
|
|
expect(manager.getAspectRatioStyle()).toEqual({ 'aspect-ratio': 'auto' });
|
|
});
|
|
|
|
it('should be auto in fullscreen', () => {
|
|
const api = createCardAPI();
|
|
const view = createView({ view: 'media' });
|
|
vi.mocked(api.getViewManager().getView).mockReturnValue(view);
|
|
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig());
|
|
vi.mocked(api.getFullscreenManager().isInFullscreen).mockReturnValue(true);
|
|
const manager = new StyleManager(api);
|
|
|
|
expect(manager.getAspectRatioStyle()).toEqual({ 'aspect-ratio': 'auto' });
|
|
});
|
|
|
|
it('should be auto when expanded', () => {
|
|
const api = createCardAPI();
|
|
const view = createView({ view: 'media' });
|
|
vi.mocked(api.getViewManager().getView).mockReturnValue(view);
|
|
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig());
|
|
vi.mocked(api.getExpandManager().isExpanded).mockReturnValue(true);
|
|
const manager = new StyleManager(api);
|
|
|
|
expect(manager.getAspectRatioStyle()).toEqual({ 'aspect-ratio': 'auto' });
|
|
});
|
|
|
|
it('should be auto when there is yet to be a view', () => {
|
|
const api = createCardAPI();
|
|
vi.mocked(api.getViewManager().getView).mockReturnValue(null);
|
|
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig());
|
|
const manager = new StyleManager(api);
|
|
|
|
expect(manager.getAspectRatioStyle()).toEqual({ 'aspect-ratio': 'auto' });
|
|
});
|
|
|
|
describe('should be auto when dynamic in certain views', () => {
|
|
it.each([
|
|
['clip' as const],
|
|
['diagnostics' as const],
|
|
['image' as const],
|
|
['media' as const],
|
|
['live' as const],
|
|
['recording' as const],
|
|
['snapshot' as const],
|
|
['timeline' as const],
|
|
])('%s', (viewName: FrigateCardView) => {
|
|
const api = createCardAPI();
|
|
const view = createView({ view: viewName });
|
|
vi.mocked(api.getViewManager().getView).mockReturnValue(view);
|
|
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(
|
|
createConfig({
|
|
dimensions: {
|
|
aspect_ratio_mode: 'dynamic',
|
|
},
|
|
}),
|
|
);
|
|
const manager = new StyleManager(api);
|
|
|
|
expect(manager.getAspectRatioStyle()).toEqual({ 'aspect-ratio': 'auto' });
|
|
});
|
|
});
|
|
|
|
describe('should be enforced when dynamic in certain views', () => {
|
|
it.each([['clips' as const], ['recordings' as const], ['snapshots' as const]])(
|
|
'%s',
|
|
(viewName: FrigateCardView) => {
|
|
const api = createCardAPI();
|
|
const view = createView({ view: viewName });
|
|
vi.mocked(api.getViewManager().getView).mockReturnValue(view);
|
|
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(
|
|
createConfig({
|
|
dimensions: {
|
|
aspect_ratio_mode: 'dynamic',
|
|
},
|
|
}),
|
|
);
|
|
const manager = new StyleManager(api);
|
|
|
|
expect(manager.getAspectRatioStyle()).toEqual({ 'aspect-ratio': '16 / 9' });
|
|
},
|
|
);
|
|
});
|
|
|
|
describe('should use media dimensions in dynamic', () => {
|
|
it.each([['clips' as const], ['recordings' as const], ['snapshots' as const]])(
|
|
'%s',
|
|
(viewName: FrigateCardView) => {
|
|
const api = createCardAPI();
|
|
const view = createView({ view: viewName });
|
|
vi.mocked(api.getViewManager().getView).mockReturnValue(view);
|
|
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(
|
|
createConfig({
|
|
dimensions: {
|
|
aspect_ratio_mode: 'dynamic',
|
|
},
|
|
}),
|
|
);
|
|
vi.mocked(api.getMediaLoadedInfoManager().getLastKnown).mockReturnValue({
|
|
width: 800,
|
|
height: 600,
|
|
});
|
|
const manager = new StyleManager(api);
|
|
|
|
expect(manager.getAspectRatioStyle()).toEqual({
|
|
'aspect-ratio': '800 / 600',
|
|
});
|
|
},
|
|
);
|
|
});
|
|
|
|
it('should respect default aspect ratio', () => {
|
|
const api = createCardAPI();
|
|
const view = createView({ view: 'clips' });
|
|
vi.mocked(api.getViewManager().getView).mockReturnValue(view);
|
|
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(
|
|
createConfig({
|
|
dimensions: {
|
|
aspect_ratio_mode: 'dynamic',
|
|
aspect_ratio: '4:3',
|
|
},
|
|
}),
|
|
);
|
|
const manager = new StyleManager(api);
|
|
|
|
expect(manager.getAspectRatioStyle()).toEqual({ 'aspect-ratio': '4 / 3' });
|
|
});
|
|
});
|
|
});
|