test: Split test utilities to improve test times (#2622)

This commit is contained in:
Dermot Duffy
2026-07-26 16:29:53 -07:00
committed by GitHub
parent 8d44fcecf1
commit ad89aa9538
234 changed files with 2730 additions and 2516 deletions
@@ -11,9 +11,9 @@ 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 { createConfig } from '../../config/test-utils';
import {
createCardAPI,
createConfig,
createHASS,
createStateEntity,
flushPromises,
@@ -122,7 +122,7 @@ describe('ConfigManager', () => {
describe('should handle error when', () => {
it('should handle no input', () => {
const manager = new ConfigManager(createCardAPI());
expect(() => manager.setConfig()).toThrowError(/Invalid configuration/);
expect(() => manager.setConfig()).toThrow(/Invalid configuration/);
});
it('should handle invalid configuration', () => {
@@ -132,7 +132,7 @@ describe('ConfigManager', () => {
.mockReturnValue({ success: false, error: new ZodError([]) });
const manager = new ConfigManager(createCardAPI());
expect(() => manager.setConfig({})).toThrowError(
expect(() => manager.setConfig({})).toThrow(
'Invalid configuration: No location hint available (bad or missing type?)',
);
@@ -141,7 +141,7 @@ describe('ConfigManager', () => {
it('should handle invalid configuration with hint', () => {
const manager = new ConfigManager(createCardAPI());
expect(() => manager.setConfig({})).toThrowError(
expect(() => manager.setConfig({})).toThrow(
'Invalid configuration: [\n "type"\n]',
);
});
@@ -154,7 +154,7 @@ describe('ConfigManager', () => {
type: 'custom:frigate-card',
cameras: 'WILL_NOT_PARSE',
}),
).toThrowError(
).toThrow(
'An automated card configuration upgrade is ' +
'available, please visit the visual card editor. ' +
'Invalid configuration: [\n "cameras"\n]',
@@ -190,17 +190,17 @@ describe('ConfigManager', () => {
expect(manager.getConfig()?.menu.alignment).toBe('left');
// Verify appropriate API calls are made.
expect(api.getConditionStateManager().setState).toBeCalledWith({
expect(api.getConditionStateManager().setState).toHaveBeenCalledWith({
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();
expect(api.getIssueManager().reset).toHaveBeenCalledWith('config_error');
expect(api.getMediaLoadedInfoManager().clear).toHaveBeenCalled();
expect(api.getViewManager().reset).toHaveBeenCalled();
expect(api.getAutomationsManager().addAutomations).toHaveBeenCalled();
expect(api.getStyleManager().updateFromConfig).toHaveBeenCalled();
expect(api.getCardElementManager().update).toHaveBeenCalled();
});
it('should apply profiles', () => {
@@ -243,12 +243,12 @@ describe('ConfigManager', () => {
};
manager.setConfig(config);
expect(api.getViewManager().reset).toBeCalled();
expect(api.getViewManager().reset).toHaveBeenCalled();
vi.mocked(api.getViewManager().reset).mockClear();
manager.setConfig(config);
expect(api.getViewManager().reset).not.toBeCalled();
expect(api.getViewManager().reset).not.toHaveBeenCalled();
});
it('should get card wide config', () => {
@@ -321,7 +321,7 @@ describe('ConfigManager', () => {
const configAfter = manager.getConfig();
expect(configAfter).toEqual(configBefore);
expect(api.getStyleManager().updateFromConfig).toBeCalledTimes(1);
expect(api.getStyleManager().updateFromConfig).toHaveBeenCalledTimes(1);
});
it('should honor override', () => {
@@ -372,7 +372,7 @@ describe('ConfigManager', () => {
stateManager.setState({ fullscreen: true });
expect(manager.getConfig()).not.toBeNull();
expect(api.getIssueManager().trigger).toBeCalledWith(
expect(api.getIssueManager().trigger).toHaveBeenCalledWith(
'config_error',
expect.objectContaining({ error: expect.any(Error) }),
);
@@ -502,9 +502,11 @@ describe('ConfigManager', () => {
await flushPromises();
expect(api.getDefaultManager().initializeIfNecessary).toBeCalledTimes(1);
expect(api.getMediaPlayerManager().initializeIfNecessary).toBeCalledTimes(1);
expect(listener).not.toBeCalledWith(
expect(api.getDefaultManager().initializeIfNecessary).toHaveBeenCalledTimes(1);
expect(api.getMediaPlayerManager().initializeIfNecessary).toHaveBeenCalledTimes(
1,
);
expect(listener).not.toHaveBeenCalledWith(
expect.objectContaining({ change: { config: expect.anything() } }),
);
@@ -515,11 +517,13 @@ describe('ConfigManager', () => {
await flushPromises();
expect(api.getDefaultManager().initializeIfNecessary).toBeCalledTimes(2);
expect(api.getMediaPlayerManager().initializeIfNecessary).toBeCalledTimes(2);
expect(api.getDefaultManager().initializeIfNecessary).toHaveBeenCalledTimes(2);
expect(api.getMediaPlayerManager().initializeIfNecessary).toHaveBeenCalledTimes(
2,
);
// Should set the config condition state.
expect(listener).toBeCalledWith(
expect(listener).toHaveBeenCalledWith(
expect.objectContaining({ change: { config: expect.anything() } }),
);
});
@@ -616,7 +620,7 @@ describe('ConfigManager', () => {
await flushPromises();
// Verify delete was called when override triggered
expect(api.getFoldersManager().deleteFolders).toBeCalled();
expect(api.getFoldersManager().deleteFolders).toHaveBeenCalled();
// Verify folder 'f' is no longer present after override
// Since the override removes folders, the folders passed should no
@@ -1,15 +1,16 @@
import { describe, expect, it, vi } from 'vitest';
import { setAutomationsFromConfig } from '../../../src/card-controller/config/load-automations';
import { createCardAPI, createConfig } from '../../test-utils';
import { createConfig } from '../../config/test-utils';
import { createCardAPI } from '../../test-utils';
describe('setAutomationsFromConfig', () => {
it('without config', () => {
const api = createCardAPI();
setAutomationsFromConfig(api);
expect(api.getAutomationsManager().deleteAutomations).toBeCalled();
expect(api.getAutomationsManager().addAutomations).toBeCalledWith([]);
expect(api.getAutomationsManager().deleteAutomations).toHaveBeenCalled();
expect(api.getAutomationsManager().addAutomations).toHaveBeenCalledWith([]);
});
it('with config', () => {
@@ -33,7 +34,7 @@ describe('setAutomationsFromConfig', () => {
setAutomationsFromConfig(api);
expect(api.getAutomationsManager().deleteAutomations).toBeCalled();
expect(api.getAutomationsManager().addAutomations).toBeCalledWith(automations);
expect(api.getAutomationsManager().deleteAutomations).toHaveBeenCalled();
expect(api.getAutomationsManager().addAutomations).toHaveBeenCalledWith(automations);
});
});
@@ -19,14 +19,10 @@ import {
isAdvancedCameraCardCustomAction,
} from '../../../src/utils/action';
import { arrayify } from '../../../src/utils/basic';
import {
createCardAPI,
createConfig,
createHASS,
createStateEntity,
createStore,
createView,
} from '../../test-utils';
import { createStore } from '../../camera-manager/test-utils';
import { createConfig } from '../../config/test-utils';
import { createCardAPI, createHASS, createStateEntity } from '../../test-utils';
import { createView } from '../../view/test-utils';
const isGeneratedAction = (action: ActionConfig): action is GeneratedActionConfig =>
'advanced_camera_card_action' in action &&
@@ -37,8 +33,8 @@ describe('setRemoteControlEntityFromConfig', () => {
const api = createCardAPI();
setRemoteControlEntityFromConfig(api);
expect(api.getAutomationsManager().deleteAutomations).toBeCalled();
expect(api.getAutomationsManager().addAutomations).not.toBeCalled();
expect(api.getAutomationsManager().deleteAutomations).toHaveBeenCalled();
expect(api.getAutomationsManager().addAutomations).not.toHaveBeenCalled();
});
it('with control entity and card priority', () => {
@@ -56,8 +52,8 @@ describe('setRemoteControlEntityFromConfig', () => {
setRemoteControlEntityFromConfig(api);
expect(api.getAutomationsManager().deleteAutomations).toBeCalled();
expect(api.getAutomationsManager().addAutomations).toBeCalledWith([
expect(api.getAutomationsManager().deleteAutomations).toHaveBeenCalled();
expect(api.getAutomationsManager().addAutomations).toHaveBeenCalledWith([
{
actions: [
{
@@ -138,8 +134,8 @@ describe('setRemoteControlEntityFromConfig', () => {
setRemoteControlEntityFromConfig(api);
expect(api.getAutomationsManager().deleteAutomations).toBeCalled();
expect(api.getAutomationsManager().addAutomations).toBeCalledWith([
expect(api.getAutomationsManager().deleteAutomations).toHaveBeenCalled();
expect(api.getAutomationsManager().addAutomations).toHaveBeenCalledWith([
{
actions: [
{
@@ -240,7 +236,7 @@ describe('setRemoteControlEntityFromConfig', () => {
);
addOptionsAction.callback(api);
expect(hass.callService).toBeCalledWith(
expect(hass.callService).toHaveBeenCalledWith(
'input_select',
'set_options',
{
@@ -290,7 +286,7 @@ describe('setRemoteControlEntityFromConfig', () => {
);
addOptionsAction.callback(api);
expect(hass.callService).not.toBeCalled();
expect(hass.callService).not.toHaveBeenCalled();
});
it('should not throw when hass is undefined setting options', () => {
@@ -371,7 +367,7 @@ describe('setRemoteControlEntityFromConfig', () => {
);
await cameraSyncAction.callback(api);
expect(hass.callService).toBeCalledWith(
expect(hass.callService).toHaveBeenCalledWith(
'input_select',
'select_option',
{
@@ -425,7 +421,7 @@ describe('setRemoteControlEntityFromConfig', () => {
cameraSyncAction.callback(api);
// Should NOT call select_option since entity already shows camera.one
expect(hass.callService).not.toBeCalled();
expect(hass.callService).not.toHaveBeenCalled();
});
it('should not select option when camera is undefined', () => {
@@ -462,7 +458,7 @@ describe('setRemoteControlEntityFromConfig', () => {
cameraSyncAction.callback(api);
// Should NOT call select_option since camera is undefined
expect(hass.callService).not.toBeCalled();
expect(hass.callService).not.toHaveBeenCalled();
});
it('should not select option when view exists but has no camera', () => {
@@ -496,13 +492,13 @@ describe('setRemoteControlEntityFromConfig', () => {
const cameraSyncAction = vi.mocked(api.getAutomationsManager().addAutomations).mock
.calls[0][0][1].actions?.[0] as InternalCallbackActionConfig;
cameraSyncAction.callback(api);
expect(hass.callService).not.toBeCalled();
expect(hass.callService).not.toHaveBeenCalled();
// Also test the 'initialized' condition callback (automation index 2)
const initializedSyncAction = vi.mocked(api.getAutomationsManager().addAutomations)
.mock.calls[0][0][2].actions?.[0] as InternalCallbackActionConfig;
initializedSyncAction.callback(api);
expect(hass.callService).not.toBeCalled();
expect(hass.callService).not.toHaveBeenCalled();
});
it('should not throw when hass is undefined', async () => {
@@ -574,7 +570,7 @@ describe('setRemoteControlEntityFromConfig', () => {
);
await cameraSyncAction.callback(api);
expect(hass.callService).toBeCalledWith(
expect(hass.callService).toHaveBeenCalledWith(
'input_select',
'select_option',
{
@@ -624,7 +620,7 @@ describe('setRemoteControlEntityFromConfig', () => {
expect(initAction.advanced_camera_card_action).toBe(INTERNAL_CALLBACK_ACTION);
await initAction.callback(api);
expect(hass.callService).toBeCalledWith(
expect(hass.callService).toHaveBeenCalledWith(
'input_select',
'select_option',
{
@@ -3,7 +3,8 @@ import { mock } from 'vitest-mock-extended';
import { setFoldersFromConfig } from '../../../src/card-controller/config/load-folders';
import type { FoldersManager } from '../../../src/card-controller/folders/manager';
import { createCardAPI, createConfig, createFolder } from '../../test-utils';
import { createConfig } from '../../config/test-utils';
import { createCardAPI, createFolder } from '../../test-utils';
describe('setFoldersFromConfig', () => {
it('should replace folders', () => {
@@ -19,8 +20,8 @@ describe('setFoldersFromConfig', () => {
setFoldersFromConfig(api);
expect(foldersManager.deleteFolders).toBeCalled();
expect(foldersManager.addFolders).toBeCalledWith(folders);
expect(foldersManager.deleteFolders).toHaveBeenCalled();
expect(foldersManager.addFolders).toHaveBeenCalledWith(folders);
});
it('should handle exceptions', () => {
@@ -40,7 +41,7 @@ describe('setFoldersFromConfig', () => {
setFoldersFromConfig(api);
expect(api.getIssueManager().trigger).toBeCalledWith('config_error', {
expect(api.getIssueManager().trigger).toHaveBeenCalledWith('config_error', {
error,
});
});
@@ -3,17 +3,18 @@ import { describe, expect, it, vi } from 'vitest';
import { setKeyboardShortcutsFromConfig } from '../../../src/card-controller/config/load-keyboard-shortcuts';
import type { PTZAction } from '../../../src/config/schema/actions/custom/ptz';
import type { PTZKeyboardShortcutName } from '../../../src/config/schema/view';
import { createCardAPI, createConfig } from '../../test-utils';
import { createConfig } from '../../config/test-utils';
import { createCardAPI } from '../../test-utils';
describe('setKeyboardShortcutsFromConfig', () => {
it('without shortcuts', () => {
const api = createCardAPI();
setKeyboardShortcutsFromConfig(api);
expect(api.getAutomationsManager().deleteAutomations).toBeCalledWith(
expect(api.getAutomationsManager().deleteAutomations).toHaveBeenCalledWith(
setKeyboardShortcutsFromConfig,
);
expect(api.getAutomationsManager().addAutomations).not.toBeCalled();
expect(api.getAutomationsManager().addAutomations).not.toHaveBeenCalled();
});
it('with shortcuts disabled', () => {
@@ -29,10 +30,10 @@ describe('setKeyboardShortcutsFromConfig', () => {
);
setKeyboardShortcutsFromConfig(api);
expect(api.getAutomationsManager().deleteAutomations).toBeCalledWith(
expect(api.getAutomationsManager().deleteAutomations).toHaveBeenCalledWith(
setKeyboardShortcutsFromConfig,
);
expect(api.getAutomationsManager().addAutomations).not.toBeCalled();
expect(api.getAutomationsManager().addAutomations).not.toHaveBeenCalled();
});
describe('PTZ shortcuts', () => {
@@ -66,10 +67,10 @@ describe('setKeyboardShortcutsFromConfig', () => {
setKeyboardShortcutsFromConfig(api);
expect(api.getAutomationsManager().deleteAutomations).toBeCalledWith(
expect(api.getAutomationsManager().deleteAutomations).toHaveBeenCalledWith(
setKeyboardShortcutsFromConfig,
);
expect(api.getAutomationsManager().addAutomations).toBeCalledWith([
expect(api.getAutomationsManager().addAutomations).toHaveBeenCalledWith([
{
actions: [
{
@@ -119,10 +120,10 @@ describe('setKeyboardShortcutsFromConfig', () => {
setKeyboardShortcutsFromConfig(api);
expect(api.getAutomationsManager().deleteAutomations).toBeCalledWith(
expect(api.getAutomationsManager().deleteAutomations).toHaveBeenCalledWith(
setKeyboardShortcutsFromConfig,
);
expect(api.getAutomationsManager().addAutomations).toBeCalledWith(
expect(api.getAutomationsManager().addAutomations).toHaveBeenCalledWith(
expect.arrayContaining([
{
actions: [
@@ -4,7 +4,8 @@ import { OverridesManager } from '../../../src/card-controller/config/overrides-
import { ConditionStateManager } from '../../../src/condition-trigger/conditions/state-manager';
import type { AdvancedCameraCardConfig } from '../../../src/config/schema/types';
import { AdvancedCameraCardError } from '../../../src/types';
import { createConfig, createMockTemplateRenderer } from '../../test-utils';
import { createConfig } from '../../config/test-utils';
import { createMockTemplateRenderer } from '../../test-utils';
describe('OverridesManager', () => {
const templateManager = createMockTemplateRenderer();
@@ -110,11 +111,11 @@ describe('OverridesManager', () => {
expect(manager.getConfig(config).menu?.style).toBe('hidden');
expect(callback).not.toBeCalled();
expect(callback).not.toHaveBeenCalled();
stateManager.setState({ fullscreen: true });
expect(callback).toBeCalledTimes(1);
expect(callback).toHaveBeenCalledTimes(1);
});
describe('should handle override merge', () => {