Files
advanced-camera-card/tests/card-controller/config/config-manager.test.ts
T
Paul Botteinanddermotduffy b33c034810 feat: Add card picker suggestion for camera entities (#2517)
Selecting a camera entity in the dashboard card picker now suggests
Advanced Camera Card under the Community section, so you can add it in
one click without searching for it manually.

Requires Home Assistant 2026.6 or later.

Docs:
https://developers.home-assistant.io/docs/frontend/custom-ui/custom-card#suggesting-your-card-for-an-entity

---------

Co-authored-by: dermotduffy <dermot.duffy@gmail.com>
2026-06-30 17:45:13 -07:00

898 lines
30 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from 'vitest';
import { ZodError, type z } from 'zod';
import { AutomationsManager } from '../../../src/card-controller/automations-manager';
import { ConfigManager } from '../../../src/card-controller/config/config-manager';
import { setRemoteControlEntityFromConfig } from '../../../src/card-controller/config/load-control-entities';
import { setKeyboardShortcutsFromConfig } from '../../../src/card-controller/config/load-keyboard-shortcuts';
import { InitializationAspect } from '../../../src/card-controller/initialization-manager';
import { ConditionStateManager } from '../../../src/condition-trigger/conditions/state-manager';
import type { Automation } from '../../../src/config/schema/automations';
import type { Trigger } from '../../../src/config/schema/condition-trigger/triggers/types';
import { advancedCameraCardConfigSchema } from '../../../src/config/schema/types';
import { createGeneralAction } from '../../../src/utils/action';
import {
createCardAPI,
createConfig,
createHASS,
createStateEntity,
flushPromises,
} from '../../test-utils';
/**
* Create a ConfigManager test setup with real AutomationsManager and ConditionStateManager.
* Includes spies for automation manager methods to track calls in tests.
*/
function createConfigManagerTestSetup(options?: {
hasHASS?: boolean;
isInitializedMandatory?: boolean;
}) {
const api = createCardAPI();
const stateManager = new ConditionStateManager();
vi.mocked(api.getConditionStateManager).mockReturnValue(stateManager);
const automationsManager = new AutomationsManager(api);
vi.mocked(api.getAutomationsManager).mockReturnValue(automationsManager);
vi.mocked(api.getHASSManager().hasHASS).mockReturnValue(options?.hasHASS ?? true);
vi.mocked(api.getInitializationManager().isInitializedMandatory).mockReturnValue(
options?.isInitializedMandatory ?? true,
);
const manager = new ConfigManager(api);
vi.mocked(api.getConfigManager).mockReturnValue(manager);
const addAutomationsSpy = vi.spyOn(automationsManager, 'addAutomations');
const deleteAutomationsSpy = vi.spyOn(automationsManager, 'deleteAutomations');
return {
api,
manager,
stateManager,
automationsManager,
addAutomationsSpy,
deleteAutomationsSpy,
};
}
// ============================================================================
// Test Constants - Centralized test data to avoid magic numbers/strings
// ============================================================================
/** Test camera entities - Primary is used for standard tests */
const TEST_CAMERAS = {
OFFICE: { camera_entity: 'camera.office' },
KITCHEN: { camera_entity: 'camera.kitchen' },
} as const;
/** Override conditions commonly used in tests */
const TEST_CONDITIONS = {
FULLSCREEN_ON: { condition: 'fullscreen' as const, fullscreen: true },
FULLSCREEN_OFF: { condition: 'fullscreen' as const, fullscreen: false },
} as const;
/** Profile settings for testing */
const TEST_PROFILES = {
CASTING: 'casting' as const,
LOW_PERFORMANCE: 'low-performance' as const,
} as const;
describe('ConfigManager', () => {
beforeEach(() => {
vi.restoreAllMocks();
});
describe('getEntitySuggestion', () => {
it('should suggest the card for a camera entity', () => {
const hass = createHASS({ 'camera.office': createStateEntity() });
expect(ConfigManager.getEntitySuggestion(hass, 'camera.office')).toEqual({
config: {
type: 'custom:advanced-camera-card',
cameras: [{ camera_entity: 'camera.office' }],
},
});
});
it('should not suggest the card for a non-camera entity', () => {
const hass = createHASS({ 'binary_sensor.motion': createStateEntity() });
expect(ConfigManager.getEntitySuggestion(hass, 'binary_sensor.motion')).toBeNull();
});
it('should not suggest the card for an unknown entity', () => {
const hass = createHASS({});
expect(ConfigManager.getEntitySuggestion(hass, 'camera.office')).toBeNull();
});
});
describe('getStubConfig', () => {
it('should handle with camera entities', () => {
expect(
ConfigManager.getStubConfig(['camera.office', 'binary_sensor.motion']),
).toEqual({
cameras: [{ camera_entity: 'camera.office' }],
});
});
it('should handle without camera entities', () => {
expect(ConfigManager.getStubConfig(['binary_sensor.motion'])).toEqual({
cameras: [{ camera_entity: 'camera.demo' }],
});
});
});
describe('should handle error when', () => {
it('should handle no input', () => {
const manager = new ConfigManager(createCardAPI());
expect(() => manager.setConfig()).toThrowError(/Invalid configuration/);
});
it('should handle invalid configuration', () => {
const schemaForMock: z.ZodType = advancedCameraCardConfigSchema;
const spy = vi
.spyOn(schemaForMock, 'safeParse')
.mockReturnValue({ success: false, error: new ZodError([]) });
const manager = new ConfigManager(createCardAPI());
expect(() => manager.setConfig({})).toThrowError(
'Invalid configuration: No location hint available (bad or missing type?)',
);
spy.mockRestore();
});
it('should handle invalid configuration with hint', () => {
const manager = new ConfigManager(createCardAPI());
expect(() => manager.setConfig({})).toThrowError(
'Invalid configuration: [\n "type"\n]',
);
});
it('should handle upgradeable config', () => {
const manager = new ConfigManager(createCardAPI());
expect(() =>
manager.setConfig({
// This key needs to be upgradeable in `management.ts` .
type: 'custom:frigate-card',
cameras: 'WILL_NOT_PARSE',
}),
).toThrowError(
'An automated card configuration upgrade is ' +
'available, please visit the visual card editor. ' +
'Invalid configuration: [\n "cameras"\n]',
);
});
});
it('should have initial state', () => {
const manager = new ConfigManager(createCardAPI());
expect(manager.getConfig()).toBeNull();
expect(manager.getNonOverriddenConfig()).toBeNull();
expect(manager.getRawConfig()).toBeNull();
});
it('should successfully parse basic config', () => {
const api = createCardAPI();
const manager = new ConfigManager(api);
const config = {
type: 'custom:advanced-camera-card',
cameras: [TEST_CAMERAS.OFFICE],
};
manager.setConfig(config);
expect(manager.hasConfig()).toBeTruthy();
expect(manager.getRawConfig()).toBe(config);
// Verify at least the camera is set.
expect(manager.getConfig()?.cameras?.[0].camera_entity).toBe('camera.office');
// Verify at least one default was set.
expect(manager.getConfig()?.menu.alignment).toBe('left');
// Verify appropriate API calls are made.
expect(api.getConditionStateManager().setState).toBeCalledWith({
view: undefined,
displayMode: undefined,
camera: undefined,
});
expect(api.getIssueManager().reset).toBeCalledWith('config_error');
expect(api.getMediaLoadedInfoManager().clear).toBeCalled();
expect(api.getViewManager().reset).toBeCalled();
expect(api.getAutomationsManager().addAutomations).toBeCalled();
expect(api.getStyleManager().updateFromConfig).toBeCalled();
expect(api.getCardElementManager().update).toBeCalled();
});
it('should apply profiles', () => {
const manager = new ConfigManager(createCardAPI());
const config = {
type: 'custom:advanced-camera-card',
cameras: [TEST_CAMERAS.OFFICE],
profiles: [TEST_PROFILES.LOW_PERFORMANCE],
};
manager.setConfig(config);
// Verify at least one low performance default.
expect(manager.getConfig()?.live.draggable).toBeFalsy();
});
it('should apply casting profile menu changes without affecting unrelated hidden buttons', () => {
const manager = new ConfigManager(createCardAPI());
const config = {
type: 'custom:advanced-camera-card',
cameras: [TEST_CAMERAS.OFFICE],
profiles: [TEST_PROFILES.CASTING],
};
manager.setConfig(config);
expect(manager.getConfig()?.menu.buttons.play.enabled).toBeTruthy();
expect(manager.getConfig()?.menu.buttons.mute.enabled).toBeTruthy();
expect(manager.getConfig()?.menu.buttons.fullscreen.enabled).toBeFalsy();
expect(manager.getConfig()?.menu.buttons.media_player.enabled).toBeFalsy();
expect(manager.getConfig()?.menu.buttons.clips.enabled).toBeFalsy();
});
it('should skip identical configs', () => {
const api = createCardAPI();
const manager = new ConfigManager(api);
const config = {
type: 'custom:advanced-camera-card',
cameras: [TEST_CAMERAS.OFFICE],
};
manager.setConfig(config);
expect(api.getViewManager().reset).toBeCalled();
vi.mocked(api.getViewManager().reset).mockClear();
manager.setConfig(config);
expect(api.getViewManager().reset).not.toBeCalled();
});
it('should get card wide config', () => {
const api = createCardAPI();
const manager = new ConfigManager(api);
const config = {
type: 'custom:advanced-camera-card',
cameras: [TEST_CAMERAS.OFFICE],
debug: {
logging: true,
},
performance: {
style: {
box_shadow: false,
},
},
};
manager.setConfig(config);
expect(manager.getCardWideConfig()).toEqual({
debug: {
logging: true,
},
performance: {
features: {
animated_progress_indicator: true,
card_loading_indicator: true,
card_loading_effects: true,
media_chunk_size: 50,
},
style: {
border_radius: true,
box_shadow: false,
},
},
});
});
describe('should override', () => {
it('should ignore overrides with same config', () => {
const api = createCardAPI();
const stateManager = new ConditionStateManager();
vi.mocked(api.getConditionStateManager).mockReturnValue(stateManager);
const manager = new ConfigManager(api);
const cameras = [TEST_CAMERAS.OFFICE];
const config = {
type: 'custom:advanced-camera-card',
cameras: cameras,
menu: {
style: 'hidden',
position: 'top',
},
overrides: [
{
conditions: [TEST_CONDITIONS.FULLSCREEN_ON],
set: {
// Override with the same.
cameras: cameras,
},
},
],
};
manager.setConfig(config);
const configBefore = manager.getConfig();
stateManager.setState({ fullscreen: true });
const configAfter = manager.getConfig();
expect(configAfter).toEqual(configBefore);
expect(api.getStyleManager().updateFromConfig).toBeCalledTimes(1);
});
it('should honor override', () => {
const api = createCardAPI();
const stateManager = new ConditionStateManager();
vi.mocked(api.getConditionStateManager).mockReturnValue(stateManager);
const manager = new ConfigManager(api);
const config = createConfig({
menu: {
style: 'hidden',
},
overrides: [
{
conditions: [TEST_CONDITIONS.FULLSCREEN_ON],
set: { 'menu.style': 'none' },
},
],
});
manager.setConfig(config);
expect(manager.getConfig()?.menu?.style).toBe('hidden');
stateManager.setState({ fullscreen: true });
expect(manager.getConfig()?.menu?.style).toBe('none');
expect(manager.getConfig()).not.toEqual(manager.getNonOverriddenConfig());
});
it('should set error on invalid override', () => {
const api = createCardAPI();
const stateManager = new ConditionStateManager();
vi.mocked(api.getConditionStateManager).mockReturnValue(stateManager);
const manager = new ConfigManager(api);
const config = {
type: 'custom:advanced-camera-card',
cameras: [TEST_CAMERAS.OFFICE],
overrides: [
{
conditions: [TEST_CONDITIONS.FULLSCREEN_ON],
delete: ['type'],
},
],
};
manager.setConfig(config);
expect(manager.getConfig()).not.toBeNull();
stateManager.setState({ fullscreen: true });
expect(manager.getConfig()).not.toBeNull();
expect(api.getIssueManager().trigger).toBeCalledWith(
'config_error',
expect.objectContaining({ error: expect.any(Error) }),
);
});
describe('should uninitialize on override', () => {
it('should uninitialize cameras', () => {
const api = createCardAPI();
const stateManager = new ConditionStateManager();
vi.mocked(api.getConditionStateManager).mockReturnValue(stateManager);
const manager = new ConfigManager(api);
const config = {
type: 'custom:advanced-camera-card',
cameras: [TEST_CAMERAS.OFFICE],
overrides: [
{
conditions: [TEST_CONDITIONS.FULLSCREEN_ON],
set: {
cameras: [TEST_CAMERAS.KITCHEN],
},
},
],
};
manager.setConfig(config);
expect(api.getInitializationManager().uninitialize).not.toHaveBeenCalledWith(
InitializationAspect.CAMERAS,
);
stateManager.setState({ fullscreen: true });
expect(api.getInitializationManager().uninitialize).toHaveBeenCalledWith(
InitializationAspect.CAMERAS,
);
});
it('should uninitialize cameras_global', () => {
const api = createCardAPI();
const stateManager = new ConditionStateManager();
vi.mocked(api.getConditionStateManager).mockReturnValue(stateManager);
const manager = new ConfigManager(api);
const config = {
type: 'custom:advanced-camera-card',
cameras: [TEST_CAMERAS.OFFICE],
overrides: [
{
conditions: [TEST_CONDITIONS.FULLSCREEN_ON],
set: {
cameras_global: { live_provider: 'jsmpeg' },
},
},
],
};
manager.setConfig(config);
expect(api.getInitializationManager().uninitialize).not.toHaveBeenCalledWith(
InitializationAspect.CAMERAS,
);
stateManager.setState({ fullscreen: true });
expect(api.getInitializationManager().uninitialize).toHaveBeenCalledWith(
InitializationAspect.CAMERAS,
);
});
it('should uninitialize live.microphone.always_connected', () => {
const api = createCardAPI();
const stateManager = new ConditionStateManager();
vi.mocked(api.getConditionStateManager).mockReturnValue(stateManager);
const manager = new ConfigManager(api);
const config = {
type: 'custom:advanced-camera-card',
cameras: [TEST_CAMERAS.OFFICE],
overrides: [
{
conditions: [TEST_CONDITIONS.FULLSCREEN_ON],
set: {
'live.microphone.always_connected': true,
},
},
],
};
manager.setConfig(config);
expect(api.getInitializationManager().uninitialize).not.toHaveBeenCalledWith(
InitializationAspect.MICROPHONE_CONNECT,
);
stateManager.setState({ fullscreen: true });
expect(api.getInitializationManager().uninitialize).toHaveBeenCalledWith(
InitializationAspect.MICROPHONE_CONNECT,
);
});
});
describe('should initialize on override', () => {
it('should initialize background items', async () => {
const api = createCardAPI();
const stateManager = new ConditionStateManager();
const listener = vi.fn();
stateManager.addListener(listener);
vi.mocked(api.getConditionStateManager).mockReturnValue(stateManager);
const manager = new ConfigManager(api);
const config = {
type: 'custom:advanced-camera-card',
cameras: [TEST_CAMERAS.OFFICE],
overrides: [
{
conditions: [TEST_CONDITIONS.FULLSCREEN_ON],
set: {
cameras: [TEST_CAMERAS.KITCHEN],
},
},
],
};
manager.setConfig(config);
await flushPromises();
expect(api.getDefaultManager().initializeIfNecessary).toBeCalledTimes(1);
expect(api.getMediaPlayerManager().initializeIfNecessary).toBeCalledTimes(1);
expect(listener).not.toBeCalledWith(
expect.objectContaining({ change: { config: expect.anything() } }),
);
vi.mocked(api.getInitializationManager().isInitializedMandatory).mockReturnValue(
true,
);
stateManager.setState({ fullscreen: true });
await flushPromises();
expect(api.getDefaultManager().initializeIfNecessary).toBeCalledTimes(2);
expect(api.getMediaPlayerManager().initializeIfNecessary).toBeCalledTimes(2);
// Should set the config condition state.
expect(listener).toBeCalledWith(
expect.objectContaining({ change: { config: expect.anything() } }),
);
});
});
describe('loaders should re-run when overrides change', () => {
it('should re-run keyboard-shortcuts loader when overrides change', async () => {
const { manager, stateManager, addAutomationsSpy } =
createConfigManagerTestSetup();
const config = createConfig({
view: {
keyboard_shortcuts: {
enabled: true,
ptz_home: { key: 'h' },
},
},
overrides: [
{
delete: ['view.keyboard_shortcuts'],
conditions: [TEST_CONDITIONS.FULLSCREEN_ON],
},
],
});
manager.setConfig(config);
await flushPromises();
// Verify keyboard shortcuts automations were added initially with ptz_home
expect(addAutomationsSpy).toHaveBeenCalledWith(
expect.arrayContaining([
expect.objectContaining({
triggers: expect.arrayContaining([
expect.objectContaining({ trigger: 'key', key: 'h' }),
]),
actions: expect.arrayContaining([
expect.objectContaining({
advanced_camera_card_action: 'ptz_multi',
}),
]),
}),
]),
);
addAutomationsSpy.mockClear();
// Trigger the override - keyboard_shortcuts should be deleted
stateManager.setState({ fullscreen: true });
await flushPromises();
// Verify newly added automations don't contain keyboard shortcuts (key: 'h')
// This confirms the override removed them (directly verified through add calls)
const addCalls = addAutomationsSpy.mock.calls;
const hasKeyboardShortcut = addCalls.some((call) =>
call[0].some((automation: Automation) =>
automation.triggers.some(
(trig: Trigger) => trig.trigger === 'key' && trig.key === 'h',
),
),
);
expect(hasKeyboardShortcut).toBe(false);
});
it('should re-run folders loader when overrides change', async () => {
const { manager, stateManager, api } = createConfigManagerTestSetup();
const folders = [{ id: 'f' }];
const config = createConfig({
folders,
overrides: [
{
delete: ['folders'],
conditions: [TEST_CONDITIONS.FULLSCREEN_ON],
},
],
});
manager.setConfig(config);
await flushPromises();
// Verify initial payload (folders may be populated with defaults, so
// assert the passed folders contain our folder id).
expect(api.getFoldersManager().addFolders).toHaveBeenCalled();
expect(api.getFoldersManager().addFolders).toHaveBeenCalledWith(
expect.arrayContaining([expect.objectContaining({ id: 'f' })]),
);
// Reset calls so we only see calls resulting from the override
vi.mocked(api.getFoldersManager().deleteFolders).mockClear();
vi.mocked(api.getFoldersManager().addFolders).mockClear();
// Trigger override which deletes folders
stateManager.setState({ fullscreen: true });
await flushPromises();
// Verify delete was called when override triggered
expect(api.getFoldersManager().deleteFolders).toBeCalled();
// Verify folder 'f' is no longer present after override
// Since the override removes folders, the folders passed should no
// longer include our folder `f`.
const calls = vi.mocked(api.getFoldersManager().addFolders).mock.calls;
expect(calls.length).toBeGreaterThanOrEqual(1);
const lastArg = calls[calls.length - 1][0] as unknown[];
expect(lastArg).not.toEqual(
expect.arrayContaining([expect.objectContaining({ id: 'f' })]),
);
// Verify folder is restored when override exits
vi.mocked(api.getFoldersManager().addFolders).mockClear();
stateManager.setState({ fullscreen: false });
await flushPromises();
// Verify the folder 'f' is restored
const restoreCalls = vi.mocked(api.getFoldersManager().addFolders).mock.calls;
expect(restoreCalls.length).toBeGreaterThanOrEqual(1);
const restoredArg = restoreCalls[restoreCalls.length - 1][0] as unknown[];
expect(restoredArg).toEqual(
expect.arrayContaining([expect.objectContaining({ id: 'f' })]),
);
});
it('should re-run automations loader when overrides change and properly manage automations', async () => {
const { manager, stateManager, api, addAutomationsSpy, deleteAutomationsSpy } =
createConfigManagerTestSetup();
// Mock executeActions to track automation execution
const executeActionsMock = vi.fn();
vi.mocked(api.getActionsManager().executeActions).mockImplementation(
executeActionsMock,
);
const automation = {
triggers: [{ trigger: 'fullscreen' as const, fullscreen: false }],
actions: [createGeneralAction('screenshot')],
};
const config = createConfig({
automations: [automation],
overrides: [
{
delete: ['automations'],
conditions: [TEST_CONDITIONS.FULLSCREEN_ON],
},
],
});
manager.setConfig(config);
await flushPromises();
// Verify automations were added initially
expect(addAutomationsSpy).toHaveBeenCalled();
// Trigger a state change to evaluate conditions (fullscreen: false matches our condition)
stateManager.setState({ fullscreen: false });
await flushPromises();
// The automation should execute since the condition matches and override is not active
expect(executeActionsMock).toHaveBeenCalled();
// Clear to observe only calls caused by the override
executeActionsMock.mockClear();
deleteAutomationsSpy.mockClear();
addAutomationsSpy.mockClear();
// Trigger the override which deletes automations
stateManager.setState({ fullscreen: true });
await flushPromises();
// Verify delete was called when override triggered
expect(deleteAutomationsSpy).toHaveBeenCalled();
// After override, the automation should have been deleted from the manager,
// so no further executions should occur
expect(executeActionsMock).not.toHaveBeenCalled();
// Clear and verify that exiting fullscreen doesn't restore the automation
executeActionsMock.mockClear();
stateManager.setState({ fullscreen: false });
await flushPromises();
// The automation should still not execute because it was deleted by the override
expect(executeActionsMock).not.toHaveBeenCalled();
});
it('should not reload user automations for unrelated override changes', async () => {
const { manager, stateManager, api, addAutomationsSpy, deleteAutomationsSpy } =
createConfigManagerTestSetup();
const executeActionsMock = vi.fn();
vi.mocked(api.getActionsManager().executeActions).mockImplementation(
executeActionsMock,
);
const automation = {
triggers: [{ trigger: 'fullscreen' as const, fullscreen: true }],
actions: [createGeneralAction('screenshot')],
};
const config = createConfig({
automations: [automation],
overrides: [
{
conditions: [TEST_CONDITIONS.FULLSCREEN_ON],
set: {
'menu.buttons.microphone.enabled': false,
},
},
],
});
manager.setConfig(config);
await flushPromises();
addAutomationsSpy.mockClear();
deleteAutomationsSpy.mockClear();
executeActionsMock.mockClear();
stateManager.setState({ fullscreen: true });
await flushPromises();
expect(deleteAutomationsSpy).not.toHaveBeenCalled();
expect(addAutomationsSpy).not.toHaveBeenCalled();
expect(executeActionsMock).toHaveBeenCalledTimes(1);
});
});
describe('remote-control loader with overrides', () => {
it('should re-run remote-control loader when overrides change', async () => {
const { manager, stateManager, addAutomationsSpy, deleteAutomationsSpy } =
createConfigManagerTestSetup();
const config = createConfig({
remote_control: {
entities: { camera: 'input_select.camera' },
},
overrides: [
{
delete: ['remote_control'],
conditions: [TEST_CONDITIONS.FULLSCREEN_ON],
},
],
});
// Initial set should register remote control automations
manager.setConfig(config);
await flushPromises();
// Verify remote-control automations were added initially with config condition
expect(addAutomationsSpy).toHaveBeenCalledWith(
expect.arrayContaining([
expect.objectContaining({
triggers: expect.arrayContaining([
expect.objectContaining({
trigger: 'config',
paths: expect.arrayContaining(['remote_control.entities.camera']),
}),
]),
}),
]),
);
addAutomationsSpy.mockClear();
deleteAutomationsSpy.mockClear();
// Trigger the override condition - remote_control should be deleted
stateManager.setState({ fullscreen: true });
await flushPromises();
// Verify delete was called
expect(deleteAutomationsSpy).toHaveBeenCalled();
// Verify new automations don't contain remote-control config conditions
const addCalls = addAutomationsSpy.mock.calls;
const hasRemoteControl = addCalls.some((call) =>
call[0].some((automation: Automation) =>
automation.triggers.some(
(trig: Trigger) =>
trig.trigger === 'config' &&
trig.paths?.includes('remote_control.entities.camera'),
),
),
);
expect(hasRemoteControl).toBe(false);
addAutomationsSpy.mockClear();
// Exit override - remote-control automations should be restored
stateManager.setState({ fullscreen: false });
await flushPromises();
// Verify remote-control automations were restored
expect(addAutomationsSpy).toHaveBeenCalledWith(
expect.arrayContaining([
expect.objectContaining({
triggers: expect.arrayContaining([
expect.objectContaining({
trigger: 'config',
paths: expect.arrayContaining(['remote_control.entities.camera']),
}),
]),
}),
]),
);
});
it('should not reload remote-control automations for unrelated override changes', async () => {
const { manager, stateManager, deleteAutomationsSpy } =
createConfigManagerTestSetup();
const config = createConfig({
remote_control: {
entities: { camera: 'input_select.camera' },
},
overrides: [
{
conditions: [TEST_CONDITIONS.FULLSCREEN_ON],
set: {
'menu.buttons.microphone.enabled': false,
},
},
],
});
manager.setConfig(config);
await flushPromises();
deleteAutomationsSpy.mockClear();
stateManager.setState({ fullscreen: true });
await flushPromises();
expect(deleteAutomationsSpy).not.toHaveBeenCalledWith(
setRemoteControlEntityFromConfig,
);
});
});
describe('keyboard-shortcuts loader with overrides', () => {
it('should not reload keyboard-shortcut automations for unrelated override changes', async () => {
const { manager, stateManager, deleteAutomationsSpy } =
createConfigManagerTestSetup();
const config = createConfig({
view: {
keyboard_shortcuts: {
enabled: true,
ptz_left: { key: 'ArrowLeft' },
},
},
overrides: [
{
conditions: [TEST_CONDITIONS.FULLSCREEN_ON],
set: {
'menu.buttons.microphone.enabled': false,
},
},
],
});
manager.setConfig(config);
await flushPromises();
deleteAutomationsSpy.mockClear();
stateManager.setState({ fullscreen: true });
await flushPromises();
expect(deleteAutomationsSpy).not.toHaveBeenCalledWith(
setKeyboardShortcutsFromConfig,
);
});
});
});
});