refactor: Retire the use of unmaintained custom-card-helpers (#1956)

- Closes #1295
This commit is contained in:
Dermot Duffy
2025-03-09 16:02:33 -07:00
committed by GitHub
parent c65ee3f0f2
commit a79ffa6edc
116 changed files with 933 additions and 545 deletions
@@ -1,8 +1,8 @@
import { afterEach, describe, expect, it, vi } from 'vitest';
import { FrigateEventWatcher } from '../../../src/camera-manager/frigate/event-watcher';
import { createHASS } from '../../test-utils';
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { FrigateEventChange } from '../../../src/camera-manager/frigate/types';
import { FrigateEventWatcher } from '../../../src/camera-manager/frigate/event-watcher.js';
import { FrigateEventChange } from '../../../src/camera-manager/frigate/types.js';
import { HomeAssistant } from '../../../src/ha/types.js';
import { createHASS } from '../../test-utils.js';
const createEventChange = (): FrigateEventChange => {
return {
+11 -11
View File
@@ -1,16 +1,15 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { add } from 'date-fns';
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
import { mock } from 'vitest-mock-extended';
import { Camera } from '../../src/camera-manager/camera';
import { Capabilities } from '../../src/camera-manager/capabilities';
import { CameraManagerEngine } from '../../src/camera-manager/engine';
import { Camera } from '../../src/camera-manager/camera.js';
import { Capabilities } from '../../src/camera-manager/capabilities.js';
import { CameraManagerEngineFactory } from '../../src/camera-manager/engine-factory.js';
import { CameraManagerEngine } from '../../src/camera-manager/engine.js';
import {
CameraManager,
QueryClassifier,
QueryResultClassifier,
} from '../../src/camera-manager/manager';
} from '../../src/camera-manager/manager.js';
import {
CameraEndpoint,
CameraEndpoints,
@@ -25,11 +24,12 @@ import {
QueryResults,
QueryResultsType,
QueryType,
} from '../../src/camera-manager/types';
import { sortMedia } from '../../src/camera-manager/utils/sort-media';
import { CardController } from '../../src/card-controller/controller';
import { CameraConfig } from '../../src/config/types';
import { ViewMedia } from '../../src/view/media';
} from '../../src/camera-manager/types.js';
import { sortMedia } from '../../src/camera-manager/utils/sort-media.js';
import { CardController } from '../../src/card-controller/controller.js';
import { CameraConfig } from '../../src/config/types.js';
import { HomeAssistant } from '../../src/ha/types.js';
import { ViewMedia } from '../../src/view/media.js';
import {
TestViewMedia,
createCamera,
@@ -39,7 +39,7 @@ import {
createConfig,
createHASS,
generateViewMediaArray,
} from '../test-utils';
} from '../test-utils.js';
describe('QueryClassifier', async () => {
it('should classify event query', async () => {
@@ -1,9 +1,9 @@
import { describe, expect, it, vi } from 'vitest';
import { createCardAPI, createHASS, createLitElement } from '../../../test-utils';
import { GenericAction } from '../../../../src/card-controller/actions/actions/generic';
import { handleActionConfig } from '@dermotduffy/custom-card-helpers';
import { createCardAPI, createHASS, createLitElement } from '../../../test-utils.js';
import { GenericAction } from '../../../../src/card-controller/actions/actions/generic.js';
import { handleActionConfig } from '../../../../src/ha/handle-action.js';
vi.mock('@dermotduffy/custom-card-helpers');
vi.mock('../../../../src/ha/handle-action.js');
describe('should handle generic action', () => {
it('without hass', async () => {
@@ -1,13 +1,13 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { mock } from 'vitest-mock-extended';
import { MediaPlayerManager } from '../../src/card-controller/media-player-manager';
import { MediaPlayerManager } from '../../src/card-controller/media-player-manager.js';
import {
MEDIA_PLAYER_SUPPORT_BROWSE_MEDIA,
MEDIA_PLAYER_SUPPORT_STOP,
MEDIA_PLAYER_SUPPORT_TURN_OFF,
} from '../../src/const';
import { ExtendedHomeAssistant } from '../../src/types';
import { EntityRegistryManager } from '../../src/utils/ha/registry/entity';
import { HomeAssistant } from '../../src/ha/types.js';
import { EntityRegistryManager } from '../../src/utils/ha/registry/entity/index.js';
import {
createCameraConfig,
createCameraManager,
@@ -18,9 +18,9 @@ import {
createStateEntity,
createStore,
TestViewMedia,
} from '../test-utils';
} from '../test-utils.js';
const createHASSWithMediaPlayers = (): ExtendedHomeAssistant => {
const createHASSWithMediaPlayers = (): HomeAssistant => {
const attributesSupported = {
supported_features: MEDIA_PLAYER_SUPPORT_BROWSE_MEDIA,
};
@@ -292,7 +292,7 @@ describe('MediaPlayerManager', () => {
);
vi.mocked(api.getCameraManager().getCameraMetadata).mockReturnValue({
title: 'camera title',
icon: 'icon',
icon: { icon: 'icon' },
});
vi.mocked(api.getHASSManager().getHASS).mockReturnValue(
createHASS({
@@ -1,29 +1,29 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import isEqual from 'lodash-es/isEqual';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { mock } from 'vitest-mock-extended';
import { Capabilities } from '../../src/camera-manager/capabilities';
import { CameraManager } from '../../src/camera-manager/manager';
import { CameraManagerCameraMetadata } from '../../src/camera-manager/types';
import { FullscreenManager } from '../../src/card-controller/fullscreen/fullscreen-manager';
import { MediaPlayerManager } from '../../src/card-controller/media-player-manager';
import { MicrophoneManager } from '../../src/card-controller/microphone-manager';
import { ViewManager } from '../../src/card-controller/view/view-manager';
import { Capabilities } from '../../src/camera-manager/capabilities.js';
import { CameraManager } from '../../src/camera-manager/manager.js';
import { CameraManagerCameraMetadata } from '../../src/camera-manager/types.js';
import { FullscreenManager } from '../../src/card-controller/fullscreen/fullscreen-manager.js';
import { MediaPlayerManager } from '../../src/card-controller/media-player-manager.js';
import { MicrophoneManager } from '../../src/card-controller/microphone-manager.js';
import { ViewManager } from '../../src/card-controller/view/view-manager.js';
import {
MenuButtonController,
MenuButtonControllerOptions,
} from '../../src/components-lib/menu-button-controller';
} from '../../src/components-lib/menu-button-controller.js';
import {
AdvancedCameraCardConfig,
AdvancedCameraCardView,
MenuItem,
ViewDisplayMode,
} from '../../src/config/types';
import { MediaPlayerController } from '../../src/types';
import { createGeneralAction, createViewAction } from '../../src/utils/action';
import { ViewMedia } from '../../src/view/media';
import { MediaQueriesResults } from '../../src/view/media-queries-results';
import { View } from '../../src/view/view';
} from '../../src/config/types.js';
import { HomeAssistant } from '../../src/ha/types.js';
import { MediaPlayerController } from '../../src/types.js';
import { createGeneralAction, createViewAction } from '../../src/utils/action.js';
import { MediaQueriesResults } from '../../src/view/media-queries-results.js';
import { ViewMedia } from '../../src/view/media.js';
import { View } from '../../src/view/view.js';
import {
createCameraConfig,
createCameraManager,
@@ -36,7 +36,7 @@ import {
createStore,
createView,
TestViewMedia,
} from '../test-utils';
} from '../test-utils.js';
vi.mock('../../src/utils/media-player-controller.js');
vi.mock('../../src/card-controller/microphone-manager.js');
+5 -5
View File
@@ -1,15 +1,15 @@
import { handleActionConfig } from '@dermotduffy/custom-card-helpers';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { MenuController } from '../../src/components-lib/menu-controller';
import { SubmenuItem } from '../../src/components/submenu/types';
import { MenuConfig, menuConfigSchema } from '../../src/config/types';
import { MenuController } from '../../src/components-lib/menu-controller.js';
import { SubmenuItem } from '../../src/components/submenu/types.js';
import { MenuConfig, menuConfigSchema } from '../../src/config/types.js';
import { handleActionConfig } from '../../src/ha/handle-action.js';
import {
createInteractionActionEvent,
createLitElement,
createSubmenuInteractionActionEvent,
} from '../test-utils';
vi.mock('@dermotduffy/custom-card-helpers');
vi.mock('../../src/ha/handle-action.js');
vi.mock('../../src/utils/ha');
const createMenuConfig = (config: unknown): MenuConfig => {
+8 -8
View File
@@ -1,7 +1,3 @@
import {
CallServiceActionConfig,
PerformActionActionConfig,
} from '@dermotduffy/custom-card-helpers';
import { describe, expect, it } from 'vitest';
import {
copyConfig,
@@ -20,14 +16,18 @@ import {
upgradeMoveToWithOverrides,
upgradeObjectRecursively,
upgradeWithOverrides,
} from '../../src/config/management';
import { PTZControlAction } from '../../src/config/ptz';
} from '../../src/config/management.js';
import { PTZControlAction } from '../../src/config/ptz.js';
import {
Actions,
RawAdvancedCameraCardConfig,
advancedCameraCardConfigSchema,
} from '../../src/config/types';
import { getParseErrorPaths } from '../../src/utils/zod';
} from '../../src/config/types.js';
import {
CallServiceActionConfig,
PerformActionActionConfig,
} from '../../src/ha/types.js';
import { getParseErrorPaths } from '../../src/utils/zod.js';
describe('general functions', () => {
it('should set value', () => {
+26
View File
@@ -0,0 +1,26 @@
import { describe, it, expect } from 'vitest';
import { computeDomain } from '../../src/ha/compute-domain.js';
describe('computeDomain', () => {
it('should return the domain of an entity ID', () => {
expect(computeDomain('light.kitchen')).toBe('light');
expect(computeDomain('sensor.temperature')).toBe('sensor');
expect(computeDomain('switch.garage')).toBe('switch');
});
it('should return an empty string if there is no dot in the entity ID', () => {
expect(computeDomain('invalidEntityId')).toBe('');
});
it('should handle entity IDs with multiple dots correctly', () => {
expect(computeDomain('light.kitchen.ceiling')).toBe('light');
});
it('should return an empty string for an empty entity ID', () => {
expect(computeDomain('')).toBe('');
});
it('should return an empty string for a dot-only entity ID', () => {
expect(computeDomain('.')).toBe('');
});
});
+24
View File
@@ -0,0 +1,24 @@
import { describe, expect, it, vi } from 'vitest';
import { fireHASSEvent } from '../../src/ha/fire-hass-event.js';
import { forwardHaptic, HapticType } from '../../src/ha/haptic.js';
vi.mock('../../src/ha/fire-hass-event.js', () => ({
fireHASSEvent: vi.fn(),
}));
// @vitest-environment jsdom
describe('forwardHaptic', () => {
it.each([
['success' as const],
['warning' as const],
['failure' as const],
['light' as const],
['medium' as const],
['heavy' as const],
['selection' as const],
])('should call fireHASSEvent with %s', (hapticType: HapticType) => {
forwardHaptic(hapticType);
expect(fireHASSEvent).toBeCalledWith(window, 'haptic', hapticType);
});
});
+4 -12
View File
@@ -1,4 +1,3 @@
import { CurrentUser } from '@dermotduffy/custom-card-helpers';
import { HassEntities, HassEntity } from 'home-assistant-js-websocket';
import { LitElement } from 'lit';
import screenfull from 'screenfull';
@@ -52,12 +51,8 @@ import {
internalAdvancedCameraCardCustomActionSchema,
performanceConfigSchema,
} from '../src/config/types';
import {
CapabilitiesRaw,
ExtendedHomeAssistant,
Interaction,
MediaLoadedInfo,
} from '../src/types';
import { CurrentUser, HomeAssistant } from '../src/ha/types';
import { CapabilitiesRaw, Interaction, MediaLoadedInfo } from '../src/types';
import { HassStateDifference } from '../src/utils/ha';
import { Device } from '../src/utils/ha/registry/device/types';
import { EntityRegistryManager } from '../src/utils/ha/registry/entity';
@@ -104,11 +99,8 @@ export const createCamera = (
return new Camera(config, engine, { capabilities: capabilities });
};
export const createHASS = (
states?: HassEntities,
user?: CurrentUser,
): ExtendedHomeAssistant => {
const hass = mock<ExtendedHomeAssistant>();
export const createHASS = (states?: HassEntities, user?: CurrentUser): HomeAssistant => {
const hass = mock<HomeAssistant>();
if (states) {
hass.states = states;
}
+4 -4
View File
@@ -1,7 +1,7 @@
import { hasAction as customCardHasAction } from '@dermotduffy/custom-card-helpers';
import { afterEach, describe, expect, it, vi } from 'vitest';
import { mock } from 'vitest-mock-extended';
import { actionSchema, INTERNAL_CALLBACK_ACTION } from '../../src/config/types';
import { actionSchema, INTERNAL_CALLBACK_ACTION } from '../../src/config/types.js';
import { hasAction as customCardHasAction } from '../../src/ha/has-action.js';
import {
convertActionToCardCustomAction,
createCameraAction,
@@ -19,9 +19,9 @@ import {
getActionConfigGivenAction,
hasAction,
stopEventFromActivatingCardWideActions,
} from '../../src/utils/action';
} from '../../src/utils/action.js';
vi.mock('@dermotduffy/custom-card-helpers');
vi.mock('../../src/ha/has-action.js');
describe('convertActionToAdvancedCameraCardCustomAction', () => {
it('should skip null action', () => {
+5 -28
View File
@@ -1,5 +1,5 @@
import { afterAll, describe, expect, it, vi } from 'vitest';
import { AdvancedCameraCardError } from '../../src/types';
import { AdvancedCameraCardError } from '../../src/types.js';
import {
allPromises,
arefloatsApproximatelyEqual,
@@ -9,7 +9,6 @@ import {
contentsChanged,
dayToDate,
desparsifyArrays,
dispatchAdvancedCameraCardEvent,
errorToConsole,
formatDate,
formatDateAndTime,
@@ -28,32 +27,8 @@ import {
setify,
setOrRemoveAttribute,
sleep,
} from '../../src/utils/basic';
import { createSlot, createSlotHost } from '../test-utils';
// @vitest-environment jsdom
describe('dispatchAdvancedCameraCardEvent', () => {
it('should dispatch event without data', () => {
const element = document.createElement('div');
const handler = vi.fn();
element.addEventListener('advanced-camera-card:foo', handler);
dispatchAdvancedCameraCardEvent(element, 'foo');
expect(handler).toBeCalled();
});
it('should dispatch event with data', () => {
const element = document.createElement('div');
const data = { bar: 2 };
const handler = vi.fn((ev) => {
expect(ev.detail).toBe(data);
});
element.addEventListener('advanced-camera-card:foo', handler);
dispatchAdvancedCameraCardEvent(element, 'foo', data);
expect(handler).toBeCalled();
});
});
} from '../../src/utils/basic.js';
import { createSlot, createSlotHost } from '../test-utils.js';
describe('prettifyTitle', () => {
it('should return undefined when passed undefined', () => {
@@ -130,6 +105,7 @@ describe('errorToConsole', () => {
});
});
// @vitest-environment jsdom
describe('isHoverableDevice', () => {
afterAll(() => {
vi.restoreAllMocks();
@@ -163,6 +139,7 @@ describe('formatDate', () => {
});
});
// @vitest-environment jsdom
describe('runWhenIdleIfSupported', () => {
const originalRequestIdleCallback = window.requestIdleCallback;
afterAll(() => {
@@ -0,0 +1,26 @@
import { describe, expect, it, vi } from 'vitest';
import { fireAdvancedCameraCardEvent } from '../../src/utils/fire-advanced-camera-card-event.js';
// @vitest-environment jsdom
describe('fireAdvancedCameraCardEvent', () => {
it('should fire event without data', () => {
const element = document.createElement('div');
const handler = vi.fn();
element.addEventListener('advanced-camera-card:foo', handler);
fireAdvancedCameraCardEvent(element, 'foo');
expect(handler).toBeCalled();
});
it('should fire event with data', () => {
const element = document.createElement('div');
const data = { bar: 2 };
const handler = vi.fn((ev) => {
expect(ev.detail).toBe(data);
});
element.addEventListener('advanced-camera-card:foo', handler);
fireAdvancedCameraCardEvent(element, 'foo', data);
expect(handler).toBeCalled();
});
});
+1 -1
View File
@@ -1,5 +1,5 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { describe, expect, it, vi } from 'vitest';
import { HomeAssistant } from '../../../src/ha/types.js';
import {
canonicalizeHAURL,
hasHAConnectionStateChanged,