test: Split test utilities to improve test times (#2622)
This commit is contained in:
@@ -8,6 +8,10 @@ import { updateElementStyleFromMediaLayoutConfig } from '../utils/media-layout';
|
||||
|
||||
const ROTATED_ATTRIBUTE = 'rotated';
|
||||
|
||||
// Resizes arrive in bursts as the browser settles the layout, so only the last
|
||||
// one in a burst is acted upon.
|
||||
export const RESIZE_DEBOUNCE_SECONDS = 0.1;
|
||||
|
||||
interface MediaDimensions {
|
||||
width: number;
|
||||
height: number;
|
||||
@@ -32,7 +36,9 @@ export class MediaDimensionsContainerController implements ReactiveController {
|
||||
private _innerContainer: HTMLElement | null = null;
|
||||
private _outerContainer: HTMLElement | null = null;
|
||||
|
||||
public resize = debounce(this._resize.bind(this), 100, { trailing: true });
|
||||
public resize = debounce(this._resize.bind(this), RESIZE_DEBOUNCE_SECONDS * 1000, {
|
||||
trailing: true,
|
||||
});
|
||||
private _resizeObserver = new ResizeObserver(this.resize);
|
||||
|
||||
private _mediaDimensions: MediaDimensions | null = null;
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { debounce, isEqual } from 'lodash-es';
|
||||
|
||||
// Balancing act: Debounce to avoid excessive calls to setHeight, when new media
|
||||
// is loading the player may be a much smaller height momentarily.
|
||||
export const SET_HEIGHT_DEBOUNCE_SECONDS = 0.3;
|
||||
|
||||
export class MediaHeightController {
|
||||
private _host: HTMLElement;
|
||||
private _selector: string;
|
||||
@@ -13,9 +17,7 @@ export class MediaHeightController {
|
||||
|
||||
private _debouncedSetHeight = debounce(
|
||||
() => this._setHeight(),
|
||||
// Balancing act: Debounce to avoid excessive calls to setHeight, when new
|
||||
// media is loading the player may be a much smaller height momentarily.
|
||||
300,
|
||||
SET_HEIGHT_DEBOUNCE_SECONDS * 1000,
|
||||
{
|
||||
trailing: true,
|
||||
leading: false,
|
||||
|
||||
@@ -25,9 +25,6 @@ export async function homeAssistantSignPath(
|
||||
signedPathSchema,
|
||||
request,
|
||||
);
|
||||
if (!response) {
|
||||
return null;
|
||||
}
|
||||
return hass.hassUrl(response.path);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,8 +13,9 @@ import { BrowseMediaWalker } from '../../../src/ha/browse-media/walker';
|
||||
import { ResolvedMediaCache } from '../../../src/ha/resolved-media';
|
||||
import { QuerySource } from '../../../src/query-source';
|
||||
import type { ViewMedia } from '../../../src/view/item';
|
||||
import { createCameraConfig } from '../../config/test-utils';
|
||||
import { EntityRegistryManagerMock } from '../../ha/registry/entity/mock';
|
||||
import { createCameraConfig, createHASS, createHASSManager } from '../../test-utils';
|
||||
import { createHASS, createHASSManager } from '../../test-utils';
|
||||
|
||||
const createEngine = (): BrowseMediaCameraManagerEngine => {
|
||||
return new BrowseMediaCameraManagerEngine(
|
||||
|
||||
@@ -8,19 +8,18 @@ import type { EventWatcherSubscriptionInterface } from '../../src/card-controlle
|
||||
import type { StateWatcherSubscriptionInterface } from '../../src/card-controller/hass/state-watcher.js';
|
||||
import { liveProviderSupports2WayAudio } from '../../src/utils/live-provider.js';
|
||||
import type * as LiveProviderUtils from '../../src/utils/live-provider.js';
|
||||
import { createCameraConfig } from '../config/test-utils';
|
||||
import { EntityRegistryManagerMock } from '../ha/registry/entity/mock.js';
|
||||
import {
|
||||
callEventWatcherCallback,
|
||||
callStateWatcherCallback,
|
||||
createCameraConfig,
|
||||
createCapabilities,
|
||||
createHASS,
|
||||
createHASSEvent,
|
||||
createHASSManager,
|
||||
createInitializedCamera,
|
||||
createRegistryEntity,
|
||||
createStateEntity,
|
||||
} from '../test-utils.js';
|
||||
import { createCapabilities, createInitializedCamera } from './test-utils';
|
||||
|
||||
// Partially mock to keep the real pure helpers (e.g. `isGo2RTCLiveProvider`
|
||||
// used by `getProxyConfig`) while mocking the async metadata fetch.
|
||||
@@ -80,7 +79,7 @@ describe('Camera', () => {
|
||||
createCameraConfig(),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
);
|
||||
expect(() => camera.getID()).toThrowError(
|
||||
expect(() => camera.getID()).toThrow(
|
||||
'Could not determine camera id for the following ' +
|
||||
"camera, may need to set 'id' parameter manually",
|
||||
);
|
||||
@@ -109,13 +108,13 @@ describe('Camera', () => {
|
||||
});
|
||||
|
||||
expect(camera.isInitialized()).toBe(true);
|
||||
expect(stateWatcher.subscribe).toBeCalledWith(expect.any(Function), [
|
||||
expect(stateWatcher.subscribe).toHaveBeenCalledWith(expect.any(Function), [
|
||||
'camera.foo',
|
||||
]);
|
||||
|
||||
await camera.destroy();
|
||||
|
||||
expect(stateWatcher.unsubscribe).toBeCalled();
|
||||
expect(stateWatcher.unsubscribe).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should skip initialization when hass is unavailable', async () => {
|
||||
@@ -134,7 +133,7 @@ describe('Camera', () => {
|
||||
capabilityOptions: { capabilities: createCapabilities({ trigger: true }) },
|
||||
});
|
||||
|
||||
expect(stateWatcher.subscribe).not.toBeCalled();
|
||||
expect(stateWatcher.subscribe).not.toHaveBeenCalled();
|
||||
expect(camera.getCapabilities()).toBeNull();
|
||||
expect(camera.isInitialized()).toBe(false);
|
||||
});
|
||||
@@ -630,7 +629,7 @@ describe('Camera', () => {
|
||||
|
||||
it('should subscribe to discovered doorbell entities for state changes', async () => {
|
||||
const { stateWatcher } = await initializeDoorbellCamera();
|
||||
expect(stateWatcher.subscribe).toBeCalledWith(expect.any(Function), [
|
||||
expect(stateWatcher.subscribe).toHaveBeenCalledWith(expect.any(Function), [
|
||||
'event.front_door_doorbell',
|
||||
]);
|
||||
});
|
||||
@@ -671,7 +670,7 @@ describe('Camera', () => {
|
||||
capabilityOptions: { capabilities: createCapabilities({ trigger: true }) },
|
||||
});
|
||||
|
||||
expect(stateWatcher.subscribe).toBeCalled();
|
||||
expect(stateWatcher.subscribe).toHaveBeenCalled();
|
||||
|
||||
const diff = {
|
||||
entityID: 'sensor.force_update',
|
||||
@@ -680,7 +679,7 @@ describe('Camera', () => {
|
||||
};
|
||||
callStateWatcherCallback(stateWatcher, diff);
|
||||
|
||||
expect(eventCallback).toBeCalledWith({
|
||||
expect(eventCallback).toHaveBeenCalledWith({
|
||||
cameraID: 'camera_1',
|
||||
id: 'sensor.force_update',
|
||||
type: eventType,
|
||||
@@ -707,7 +706,7 @@ describe('Camera', () => {
|
||||
capabilityOptions: { capabilities: createCapabilities({ trigger: true }) },
|
||||
});
|
||||
|
||||
expect(eventWatcher.subscribe).toBeCalledTimes(1);
|
||||
expect(eventWatcher.subscribe).toHaveBeenCalledTimes(1);
|
||||
const request = vi.mocked(eventWatcher.subscribe).mock.calls[0][0];
|
||||
expect(request.event_type).toBe('zha_event');
|
||||
expect(request.matcher).toBeUndefined();
|
||||
@@ -717,14 +716,14 @@ describe('Camera', () => {
|
||||
createHASSEvent('zha_event', { command: 'press' }),
|
||||
);
|
||||
|
||||
expect(eventCallback).toBeCalledWith({
|
||||
expect(eventCallback).toHaveBeenCalledWith({
|
||||
cameraID: 'camera_1',
|
||||
id: 'event:zha_event',
|
||||
type: 'momentary',
|
||||
});
|
||||
|
||||
await camera.destroy();
|
||||
expect(eventWatcher.unsubscribe).toBeCalled();
|
||||
expect(eventWatcher.unsubscribe).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should attach a context-only matcher when only a context filter is set', async () => {
|
||||
@@ -775,7 +774,7 @@ describe('Camera', () => {
|
||||
capabilityOptions: { capabilities: createCapabilities({ trigger: true }) },
|
||||
});
|
||||
|
||||
expect(eventWatcher.subscribe).toBeCalledTimes(2);
|
||||
expect(eventWatcher.subscribe).toHaveBeenCalledTimes(2);
|
||||
expect(vi.mocked(eventWatcher.subscribe).mock.calls[0][0].event_type).toBe(
|
||||
'zha_event',
|
||||
);
|
||||
@@ -828,7 +827,7 @@ describe('Camera', () => {
|
||||
capabilityOptions: { capabilities: createCapabilities({ trigger: false }) },
|
||||
});
|
||||
|
||||
expect(eventWatcher.subscribe).not.toBeCalled();
|
||||
expect(eventWatcher.subscribe).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not dispatch when the helper returns null', async () => {
|
||||
@@ -860,7 +859,7 @@ describe('Camera', () => {
|
||||
newState: createStateEntity({ state: '2026-05-24T12:00:05.123+00:00' }),
|
||||
});
|
||||
|
||||
expect(eventCallback).not.toBeCalled();
|
||||
expect(eventCallback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should dispatch a momentary event for an event entity fire', async () => {
|
||||
@@ -892,8 +891,8 @@ describe('Camera', () => {
|
||||
newState: createStateEntity({ state: '2026-05-24T12:00:05.123+00:00' }),
|
||||
});
|
||||
|
||||
expect(eventCallback).toBeCalledTimes(1);
|
||||
expect(eventCallback).toBeCalledWith({
|
||||
expect(eventCallback).toHaveBeenCalledTimes(1);
|
||||
expect(eventCallback).toHaveBeenCalledWith({
|
||||
cameraID: 'camera_1',
|
||||
id: 'event.front_door_doorbell',
|
||||
type: 'momentary',
|
||||
@@ -921,7 +920,7 @@ describe('Camera', () => {
|
||||
capabilityOptions: { capabilities: createCapabilities({ trigger: false }) },
|
||||
});
|
||||
|
||||
expect(stateWatcher.subscribe).not.toBeCalled();
|
||||
expect(stateWatcher.subscribe).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -12,9 +12,9 @@ import type { CardWideConfig } from '../../src/config/schema/types.js';
|
||||
import type { DeviceRegistryManager } from '../../src/ha/registry/device';
|
||||
import type { EntityRegistryManager } from '../../src/ha/registry/entity/types.js';
|
||||
import type { ResolvedMediaCache } from '../../src/ha/resolved-media.js';
|
||||
import { createCameraConfig } from '../config/test-utils';
|
||||
import { EntityRegistryManagerMock } from '../ha/registry/entity/mock.js';
|
||||
import {
|
||||
createCameraConfig,
|
||||
createHASS,
|
||||
createHASSManager,
|
||||
createRegistryEntity,
|
||||
|
||||
@@ -26,15 +26,15 @@ import type {
|
||||
EntityRegistryManager,
|
||||
} from '../../../src/ha/registry/entity/types';
|
||||
import { ViewMediaType } from '../../../src/view/item';
|
||||
import { createCameraConfig } from '../../config/test-utils';
|
||||
import { EntityRegistryManagerMock } from '../../ha/registry/entity/mock';
|
||||
import {
|
||||
createCameraConfig,
|
||||
createCapabilities,
|
||||
createHASS,
|
||||
createHASSManager,
|
||||
createRegistryEntity,
|
||||
createStateEntity,
|
||||
} from '../../test-utils';
|
||||
import { createCapabilities } from '../test-utils';
|
||||
|
||||
vi.mock('../../../src/camera-manager/frigate/requests');
|
||||
|
||||
@@ -98,7 +98,7 @@ describe('FrigateCamera', () => {
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
}),
|
||||
).rejects.toThrowError(/Could not find camera entity/);
|
||||
).rejects.toThrow(/Could not find camera entity/);
|
||||
});
|
||||
|
||||
it('with a valid camera_entity', async () => {
|
||||
@@ -315,7 +315,7 @@ describe('FrigateCamera', () => {
|
||||
expect(camera.getCapabilities()?.has('snapshots')).toBeTruthy();
|
||||
expect(camera.getCapabilities()?.has('recordings')).toBeTruthy();
|
||||
expect(camera.getCapabilities()?.has('trigger')).toBeTruthy();
|
||||
expect(vi.mocked(getPTZInfo)).toBeCalled();
|
||||
expect(vi.mocked(getPTZInfo)).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('basic birdseye', async () => {
|
||||
@@ -342,7 +342,7 @@ describe('FrigateCamera', () => {
|
||||
expect(camera.getCapabilities()?.has('snapshots')).toBeFalsy();
|
||||
expect(camera.getCapabilities()?.has('recordings')).toBeFalsy();
|
||||
expect(camera.getCapabilities()?.has('trigger')).toBeTruthy();
|
||||
expect(vi.mocked(getPTZInfo)).not.toBeCalled();
|
||||
expect(vi.mocked(getPTZInfo)).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('with ptz', () => {
|
||||
@@ -368,7 +368,7 @@ describe('FrigateCamera', () => {
|
||||
|
||||
expect(camera.getCapabilities()?.has('ptz')).toBeFalsy();
|
||||
expect(camera.getCapabilities()?.hasPTZCapability()).toBeFalsy();
|
||||
expect(consoleSpy).toBeCalled();
|
||||
expect(consoleSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('when getPTZInfo call succeeds with continuous motion', async () => {
|
||||
@@ -824,7 +824,7 @@ describe('FrigateCamera', () => {
|
||||
frigateEventWatcher: eventWatcher,
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
expect(eventWatcher.subscribe).toBeCalledWith(
|
||||
expect(eventWatcher.subscribe).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
instanceID: 'CLIENT_ID',
|
||||
}),
|
||||
@@ -853,7 +853,7 @@ describe('FrigateCamera', () => {
|
||||
frigateEventWatcher: eventWatcher,
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
expect(eventWatcher.subscribe).not.toBeCalled();
|
||||
expect(eventWatcher.subscribe).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not subscribe without trigger capability', async () => {
|
||||
@@ -878,7 +878,7 @@ describe('FrigateCamera', () => {
|
||||
frigateEventWatcher: eventWatcher,
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
expect(eventWatcher.subscribe).not.toBeCalled();
|
||||
expect(eventWatcher.subscribe).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not subscribe with no camera name', async () => {
|
||||
@@ -902,7 +902,7 @@ describe('FrigateCamera', () => {
|
||||
frigateEventWatcher: eventWatcher,
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
expect(eventWatcher.subscribe).not.toBeCalled();
|
||||
expect(eventWatcher.subscribe).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should unsubscribe on destroy', async () => {
|
||||
@@ -926,10 +926,10 @@ describe('FrigateCamera', () => {
|
||||
frigateEventWatcher: eventWatcher,
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
expect(eventWatcher.unsubscribe).not.toBeCalled();
|
||||
expect(eventWatcher.unsubscribe).not.toHaveBeenCalled();
|
||||
|
||||
await camera.destroy();
|
||||
expect(eventWatcher.unsubscribe).toBeCalled();
|
||||
expect(eventWatcher.unsubscribe).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not subscribe when destroyed while base initialization is pending', async () => {
|
||||
@@ -965,22 +965,22 @@ describe('FrigateCamera', () => {
|
||||
frigateReviewWatcher: reviewWatcher,
|
||||
capabilityOptions: { capabilities: createCapabilities({ trigger: true }) },
|
||||
});
|
||||
await vi.waitFor(() => expect(entityRegistryManager.getEntity).toBeCalled());
|
||||
await vi.waitFor(() => expect(entityRegistryManager.getEntity).toHaveBeenCalled());
|
||||
|
||||
await camera.destroy();
|
||||
|
||||
// `_destroyed` short-circuits initialize() after the pending await, so
|
||||
// neither watcher is ever subscribed.
|
||||
expect(eventWatcher.subscribe).not.toBeCalled();
|
||||
expect(reviewWatcher.subscribe).not.toBeCalled();
|
||||
expect(eventWatcher.subscribe).not.toHaveBeenCalled();
|
||||
expect(reviewWatcher.subscribe).not.toHaveBeenCalled();
|
||||
|
||||
resolveEntity();
|
||||
await initializePromise;
|
||||
|
||||
expect(eventWatcher.subscribe).not.toBeCalled();
|
||||
expect(eventWatcher.unsubscribe).not.toBeCalled();
|
||||
expect(reviewWatcher.subscribe).not.toBeCalled();
|
||||
expect(reviewWatcher.unsubscribe).not.toBeCalled();
|
||||
expect(eventWatcher.subscribe).not.toHaveBeenCalled();
|
||||
expect(eventWatcher.unsubscribe).not.toHaveBeenCalled();
|
||||
expect(reviewWatcher.subscribe).not.toHaveBeenCalled();
|
||||
expect(reviewWatcher.unsubscribe).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('should call handler correctly', () => {
|
||||
@@ -1097,7 +1097,7 @@ describe('FrigateCamera', () => {
|
||||
});
|
||||
|
||||
if (call) {
|
||||
expect(eventCallback).toBeCalledWith({
|
||||
expect(eventCallback).toHaveBeenCalledWith({
|
||||
type: 'new',
|
||||
cameraID: 'CAMERA_1',
|
||||
id: 'event-1',
|
||||
@@ -1106,7 +1106,7 @@ describe('FrigateCamera', () => {
|
||||
fidelity: 'high',
|
||||
});
|
||||
} else {
|
||||
expect(eventCallback).not.toBeCalled();
|
||||
expect(eventCallback).not.toHaveBeenCalled();
|
||||
}
|
||||
},
|
||||
);
|
||||
@@ -1170,7 +1170,7 @@ describe('FrigateCamera', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(eventCallback).toBeCalledWith({
|
||||
expect(eventCallback).toHaveBeenCalledWith({
|
||||
type: 'end',
|
||||
cameraID: 'CAMERA_1',
|
||||
id: 'event-1',
|
||||
@@ -1378,7 +1378,7 @@ describe('FrigateCamera', () => {
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: reviewWatcher,
|
||||
});
|
||||
expect(reviewWatcher.subscribe).toBeCalledWith(
|
||||
expect(reviewWatcher.subscribe).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
instanceID: 'CLIENT_ID',
|
||||
}),
|
||||
@@ -1409,7 +1409,7 @@ describe('FrigateCamera', () => {
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: reviewWatcher,
|
||||
});
|
||||
expect(reviewWatcher.subscribe).not.toBeCalled();
|
||||
expect(reviewWatcher.subscribe).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not subscribe to reviews with description only (no severities)', async () => {
|
||||
@@ -1438,7 +1438,7 @@ describe('FrigateCamera', () => {
|
||||
frigateReviewWatcher: reviewWatcher,
|
||||
});
|
||||
// Severities are required - description alone is not enough
|
||||
expect(reviewWatcher.subscribe).not.toBeCalled();
|
||||
expect(reviewWatcher.subscribe).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('should call handler correctly', () => {
|
||||
@@ -1495,7 +1495,7 @@ describe('FrigateCamera', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(eventCallback).toBeCalledWith({
|
||||
expect(eventCallback).toHaveBeenCalledWith({
|
||||
type: 'new',
|
||||
cameraID: 'CAMERA_1',
|
||||
id: '123',
|
||||
@@ -1566,7 +1566,7 @@ describe('FrigateCamera', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(eventCallback).toBeCalledWith({
|
||||
expect(eventCallback).toHaveBeenCalledWith({
|
||||
type: 'update',
|
||||
cameraID: 'CAMERA_1',
|
||||
id: '123',
|
||||
@@ -1637,7 +1637,7 @@ describe('FrigateCamera', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(eventCallback).toBeCalledWith({
|
||||
expect(eventCallback).toHaveBeenCalledWith({
|
||||
type: 'update',
|
||||
cameraID: 'CAMERA_1',
|
||||
id: '123',
|
||||
@@ -1995,7 +1995,7 @@ describe('FrigateCamera', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(eventCallback).toBeCalledWith({
|
||||
expect(eventCallback).toHaveBeenCalledWith({
|
||||
type: 'end',
|
||||
cameraID: 'CAMERA_1',
|
||||
id: '123',
|
||||
@@ -2123,7 +2123,7 @@ describe('FrigateCamera', () => {
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
}),
|
||||
).rejects.toThrowError(/Could not find camera entity/);
|
||||
).rejects.toThrow(/Could not find camera entity/);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2284,7 +2284,7 @@ describe('FrigateCamera', () => {
|
||||
const executor = mock<ActionsExecutor>();
|
||||
await camera.executePTZAction(executor, 'preset');
|
||||
|
||||
expect(executor.executeActions).not.toBeCalled();
|
||||
expect(executor.executeActions).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should ignore actions with configured action', async () => {
|
||||
@@ -2316,7 +2316,7 @@ describe('FrigateCamera', () => {
|
||||
const executor = mock<ActionsExecutor>();
|
||||
await camera.executePTZAction(executor, 'left', { phase: 'start' });
|
||||
|
||||
expect(executor.executeActions).toBeCalledTimes(1);
|
||||
expect(executor.executeActions).toHaveBeenCalledTimes(1);
|
||||
expect(executor.executeActions).toHaveBeenLastCalledWith({
|
||||
actions: {
|
||||
action: 'perform-action',
|
||||
|
||||
@@ -38,17 +38,17 @@ import type { RawAdvancedCameraCardConfig } from '../../../src/config/types';
|
||||
import { QuerySource } from '../../../src/query-source';
|
||||
import type { Severity } from '../../../src/severity';
|
||||
import { ViewMedia, ViewMediaType } from '../../../src/view/item';
|
||||
import { createCameraConfig } from '../../config/test-utils';
|
||||
import { EntityRegistryManagerMock } from '../../ha/registry/entity/mock';
|
||||
import {
|
||||
createCameraConfig,
|
||||
createFrigateEvent,
|
||||
createFrigateRecording,
|
||||
createFrigateReview,
|
||||
createHASS,
|
||||
createHASSManager,
|
||||
createStore,
|
||||
TestViewMedia,
|
||||
} from '../../test-utils';
|
||||
import { TestViewMedia } from '../../view/test-utils';
|
||||
import { createStore } from '../test-utils';
|
||||
|
||||
vi.mock('../../../src/camera-manager/frigate/requests');
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ import {
|
||||
FrigateViewMediaFactory,
|
||||
} from '../../../src/camera-manager/frigate/media';
|
||||
import { ViewMediaType } from '../../../src/view/item';
|
||||
import { createCameraConfig } from '../../config/test-utils';
|
||||
import {
|
||||
createCameraConfig,
|
||||
createFrigateEvent,
|
||||
createFrigateRecording,
|
||||
createFrigateReview,
|
||||
|
||||
@@ -46,7 +46,7 @@ describe('frigate requests', () => {
|
||||
expect(await getRecordingsSummary(hass, 'clientID', 'camera.office')).toBe(
|
||||
recordingSummary,
|
||||
);
|
||||
expect(homeAssistantWSRequest).toBeCalledWith(
|
||||
expect(homeAssistantWSRequest).toHaveBeenCalledWith(
|
||||
hass,
|
||||
recordingSummarySchema,
|
||||
expect.objectContaining({
|
||||
@@ -77,7 +77,7 @@ describe('frigate requests', () => {
|
||||
before: 0,
|
||||
}),
|
||||
).toBe(recordingSegments);
|
||||
expect(homeAssistantWSRequest).toBeCalledWith(
|
||||
expect(homeAssistantWSRequest).toHaveBeenCalledWith(
|
||||
hass,
|
||||
recordingSegmentsSchema,
|
||||
expect.objectContaining({
|
||||
@@ -101,7 +101,7 @@ describe('frigate requests', () => {
|
||||
const hass = createHASS();
|
||||
retainEvent(hass, 'clientID', 'eventID', true);
|
||||
|
||||
expect(homeAssistantWSRequest).toBeCalledWith(
|
||||
expect(homeAssistantWSRequest).toHaveBeenCalledWith(
|
||||
hass,
|
||||
retainResultSchema,
|
||||
expect.objectContaining({
|
||||
@@ -121,10 +121,10 @@ describe('frigate requests', () => {
|
||||
});
|
||||
|
||||
const hass = createHASS();
|
||||
await expect(retainEvent(hass, 'clientID', 'eventID', true)).rejects.toThrowError(
|
||||
await expect(retainEvent(hass, 'clientID', 'eventID', true)).rejects.toThrow(
|
||||
/Could not retain event/,
|
||||
);
|
||||
expect(homeAssistantWSRequest).toBeCalledWith(
|
||||
expect(homeAssistantWSRequest).toHaveBeenCalledWith(
|
||||
hass,
|
||||
retainResultSchema,
|
||||
expect.objectContaining({
|
||||
@@ -157,7 +157,7 @@ describe('frigate requests', () => {
|
||||
favorites: true,
|
||||
}),
|
||||
).toBe(events);
|
||||
expect(homeAssistantWSRequest).toBeCalledWith(
|
||||
expect(homeAssistantWSRequest).toHaveBeenCalledWith(
|
||||
hass,
|
||||
frigateEventsSchema,
|
||||
expect.objectContaining({
|
||||
@@ -193,7 +193,7 @@ describe('frigate requests', () => {
|
||||
|
||||
vi.mocked(homeAssistantWSRequest).mockResolvedValue(eventSummary);
|
||||
expect(await getEventSummary(hass, 'clientID')).toBe(eventSummary);
|
||||
expect(homeAssistantWSRequest).toBeCalledWith(
|
||||
expect(homeAssistantWSRequest).toHaveBeenCalledWith(
|
||||
hass,
|
||||
eventSummarySchema,
|
||||
expect.objectContaining({
|
||||
@@ -216,7 +216,7 @@ describe('frigate requests', () => {
|
||||
const hass = createHASS();
|
||||
vi.mocked(homeAssistantWSRequest).mockResolvedValue(ptzInfo);
|
||||
expect(await getPTZInfo(hass, 'clientID', 'camera.office')).toBe(ptzInfo);
|
||||
expect(homeAssistantWSRequest).toBeCalledWith(
|
||||
expect(homeAssistantWSRequest).toHaveBeenCalledWith(
|
||||
hass,
|
||||
ptzInfoSchema,
|
||||
expect.objectContaining({
|
||||
@@ -259,7 +259,7 @@ describe('frigate requests', () => {
|
||||
reviewed: false,
|
||||
}),
|
||||
).toBe(reviews);
|
||||
expect(homeAssistantWSRequest).toBeCalledWith(
|
||||
expect(homeAssistantWSRequest).toHaveBeenCalledWith(
|
||||
hass,
|
||||
frigateReviewsSchema,
|
||||
expect.objectContaining({
|
||||
@@ -288,7 +288,7 @@ describe('frigate requests', () => {
|
||||
const hass = createHASS();
|
||||
setReviewsReviewed(hass, 'clientID', ['review_id'], true);
|
||||
|
||||
expect(homeAssistantWSRequest).toBeCalledWith(
|
||||
expect(homeAssistantWSRequest).toHaveBeenCalledWith(
|
||||
hass,
|
||||
reviewResultSchema,
|
||||
expect.objectContaining({
|
||||
@@ -309,8 +309,8 @@ describe('frigate requests', () => {
|
||||
const hass = createHASS();
|
||||
await expect(
|
||||
setReviewsReviewed(hass, 'clientID', ['review_id'], true),
|
||||
).rejects.toThrowError(/Failed to receive response from Home Assistant/);
|
||||
expect(homeAssistantWSRequest).toBeCalledWith(
|
||||
).rejects.toThrow(/Failed to receive response from Home Assistant/);
|
||||
expect(homeAssistantWSRequest).toHaveBeenCalledWith(
|
||||
hass,
|
||||
reviewResultSchema,
|
||||
expect.objectContaining({
|
||||
|
||||
@@ -15,8 +15,8 @@ import {
|
||||
getReviewTitle,
|
||||
} from '../../../src/camera-manager/frigate/util';
|
||||
import type { CameraConfig } from '../../../src/config/schema/cameras';
|
||||
import { createCameraConfig } from '../../config/test-utils';
|
||||
import {
|
||||
createCameraConfig,
|
||||
createFrigateEvent,
|
||||
createFrigateRecording,
|
||||
createFrigateReview,
|
||||
|
||||
@@ -93,7 +93,7 @@ describe('FrigateEventWatcher', () => {
|
||||
watcher.subscribe({ instanceID: 'frigate', callback: vi.fn() });
|
||||
await flushPromises();
|
||||
|
||||
expect(hass.connection.subscribeMessage).toBeCalledWith(
|
||||
expect(hass.connection.subscribeMessage).toHaveBeenCalledWith(
|
||||
expect.any(Function),
|
||||
expect.objectContaining({
|
||||
type: 'frigate/events/subscribe',
|
||||
@@ -116,7 +116,7 @@ describe('FrigateEventWatcher', () => {
|
||||
watcher.unsubscribe(request);
|
||||
await flushPromises();
|
||||
|
||||
expect(unsub).toBeCalledTimes(1);
|
||||
expect(unsub).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should drop messages from an old-connection subscription after a swap', async () => {
|
||||
@@ -140,7 +140,7 @@ describe('FrigateEventWatcher', () => {
|
||||
await flushPromises();
|
||||
|
||||
oldDispatcher(JSON.stringify(createEventChange()));
|
||||
expect(callback).not.toBeCalled();
|
||||
expect(callback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('should call handler', () => {
|
||||
@@ -156,8 +156,8 @@ describe('FrigateEventWatcher', () => {
|
||||
await flushPromises();
|
||||
fireMessage(hass, 'NOT_JSON');
|
||||
|
||||
expect(callback).not.toBeCalled();
|
||||
expect(spy).toBeCalledWith(
|
||||
expect(callback).not.toHaveBeenCalled();
|
||||
expect(spy).toHaveBeenCalledWith(
|
||||
'Received non-JSON payload from subscription: frigate/events/subscribe',
|
||||
'NOT_JSON',
|
||||
);
|
||||
@@ -176,8 +176,8 @@ describe('FrigateEventWatcher', () => {
|
||||
const data = JSON.stringify({});
|
||||
fireMessage(hass, data);
|
||||
|
||||
expect(callback).not.toBeCalled();
|
||||
expect(spy).toBeCalledWith(
|
||||
expect(callback).not.toHaveBeenCalled();
|
||||
expect(spy).toHaveBeenCalledWith(
|
||||
'Received malformed message from subscription: frigate/events/subscribe',
|
||||
data,
|
||||
);
|
||||
@@ -194,7 +194,7 @@ describe('FrigateEventWatcher', () => {
|
||||
const eventChange = createEventChange();
|
||||
fireMessage(hass, JSON.stringify(eventChange));
|
||||
|
||||
expect(callback).toBeCalledWith(eventChange);
|
||||
expect(callback).toHaveBeenCalledWith(eventChange);
|
||||
});
|
||||
|
||||
it('with a matcher', async () => {
|
||||
@@ -219,8 +219,8 @@ describe('FrigateEventWatcher', () => {
|
||||
const eventChange = createEventChange();
|
||||
fireMessage(hass, JSON.stringify(eventChange));
|
||||
|
||||
expect(non_matching_callback).not.toBeCalledWith(eventChange);
|
||||
expect(matching_callback).toBeCalledWith(eventChange);
|
||||
expect(non_matching_callback).not.toHaveBeenCalledWith(eventChange);
|
||||
expect(matching_callback).toHaveBeenCalledWith(eventChange);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -239,7 +239,7 @@ describe('FrigateReviewWatcher', () => {
|
||||
watcher.subscribe({ instanceID: 'frigate', callback });
|
||||
await flushPromises();
|
||||
|
||||
expect(hass.connection.subscribeMessage).toBeCalledWith(
|
||||
expect(hass.connection.subscribeMessage).toHaveBeenCalledWith(
|
||||
expect.any(Function),
|
||||
expect.objectContaining({
|
||||
type: 'frigate/reviews/subscribe',
|
||||
@@ -249,6 +249,6 @@ describe('FrigateReviewWatcher', () => {
|
||||
const reviewChange = createReviewChange();
|
||||
fireMessage(hass, JSON.stringify(reviewChange));
|
||||
|
||||
expect(callback).toBeCalledWith(reviewChange);
|
||||
expect(callback).toHaveBeenCalledWith(reviewChange);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,14 +5,10 @@ import { Engine, QueryResultsType, QueryType } from '../../../src/camera-manager
|
||||
import type { CameraConfig } from '../../../src/config/schema/cameras';
|
||||
import type { RawAdvancedCameraCardConfig } from '../../../src/config/types';
|
||||
import { QuerySource } from '../../../src/query-source';
|
||||
import {
|
||||
createCameraConfig,
|
||||
createHASS,
|
||||
createHASSManager,
|
||||
createStateEntity,
|
||||
createStore,
|
||||
TestViewMedia,
|
||||
} from '../../test-utils';
|
||||
import { createCameraConfig } from '../../config/test-utils';
|
||||
import { createHASS, createHASSManager, createStateEntity } from '../../test-utils';
|
||||
import { TestViewMedia } from '../../view/test-utils';
|
||||
import { createStore } from '../test-utils';
|
||||
|
||||
const createEngine = (): GenericCameraManagerEngine => {
|
||||
return new GenericCameraManagerEngine(createHASSManager());
|
||||
|
||||
@@ -36,17 +36,10 @@ import { QuerySource } from '../../src/query-source.js';
|
||||
import { PTZMovementType, type Endpoint } from '../../src/types.js';
|
||||
import { ViewFolder, type ViewItem, type ViewMedia } from '../../src/view/item.js';
|
||||
import type { ViewItemCapabilities } from '../../src/view/types.js';
|
||||
import {
|
||||
createCameraConfig,
|
||||
createCapabilities,
|
||||
createCardAPI,
|
||||
createConfig,
|
||||
createFolder,
|
||||
createHASS,
|
||||
createInitializedCamera,
|
||||
generateViewMediaArray,
|
||||
TestViewMedia,
|
||||
} from '../test-utils.js';
|
||||
import { createCameraConfig, createConfig } from '../config/test-utils';
|
||||
import { createCardAPI, createFolder, createHASS } from '../test-utils.js';
|
||||
import { generateViewMediaArray, TestViewMedia } from '../view/test-utils';
|
||||
import { createCapabilities, createInitializedCamera } from './test-utils';
|
||||
|
||||
describe('QueryClassifier', () => {
|
||||
it('should classify event query', () => {
|
||||
@@ -481,7 +474,7 @@ describe('CameraManager', () => {
|
||||
type: 'new',
|
||||
};
|
||||
eventCallback?.(cameraEvent);
|
||||
expect(api.getCameraTriggersManager().handleCameraEvent).toBeCalledWith(
|
||||
expect(api.getCameraTriggersManager().handleCameraEvent).toHaveBeenCalledWith(
|
||||
cameraEvent,
|
||||
);
|
||||
});
|
||||
@@ -505,7 +498,7 @@ describe('CameraManager', () => {
|
||||
]);
|
||||
|
||||
await manager.initializeCamerasFromConfig();
|
||||
expect(api.getEntityRegistryManager().fetchEntityList).toBeCalled();
|
||||
expect(api.getEntityRegistryManager().fetchEntityList).toHaveBeenCalled();
|
||||
},
|
||||
);
|
||||
|
||||
@@ -516,7 +509,7 @@ describe('CameraManager', () => {
|
||||
const manager = createCameraManager(api);
|
||||
|
||||
await manager.initializeCamerasFromConfig();
|
||||
expect(api.getEntityRegistryManager().fetchEntityList).not.toBeCalled();
|
||||
expect(api.getEntityRegistryManager().fetchEntityList).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -710,7 +703,7 @@ describe('CameraManager', () => {
|
||||
const results = new Map([[baseEventQuery, baseEventQueryResults]]);
|
||||
engine.getEvents.mockResolvedValue(results);
|
||||
expect(await manager.getEvents(baseEventQuery, engineOptions)).toEqual(results);
|
||||
expect(engine.getEvents).toBeCalledWith(
|
||||
expect(engine.getEvents).toHaveBeenCalledWith(
|
||||
hass,
|
||||
expect.anything(),
|
||||
baseEventQuery,
|
||||
@@ -743,7 +736,12 @@ describe('CameraManager', () => {
|
||||
|
||||
await manager.reviewMedia(media, true);
|
||||
|
||||
expect(engine.reviewMedia).toBeCalledWith(hass, expect.anything(), media, true);
|
||||
expect(engine.reviewMedia).toHaveBeenCalledWith(
|
||||
hass,
|
||||
expect.anything(),
|
||||
media,
|
||||
true,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1210,7 +1208,7 @@ describe('CameraManager', () => {
|
||||
const manager = createCameraManager(createCardAPI(), engine);
|
||||
manager.favoriteMedia(new TestViewMedia(), true);
|
||||
|
||||
expect(engine.favoriteMedia).not.toBeCalled();
|
||||
expect(engine.favoriteMedia).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should succeed', async () => {
|
||||
@@ -1225,7 +1223,12 @@ describe('CameraManager', () => {
|
||||
|
||||
const media = new TestViewMedia({ cameraID: 'id' });
|
||||
manager.favoriteMedia(media, true);
|
||||
expect(engine.favoriteMedia).toBeCalledWith(hass, expect.anything(), media, true);
|
||||
expect(engine.favoriteMedia).toHaveBeenCalledWith(
|
||||
hass,
|
||||
expect.anything(),
|
||||
media,
|
||||
true,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1396,7 +1399,7 @@ describe('CameraManager', () => {
|
||||
vi.mocked(api.getHASSManager().getHASS).mockReturnValue(null);
|
||||
manager.executePTZAction('another', 'left');
|
||||
|
||||
expect(api.getActionsManager().executeActions).toBeCalledWith({
|
||||
expect(api.getActionsManager().executeActions).toHaveBeenCalledWith({
|
||||
actions: action,
|
||||
});
|
||||
});
|
||||
@@ -1425,7 +1428,9 @@ describe('CameraManager', () => {
|
||||
|
||||
manager.executePTZAction('another', 'left');
|
||||
|
||||
expect(api.getActionsManager().executeActions).toBeCalledWith({ actions: action });
|
||||
expect(api.getActionsManager().executeActions).toHaveBeenCalledWith({
|
||||
actions: action,
|
||||
});
|
||||
});
|
||||
|
||||
describe('with rotation', () => {
|
||||
@@ -1544,7 +1549,7 @@ describe('CameraManager', () => {
|
||||
preset: presetAction,
|
||||
};
|
||||
|
||||
expect(api.getActionsManager().executeActions).toBeCalledWith({
|
||||
expect(api.getActionsManager().executeActions).toHaveBeenCalledWith({
|
||||
actions: expectedActionMap[expectedAction],
|
||||
});
|
||||
},
|
||||
@@ -1657,7 +1662,7 @@ describe('CameraManager', () => {
|
||||
});
|
||||
expect(await manager.getMediaSeekTime(media, middleTime)).toBe(42);
|
||||
|
||||
expect(engine.getMediaSeekTime).toBeCalledWith(
|
||||
expect(engine.getMediaSeekTime).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
expect.anything(),
|
||||
media,
|
||||
|
||||
@@ -3,12 +3,9 @@ import { mock } from 'vitest-mock-extended';
|
||||
|
||||
import type { CameraManagerEngine } from '../../../src/camera-manager/engine';
|
||||
import { MotionEyeCamera } from '../../../src/camera-manager/motioneye/camera';
|
||||
import { createCameraConfig } from '../../config/test-utils';
|
||||
import { EntityRegistryManagerMock } from '../../ha/registry/entity/mock';
|
||||
import {
|
||||
createCameraConfig,
|
||||
createHASSManager,
|
||||
createRegistryEntity,
|
||||
} from '../../test-utils';
|
||||
import { createHASSManager, createRegistryEntity } from '../../test-utils';
|
||||
|
||||
const cameraEntity = createRegistryEntity({
|
||||
entity_id: 'camera.motioneye',
|
||||
|
||||
@@ -22,9 +22,9 @@ import {
|
||||
import type { Entity } from '../../../src/ha/registry/entity/types';
|
||||
import { ResolvedMediaCache } from '../../../src/ha/resolved-media';
|
||||
import { QuerySource } from '../../../src/query-source';
|
||||
import { createCameraConfig } from '../../config/test-utils';
|
||||
import { EntityRegistryManagerMock } from '../../ha/registry/entity/mock';
|
||||
import {
|
||||
createCameraConfig,
|
||||
createHASS,
|
||||
createHASSManager,
|
||||
createRegistryEntity,
|
||||
|
||||
@@ -7,9 +7,9 @@ import type { CameraProxyConfig } from '../../../src/camera-manager/types';
|
||||
import type { ActionsExecutor } from '../../../src/card-controller/actions/types';
|
||||
import type { DeviceRegistryManager } from '../../../src/ha/registry/device';
|
||||
import type { EntityRegistryManagerLive } from '../../../src/ha/registry/entity';
|
||||
import { createCameraConfig } from '../../config/test-utils';
|
||||
import { EntityRegistryManagerMock } from '../../ha/registry/entity/mock';
|
||||
import {
|
||||
createCameraConfig,
|
||||
createHASS,
|
||||
createHASSManager,
|
||||
createRegistryEntity,
|
||||
@@ -107,7 +107,7 @@ describe('ReolinkCamera', () => {
|
||||
entityRegistryManager: mock<EntityRegistryManagerLive>(),
|
||||
deviceRegistryManager: mock<DeviceRegistryManager>(),
|
||||
}),
|
||||
).rejects.toThrowError('Could not find camera entity');
|
||||
).rejects.toThrow('Could not find camera entity');
|
||||
});
|
||||
|
||||
it('without a unique_id', async () => {
|
||||
@@ -130,7 +130,7 @@ describe('ReolinkCamera', () => {
|
||||
entityRegistryManager,
|
||||
deviceRegistryManager: mock<DeviceRegistryManager>(),
|
||||
}),
|
||||
).rejects.toThrowError('Could not initialize Reolink camera');
|
||||
).rejects.toThrow('Could not initialize Reolink camera');
|
||||
});
|
||||
|
||||
it('without a valid unique_id', async () => {
|
||||
@@ -153,7 +153,7 @@ describe('ReolinkCamera', () => {
|
||||
entityRegistryManager,
|
||||
deviceRegistryManager: mock<DeviceRegistryManager>(),
|
||||
}),
|
||||
).rejects.toThrowError('Could not initialize Reolink camera');
|
||||
).rejects.toThrow('Could not initialize Reolink camera');
|
||||
});
|
||||
|
||||
it('successfully with a directly connected camera', async () => {
|
||||
@@ -729,7 +729,7 @@ describe('ReolinkCamera', () => {
|
||||
await camera.executePTZAction(executor, 'left');
|
||||
await camera.executePTZAction(executor, 'left', { phase: 'start' });
|
||||
|
||||
expect(executor.executeActions).not.toBeCalled();
|
||||
expect(executor.executeActions).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should ignore actions with configured action', async () => {
|
||||
@@ -758,7 +758,7 @@ describe('ReolinkCamera', () => {
|
||||
const executor = mock<ActionsExecutor>();
|
||||
await camera.executePTZAction(executor, 'left', { phase: 'start' });
|
||||
|
||||
expect(executor.executeActions).toBeCalledTimes(1);
|
||||
expect(executor.executeActions).toHaveBeenCalledTimes(1);
|
||||
expect(executor.executeActions).toHaveBeenLastCalledWith({
|
||||
actions: {
|
||||
action: 'perform-action',
|
||||
|
||||
@@ -31,15 +31,10 @@ import type { EntityRegistryManager } from '../../../src/ha/registry/entity/type
|
||||
import { ResolvedMediaCache } from '../../../src/ha/resolved-media';
|
||||
import { homeAssistantWSRequest } from '../../../src/ha/ws-request';
|
||||
import { QuerySource } from '../../../src/query-source';
|
||||
import { createCameraConfig } from '../../config/test-utils';
|
||||
import { EntityRegistryManagerMock } from '../../ha/registry/entity/mock';
|
||||
import {
|
||||
createCameraConfig,
|
||||
createHASS,
|
||||
createHASSManager,
|
||||
createInitializedCamera,
|
||||
createRegistryEntity,
|
||||
createStore,
|
||||
} from '../../test-utils';
|
||||
import { createHASS, createHASSManager, createRegistryEntity } from '../../test-utils';
|
||||
import { createInitializedCamera, createStore } from '../test-utils';
|
||||
|
||||
vi.mock('../../../src/ha/ws-request');
|
||||
|
||||
|
||||
@@ -9,12 +9,10 @@ import { Engine } from '../../src/camera-manager/types.js';
|
||||
import type { DeviceRegistryManager } from '../../src/ha/registry/device/index.js';
|
||||
import type { EntityRegistryManager } from '../../src/ha/registry/entity/types.js';
|
||||
import type { ResolvedMediaCache } from '../../src/ha/resolved-media.js';
|
||||
import {
|
||||
createCameraConfig,
|
||||
createHASSManager,
|
||||
createInitializedCamera,
|
||||
TestViewMedia,
|
||||
} from '../test-utils.js';
|
||||
import { createCameraConfig } from '../config/test-utils';
|
||||
import { createHASSManager } from '../test-utils.js';
|
||||
import { TestViewMedia } from '../view/test-utils';
|
||||
import { createInitializedCamera } from './test-utils';
|
||||
|
||||
describe('CameraManagerStore', async () => {
|
||||
const configVisible = createCameraConfig({
|
||||
@@ -144,7 +142,7 @@ describe('CameraManagerStore', async () => {
|
||||
|
||||
expect(store.getCameraCount()).toBe(0);
|
||||
for (const camera of cameras) {
|
||||
expect(camera.destroy).toBeCalled();
|
||||
expect(camera.destroy).toHaveBeenCalled();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -381,10 +379,10 @@ describe('CameraManagerStore', async () => {
|
||||
expect(store.getCamera('camera-3')).toBe(camera_3_new);
|
||||
expect(store.getCamera('camera-4')).toBe(camera_4);
|
||||
|
||||
expect(camera_1.destroy).toBeCalled();
|
||||
expect(camera_2.destroy).not.toBeCalled();
|
||||
expect(camera_3.destroy).toBeCalled();
|
||||
expect(camera_3_new.destroy).not.toBeCalled();
|
||||
expect(camera_4.destroy).not.toBeCalled();
|
||||
expect(camera_1.destroy).toHaveBeenCalled();
|
||||
expect(camera_2.destroy).not.toHaveBeenCalled();
|
||||
expect(camera_3.destroy).toHaveBeenCalled();
|
||||
expect(camera_3_new.destroy).not.toHaveBeenCalled();
|
||||
expect(camera_4.destroy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
import { vi } from 'vitest';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
|
||||
import { Camera } from '../../src/camera-manager/camera';
|
||||
import { Capabilities } from '../../src/camera-manager/capabilities';
|
||||
import type { CameraManagerEngine } from '../../src/camera-manager/engine';
|
||||
import { GenericCameraManagerEngine } from '../../src/camera-manager/generic/engine-generic';
|
||||
import type { CameraManager } from '../../src/camera-manager/manager';
|
||||
import { CameraManagerStore } from '../../src/camera-manager/store';
|
||||
import { type CameraEventCallback } from '../../src/camera-manager/types';
|
||||
import type { StateWatcherSubscriptionInterface } from '../../src/card-controller/hass/state-watcher';
|
||||
import { type CameraConfig } from '../../src/config/schema/cameras';
|
||||
import type { EntityRegistryManager } from '../../src/ha/registry/entity/types';
|
||||
import type { CapabilitiesRaw } from '../../src/types';
|
||||
import { createCameraConfig } from '../config/test-utils';
|
||||
import { createHASSManager } from '../test-utils';
|
||||
|
||||
export const createCapabilities = (capabilities?: CapabilitiesRaw): Capabilities => {
|
||||
return new Capabilities({
|
||||
'favorite-events': false,
|
||||
'favorite-recordings': false,
|
||||
'remote-control-entity': true,
|
||||
clips: false,
|
||||
live: false,
|
||||
recordings: false,
|
||||
seek: false,
|
||||
snapshots: false,
|
||||
trigger: true,
|
||||
...capabilities,
|
||||
});
|
||||
};
|
||||
|
||||
export const createInitializedCamera = async (
|
||||
config: CameraConfig,
|
||||
engine: CameraManagerEngine,
|
||||
capabilities?: Capabilities,
|
||||
stateWatcher?: StateWatcherSubscriptionInterface,
|
||||
): Promise<Camera> => {
|
||||
const camera = new Camera(config, engine);
|
||||
await camera.initialize({
|
||||
hassManager: createHASSManager({ stateWatcher }),
|
||||
...(capabilities ? { capabilityOptions: { capabilities } } : {}),
|
||||
});
|
||||
return camera;
|
||||
};
|
||||
|
||||
export const createStore = (
|
||||
cameras?: {
|
||||
cameraID: string;
|
||||
engine?: CameraManagerEngine;
|
||||
config?: CameraConfig;
|
||||
capabilities?: Capabilities | null;
|
||||
eventCallback?: CameraEventCallback;
|
||||
}[],
|
||||
): CameraManagerStore => {
|
||||
const store = new CameraManagerStore();
|
||||
for (const cameraProps of cameras ?? []) {
|
||||
const eventCallback = cameraProps.eventCallback ?? vi.fn();
|
||||
const capabilities =
|
||||
cameraProps.capabilities === undefined
|
||||
? createCapabilities()
|
||||
: cameraProps.capabilities ?? undefined;
|
||||
const camera = new Camera(
|
||||
cameraProps.config ?? createCameraConfig(),
|
||||
cameraProps.engine ??
|
||||
new GenericCameraManagerEngine(
|
||||
createHASSManager(),
|
||||
mock<EntityRegistryManager>(),
|
||||
eventCallback,
|
||||
),
|
||||
{ eventCallback, capabilities },
|
||||
);
|
||||
camera.setID(cameraProps.cameraID);
|
||||
store.addCamera(camera);
|
||||
}
|
||||
return store;
|
||||
};
|
||||
|
||||
export const createCameraManager = (store?: CameraManagerStore): CameraManager => {
|
||||
const cameraStore = store ?? createStore();
|
||||
const cameraManager = mock<CameraManager>();
|
||||
vi.mocked(cameraManager.getStore).mockReturnValue(cameraStore);
|
||||
vi.mocked(cameraManager.getCameraCapabilities).mockImplementation(
|
||||
(cameraID: string): Capabilities | null => {
|
||||
return cameraStore.getCamera(cameraID)?.getCapabilities() ?? null;
|
||||
},
|
||||
);
|
||||
|
||||
return cameraManager;
|
||||
};
|
||||
@@ -4,12 +4,9 @@ import { mock } from 'vitest-mock-extended';
|
||||
import type { CameraManagerEngine } from '../../../src/camera-manager/engine';
|
||||
import { TPLinkCamera } from '../../../src/camera-manager/tplink/camera';
|
||||
import type { ActionsExecutor } from '../../../src/card-controller/actions/types';
|
||||
import { createCameraConfig } from '../../config/test-utils';
|
||||
import { EntityRegistryManagerMock } from '../../ha/registry/entity/mock';
|
||||
import {
|
||||
createCameraConfig,
|
||||
createHASSManager,
|
||||
createRegistryEntity,
|
||||
} from '../../test-utils';
|
||||
import { createHASSManager, createRegistryEntity } from '../../test-utils';
|
||||
|
||||
describe('TPLinkCamera', () => {
|
||||
// Entity patterns from: https://github.com/dermotduffy/advanced-camera-card/issues/2183
|
||||
@@ -83,7 +80,7 @@ describe('TPLinkCamera', () => {
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock(),
|
||||
}),
|
||||
).rejects.toThrowError('Could not find camera entity');
|
||||
).rejects.toThrow('Could not find camera entity');
|
||||
});
|
||||
|
||||
it('without a matching entity in registry', async () => {
|
||||
@@ -98,7 +95,7 @@ describe('TPLinkCamera', () => {
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock(),
|
||||
}),
|
||||
).rejects.toThrowError('Could not find camera entity');
|
||||
).rejects.toThrow('Could not find camera entity');
|
||||
});
|
||||
|
||||
it('successfully with webrtc_card.entity fallback', async () => {
|
||||
@@ -204,7 +201,7 @@ describe('TPLinkCamera', () => {
|
||||
await camera.executePTZAction(executor, 'left', { phase: 'start' }),
|
||||
).toBeFalsy();
|
||||
|
||||
expect(executor.executeActions).not.toBeCalled();
|
||||
expect(executor.executeActions).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should ignore zoom actions (not supported by TPLink)', async () => {
|
||||
@@ -226,7 +223,7 @@ describe('TPLinkCamera', () => {
|
||||
await camera.executePTZAction(executor, 'zoom_out', { phase: 'start' }),
|
||||
).toBeFalsy();
|
||||
|
||||
expect(executor.executeActions).not.toBeCalled();
|
||||
expect(executor.executeActions).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should ignore preset actions (not supported by TPLink)', async () => {
|
||||
@@ -245,7 +242,7 @@ describe('TPLinkCamera', () => {
|
||||
await camera.executePTZAction(executor, 'preset', { preset: 'home' }),
|
||||
).toBeFalsy();
|
||||
|
||||
expect(executor.executeActions).not.toBeCalled();
|
||||
expect(executor.executeActions).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should handle stop phase (no-op for TPLink)', async () => {
|
||||
@@ -265,7 +262,7 @@ describe('TPLinkCamera', () => {
|
||||
await camera.executePTZAction(executor, 'left', { phase: 'stop' }),
|
||||
).toBeTruthy();
|
||||
|
||||
expect(executor.executeActions).not.toBeCalled();
|
||||
expect(executor.executeActions).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it.each([
|
||||
@@ -353,7 +350,7 @@ describe('TPLinkCamera', () => {
|
||||
const executor = mock<ActionsExecutor>();
|
||||
await camera.executePTZAction(executor, 'left', { phase: 'start' });
|
||||
|
||||
expect(executor.executeActions).toBeCalledTimes(1);
|
||||
expect(executor.executeActions).toHaveBeenCalledTimes(1);
|
||||
expect(executor.executeActions).toHaveBeenLastCalledWith({
|
||||
actions: {
|
||||
action: 'perform-action',
|
||||
|
||||
@@ -2,13 +2,9 @@ import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { TPLinkCameraManagerEngine } from '../../../src/camera-manager/tplink/engine-tplink';
|
||||
import { Engine } from '../../../src/camera-manager/types';
|
||||
import { createCameraConfig } from '../../config/test-utils';
|
||||
import { EntityRegistryManagerMock } from '../../ha/registry/entity/mock';
|
||||
import {
|
||||
createCameraConfig,
|
||||
createHASS,
|
||||
createHASSManager,
|
||||
createRegistryEntity,
|
||||
} from '../../test-utils';
|
||||
import { createHASS, createHASSManager, createRegistryEntity } from '../../test-utils';
|
||||
|
||||
const createEngine = (options?: {
|
||||
entityRegistryManager?: EntityRegistryManagerMock;
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
getGo2RTCMetadataEndpoint,
|
||||
getGo2RTCStreamEndpoint,
|
||||
} from '../../../src/camera-manager/utils/go2rtc/endpoint.js';
|
||||
import { createCameraConfig } from '../../test-utils.js';
|
||||
import { createCameraConfig } from '../../config/test-utils';
|
||||
|
||||
describe('getGo2RTCStreamEndpoint', () => {
|
||||
it('with local configuration', () => {
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
} from '../../../src/camera-manager/utils/ptz';
|
||||
import type { PTZAction } from '../../../src/config/schema/actions/custom/ptz';
|
||||
import { PTZMovementType } from '../../../src/types';
|
||||
import { createCameraConfig } from '../../test-utils';
|
||||
import { createCameraConfig } from '../../config/test-utils';
|
||||
|
||||
const action = {
|
||||
action: 'perform-action' as const,
|
||||
|
||||
@@ -22,14 +22,14 @@ import {
|
||||
createLogAction,
|
||||
} from '../../../src/utils/action';
|
||||
import { arrayify } from '../../../src/utils/basic';
|
||||
import { createConfig } from '../../config/test-utils';
|
||||
import {
|
||||
createCardAPI,
|
||||
createConfig,
|
||||
createHASS,
|
||||
createMockTemplateRenderer,
|
||||
createView,
|
||||
stubConnectedHomeAssistant,
|
||||
} from '../../test-utils';
|
||||
import { createView } from '../../view/test-utils';
|
||||
|
||||
const createAPI = (): CardController => {
|
||||
const api = createCardAPI();
|
||||
@@ -215,7 +215,7 @@ describe('ActionsManager', () => {
|
||||
await manager.handleInteractionEvent(
|
||||
new CustomEvent<Interaction>('event', { detail: { action: 'tap' } }),
|
||||
);
|
||||
expect(consoleSpy).toBeCalled();
|
||||
expect(consoleSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('should handle unexpected interactions', () => {
|
||||
@@ -246,7 +246,7 @@ describe('ActionsManager', () => {
|
||||
detail: { action: interaction as unknown as InteractionName },
|
||||
}),
|
||||
);
|
||||
expect(consoleSpy).not.toBeCalled();
|
||||
expect(consoleSpy).not.toHaveBeenCalled();
|
||||
},
|
||||
);
|
||||
});
|
||||
@@ -271,7 +271,7 @@ describe('ActionsManager', () => {
|
||||
|
||||
const consoleSpy = vi.spyOn(global.console, 'info').mockReturnValue(undefined);
|
||||
await manager.handleCustomActionEvent(event);
|
||||
expect(consoleSpy).toBeCalled();
|
||||
expect(consoleSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not handle generic event', async () => {
|
||||
@@ -292,7 +292,7 @@ describe('ActionsManager', () => {
|
||||
|
||||
await manager.handleCustomActionEvent(event);
|
||||
|
||||
expect(handler).not.toBeCalled();
|
||||
expect(handler).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not handle event without detail', async () => {
|
||||
@@ -300,7 +300,7 @@ describe('ActionsManager', () => {
|
||||
|
||||
const consoleSpy = vi.spyOn(global.console, 'info').mockReturnValue(undefined);
|
||||
await manager.handleCustomActionEvent(new Event('ll-custom'));
|
||||
expect(consoleSpy).not.toBeCalled();
|
||||
expect(consoleSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -319,7 +319,7 @@ describe('ActionsManager', () => {
|
||||
detail: { actions: createLogAction('Hello, world!') },
|
||||
}),
|
||||
);
|
||||
expect(consoleSpy).toBeCalled();
|
||||
expect(consoleSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -334,7 +334,7 @@ describe('ActionsManager', () => {
|
||||
|
||||
const consoleSpy = vi.spyOn(global.console, 'info').mockReturnValue(undefined);
|
||||
await manager.executeActions({ actions: createLogAction('Hello, world!') });
|
||||
expect(consoleSpy).toBeCalled();
|
||||
expect(consoleSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should execute actions', async () => {
|
||||
@@ -343,7 +343,7 @@ describe('ActionsManager', () => {
|
||||
|
||||
const consoleSpy = vi.spyOn(global.console, 'info').mockReturnValue(undefined);
|
||||
await manager.executeActions({ actions: createLogAction('Hello, world!') });
|
||||
expect(consoleSpy).toBeCalled();
|
||||
expect(consoleSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should render templates', async () => {
|
||||
@@ -372,14 +372,12 @@ describe('ActionsManager', () => {
|
||||
|
||||
await manager.executeActions({ actions: action, config, triggerData });
|
||||
|
||||
expect(vi.mocked(api.getTemplateManager().renderRecursivelyAsType)).toBeCalledWith(
|
||||
hass,
|
||||
action,
|
||||
{
|
||||
expect(
|
||||
vi.mocked(api.getTemplateManager().renderRecursivelyAsType),
|
||||
).toHaveBeenCalledWith(hass, action, {
|
||||
conditionState,
|
||||
triggerData,
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('should filter actions through the lock manager before rendering them', async () => {
|
||||
@@ -403,9 +401,9 @@ describe('ActionsManager', () => {
|
||||
|
||||
// The lock manager sees the raw (unrendered) action; only the action it
|
||||
// returns is rendered and run.
|
||||
expect(api.getLockManager().getAllowedActions).toBeCalledWith([rawAction]);
|
||||
expect(allowedRan).toBeCalled();
|
||||
expect(rawRan).not.toBeCalled();
|
||||
expect(api.getLockManager().getAllowedActions).toHaveBeenCalledWith([rawAction]);
|
||||
expect(allowedRan).toHaveBeenCalled();
|
||||
expect(rawRan).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should render each action against the state at its turn', async () => {
|
||||
@@ -481,7 +479,7 @@ describe('ActionsManager', () => {
|
||||
expect(ran).toEqual(['one', 'two']);
|
||||
expect(
|
||||
vi.mocked(api.getTemplateManager().renderRecursivelyAsType),
|
||||
).toBeCalledTimes(1);
|
||||
).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should abort the remaining actions when one fails to render', async () => {
|
||||
@@ -519,7 +517,7 @@ describe('ActionsManager', () => {
|
||||
// The first action ran; the second's render threw, aborting the rest. The
|
||||
// error was caught by executeActions().
|
||||
expect(ran).toEqual(['first']);
|
||||
expect(warnSpy).toBeCalled();
|
||||
expect(warnSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should hand an if-action branch to the executor unrendered, with the trigger data', async () => {
|
||||
@@ -549,7 +547,7 @@ describe('ActionsManager', () => {
|
||||
// The branch is left raw (template intact) and forwarded with the trigger
|
||||
// data, so the nested executor renders it per-step when it runs -- not
|
||||
// frozen against the state at the `if` step.
|
||||
expect(api.getActionsManager().executeNestedActions).toBeCalledWith({
|
||||
expect(api.getActionsManager().executeNestedActions).toHaveBeenCalledWith({
|
||||
actions: [thenAction],
|
||||
config: undefined,
|
||||
triggerData: { platform: 'state', entity_id: 'binary_sensor.door' },
|
||||
@@ -557,7 +555,7 @@ describe('ActionsManager', () => {
|
||||
|
||||
// The log action is handed to the (mocked) nested executor, not run here,
|
||||
// so it must not actually log.
|
||||
expect(consoleSpy).not.toBeCalled();
|
||||
expect(consoleSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should render if-action branch actions per-step', async () => {
|
||||
@@ -633,7 +631,7 @@ describe('ActionsManager', () => {
|
||||
|
||||
await manager.executeActions({ actions: createLogAction('Blocked') });
|
||||
|
||||
expect(consoleSpy).not.toBeCalled();
|
||||
expect(consoleSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('should forward haptics', () => {
|
||||
@@ -651,7 +649,9 @@ describe('ActionsManager', () => {
|
||||
|
||||
await manager.executeActions({ actions: { action: 'none' } });
|
||||
|
||||
expect(handler).toBeCalledWith(expect.objectContaining({ detail: 'success' }));
|
||||
expect(handler).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ detail: 'success' }),
|
||||
);
|
||||
});
|
||||
|
||||
it('should forward warning haptic', async () => {
|
||||
@@ -669,7 +669,9 @@ describe('ActionsManager', () => {
|
||||
actions: { action: 'none', confirmation: true },
|
||||
});
|
||||
|
||||
expect(handler).toBeCalledWith(expect.objectContaining({ detail: 'warning' }));
|
||||
expect(handler).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ detail: 'warning' }),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -712,7 +714,7 @@ describe('ActionsManager', () => {
|
||||
await promise;
|
||||
|
||||
// Action set will not continue.
|
||||
expect(consoleSpy).not.toBeCalled();
|
||||
expect(consoleSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -44,7 +44,7 @@ describe('should handle base action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(confirm).not.toBeCalled();
|
||||
expect(confirm).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should continue execution when confirmed', async () => {
|
||||
@@ -61,7 +61,7 @@ describe('should handle base action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(confirm).toBeCalled();
|
||||
expect(confirm).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should abort execution when not confirmed', async () => {
|
||||
@@ -76,7 +76,7 @@ describe('should handle base action', () => {
|
||||
|
||||
vi.mocked(confirm).mockReturnValue(false);
|
||||
|
||||
expect(async () => await action.execute(api)).rejects.toThrowError(/Aborted action/);
|
||||
expect(async () => await action.execute(api)).rejects.toThrow(/Aborted action/);
|
||||
});
|
||||
|
||||
it('should not confirm when exempted', async () => {
|
||||
@@ -100,7 +100,7 @@ describe('should handle base action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(confirm).not.toBeCalled();
|
||||
expect(confirm).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('should show correct confirmation text', () => {
|
||||
@@ -121,7 +121,7 @@ describe('should handle base action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(confirm).toBeCalledWith(
|
||||
expect(confirm).toHaveBeenCalledWith(
|
||||
'Are you sure you want to perform this action: more-info',
|
||||
);
|
||||
});
|
||||
@@ -143,7 +143,7 @@ describe('should handle base action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(confirm).toBeCalledWith(
|
||||
expect(confirm).toHaveBeenCalledWith(
|
||||
'Are you sure you want to perform this action: clips',
|
||||
);
|
||||
});
|
||||
@@ -167,7 +167,7 @@ describe('should handle base action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(confirm).toBeCalledWith('Test text');
|
||||
expect(confirm).toHaveBeenCalledWith('Test text');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,5 +15,5 @@ it('should handle call_answer action', async () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getCallManager().answer).toBeCalled();
|
||||
expect(api.getCallManager().answer).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -15,5 +15,5 @@ it('should handle call_end action', async () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getCallManager().end).toBeCalled();
|
||||
expect(api.getCallManager().end).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -20,7 +20,7 @@ describe('CallServiceAction', () => {
|
||||
);
|
||||
await action.execute(api);
|
||||
|
||||
expect(hass.callService).toBeCalledWith(
|
||||
expect(hass.callService).toHaveBeenCalledWith(
|
||||
'light',
|
||||
'turn_on',
|
||||
{
|
||||
|
||||
@@ -15,7 +15,7 @@ it('should handle call_start action without a camera or stream', async () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getCallManager().start).toBeCalledWith({
|
||||
expect(api.getCallManager().start).toHaveBeenCalledWith({
|
||||
cameraID: undefined,
|
||||
streamID: undefined,
|
||||
});
|
||||
@@ -35,7 +35,7 @@ it('should handle call_start action with a camera and stream', async () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getCallManager().start).toBeCalledWith({
|
||||
expect(api.getCallManager().start).toHaveBeenCalledWith({
|
||||
cameraID: 'camera.front',
|
||||
streamID: 'camera.front_doorbell',
|
||||
});
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { CameraSelectAction } from '../../../../src/card-controller/actions/actions/camera-select';
|
||||
import { createCardAPI, createConfig, createView } from '../../../test-utils';
|
||||
import { createConfig } from '../../../config/test-utils';
|
||||
import { createCardAPI } from '../../../test-utils';
|
||||
import { createView } from '../../../view/test-utils';
|
||||
|
||||
describe('should handle camera_select action', () => {
|
||||
it('with valid camera and view', async () => {
|
||||
@@ -19,7 +21,7 @@ describe('should handle camera_select action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).toBeCalledWith(
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
params: {
|
||||
view: 'live',
|
||||
@@ -49,7 +51,7 @@ describe('should handle camera_select action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('without config', async () => {
|
||||
@@ -72,7 +74,7 @@ describe('should handle camera_select action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).toBeCalledWith(
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
params: {
|
||||
view: 'timeline',
|
||||
@@ -110,7 +112,7 @@ describe('should handle camera_select action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).toBeCalledWith(
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
params: {
|
||||
view: 'clips',
|
||||
@@ -139,7 +141,7 @@ describe('should handle camera_select action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).toBeCalledWith(
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
params: {
|
||||
view: 'live',
|
||||
@@ -167,7 +169,7 @@ describe('should handle camera_select action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('without a current view', async () => {
|
||||
@@ -184,6 +186,6 @@ describe('should handle camera_select action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,5 +15,5 @@ it('should handle camera_ui action', async () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getCameraURLManager().openURL).toBeCalled();
|
||||
expect(api.getCameraURLManager().openURL).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -29,7 +29,7 @@ describe('CustomAction', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(handler).toBeCalledWith(
|
||||
expect(handler).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
detail: { action: 'fire-dom-event', foo: 'bar', 1: 2 },
|
||||
}),
|
||||
|
||||
@@ -15,5 +15,5 @@ it('should handle default action', async () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).toBeCalled();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -16,7 +16,7 @@ it('should handle default action', async () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).toBeCalledWith({
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).toHaveBeenCalledWith({
|
||||
params: {
|
||||
displayMode: 'grid',
|
||||
},
|
||||
|
||||
@@ -2,7 +2,8 @@ import { expect, it, vi } from 'vitest';
|
||||
|
||||
import { DownloadAction } from '../../../../src/card-controller/actions/actions/download';
|
||||
import { QueryResults } from '../../../../src/view/query-results';
|
||||
import { createCardAPI, createView, TestViewMedia } from '../../../test-utils';
|
||||
import { createCardAPI } from '../../../test-utils';
|
||||
import { createView, TestViewMedia } from '../../../view/test-utils';
|
||||
|
||||
it('should handle download action with selected media', async () => {
|
||||
const api = createCardAPI();
|
||||
@@ -23,7 +24,7 @@ it('should handle download action with selected media', async () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getViewItemManager().download).toBeCalledWith(selectedMedia);
|
||||
expect(api.getViewItemManager().download).toHaveBeenCalledWith(selectedMedia);
|
||||
});
|
||||
|
||||
it('should handle download action without selected media', async () => {
|
||||
@@ -40,5 +41,5 @@ it('should handle download action without selected media', async () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getViewItemManager().download).not.toBeCalled();
|
||||
expect(api.getViewItemManager().download).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -15,5 +15,5 @@ it('should handle expand action', async () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getExpandManager().toggleExpanded).toBeCalled();
|
||||
expect(api.getExpandManager().toggleExpanded).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -15,5 +15,5 @@ it('should handle fullscreen action', async () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getFullscreenManager().toggleFullscreen).toBeCalled();
|
||||
expect(api.getFullscreenManager().toggleFullscreen).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -17,7 +17,7 @@ describe('GeneratedAction', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getActionsManager().executeNestedActions).toBeCalledWith({
|
||||
expect(api.getActionsManager().executeNestedActions).toHaveBeenCalledWith({
|
||||
actions: generated,
|
||||
config: undefined,
|
||||
triggerData: undefined,
|
||||
@@ -37,7 +37,7 @@ describe('GeneratedAction', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getActionsManager().executeNestedActions).toBeCalledWith({
|
||||
expect(api.getActionsManager().executeNestedActions).toHaveBeenCalledWith({
|
||||
actions: generated,
|
||||
config: undefined,
|
||||
triggerData: undefined,
|
||||
@@ -53,7 +53,7 @@ describe('GeneratedAction', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getActionsManager().executeNestedActions).not.toBeCalled();
|
||||
expect(api.getActionsManager().executeNestedActions).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should pass the api and trigger data to the generator', async () => {
|
||||
@@ -72,6 +72,6 @@ describe('GeneratedAction', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(generator).toBeCalledWith({ api, triggerData });
|
||||
expect(generator).toHaveBeenCalledWith({ api, triggerData });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -35,7 +35,7 @@ describe('IfAction', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getActionsManager().executeNestedActions).toBeCalledWith({
|
||||
expect(api.getActionsManager().executeNestedActions).toHaveBeenCalledWith({
|
||||
actions: thenActions,
|
||||
config: undefined,
|
||||
triggerData: undefined,
|
||||
@@ -59,7 +59,7 @@ describe('IfAction', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getActionsManager().executeNestedActions).toBeCalledWith({
|
||||
expect(api.getActionsManager().executeNestedActions).toHaveBeenCalledWith({
|
||||
actions: elseActions,
|
||||
config: undefined,
|
||||
triggerData: undefined,
|
||||
@@ -82,6 +82,6 @@ describe('IfAction', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getActionsManager().executeNestedActions).not.toBeCalled();
|
||||
expect(api.getActionsManager().executeNestedActions).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,7 +3,8 @@ import { describe, expect, it, vi } from 'vitest';
|
||||
import { InfoAction } from '../../../../src/card-controller/actions/actions/info';
|
||||
import { QueryResults } from '../../../../src/view/query-results';
|
||||
import { View } from '../../../../src/view/view';
|
||||
import { createCardAPI, TestViewMedia } from '../../../test-utils';
|
||||
import { createCardAPI } from '../../../test-utils';
|
||||
import { TestViewMedia } from '../../../view/test-utils';
|
||||
|
||||
describe('InfoAction', () => {
|
||||
it('should handle info action with media', async () => {
|
||||
@@ -29,7 +30,7 @@ describe('InfoAction', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getNotificationManager().setNotification).toBeCalled();
|
||||
expect(api.getNotificationManager().setNotification).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not handle info action without media', async () => {
|
||||
@@ -46,6 +47,6 @@ describe('InfoAction', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getNotificationManager().setNotification).not.toBeCalled();
|
||||
expect(api.getNotificationManager().setNotification).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -18,5 +18,5 @@ it('should handle internal callback action', async () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(callback).toBeCalledWith(api);
|
||||
expect(callback).toHaveBeenCalledWith(api);
|
||||
});
|
||||
|
||||
@@ -21,5 +21,5 @@ it('should handle log action', async () => {
|
||||
|
||||
const spy = vi.spyOn(global.console, 'warn').mockImplementation(() => true);
|
||||
await action.execute(api);
|
||||
expect(spy).toBeCalledWith('Hello, world!');
|
||||
expect(spy).toHaveBeenCalledWith('Hello, world!');
|
||||
});
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { MediaPlayerAction } from '../../../../src/card-controller/actions/actions/media-player';
|
||||
import { createCardAPI, createView, createViewWithMedia } from '../../../test-utils';
|
||||
import { createCardAPI } from '../../../test-utils';
|
||||
import { createView, createViewWithMedia } from '../../../view/test-utils';
|
||||
|
||||
afterEach(() => {
|
||||
vi.resetAllMocks();
|
||||
@@ -23,7 +24,9 @@ describe('should handle media_player action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getMediaPlayerManager().stop).toBeCalledWith('this_is_a_media_player');
|
||||
expect(api.getMediaPlayerManager().stop).toHaveBeenCalledWith(
|
||||
'this_is_a_media_player',
|
||||
);
|
||||
});
|
||||
|
||||
it('to play live', async () => {
|
||||
@@ -47,7 +50,7 @@ describe('should handle media_player action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getMediaPlayerManager().playLive).toBeCalledWith(
|
||||
expect(api.getMediaPlayerManager().playLive).toHaveBeenCalledWith(
|
||||
'this_is_a_media_player',
|
||||
'camera',
|
||||
);
|
||||
@@ -74,7 +77,7 @@ describe('should handle media_player action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getMediaPlayerManager().playMedia).toBeCalledWith(
|
||||
expect(api.getMediaPlayerManager().playMedia).toHaveBeenCalledWith(
|
||||
'this_is_a_media_player',
|
||||
view.queryResults?.getSelectedResult(),
|
||||
);
|
||||
@@ -100,7 +103,7 @@ describe('should handle media_player action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getMediaPlayerManager().playMedia).not.toBeCalled();
|
||||
expect(api.getMediaPlayerManager().playMedia).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('to not play live without camera', async () => {
|
||||
@@ -124,6 +127,6 @@ describe('should handle media_player action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getMediaPlayerManager().playLive).not.toBeCalled();
|
||||
expect(api.getMediaPlayerManager().playLive).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,5 +15,5 @@ it('should handle menu toggle action', async () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getCardElementManager().toggleMenu).toBeCalled();
|
||||
expect(api.getCardElementManager().toggleMenu).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -15,5 +15,5 @@ it('should handle microphone_connect action', async () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getMicrophoneManager().connect).toBeCalled();
|
||||
expect(api.getMicrophoneManager().connect).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -15,5 +15,5 @@ it('should handle microphone_disconnect action', async () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getMicrophoneManager().disconnect).toBeCalled();
|
||||
expect(api.getMicrophoneManager().disconnect).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -15,5 +15,5 @@ it('should handle microphone_mute action', async () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getMicrophoneManager().mute).toBeCalled();
|
||||
expect(api.getMicrophoneManager().mute).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -15,5 +15,5 @@ it('should handle microphone_unmute action', async () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getMicrophoneManager().unmute).toBeCalled();
|
||||
expect(api.getMicrophoneManager().unmute).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -24,7 +24,7 @@ describe('should handle more-info action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(handler).toBeCalledWith(
|
||||
expect(handler).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
detail: { entityId: 'light.office' },
|
||||
}),
|
||||
@@ -51,7 +51,7 @@ describe('should handle more-info action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(handler).toBeCalledWith(
|
||||
expect(handler).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
detail: { entityId: 'light.office' },
|
||||
}),
|
||||
@@ -76,6 +76,6 @@ describe('should handle more-info action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(handler).not.toBeCalled();
|
||||
expect(handler).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -23,5 +23,5 @@ it('should handle mute action', async () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(mediaPlayerController.mute).toBeCalled();
|
||||
expect(mediaPlayerController.mute).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -23,7 +23,7 @@ describe('should handle navigate action', () => {
|
||||
await action.execute(createCardAPI());
|
||||
|
||||
expect(history.length).toBe(historyLength + 1);
|
||||
expect(handler).toBeCalledWith(
|
||||
expect(handler).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
detail: { replace: false },
|
||||
}),
|
||||
@@ -49,7 +49,7 @@ describe('should handle navigate action', () => {
|
||||
await action.execute(createCardAPI());
|
||||
|
||||
expect(history.length).toBe(historyLength);
|
||||
expect(handler).toBeCalledWith(
|
||||
expect(handler).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
detail: { replace: true },
|
||||
}),
|
||||
|
||||
@@ -25,5 +25,5 @@ it('should handle pause action', async () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(mediaPlayerController.playback?.pause).toBeCalled();
|
||||
expect(mediaPlayerController.playback?.pause).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -20,7 +20,7 @@ describe('PerformActionAction', () => {
|
||||
);
|
||||
await action.execute(api);
|
||||
|
||||
expect(hass.callService).toBeCalledWith(
|
||||
expect(hass.callService).toHaveBeenCalledWith(
|
||||
'light',
|
||||
'turn_on',
|
||||
{
|
||||
|
||||
@@ -15,5 +15,5 @@ it('should toggle PIP', async () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getPIPManager().togglePIP).toBeCalled();
|
||||
expect(api.getPIPManager().togglePIP).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -25,5 +25,5 @@ it('should handle play action', async () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(mediaPlayerController.playback?.play).toBeCalled();
|
||||
expect(mediaPlayerController.playback?.play).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -20,7 +20,7 @@ describe('PTZControlsAction', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getViewManager().setViewWithMergedContext).toBeCalledWith({
|
||||
expect(api.getViewManager().setViewWithMergedContext).toHaveBeenCalledWith({
|
||||
ptzControls: { enabled: true, type: 'buttons' },
|
||||
});
|
||||
});
|
||||
@@ -41,7 +41,7 @@ describe('PTZControlsAction', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getViewManager().setViewWithMergedContext).toBeCalledWith({
|
||||
expect(api.getViewManager().setViewWithMergedContext).toHaveBeenCalledWith({
|
||||
ptzControls: { enabled: false },
|
||||
});
|
||||
});
|
||||
@@ -59,7 +59,7 @@ describe('PTZControlsAction', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getViewManager().setViewWithMergedContext).toBeCalledWith({
|
||||
expect(api.getViewManager().setViewWithMergedContext).toHaveBeenCalledWith({
|
||||
ptzControls: {},
|
||||
});
|
||||
});
|
||||
@@ -78,7 +78,7 @@ describe('PTZControlsAction', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getViewManager().setViewWithMergedContext).toBeCalledWith({
|
||||
expect(api.getViewManager().setViewWithMergedContext).toHaveBeenCalledWith({
|
||||
ptzControls: { type: 'gestures' },
|
||||
});
|
||||
});
|
||||
@@ -100,7 +100,7 @@ describe('PTZControlsAction', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getViewManager().setViewWithMergedContext).toBeCalledWith({
|
||||
expect(api.getViewManager().setViewWithMergedContext).toHaveBeenCalledWith({
|
||||
ptzControls: { type: 'buttons' },
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,7 +6,8 @@ import type {
|
||||
ZoomSettingsObserved,
|
||||
} from '../../../../src/components-lib/zoom/types';
|
||||
import type { PTZAction } from '../../../../src/config/schema/actions/custom/ptz';
|
||||
import { createCardAPI, createView } from '../../../test-utils';
|
||||
import { createCardAPI } from '../../../test-utils';
|
||||
import { createView } from '../../../view/test-utils';
|
||||
|
||||
describe('should handle ptz digital action', () => {
|
||||
const defaultSettings = {
|
||||
@@ -47,7 +48,7 @@ describe('should handle ptz digital action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getViewManager().setViewWithMergedContext).toBeCalledWith({
|
||||
expect(api.getViewManager().setViewWithMergedContext).toHaveBeenCalledWith({
|
||||
zoom: {
|
||||
camera: {
|
||||
observed: undefined,
|
||||
@@ -77,7 +78,7 @@ describe('should handle ptz digital action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getViewManager().setViewWithMergedContext).toBeCalledWith({
|
||||
expect(api.getViewManager().setViewWithMergedContext).toHaveBeenCalledWith({
|
||||
zoom: {
|
||||
camera: {
|
||||
observed: undefined,
|
||||
@@ -101,7 +102,7 @@ describe('should handle ptz digital action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getViewManager().setViewWithMergedContext).not.toBeCalledWith();
|
||||
expect(api.getViewManager().setViewWithMergedContext).not.toHaveBeenCalledWith();
|
||||
});
|
||||
|
||||
it('should do nothing without a camera', async () => {
|
||||
@@ -125,7 +126,7 @@ describe('should handle ptz digital action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getViewManager().setViewWithMergedContext).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewWithMergedContext).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('should honor ptz_action', () => {
|
||||
@@ -338,7 +339,7 @@ describe('should handle ptz digital action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getViewManager().setViewWithMergedContext).toBeCalledWith({
|
||||
expect(api.getViewManager().setViewWithMergedContext).toHaveBeenCalledWith({
|
||||
zoom: {
|
||||
camera: {
|
||||
observed: undefined,
|
||||
@@ -428,12 +429,12 @@ describe('should handle ptz digital action', () => {
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(api.getViewManager().setViewWithMergedContext).toBeCalledTimes(2);
|
||||
expect(api.getViewManager().setViewWithMergedContext).toHaveBeenCalledTimes(2);
|
||||
|
||||
action.stop();
|
||||
vi.runOnlyPendingTimers();
|
||||
|
||||
expect(api.getViewManager().setViewWithMergedContext).toBeCalledTimes(2);
|
||||
expect(api.getViewManager().setViewWithMergedContext).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('stop', async () => {
|
||||
@@ -463,7 +464,7 @@ describe('should handle ptz digital action', () => {
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(api.getViewManager().setViewWithMergedContext).toBeCalledTimes(1);
|
||||
expect(api.getViewManager().setViewWithMergedContext).toHaveBeenCalledTimes(1);
|
||||
|
||||
const stopAction = new PTZDigitalAction(context, {
|
||||
action: 'fire-dom-event',
|
||||
@@ -474,7 +475,7 @@ describe('should handle ptz digital action', () => {
|
||||
|
||||
vi.runOnlyPendingTimers();
|
||||
|
||||
expect(api.getViewManager().setViewWithMergedContext).toBeCalledTimes(1);
|
||||
expect(api.getViewManager().setViewWithMergedContext).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,12 +3,9 @@ import { describe, expect, it, vi } from 'vitest';
|
||||
import { Capabilities } from '../../../../src/camera-manager/capabilities';
|
||||
import { PTZMultiAction } from '../../../../src/card-controller/actions/actions/ptz-multi';
|
||||
import { PTZMovementType } from '../../../../src/types';
|
||||
import {
|
||||
createCameraManager,
|
||||
createCardAPI,
|
||||
createStore,
|
||||
createView,
|
||||
} from '../../../test-utils';
|
||||
import { createCameraManager, createStore } from '../../../camera-manager/test-utils';
|
||||
import { createCardAPI } from '../../../test-utils';
|
||||
import { createView } from '../../../view/test-utils';
|
||||
|
||||
describe('should handle ptz multi action', () => {
|
||||
describe.each([
|
||||
@@ -42,7 +39,7 @@ describe('should handle ptz multi action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getCameraManager().executePTZAction).toBeCalledWith(
|
||||
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledWith(
|
||||
'camera.office',
|
||||
'left',
|
||||
{
|
||||
@@ -50,7 +47,7 @@ describe('should handle ptz multi action', () => {
|
||||
preset: undefined,
|
||||
},
|
||||
);
|
||||
expect(api.getViewManager().setViewWithMergedContext).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewWithMergedContext).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should use digital ptz when camera does not have ptz support', async () => {
|
||||
@@ -79,7 +76,7 @@ describe('should handle ptz multi action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getCameraManager().executePTZAction).not.toBeCalled();
|
||||
expect(api.getCameraManager().executePTZAction).not.toHaveBeenCalled();
|
||||
expect(api.getViewManager().setViewWithMergedContext).toHaveBeenLastCalledWith({
|
||||
zoom: {
|
||||
'camera.office': {
|
||||
@@ -117,8 +114,8 @@ describe('should handle ptz multi action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getCameraManager().executePTZAction).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewWithMergedContext).not.toBeCalled();
|
||||
expect(api.getCameraManager().executePTZAction).not.toHaveBeenCalled();
|
||||
expect(api.getViewManager().setViewWithMergedContext).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should do nothing with a media-less view without an explicit target_id', async () => {
|
||||
@@ -146,7 +143,7 @@ describe('should handle ptz multi action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getCameraManager().executePTZAction).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewWithMergedContext).not.toBeCalled();
|
||||
expect(api.getCameraManager().executePTZAction).not.toHaveBeenCalled();
|
||||
expect(api.getViewManager().setViewWithMergedContext).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,13 +3,10 @@ import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest';
|
||||
import { Capabilities } from '../../../../src/camera-manager/capabilities';
|
||||
import { PTZAction } from '../../../../src/card-controller/actions/actions/ptz';
|
||||
import { PTZMovementType } from '../../../../src/types';
|
||||
import {
|
||||
createCameraConfig,
|
||||
createCameraManager,
|
||||
createCardAPI,
|
||||
createStore,
|
||||
createView,
|
||||
} from '../../../test-utils';
|
||||
import { createCameraManager, createStore } from '../../../camera-manager/test-utils';
|
||||
import { createCameraConfig } from '../../../config/test-utils';
|
||||
import { createCardAPI } from '../../../test-utils';
|
||||
import { createView } from '../../../view/test-utils';
|
||||
|
||||
describe('should handle ptz action', () => {
|
||||
it('should execute simple action', async () => {
|
||||
@@ -39,7 +36,7 @@ describe('should handle ptz action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getCameraManager().executePTZAction).toBeCalledWith(
|
||||
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledWith(
|
||||
'camera.office',
|
||||
'left',
|
||||
{
|
||||
@@ -74,7 +71,7 @@ describe('should handle ptz action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getCameraManager().executePTZAction).toBeCalledWith(
|
||||
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledWith(
|
||||
'camera.office',
|
||||
'left',
|
||||
{
|
||||
@@ -121,7 +118,7 @@ describe('should handle ptz action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getCameraManager().executePTZAction).toBeCalledWith(
|
||||
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledWith(
|
||||
'camera.office_hd',
|
||||
'left',
|
||||
{
|
||||
@@ -149,7 +146,7 @@ describe('should handle ptz action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getCameraManager().executePTZAction).not.toBeCalled();
|
||||
expect(api.getCameraManager().executePTZAction).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -168,7 +165,7 @@ describe('should handle ptz action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getCameraManager().executePTZAction).not.toBeCalled();
|
||||
expect(api.getCameraManager().executePTZAction).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('when there is no action', () => {
|
||||
@@ -195,7 +192,7 @@ describe('should handle ptz action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getCameraManager().executePTZAction).toBeCalledWith(
|
||||
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledWith(
|
||||
'camera.office',
|
||||
'preset',
|
||||
{
|
||||
@@ -244,7 +241,7 @@ describe('should handle ptz action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getCameraManager().executePTZAction).toBeCalledWith(
|
||||
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledWith(
|
||||
'camera.office',
|
||||
'preset',
|
||||
{
|
||||
@@ -290,7 +287,7 @@ describe('should handle ptz action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getCameraManager().executePTZAction).toBeCalledWith(
|
||||
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledWith(
|
||||
'camera.office',
|
||||
'preset',
|
||||
{
|
||||
@@ -328,7 +325,7 @@ describe('should handle ptz action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getCameraManager().executePTZAction).not.toBeCalled();
|
||||
expect(api.getCameraManager().executePTZAction).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -361,7 +358,7 @@ describe('should handle ptz action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getCameraManager().executePTZAction).toBeCalledWith(
|
||||
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledWith(
|
||||
'camera.office',
|
||||
'preset',
|
||||
{
|
||||
@@ -400,7 +397,7 @@ describe('should handle ptz action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getCameraManager().executePTZAction).toBeCalledWith(
|
||||
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledWith(
|
||||
'camera.office',
|
||||
'left',
|
||||
{
|
||||
@@ -447,7 +444,7 @@ describe('should handle ptz action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getCameraManager().executePTZAction).toBeCalledWith(
|
||||
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledWith(
|
||||
'camera.office',
|
||||
'left',
|
||||
{
|
||||
@@ -456,7 +453,7 @@ describe('should handle ptz action', () => {
|
||||
);
|
||||
|
||||
vi.runOnlyPendingTimers();
|
||||
expect(api.getCameraManager().executePTZAction).toBeCalledWith(
|
||||
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledWith(
|
||||
'camera.office',
|
||||
'left',
|
||||
{
|
||||
@@ -491,12 +488,12 @@ describe('should handle ptz action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getCameraManager().executePTZAction).toBeCalledTimes(1);
|
||||
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledTimes(1);
|
||||
|
||||
action.stop();
|
||||
vi.runOnlyPendingTimers();
|
||||
|
||||
expect(api.getCameraManager().executePTZAction).toBeCalledTimes(1);
|
||||
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -535,20 +532,20 @@ describe('should handle ptz action', () => {
|
||||
});
|
||||
await startAction.execute(api);
|
||||
|
||||
expect(api.getCameraManager().executePTZAction).toBeCalledWith(
|
||||
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledWith(
|
||||
'camera.office',
|
||||
'left',
|
||||
{
|
||||
phase: undefined,
|
||||
},
|
||||
);
|
||||
expect(api.getCameraManager().executePTZAction).toBeCalledTimes(1);
|
||||
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledTimes(1);
|
||||
|
||||
await vi.runOnlyPendingTimersAsync();
|
||||
expect(api.getCameraManager().executePTZAction).toBeCalledTimes(2);
|
||||
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledTimes(2);
|
||||
|
||||
await vi.runOnlyPendingTimersAsync();
|
||||
expect(api.getCameraManager().executePTZAction).toBeCalledTimes(3);
|
||||
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledTimes(3);
|
||||
|
||||
const stopAction = new PTZAction(context, {
|
||||
action: 'fire-dom-event',
|
||||
@@ -560,7 +557,7 @@ describe('should handle ptz action', () => {
|
||||
|
||||
// There should be no additional calls.
|
||||
await vi.runOnlyPendingTimersAsync();
|
||||
expect(api.getCameraManager().executePTZAction).toBeCalledTimes(3);
|
||||
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
|
||||
it('should honor stop', async () => {
|
||||
@@ -590,10 +587,10 @@ describe('should handle ptz action', () => {
|
||||
});
|
||||
|
||||
await action.execute(api);
|
||||
expect(api.getCameraManager().executePTZAction).toBeCalledTimes(1);
|
||||
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledTimes(1);
|
||||
|
||||
await vi.runOnlyPendingTimersAsync();
|
||||
expect(api.getCameraManager().executePTZAction).toBeCalledTimes(2);
|
||||
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledTimes(2);
|
||||
|
||||
// Emulate the stop being called while the action is running, but before
|
||||
// the *next* timer is scheduled.
|
||||
@@ -604,7 +601,7 @@ describe('should handle ptz action', () => {
|
||||
vi.mocked(cameraManager.executePTZAction).mockReturnValueOnce(promise);
|
||||
|
||||
await vi.runOnlyPendingTimersAsync();
|
||||
expect(api.getCameraManager().executePTZAction).toBeCalledTimes(3);
|
||||
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledTimes(3);
|
||||
|
||||
action.stop();
|
||||
|
||||
@@ -612,7 +609,7 @@ describe('should handle ptz action', () => {
|
||||
await vi.runOnlyPendingTimersAsync();
|
||||
|
||||
// There should be no additional calls.
|
||||
expect(api.getCameraManager().executePTZAction).toBeCalledTimes(3);
|
||||
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -25,6 +25,6 @@ describe('should handle reload action', async () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(location.reload).toBeCalledTimes(1);
|
||||
expect(location.reload).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -34,7 +34,7 @@ describe('should handle screenshot action', async () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(downloadURL).toBeCalledWith('screenshot-url', 'screenshot.jpg');
|
||||
expect(downloadURL).toHaveBeenCalledWith('screenshot-url', 'screenshot.jpg');
|
||||
});
|
||||
|
||||
it('should handle screenshot action without screenshot URL', async () => {
|
||||
@@ -58,6 +58,6 @@ describe('should handle screenshot action', async () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(downloadURL).not.toBeCalled();
|
||||
expect(downloadURL).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,7 +3,8 @@ import { describe, expect, it, vi } from 'vitest';
|
||||
import { SetReviewAction } from '../../../../src/card-controller/actions/actions/set-review';
|
||||
import { ViewMediaType } from '../../../../src/view/item';
|
||||
import { QueryResults } from '../../../../src/view/query-results';
|
||||
import { createCardAPI, createView, TestViewMedia } from '../../../test-utils';
|
||||
import { createCardAPI } from '../../../test-utils';
|
||||
import { createView, TestViewMedia } from '../../../view/test-utils';
|
||||
|
||||
describe('SetReviewAction', () => {
|
||||
it('should toggle item reviewed state', async () => {
|
||||
@@ -27,13 +28,13 @@ describe('SetReviewAction', () => {
|
||||
);
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getViewItemManager().reviewMedia).toBeCalledWith(item, true);
|
||||
expect(api.getViewItemManager().reviewMedia).toHaveBeenCalledWith(item, true);
|
||||
|
||||
// toggleReviewed mutates the item in-place
|
||||
expect(item.isReviewed()).toBe(true);
|
||||
|
||||
// Verify UI update is triggered to refresh menu icon
|
||||
expect(api.getCardElementManager().update).toBeCalled();
|
||||
expect(api.getCardElementManager().update).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should set reviewed to true when requested and currently false', async () => {
|
||||
@@ -58,7 +59,7 @@ describe('SetReviewAction', () => {
|
||||
);
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getViewItemManager().reviewMedia).toBeCalledWith(item, true);
|
||||
expect(api.getViewItemManager().reviewMedia).toHaveBeenCalledWith(item, true);
|
||||
expect(item.isReviewed()).toBe(true);
|
||||
});
|
||||
|
||||
@@ -84,7 +85,7 @@ describe('SetReviewAction', () => {
|
||||
);
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getViewItemManager().reviewMedia).not.toBeCalled();
|
||||
expect(api.getViewItemManager().reviewMedia).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not act on non-review media', async () => {
|
||||
@@ -108,7 +109,7 @@ describe('SetReviewAction', () => {
|
||||
);
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getViewItemManager().reviewMedia).not.toBeCalled();
|
||||
expect(api.getViewItemManager().reviewMedia).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not act without a view', async () => {
|
||||
@@ -125,7 +126,7 @@ describe('SetReviewAction', () => {
|
||||
);
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getViewItemManager().reviewMedia).not.toBeCalled();
|
||||
expect(api.getViewItemManager().reviewMedia).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not act without query results', async () => {
|
||||
@@ -143,7 +144,7 @@ describe('SetReviewAction', () => {
|
||||
);
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getViewItemManager().reviewMedia).not.toBeCalled();
|
||||
expect(api.getViewItemManager().reviewMedia).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not update UI if review action fails', async () => {
|
||||
@@ -170,7 +171,7 @@ describe('SetReviewAction', () => {
|
||||
);
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getViewItemManager().reviewMedia).toBeCalledWith(item, true);
|
||||
expect(api.getCardElementManager().update).not.toBeCalled();
|
||||
expect(api.getViewItemManager().reviewMedia).toHaveBeenCalledWith(item, true);
|
||||
expect(api.getCardElementManager().update).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -25,7 +25,7 @@ describe('ActionSet', () => {
|
||||
|
||||
const consoleSpy = vi.spyOn(global.console, 'info').mockReturnValue(undefined);
|
||||
await set.execute(api);
|
||||
expect(consoleSpy).toBeCalled();
|
||||
expect(consoleSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not execute invalid action', async () => {
|
||||
@@ -39,7 +39,7 @@ describe('ActionSet', () => {
|
||||
|
||||
const consoleSpy = vi.spyOn(global.console, 'info').mockReturnValue(undefined);
|
||||
await set.execute(api);
|
||||
expect(consoleSpy).not.toBeCalled();
|
||||
expect(consoleSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should stop execution', async () => {
|
||||
@@ -50,6 +50,6 @@ describe('ActionSet', () => {
|
||||
const consoleSpy = vi.spyOn(global.console, 'info').mockReturnValue(undefined);
|
||||
await set.stop();
|
||||
await set.execute(api);
|
||||
expect(consoleSpy).not.toBeCalled();
|
||||
expect(consoleSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -22,5 +22,5 @@ it('should handle sleep action', async () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(sleep).toBeCalledWith(5.2);
|
||||
expect(sleep).toHaveBeenCalledWith(5.2);
|
||||
});
|
||||
|
||||
@@ -17,7 +17,9 @@ describe('should handle status bar action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getStatusBarItemManager().removeAllDynamicStatusBarItems).toBeCalled();
|
||||
expect(
|
||||
api.getStatusBarItemManager().removeAllDynamicStatusBarItems,
|
||||
).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('add', async () => {
|
||||
@@ -39,7 +41,9 @@ describe('should handle status bar action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getStatusBarItemManager().addDynamicStatusBarItem).toBeCalledWith(item);
|
||||
expect(api.getStatusBarItemManager().addDynamicStatusBarItem).toHaveBeenCalledWith(
|
||||
item,
|
||||
);
|
||||
});
|
||||
|
||||
it('remove', async () => {
|
||||
@@ -61,8 +65,8 @@ describe('should handle status bar action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getStatusBarItemManager().removeDynamicStatusBarItem).toBeCalledWith(
|
||||
item,
|
||||
);
|
||||
expect(
|
||||
api.getStatusBarItemManager().removeDynamicStatusBarItem,
|
||||
).toHaveBeenCalledWith(item);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,7 +4,8 @@ import { SubstreamOffAction } from '../../../../src/card-controller/actions/acti
|
||||
import { applyViewModifiers } from '../../../../src/card-controller/view/modifiers';
|
||||
import { createSubstreamOffAction } from '../../../../src/utils/action';
|
||||
import type { View } from '../../../../src/view/view';
|
||||
import { createCardAPI, createView } from '../../../test-utils';
|
||||
import { createCardAPI } from '../../../test-utils';
|
||||
import { createView } from '../../../view/test-utils';
|
||||
|
||||
// Runs the off-action for `view` and applies the modifier it produces.
|
||||
const applySubstreamOff = async (
|
||||
|
||||
@@ -7,13 +7,13 @@ import { createSubstreamOnAction } from '../../../../src/utils/action';
|
||||
import { getStreamCameraID } from '../../../../src/view/substream';
|
||||
import type { View } from '../../../../src/view/view';
|
||||
import {
|
||||
createCameraConfig,
|
||||
createCameraManager,
|
||||
createCapabilities,
|
||||
createCardAPI,
|
||||
createStore,
|
||||
createView,
|
||||
} from '../../../test-utils';
|
||||
} from '../../../camera-manager/test-utils';
|
||||
import { createCameraConfig } from '../../../config/test-utils';
|
||||
import { createCardAPI } from '../../../test-utils';
|
||||
import { createView } from '../../../view/test-utils';
|
||||
|
||||
// A store where `camera.office` has one substream dependency, `camera.kitchen`.
|
||||
const createStoreWithSubstreams = (): CameraManagerStore =>
|
||||
@@ -181,6 +181,6 @@ describe('SubstreamOnAction', () => {
|
||||
|
||||
await new SubstreamOnAction({}, createSubstreamOnAction()).execute(api);
|
||||
|
||||
expect(api.getViewManager().setViewByParameters).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewByParameters).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -46,9 +46,13 @@ describe('ToggleAction', () => {
|
||||
const action = new ToggleAction({}, { action: 'toggle' }, { entity: entityID });
|
||||
await action.execute(api);
|
||||
|
||||
expect(hass.callService).toBeCalledWith(expectedServiceDomain, expectedService, {
|
||||
expect(hass.callService).toHaveBeenCalledWith(
|
||||
expectedServiceDomain,
|
||||
expectedService,
|
||||
{
|
||||
entity_id: entityID,
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
@@ -62,7 +66,7 @@ describe('ToggleAction', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(hass.callService).not.toBeCalled();
|
||||
expect(hass.callService).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should do nothing without an entity state', async () => {
|
||||
@@ -77,6 +81,6 @@ describe('ToggleAction', () => {
|
||||
);
|
||||
await action.execute(api);
|
||||
|
||||
expect(hass.callService).not.toBeCalled();
|
||||
expect(hass.callService).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -23,5 +23,5 @@ it('should handle unmute action', async () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(mediaPlayerController.unmute).toBeCalled();
|
||||
expect(mediaPlayerController.unmute).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -28,7 +28,7 @@ describe('should handle view action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).toBeCalledWith(
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
params: {
|
||||
view: viewName,
|
||||
@@ -53,7 +53,7 @@ describe('should handle folder view action', () => {
|
||||
|
||||
await action.execute(api);
|
||||
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).toBeCalledWith(
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
params: {
|
||||
view: viewName,
|
||||
|
||||
@@ -40,7 +40,7 @@ describe('AutomationsManager', () => {
|
||||
|
||||
stateManager.setState({ fullscreen: true });
|
||||
|
||||
expect(api.getActionsManager().executeActions).not.toBeCalled();
|
||||
expect(api.getActionsManager().executeActions).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should do nothing without being initialized', () => {
|
||||
@@ -57,7 +57,7 @@ describe('AutomationsManager', () => {
|
||||
|
||||
stateManager.setState({ fullscreen: true });
|
||||
|
||||
expect(api.getActionsManager().executeActions).not.toBeCalled();
|
||||
expect(api.getActionsManager().executeActions).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should do nothing when an issue is present', () => {
|
||||
@@ -78,7 +78,7 @@ describe('AutomationsManager', () => {
|
||||
|
||||
stateManager.setState({ fullscreen: true });
|
||||
|
||||
expect(api.getActionsManager().executeActions).not.toBeCalled();
|
||||
expect(api.getActionsManager().executeActions).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -96,17 +96,17 @@ describe('AutomationsManager', () => {
|
||||
|
||||
stateManager.setState({ fullscreen: true });
|
||||
|
||||
expect(api.getActionsManager().executeActions).toBeCalledTimes(1);
|
||||
expect(api.getActionsManager().executeActions).toHaveBeenCalledTimes(1);
|
||||
|
||||
// It does not re-trigger while its source stays in the same state.
|
||||
stateManager.setState({ fullscreen: true });
|
||||
expect(api.getActionsManager().executeActions).toBeCalledTimes(1);
|
||||
expect(api.getActionsManager().executeActions).toHaveBeenCalledTimes(1);
|
||||
|
||||
stateManager.setState({ fullscreen: false });
|
||||
expect(api.getActionsManager().executeActions).toBeCalledTimes(1);
|
||||
expect(api.getActionsManager().executeActions).toHaveBeenCalledTimes(1);
|
||||
|
||||
stateManager.setState({ fullscreen: true });
|
||||
expect(api.getActionsManager().executeActions).toBeCalledTimes(2);
|
||||
expect(api.getActionsManager().executeActions).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('should subscribe automations registered before initialization', () => {
|
||||
@@ -125,7 +125,7 @@ describe('AutomationsManager', () => {
|
||||
// Registered before initialization: the triggers are not yet subscribed, so
|
||||
// a matching change does nothing.
|
||||
stateManager.setState({ fullscreen: true });
|
||||
expect(api.getActionsManager().executeActions).not.toBeCalled();
|
||||
expect(api.getActionsManager().executeActions).not.toHaveBeenCalled();
|
||||
|
||||
// Initialization completes and subscribes the dormant automations.
|
||||
isInitialized.mockReturnValue(true);
|
||||
@@ -133,7 +133,7 @@ describe('AutomationsManager', () => {
|
||||
|
||||
stateManager.setState({ fullscreen: false });
|
||||
stateManager.setState({ fullscreen: true });
|
||||
expect(api.getActionsManager().executeActions).toBeCalledTimes(1);
|
||||
expect(api.getActionsManager().executeActions).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should run actions when the ongoing conditions hold', () => {
|
||||
@@ -158,7 +158,7 @@ describe('AutomationsManager', () => {
|
||||
stateManager.setState({ expand: true });
|
||||
stateManager.setState({ fullscreen: true });
|
||||
|
||||
expect(api.getActionsManager().executeActions).toBeCalledWith({
|
||||
expect(api.getActionsManager().executeActions).toHaveBeenCalledWith({
|
||||
actions: actions,
|
||||
triggerData: { platform: 'acc', type: 'fullscreen' },
|
||||
});
|
||||
@@ -186,7 +186,7 @@ describe('AutomationsManager', () => {
|
||||
// nothing runs.
|
||||
stateManager.setState({ fullscreen: true });
|
||||
|
||||
expect(api.getActionsManager().executeActions).not.toBeCalled();
|
||||
expect(api.getActionsManager().executeActions).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should do nothing when the actions are empty', () => {
|
||||
@@ -208,7 +208,7 @@ describe('AutomationsManager', () => {
|
||||
|
||||
stateManager.setState({ fullscreen: true });
|
||||
|
||||
expect(api.getActionsManager().executeActions).not.toBeCalled();
|
||||
expect(api.getActionsManager().executeActions).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should prevent automation loops', () => {
|
||||
@@ -245,7 +245,7 @@ describe('AutomationsManager', () => {
|
||||
|
||||
stateManager.setState({ camera: camera });
|
||||
|
||||
expect(api.getNotificationManager().setNotification).toBeCalledWith({
|
||||
expect(api.getNotificationManager().setNotification).toHaveBeenCalledWith({
|
||||
heading: {
|
||||
text: 'Too many nested automation calls, please check your configuration for loops',
|
||||
icon: 'mdi:alert',
|
||||
@@ -253,7 +253,7 @@ describe('AutomationsManager', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(api.getActionsManager().executeActions).toBeCalledTimes(10);
|
||||
expect(api.getActionsManager().executeActions).toHaveBeenCalledTimes(10);
|
||||
});
|
||||
|
||||
it('should reset the nested-execution counter after an overflow', async () => {
|
||||
@@ -284,7 +284,7 @@ describe('AutomationsManager', () => {
|
||||
);
|
||||
|
||||
stateManager.setState({ camera: camera });
|
||||
expect(api.getActionsManager().executeActions).toBeCalledTimes(10);
|
||||
expect(api.getActionsManager().executeActions).toHaveBeenCalledTimes(10);
|
||||
|
||||
// The counter is decremented on the microtasks that resume after each
|
||||
// awaited execution, so let them drain before the next batch.
|
||||
@@ -296,7 +296,7 @@ describe('AutomationsManager', () => {
|
||||
// again -- only possible if the counter returned to zero. A leaked counter
|
||||
// (overflow returning without decrementing) would cut this batch short.
|
||||
stateManager.setState({ camera: 'three' });
|
||||
expect(api.getActionsManager().executeActions).toBeCalledTimes(10);
|
||||
expect(api.getActionsManager().executeActions).toHaveBeenCalledTimes(10);
|
||||
});
|
||||
|
||||
it('should execute actions on a matching HA bus event trigger', () => {
|
||||
@@ -321,13 +321,13 @@ describe('AutomationsManager', () => {
|
||||
},
|
||||
]);
|
||||
|
||||
expect(eventWatcher.subscribe).toBeCalledTimes(1);
|
||||
expect(eventWatcher.subscribe).toHaveBeenCalledTimes(1);
|
||||
|
||||
// Simulate an event arrival.
|
||||
const event = createHASSEvent('zha_event', { command: 'press' });
|
||||
vi.mocked(eventWatcher.subscribe).mock.calls[0][0].callback(event);
|
||||
|
||||
expect(api.getActionsManager().executeActions).toBeCalledTimes(1);
|
||||
expect(api.getActionsManager().executeActions).toHaveBeenCalledTimes(1);
|
||||
expect(
|
||||
vi.mocked(api.getActionsManager().executeActions).mock.calls[0][0].triggerData,
|
||||
).toEqual({ platform: 'event', event });
|
||||
@@ -356,23 +356,23 @@ describe('AutomationsManager', () => {
|
||||
]);
|
||||
|
||||
stateManager.setState({ fullscreen: true });
|
||||
expect(api.getActionsManager().executeActions).toBeCalledTimes(1);
|
||||
expect(api.getActionsManager().executeActions).toHaveBeenCalledTimes(1);
|
||||
|
||||
// Delete the fullscreen automation.
|
||||
automationsManager.deleteAutomations('fullscreen');
|
||||
|
||||
stateManager.setState({ fullscreen: false });
|
||||
stateManager.setState({ fullscreen: true });
|
||||
expect(api.getActionsManager().executeActions).toBeCalledTimes(1);
|
||||
expect(api.getActionsManager().executeActions).toHaveBeenCalledTimes(1);
|
||||
|
||||
stateManager.setState({ expand: true });
|
||||
expect(api.getActionsManager().executeActions).toBeCalledTimes(2);
|
||||
expect(api.getActionsManager().executeActions).toHaveBeenCalledTimes(2);
|
||||
|
||||
// Delete all automations.
|
||||
automationsManager.deleteAutomations();
|
||||
|
||||
stateManager.setState({ expand: false });
|
||||
stateManager.setState({ expand: true });
|
||||
expect(api.getActionsManager().executeActions).toBeCalledTimes(2);
|
||||
expect(api.getActionsManager().executeActions).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16,16 +16,15 @@ import type { TriggerOfType } from '../../../src/condition-trigger/triggers/trig
|
||||
import type { RingtoneConfig } from '../../../src/config/schema/live';
|
||||
import type { AdvancedCameraCardConfig } from '../../../src/config/schema/types';
|
||||
import { View } from '../../../src/view/view';
|
||||
import { createTriggerEvaluatorContext } from '../../condition-trigger/triggers/triggers/test-utils';
|
||||
import {
|
||||
createCameraConfig,
|
||||
createCameraManager,
|
||||
createCapabilities,
|
||||
createCardAPI,
|
||||
createConfig,
|
||||
createStore,
|
||||
createView,
|
||||
} from '../../test-utils';
|
||||
} from '../../camera-manager/test-utils';
|
||||
import { createTriggerEvaluatorContext } from '../../condition-trigger/triggers/triggers/test-utils';
|
||||
import { createCameraConfig, createConfig } from '../../config/test-utils';
|
||||
import { createCardAPI } from '../../test-utils';
|
||||
import { createView } from '../../view/test-utils';
|
||||
|
||||
// Replace Ringtone with a fresh `mock<Ringtone>()` per construction so each
|
||||
// CallManager gets an isolated, type-safe ringtone we can assert on. The
|
||||
@@ -130,7 +129,7 @@ describe('start', () => {
|
||||
|
||||
expect(await new CallManager(api).start()).toBe(false);
|
||||
|
||||
expect(api.getViewManager().setViewByParameters).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewByParameters).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should do nothing when already active for the camera', async () => {
|
||||
@@ -141,7 +140,7 @@ describe('start', () => {
|
||||
vi.mocked(api.getViewManager().setViewByParameters).mockClear();
|
||||
expect(await manager.start()).toBe(true);
|
||||
|
||||
expect(api.getViewManager().setViewByParameters).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewByParameters).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should start a call on the selected camera', async () => {
|
||||
@@ -149,7 +148,7 @@ describe('start', () => {
|
||||
|
||||
expect(await new CallManager(api).start()).toBe(true);
|
||||
|
||||
expect(api.getViewManager().setViewByParameters).toBeCalledWith({
|
||||
expect(api.getViewManager().setViewByParameters).toHaveBeenCalledWith({
|
||||
modifiers: [expect.any(SubstreamViewModifier)],
|
||||
force: true,
|
||||
});
|
||||
@@ -162,7 +161,7 @@ describe('start', () => {
|
||||
|
||||
expect(await new CallManager(api).start()).toBe(true);
|
||||
|
||||
expect(api.getViewManager().setViewByParameters).toBeCalledWith({
|
||||
expect(api.getViewManager().setViewByParameters).toHaveBeenCalledWith({
|
||||
params: { view: 'live', camera: 'camera.office' },
|
||||
modifiers: [expect.any(SubstreamViewModifier)],
|
||||
force: true,
|
||||
@@ -176,11 +175,11 @@ describe('start', () => {
|
||||
|
||||
expect(await new CallManager(api).start()).toBe(true);
|
||||
|
||||
expect(api.getViewManager().setViewByParameters).toBeCalledWith({
|
||||
expect(api.getViewManager().setViewByParameters).toHaveBeenCalledWith({
|
||||
modifiers: [expect.any(SubstreamViewModifier)],
|
||||
force: true,
|
||||
});
|
||||
expect(api.getViewManager().setViewByParameters).not.toBeCalledWith(
|
||||
expect(api.getViewManager().setViewByParameters).not.toHaveBeenCalledWith(
|
||||
expect.objectContaining({ params: expect.anything() }),
|
||||
);
|
||||
});
|
||||
@@ -251,7 +250,7 @@ describe('start', () => {
|
||||
expect(call?.cameraID).toBe('camera.office');
|
||||
expect(call?.previousView?.view).toBe('folder');
|
||||
expect(call?.previousView?.camera).toBeNull();
|
||||
expect(api.getViewManager().setViewByParameters).toBeCalledWith({
|
||||
expect(api.getViewManager().setViewByParameters).toHaveBeenCalledWith({
|
||||
params: { view: 'live', camera: 'camera.office' },
|
||||
modifiers: [expect.any(SubstreamViewModifier)],
|
||||
force: true,
|
||||
@@ -280,7 +279,7 @@ describe('start', () => {
|
||||
expect(call?.cameraID).toBe('camera.garage');
|
||||
expect(call?.previousView?.view).toBe('live');
|
||||
expect(call?.previousView?.camera).toBe('camera.office');
|
||||
expect(api.getViewManager().setViewByParameters).toBeCalledWith({
|
||||
expect(api.getViewManager().setViewByParameters).toHaveBeenCalledWith({
|
||||
params: { view: 'live', camera: 'camera.garage' },
|
||||
modifiers: [expect.any(SubstreamViewModifier)],
|
||||
force: true,
|
||||
@@ -321,8 +320,8 @@ describe('start', () => {
|
||||
|
||||
expect(await new CallManager(api).start({ cameraID: 'camera.unknown' })).toBe(false);
|
||||
|
||||
expect(api.getViewManager().setViewByParameters).not.toBeCalled();
|
||||
expect(api.getNotificationManager().setNotification).toBeCalled();
|
||||
expect(api.getViewManager().setViewByParameters).not.toHaveBeenCalled();
|
||||
expect(api.getNotificationManager().setNotification).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should abort when the requested stream is not 2-way audio of the parent camera', async () => {
|
||||
@@ -347,8 +346,8 @@ describe('start', () => {
|
||||
}),
|
||||
).toBe(false);
|
||||
|
||||
expect(api.getViewManager().setViewByParameters).not.toBeCalled();
|
||||
expect(api.getNotificationManager().setNotification).toBeCalled();
|
||||
expect(api.getViewManager().setViewByParameters).not.toHaveBeenCalled();
|
||||
expect(api.getNotificationManager().setNotification).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should supersede an active call on a different camera', async () => {
|
||||
@@ -439,8 +438,8 @@ describe('start', () => {
|
||||
|
||||
expect(await new CallManager(api).start()).toBe(false);
|
||||
|
||||
expect(api.getViewManager().setViewByParameters).not.toBeCalled();
|
||||
expect(api.getNotificationManager().setNotification).toBeCalled();
|
||||
expect(api.getViewManager().setViewByParameters).not.toHaveBeenCalled();
|
||||
expect(api.getNotificationManager().setNotification).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should engage the active substream when it is call-capable', async () => {
|
||||
@@ -464,7 +463,7 @@ describe('start', () => {
|
||||
|
||||
expect(await manager.start()).toBe(true);
|
||||
|
||||
expect(api.getViewManager().setViewByParameters).toBeCalledWith({
|
||||
expect(api.getViewManager().setViewByParameters).toHaveBeenCalledWith({
|
||||
modifiers: [expect.any(SubstreamViewModifier)],
|
||||
force: true,
|
||||
});
|
||||
@@ -493,7 +492,7 @@ describe('start', () => {
|
||||
|
||||
expect(await new CallManager(api).start()).toBe(true);
|
||||
|
||||
expect(api.getViewManager().setViewByParameters).toBeCalledWith({
|
||||
expect(api.getViewManager().setViewByParameters).toHaveBeenCalledWith({
|
||||
modifiers: [expect.any(SubstreamViewModifier)],
|
||||
force: true,
|
||||
});
|
||||
@@ -507,8 +506,8 @@ describe('start', () => {
|
||||
|
||||
expect(await new CallManager(api).start()).toBe(false);
|
||||
|
||||
expect(api.getViewManager().setViewByParameters).not.toBeCalled();
|
||||
expect(api.getNotificationManager().setNotification).toBeCalled();
|
||||
expect(api.getViewManager().setViewByParameters).not.toHaveBeenCalled();
|
||||
expect(api.getNotificationManager().setNotification).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should abort when the microphone is forbidden', async () => {
|
||||
@@ -519,8 +518,8 @@ describe('start', () => {
|
||||
|
||||
expect(await new CallManager(api).start()).toBe(false);
|
||||
|
||||
expect(api.getViewManager().setViewByParameters).not.toBeCalled();
|
||||
expect(api.getNotificationManager().setNotification).toBeCalled();
|
||||
expect(api.getViewManager().setViewByParameters).not.toHaveBeenCalled();
|
||||
expect(api.getNotificationManager().setNotification).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should connect the microphone when not already connected', async () => {
|
||||
@@ -532,8 +531,8 @@ describe('start', () => {
|
||||
|
||||
expect(await new CallManager(api).start()).toBe(true);
|
||||
|
||||
expect(api.getMicrophoneManager().connect).toBeCalled();
|
||||
expect(api.getViewManager().setViewByParameters).toBeCalled();
|
||||
expect(api.getMicrophoneManager().connect).toHaveBeenCalled();
|
||||
expect(api.getViewManager().setViewByParameters).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should abort when connecting the microphone fails', async () => {
|
||||
@@ -545,8 +544,8 @@ describe('start', () => {
|
||||
|
||||
expect(await new CallManager(api).start()).toBe(false);
|
||||
|
||||
expect(api.getViewManager().setViewByParameters).not.toBeCalled();
|
||||
expect(api.getNotificationManager().setNotification).toBeCalled();
|
||||
expect(api.getViewManager().setViewByParameters).not.toHaveBeenCalled();
|
||||
expect(api.getNotificationManager().setNotification).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should ring an inbound call without connecting the microphone', async () => {
|
||||
@@ -562,8 +561,8 @@ describe('start', () => {
|
||||
// that would fail must not stop the call from ringing.
|
||||
expect(await manager.start({ inbound: true })).toBe(true);
|
||||
|
||||
expect(api.getMicrophoneManager().connect).not.toBeCalled();
|
||||
expect(getRingtone().start).toBeCalled();
|
||||
expect(api.getMicrophoneManager().connect).not.toHaveBeenCalled();
|
||||
expect(getRingtone().start).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should ring an inbound call when the microphone is forbidden', async () => {
|
||||
@@ -578,7 +577,7 @@ describe('start', () => {
|
||||
// microphone, and answering retries the connect.
|
||||
expect(await manager.start({ inbound: true })).toBe(true);
|
||||
|
||||
expect(getRingtone().start).toBeCalled();
|
||||
expect(getRingtone().start).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should abort an inbound call when the microphone is unsupported', async () => {
|
||||
@@ -593,7 +592,7 @@ describe('start', () => {
|
||||
// supporting it while the page is loaded, so the call can never be taken.
|
||||
expect(await manager.start({ inbound: true })).toBe(false);
|
||||
|
||||
expect(getRingtone().start).not.toBeCalled();
|
||||
expect(getRingtone().start).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -692,7 +691,7 @@ describe('end', () => {
|
||||
|
||||
expect(new CallManager(api).end()).toBe(false);
|
||||
|
||||
expect(api.getViewManager().setViewByParameters).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewByParameters).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should end an active call', async () => {
|
||||
@@ -704,7 +703,7 @@ describe('end', () => {
|
||||
expect(manager.end()).toBe(true);
|
||||
|
||||
expect(manager.isActive()).toBe(false);
|
||||
expect(api.getViewManager().setViewByParameters).toBeCalledWith({
|
||||
expect(api.getViewManager().setViewByParameters).toHaveBeenCalledWith({
|
||||
modifiers: [expect.any(SubstreamViewModifier)],
|
||||
force: true,
|
||||
});
|
||||
@@ -734,7 +733,7 @@ describe('end', () => {
|
||||
expect(manager.end()).toBe(true);
|
||||
|
||||
// The recorded pre-call substream (`camera.sub`) is reinstated.
|
||||
expect(api.getViewManager().setViewByParameters).toBeCalledWith({
|
||||
expect(api.getViewManager().setViewByParameters).toHaveBeenCalledWith({
|
||||
modifiers: [expect.any(SubstreamViewModifier)],
|
||||
force: true,
|
||||
});
|
||||
@@ -749,7 +748,9 @@ describe('end', () => {
|
||||
|
||||
expect(manager.end()).toBe(true);
|
||||
|
||||
expect(api.getViewManager().setViewByParametersWithExistingQuery).toBeCalledWith({
|
||||
expect(
|
||||
api.getViewManager().setViewByParametersWithExistingQuery,
|
||||
).toHaveBeenCalledWith({
|
||||
baseView: expect.any(View),
|
||||
force: true,
|
||||
});
|
||||
@@ -770,11 +771,13 @@ describe('end', () => {
|
||||
expect(manager.end()).toBe(true);
|
||||
|
||||
// No navigation: only the substream is undone.
|
||||
expect(api.getViewManager().setViewByParameters).toBeCalledWith({
|
||||
expect(api.getViewManager().setViewByParameters).toHaveBeenCalledWith({
|
||||
modifiers: [expect.any(SubstreamViewModifier)],
|
||||
force: true,
|
||||
});
|
||||
expect(api.getViewManager().setViewByParametersWithExistingQuery).not.toBeCalled();
|
||||
expect(
|
||||
api.getViewManager().setViewByParametersWithExistingQuery,
|
||||
).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should return to a camera-less pre-call view on an explicit end', async () => {
|
||||
@@ -957,7 +960,7 @@ describe('condition state changes', () => {
|
||||
});
|
||||
|
||||
expect(manager.isActive()).toBe(false);
|
||||
expect(api.getViewManager().setViewByParameters).toBeCalledWith({
|
||||
expect(api.getViewManager().setViewByParameters).toHaveBeenCalledWith({
|
||||
modifiers: [expect.any(SubstreamViewModifier)],
|
||||
force: true,
|
||||
});
|
||||
@@ -979,7 +982,9 @@ describe('condition state changes', () => {
|
||||
});
|
||||
|
||||
expect(manager.isActive()).toBe(false);
|
||||
expect(api.getViewManager().setViewByParametersWithExistingQuery).not.toBeCalled();
|
||||
expect(
|
||||
api.getViewManager().setViewByParametersWithExistingQuery,
|
||||
).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should end the call when the view leaves live', async () => {
|
||||
@@ -996,7 +1001,7 @@ describe('condition state changes', () => {
|
||||
});
|
||||
|
||||
expect(manager.isActive()).toBe(false);
|
||||
expect(api.getViewManager().setViewByParameters).toBeCalledWith({
|
||||
expect(api.getViewManager().setViewByParameters).toHaveBeenCalledWith({
|
||||
modifiers: [expect.any(SubstreamViewModifier)],
|
||||
force: true,
|
||||
});
|
||||
@@ -1027,7 +1032,7 @@ describe('condition state changes', () => {
|
||||
new: { camera: 'camera.other' },
|
||||
});
|
||||
|
||||
expect(api.getViewManager().setViewByParameters).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewByParameters).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should end the call when the substream changes away', async () => {
|
||||
@@ -1103,7 +1108,7 @@ describe('initialize / uninitialize', () => {
|
||||
const api = createAPI();
|
||||
new CallManager(api);
|
||||
|
||||
expect(api.getConditionStateManager().addListener).not.toBeCalled();
|
||||
expect(api.getConditionStateManager().addListener).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should register the condition state listener on initialize', () => {
|
||||
@@ -1112,7 +1117,7 @@ describe('initialize / uninitialize', () => {
|
||||
|
||||
manager.initialize();
|
||||
|
||||
expect(api.getConditionStateManager().addListener).toBeCalled();
|
||||
expect(api.getConditionStateManager().addListener).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should remove the condition state listener on uninitialize', () => {
|
||||
@@ -1123,7 +1128,7 @@ describe('initialize / uninitialize', () => {
|
||||
|
||||
manager.uninitialize();
|
||||
|
||||
expect(api.getConditionStateManager().removeListener).toBeCalledWith(listener);
|
||||
expect(api.getConditionStateManager().removeListener).toHaveBeenCalledWith(listener);
|
||||
});
|
||||
|
||||
it('should tear down any active call session on uninitialize', async () => {
|
||||
@@ -1156,7 +1161,7 @@ describe('initialize / uninitialize', () => {
|
||||
new: { camera: 'camera.other', view: 'live' },
|
||||
});
|
||||
|
||||
expect(api.getViewManager().setViewByParameters).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewByParameters).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1179,7 +1184,7 @@ describe('inbound option', () => {
|
||||
|
||||
expect(await new CallManager(api).start({ inbound: true })).toBe(false);
|
||||
|
||||
expect(api.getNotificationManager().setNotification).not.toBeCalled();
|
||||
expect(api.getNotificationManager().setNotification).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should suppress notification when the microphone is unsupported', async () => {
|
||||
@@ -1190,7 +1195,7 @@ describe('inbound option', () => {
|
||||
|
||||
expect(await new CallManager(api).start({ inbound: true })).toBe(false);
|
||||
|
||||
expect(api.getNotificationManager().setNotification).not.toBeCalled();
|
||||
expect(api.getNotificationManager().setNotification).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should suppress notification when an explicit stream is not 2-way audio', async () => {
|
||||
@@ -1203,7 +1208,7 @@ describe('inbound option', () => {
|
||||
}),
|
||||
).toBe(false);
|
||||
|
||||
expect(api.getNotificationManager().setNotification).not.toBeCalled();
|
||||
expect(api.getNotificationManager().setNotification).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should suppress notification when no stream supports 2-way audio', async () => {
|
||||
@@ -1219,7 +1224,7 @@ describe('inbound option', () => {
|
||||
|
||||
expect(await new CallManager(api).start({ inbound: true })).toBe(false);
|
||||
|
||||
expect(api.getNotificationManager().setNotification).not.toBeCalled();
|
||||
expect(api.getNotificationManager().setNotification).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should record the call as inbound on the session', async () => {
|
||||
@@ -1274,7 +1279,7 @@ describe('answer', () => {
|
||||
expect(await manager.start({ inbound: true })).toBe(true);
|
||||
|
||||
expect(manager.getCall()?.answered).toBe(false);
|
||||
expect(getRingtone().start).toBeCalled();
|
||||
expect(getRingtone().start).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should no-op when no call is active', async () => {
|
||||
@@ -1298,8 +1303,8 @@ describe('answer', () => {
|
||||
|
||||
expect(await manager.answer()).toBe(false);
|
||||
|
||||
expect(getRingtone().stop).not.toBeCalled();
|
||||
expect(api.getCardElementManager().update).not.toBeCalled();
|
||||
expect(getRingtone().stop).not.toHaveBeenCalled();
|
||||
expect(api.getCardElementManager().update).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should mark answered and replace the session immutably', async () => {
|
||||
@@ -1345,7 +1350,7 @@ describe('answer', () => {
|
||||
|
||||
expect(await manager.answer()).toBe(true);
|
||||
|
||||
expect(getRingtone().stop).toBeCalled();
|
||||
expect(getRingtone().stop).toHaveBeenCalled();
|
||||
|
||||
// Timer was armed and should now be cancelled: advancing past the
|
||||
// timeout must not end the (now-answered) call.
|
||||
@@ -1369,7 +1374,7 @@ describe('answer', () => {
|
||||
|
||||
expect(await manager.answer()).toBe(true);
|
||||
|
||||
expect(api.getMicrophoneManager().connect).toBeCalled();
|
||||
expect(api.getMicrophoneManager().connect).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should silence the ringtone before the microphone connect', async () => {
|
||||
@@ -1393,7 +1398,7 @@ describe('answer', () => {
|
||||
|
||||
// The user has acknowledged the ring, so it must stop without waiting for a
|
||||
// microphone permission prompt to be dealt with.
|
||||
expect(getRingtone().stop).toBeCalled();
|
||||
expect(getRingtone().stop).toHaveBeenCalled();
|
||||
|
||||
resolveConnect();
|
||||
expect(await answerPromise).toBe(true);
|
||||
@@ -1414,7 +1419,7 @@ describe('answer', () => {
|
||||
|
||||
// Answering is an explicit user gesture, so the failure is surfaced and the
|
||||
// call remains answerable.
|
||||
expect(api.getNotificationManager().setNotification).toBeCalled();
|
||||
expect(api.getNotificationManager().setNotification).toHaveBeenCalled();
|
||||
expect(manager.getCall()?.answered).toBe(false);
|
||||
});
|
||||
|
||||
@@ -1433,7 +1438,7 @@ describe('answer', () => {
|
||||
// The card subtree depends on `getCall().answered`, which the manager
|
||||
// mutates outside the view-manager epoch -- so `update()` is what drives
|
||||
// the re-render through to the call-controls overlay.
|
||||
expect(api.getCardElementManager().update).toBeCalled();
|
||||
expect(api.getCardElementManager().update).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not mark non-inbound (outbound) calls via answer (already answered)', async () => {
|
||||
@@ -1483,12 +1488,12 @@ describe('microphone usage', () => {
|
||||
|
||||
expect(await manager.start()).toBe(true);
|
||||
|
||||
expect(api.getMicrophoneManager().startUsing).toBeCalledTimes(1);
|
||||
expect(api.getMicrophoneManager().stopUsing).not.toBeCalled();
|
||||
expect(api.getMicrophoneManager().startUsing).toHaveBeenCalledTimes(1);
|
||||
expect(api.getMicrophoneManager().stopUsing).not.toHaveBeenCalled();
|
||||
|
||||
manager.end();
|
||||
|
||||
expect(api.getMicrophoneManager().stopUsing).toBeCalledTimes(1);
|
||||
expect(api.getMicrophoneManager().stopUsing).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should not mark the microphone in use when the start is aborted', async () => {
|
||||
@@ -1500,7 +1505,7 @@ describe('microphone usage', () => {
|
||||
|
||||
expect(await new CallManager(api).start()).toBe(false);
|
||||
|
||||
expect(api.getMicrophoneManager().startUsing).not.toBeCalled();
|
||||
expect(api.getMicrophoneManager().startUsing).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should keep the microphone in use when a call supersedes another', async () => {
|
||||
@@ -1522,8 +1527,8 @@ describe('microphone usage', () => {
|
||||
expect(await manager.start()).toBe(true);
|
||||
expect(await manager.start({ cameraID: 'camera.garage' })).toBe(true);
|
||||
|
||||
expect(api.getMicrophoneManager().startUsing).toBeCalledTimes(2);
|
||||
expect(api.getMicrophoneManager().stopUsing).toBeCalledTimes(1);
|
||||
expect(api.getMicrophoneManager().startUsing).toHaveBeenCalledTimes(2);
|
||||
expect(api.getMicrophoneManager().stopUsing).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should mark the microphone unused on uninitialization', async () => {
|
||||
@@ -1533,7 +1538,7 @@ describe('microphone usage', () => {
|
||||
expect(await manager.start()).toBe(true);
|
||||
manager.uninitialize();
|
||||
|
||||
expect(api.getMicrophoneManager().stopUsing).toBeCalledTimes(1);
|
||||
expect(api.getMicrophoneManager().stopUsing).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should not mark the microphone unused when uninitializing without a call', () => {
|
||||
@@ -1541,7 +1546,7 @@ describe('microphone usage', () => {
|
||||
|
||||
new CallManager(api).uninitialize();
|
||||
|
||||
expect(api.getMicrophoneManager().stopUsing).not.toBeCalled();
|
||||
expect(api.getMicrophoneManager().stopUsing).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1559,7 +1564,7 @@ describe('ringtone', () => {
|
||||
|
||||
expect(await manager.start({ inbound: true })).toBe(true);
|
||||
|
||||
expect(getRingtone().start).toBeCalledWith(expect.objectContaining(ringtone));
|
||||
expect(getRingtone().start).toHaveBeenCalledWith(expect.objectContaining(ringtone));
|
||||
});
|
||||
|
||||
it('should not start the ringtone for a non-inbound call', async () => {
|
||||
@@ -1572,7 +1577,7 @@ describe('ringtone', () => {
|
||||
|
||||
expect(await manager.start()).toBe(true);
|
||||
|
||||
expect(getRingtone().start).not.toBeCalled();
|
||||
expect(getRingtone().start).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should not start the ringtone when type is 'none'", async () => {
|
||||
@@ -1585,7 +1590,7 @@ describe('ringtone', () => {
|
||||
|
||||
expect(await manager.start({ inbound: true })).toBe(true);
|
||||
|
||||
expect(getRingtone().start).not.toBeCalled();
|
||||
expect(getRingtone().start).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should stop the ringtone when the call ends', async () => {
|
||||
@@ -1600,7 +1605,7 @@ describe('ringtone', () => {
|
||||
|
||||
expect(manager.end()).toBe(true);
|
||||
|
||||
expect(getRingtone().stop).toBeCalled();
|
||||
expect(getRingtone().stop).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should stop the ringtone on uninitialize', async () => {
|
||||
@@ -1615,7 +1620,7 @@ describe('ringtone', () => {
|
||||
|
||||
manager.uninitialize();
|
||||
|
||||
expect(getRingtone().stop).toBeCalled();
|
||||
expect(getRingtone().stop).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1764,7 +1769,7 @@ describe('session end during setState', () => {
|
||||
|
||||
expect(await manager.start({ inbound: true })).toBe(false);
|
||||
|
||||
expect(getRingtone().start).not.toBeCalled();
|
||||
expect(getRingtone().start).not.toHaveBeenCalled();
|
||||
expect(manager.isActive()).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -1790,7 +1795,7 @@ describe('state changes during in-flight start', () => {
|
||||
|
||||
expect(await startPromise).toBe(false);
|
||||
expect(manager.isActive()).toBe(false);
|
||||
expect(api.getViewManager().setViewByParameters).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewByParameters).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not install a session when uninitialized and re-initialized mid-await', async () => {
|
||||
@@ -1814,7 +1819,7 @@ describe('state changes during in-flight start', () => {
|
||||
|
||||
expect(await startPromise).toBe(false);
|
||||
expect(manager.isActive()).toBe(false);
|
||||
expect(api.getViewManager().setViewByParameters).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewByParameters).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should supersede a session installed by another start mid-await', async () => {
|
||||
@@ -1853,8 +1858,8 @@ describe('state changes during in-flight start', () => {
|
||||
// overwrite it, leaving exactly one live session and no stranded microphone
|
||||
// marking.
|
||||
expect(manager.getCall()?.cameraID).toBe('camera.garage');
|
||||
expect(api.getMicrophoneManager().startUsing).toBeCalledTimes(2);
|
||||
expect(api.getMicrophoneManager().stopUsing).toBeCalledTimes(1);
|
||||
expect(api.getMicrophoneManager().startUsing).toHaveBeenCalledTimes(2);
|
||||
expect(api.getMicrophoneManager().stopUsing).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should suppress the microphone-failure notification when uninitialized mid-await', async () => {
|
||||
@@ -1876,7 +1881,7 @@ describe('state changes during in-flight start', () => {
|
||||
rejectConnect(new Error('denied'));
|
||||
|
||||
expect(await startPromise).toBe(false);
|
||||
expect(api.getNotificationManager().setNotification).not.toBeCalled();
|
||||
expect(api.getNotificationManager().setNotification).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1939,7 +1944,7 @@ describe('state changes during in-flight answer', () => {
|
||||
rejectConnect(new Error('denied'));
|
||||
|
||||
expect(await answerPromise).toBe(false);
|
||||
expect(api.getNotificationManager().setNotification).not.toBeCalled();
|
||||
expect(api.getNotificationManager().setNotification).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not answer a session that ended mid-await', async () => {
|
||||
|
||||
@@ -59,25 +59,25 @@ describe('factory dispatch', () => {
|
||||
it('should construct a ChimeTone for type "chime"', () => {
|
||||
new Ringtone(new Set()).start({ type: 'chime', repeat: 3 });
|
||||
|
||||
expect(ChimeTone).toBeCalledWith(3);
|
||||
expect(ChimeTone).toHaveBeenCalledWith(3);
|
||||
});
|
||||
|
||||
it('should construct a WestminsterTone for type "westminster"', () => {
|
||||
new Ringtone(new Set()).start({ type: 'westminster', repeat: 2 });
|
||||
|
||||
expect(WestminsterTone).toBeCalledWith(2);
|
||||
expect(WestminsterTone).toHaveBeenCalledWith(2);
|
||||
});
|
||||
|
||||
it('should construct an ArpeggioTone for type "arpeggio"', () => {
|
||||
new Ringtone(new Set()).start({ type: 'arpeggio', repeat: 1 });
|
||||
|
||||
expect(ArpeggioTone).toBeCalledWith(1);
|
||||
expect(ArpeggioTone).toHaveBeenCalledWith(1);
|
||||
});
|
||||
|
||||
it('should construct a MelodyTone for type "melody"', () => {
|
||||
new Ringtone(new Set()).start({ type: 'melody', repeat: 5 });
|
||||
|
||||
expect(MelodyTone).toBeCalledWith(5);
|
||||
expect(MelodyTone).toHaveBeenCalledWith(5);
|
||||
});
|
||||
|
||||
it('should construct a CustomTone for type "custom" with a URL', () => {
|
||||
@@ -87,7 +87,7 @@ describe('factory dispatch', () => {
|
||||
repeat: 0,
|
||||
});
|
||||
|
||||
expect(CustomTone).toBeCalledWith('http://localhost/ring.mp3', 0);
|
||||
expect(CustomTone).toHaveBeenCalledWith('http://localhost/ring.mp3', 0);
|
||||
});
|
||||
|
||||
it('should construct no tone for type "custom" without a URL', () => {
|
||||
@@ -95,7 +95,7 @@ describe('factory dispatch', () => {
|
||||
|
||||
ringtone.start({ type: 'custom', repeat: 0 });
|
||||
|
||||
expect(CustomTone).not.toBeCalled();
|
||||
expect(CustomTone).not.toHaveBeenCalled();
|
||||
expect(ringtone.isPlaying()).toBe(false);
|
||||
});
|
||||
|
||||
@@ -104,7 +104,7 @@ describe('factory dispatch', () => {
|
||||
|
||||
ringtone.start({ type: 'none', repeat: 0 });
|
||||
|
||||
expect(ChimeTone).not.toBeCalled();
|
||||
expect(ChimeTone).not.toHaveBeenCalled();
|
||||
expect(ringtone.isPlaying()).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -115,7 +115,7 @@ describe('start', () => {
|
||||
|
||||
ringtone.start(chimeConfig);
|
||||
|
||||
expect(lastInstance(vi.mocked(ChimeTone)).start).toBeCalled();
|
||||
expect(lastInstance(vi.mocked(ChimeTone)).start).toHaveBeenCalled();
|
||||
expect(ringtone.isPlaying()).toBe(true);
|
||||
});
|
||||
|
||||
@@ -125,8 +125,8 @@ describe('start', () => {
|
||||
ringtone.start(chimeConfig);
|
||||
ringtone.start(chimeConfig);
|
||||
|
||||
expect(ChimeTone).toBeCalledTimes(1);
|
||||
expect(lastInstance(vi.mocked(ChimeTone)).start).toBeCalledTimes(1);
|
||||
expect(ChimeTone).toHaveBeenCalledTimes(1);
|
||||
expect(lastInstance(vi.mocked(ChimeTone)).start).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should claim the lock when a tone starts', () => {
|
||||
@@ -158,7 +158,7 @@ describe('lock', () => {
|
||||
vi.mocked(ChimeTone).mockClear();
|
||||
second.start(chimeConfig);
|
||||
|
||||
expect(ChimeTone).not.toBeCalled();
|
||||
expect(ChimeTone).not.toHaveBeenCalled();
|
||||
expect(second.isPlaying()).toBe(false);
|
||||
expect(first.isPlaying()).toBe(true);
|
||||
});
|
||||
@@ -171,11 +171,11 @@ describe('lock', () => {
|
||||
first.start(chimeConfig);
|
||||
const firstTone = lastInstance(vi.mocked(ChimeTone));
|
||||
first.stop();
|
||||
expect(firstTone.stop).toBeCalled();
|
||||
expect(firstTone.stop).toHaveBeenCalled();
|
||||
|
||||
second.start(chimeConfig);
|
||||
|
||||
expect(lastInstance(vi.mocked(ChimeTone)).start).toBeCalled();
|
||||
expect(lastInstance(vi.mocked(ChimeTone)).start).toHaveBeenCalled();
|
||||
expect(second.isPlaying()).toBe(true);
|
||||
});
|
||||
|
||||
@@ -227,7 +227,7 @@ describe('stop', () => {
|
||||
ringtone.start(chimeConfig);
|
||||
ringtone.stop();
|
||||
|
||||
expect(lastInstance(vi.mocked(ChimeTone)).stop).toBeCalled();
|
||||
expect(lastInstance(vi.mocked(ChimeTone)).stop).toHaveBeenCalled();
|
||||
expect(lock.has(ringtone)).toBe(false);
|
||||
expect(ringtone.isPlaying()).toBe(false);
|
||||
});
|
||||
@@ -250,7 +250,7 @@ describe('default lock', () => {
|
||||
vi.mocked(ChimeTone).mockClear();
|
||||
second.start(chimeConfig);
|
||||
|
||||
expect(ChimeTone).not.toBeCalled();
|
||||
expect(ChimeTone).not.toHaveBeenCalled();
|
||||
first.stop();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -19,15 +19,15 @@ describe('ArpeggioTone', () => {
|
||||
|
||||
// G5 (783.99) at t=0.
|
||||
expect(audio.oscillators[1].frequency.value).toBe(783.99);
|
||||
expect(audio.oscillators[1].start).toBeCalledWith(0);
|
||||
expect(audio.oscillators[1].start).toHaveBeenCalledWith(0);
|
||||
|
||||
// E5 (659.25) at t=0.25.
|
||||
expect(audio.oscillators[4].frequency.value).toBe(659.25);
|
||||
expect(audio.oscillators[4].start).toBeCalledWith(0.25);
|
||||
expect(audio.oscillators[4].start).toHaveBeenCalledWith(0.25);
|
||||
|
||||
// C5 (523.25) at t=0.5.
|
||||
expect(audio.oscillators[7].frequency.value).toBe(523.25);
|
||||
expect(audio.oscillators[7].start).toBeCalledWith(0.5);
|
||||
expect(audio.oscillators[7].start).toHaveBeenCalledWith(0.5);
|
||||
});
|
||||
|
||||
it('should use the lighter PLUCK envelope for every strike', () => {
|
||||
@@ -36,15 +36,15 @@ describe('ArpeggioTone', () => {
|
||||
// Sparkle / fundamental / hum peaks for every strike.
|
||||
for (let strike = 0; strike < 3; strike++) {
|
||||
const i = strike * 3;
|
||||
expect(audio.gainParams[i].linearRampToValueAtTime).toBeCalledWith(
|
||||
expect(audio.gainParams[i].linearRampToValueAtTime).toHaveBeenCalledWith(
|
||||
0.05,
|
||||
expect.any(Number),
|
||||
);
|
||||
expect(audio.gainParams[i + 1].linearRampToValueAtTime).toBeCalledWith(
|
||||
expect(audio.gainParams[i + 1].linearRampToValueAtTime).toHaveBeenCalledWith(
|
||||
0.13,
|
||||
expect.any(Number),
|
||||
);
|
||||
expect(audio.gainParams[i + 2].linearRampToValueAtTime).toBeCalledWith(
|
||||
expect(audio.gainParams[i + 2].linearRampToValueAtTime).toHaveBeenCalledWith(
|
||||
0.04,
|
||||
expect.any(Number),
|
||||
);
|
||||
|
||||
@@ -18,7 +18,7 @@ describe('start', () => {
|
||||
it('should construct an AudioContext and play one iteration', () => {
|
||||
new ChimeTone(0).start();
|
||||
|
||||
expect(audio.audioContextCtor).toBeCalledTimes(1);
|
||||
expect(audio.audioContextCtor).toHaveBeenCalledTimes(1);
|
||||
expect(audio.oscillators).toHaveLength(ITERATION_OSCILLATORS);
|
||||
});
|
||||
|
||||
@@ -28,7 +28,7 @@ describe('start', () => {
|
||||
tone.start();
|
||||
tone.start();
|
||||
|
||||
expect(audio.audioContextCtor).toBeCalledTimes(1);
|
||||
expect(audio.audioContextCtor).toHaveBeenCalledTimes(1);
|
||||
expect(audio.oscillators).toHaveLength(ITERATION_OSCILLATORS);
|
||||
});
|
||||
|
||||
@@ -40,7 +40,7 @@ describe('start', () => {
|
||||
|
||||
new ChimeTone(0).start(onFinished);
|
||||
|
||||
expect(onFinished).toBeCalled();
|
||||
expect(onFinished).toHaveBeenCalled();
|
||||
expect(audio.oscillators).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
@@ -52,7 +52,7 @@ describe('stop', () => {
|
||||
|
||||
tone.stop();
|
||||
|
||||
expect(audio.audioContext.close).toBeCalled();
|
||||
expect(audio.audioContext.close).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not fire finishedHandler on external stop', () => {
|
||||
@@ -62,7 +62,7 @@ describe('stop', () => {
|
||||
|
||||
tone.stop();
|
||||
|
||||
expect(onFinished).not.toBeCalled();
|
||||
expect(onFinished).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should swallow AudioContext.close rejections silently', () => {
|
||||
@@ -91,7 +91,7 @@ describe('repeat counter', () => {
|
||||
vi.advanceTimersByTime(ITERATION_INTERVAL_MS);
|
||||
expect(audio.oscillators).toHaveLength(ITERATION_OSCILLATORS * i);
|
||||
}
|
||||
expect(audio.audioContext.close).not.toBeCalled();
|
||||
expect(audio.audioContext.close).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should play exactly `repeat` iterations and then finish', () => {
|
||||
@@ -110,8 +110,8 @@ describe('repeat counter', () => {
|
||||
// decay tail, then fires the finished handler and stops.
|
||||
vi.advanceTimersByTime(ITERATION_INTERVAL_MS);
|
||||
expect(audio.oscillators).toHaveLength(ITERATION_OSCILLATORS * 3);
|
||||
expect(onFinished).toBeCalledTimes(1);
|
||||
expect(audio.audioContext.close).toBeCalled();
|
||||
expect(onFinished).toHaveBeenCalledTimes(1);
|
||||
expect(audio.audioContext.close).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not fire finishedHandler when stopped mid-sequence', () => {
|
||||
@@ -124,6 +124,6 @@ describe('repeat counter', () => {
|
||||
// Even if any stale scheduled work fires, finishedHandler stays silent.
|
||||
vi.advanceTimersByTime(ITERATION_INTERVAL_MS * 10);
|
||||
|
||||
expect(onFinished).not.toBeCalled();
|
||||
expect(onFinished).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -21,41 +21,53 @@ describe('ChimeTone', () => {
|
||||
expect(audio.oscillators[0].frequency.value).toBe(622.25 * 2);
|
||||
expect(audio.oscillators[1].frequency.value).toBe(622.25);
|
||||
expect(audio.oscillators[2].frequency.value).toBe(622.25 / 2);
|
||||
expect(audio.oscillators[0].start).toBeCalledWith(0);
|
||||
expect(audio.oscillators[1].start).toBeCalledWith(0);
|
||||
expect(audio.oscillators[2].start).toBeCalledWith(0);
|
||||
expect(audio.oscillators[0].start).toHaveBeenCalledWith(0);
|
||||
expect(audio.oscillators[1].start).toHaveBeenCalledWith(0);
|
||||
expect(audio.oscillators[2].start).toHaveBeenCalledWith(0);
|
||||
|
||||
// DOOOOONG -- B4 (493.88Hz) at t=0.5.
|
||||
expect(audio.oscillators[3].frequency.value).toBe(493.88 * 2);
|
||||
expect(audio.oscillators[4].frequency.value).toBe(493.88);
|
||||
expect(audio.oscillators[5].frequency.value).toBe(493.88 / 2);
|
||||
expect(audio.oscillators[3].start).toBeCalledWith(0.5);
|
||||
expect(audio.oscillators[4].start).toBeCalledWith(0.5);
|
||||
expect(audio.oscillators[5].start).toBeCalledWith(0.5);
|
||||
expect(audio.oscillators[3].start).toHaveBeenCalledWith(0.5);
|
||||
expect(audio.oscillators[4].start).toHaveBeenCalledWith(0.5);
|
||||
expect(audio.oscillators[5].start).toHaveBeenCalledWith(0.5);
|
||||
});
|
||||
|
||||
it('should give DING a brighter, shorter bell envelope', () => {
|
||||
new ChimeTone(0).start();
|
||||
|
||||
// Sparkle / fundamental / hum peaks for DING.
|
||||
expect(audio.gainParams[0].linearRampToValueAtTime).toBeCalledWith(0.1, 0.005);
|
||||
expect(audio.gainParams[1].linearRampToValueAtTime).toBeCalledWith(0.22, 0.005);
|
||||
expect(audio.gainParams[2].linearRampToValueAtTime).toBeCalledWith(0.08, 0.005);
|
||||
expect(audio.gainParams[0].linearRampToValueAtTime).toHaveBeenCalledWith(0.1, 0.005);
|
||||
expect(audio.gainParams[1].linearRampToValueAtTime).toHaveBeenCalledWith(
|
||||
0.22,
|
||||
0.005,
|
||||
);
|
||||
expect(audio.gainParams[2].linearRampToValueAtTime).toHaveBeenCalledWith(
|
||||
0.08,
|
||||
0.005,
|
||||
);
|
||||
// Decay constants (sparkle fades fastest, hum lingers).
|
||||
expect(audio.gainParams[0].setTargetAtTime).toBeCalledWith(0, 0.005, 0.3);
|
||||
expect(audio.gainParams[1].setTargetAtTime).toBeCalledWith(0, 0.005, 0.8);
|
||||
expect(audio.gainParams[2].setTargetAtTime).toBeCalledWith(0, 0.005, 1.2);
|
||||
expect(audio.gainParams[0].setTargetAtTime).toHaveBeenCalledWith(0, 0.005, 0.3);
|
||||
expect(audio.gainParams[1].setTargetAtTime).toHaveBeenCalledWith(0, 0.005, 0.8);
|
||||
expect(audio.gainParams[2].setTargetAtTime).toHaveBeenCalledWith(0, 0.005, 1.2);
|
||||
});
|
||||
|
||||
it('should give DOOOOONG a fuller, longer bell envelope', () => {
|
||||
new ChimeTone(0).start();
|
||||
|
||||
expect(audio.gainParams[3].linearRampToValueAtTime).toBeCalledWith(0.11, 0.505);
|
||||
expect(audio.gainParams[4].linearRampToValueAtTime).toBeCalledWith(0.28, 0.505);
|
||||
expect(audio.gainParams[5].linearRampToValueAtTime).toBeCalledWith(0.1, 0.505);
|
||||
expect(audio.gainParams[3].setTargetAtTime).toBeCalledWith(0, 0.505, 0.5);
|
||||
expect(audio.gainParams[4].setTargetAtTime).toBeCalledWith(0, 0.505, 1.3);
|
||||
expect(audio.gainParams[5].setTargetAtTime).toBeCalledWith(0, 0.505, 1.8);
|
||||
expect(audio.gainParams[3].linearRampToValueAtTime).toHaveBeenCalledWith(
|
||||
0.11,
|
||||
0.505,
|
||||
);
|
||||
expect(audio.gainParams[4].linearRampToValueAtTime).toHaveBeenCalledWith(
|
||||
0.28,
|
||||
0.505,
|
||||
);
|
||||
expect(audio.gainParams[5].linearRampToValueAtTime).toHaveBeenCalledWith(0.1, 0.505);
|
||||
expect(audio.gainParams[3].setTargetAtTime).toHaveBeenCalledWith(0, 0.505, 0.5);
|
||||
expect(audio.gainParams[4].setTargetAtTime).toHaveBeenCalledWith(0, 0.505, 1.3);
|
||||
expect(audio.gainParams[5].setTargetAtTime).toHaveBeenCalledWith(0, 0.505, 1.8);
|
||||
});
|
||||
|
||||
describe('with fake timers', () => {
|
||||
|
||||
@@ -59,14 +59,14 @@ describe('start', () => {
|
||||
it('should construct an Audio element with the configured URL', () => {
|
||||
new CustomTone('http://example/ring.mp3', 0).start();
|
||||
|
||||
expect(audio.ctor).toBeCalledWith('http://example/ring.mp3');
|
||||
expect(audio.ctor).toHaveBeenCalledWith('http://example/ring.mp3');
|
||||
});
|
||||
|
||||
it('should loop indefinitely when repeat is 0', () => {
|
||||
new CustomTone('http://example/ring.mp3', 0).start();
|
||||
|
||||
expect(audio.instances[0].loop).toBe(true);
|
||||
expect(audio.instances[0].play).toBeCalled();
|
||||
expect(audio.instances[0].play).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should re-play (not loop natively) when repeat is finite', () => {
|
||||
@@ -76,14 +76,14 @@ describe('start', () => {
|
||||
// Observable proof the 'ended' listener was registered: dispatching the
|
||||
// event triggers a second play().
|
||||
audio.instances[0].dispatchEvent(new Event('ended'));
|
||||
expect(audio.instances[0].play).toBeCalledTimes(2);
|
||||
expect(audio.instances[0].play).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('should reset currentTime before play', () => {
|
||||
new CustomTone('http://example/ring.mp3', 0).start();
|
||||
|
||||
expect(audio.instances[0].currentTime).toBe(0);
|
||||
expect(audio.instances[0].play).toBeCalled();
|
||||
expect(audio.instances[0].play).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should no-op when called twice without stop', () => {
|
||||
@@ -92,7 +92,7 @@ describe('start', () => {
|
||||
tone.start();
|
||||
tone.start();
|
||||
|
||||
expect(audio.ctor).toBeCalledTimes(1);
|
||||
expect(audio.ctor).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should fire finishedHandler when Audio construction throws', () => {
|
||||
@@ -103,7 +103,7 @@ describe('start', () => {
|
||||
|
||||
new CustomTone('http://example/ring.mp3', 0).start(onFinished);
|
||||
|
||||
expect(onFinished).toBeCalled();
|
||||
expect(onFinished).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should fire finishedHandler when play() rejects (e.g. autoplay block)', async () => {
|
||||
@@ -116,7 +116,7 @@ describe('start', () => {
|
||||
|
||||
await flushPromises();
|
||||
|
||||
expect(onFinished).toBeCalled();
|
||||
expect(onFinished).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -128,15 +128,15 @@ describe('repeat counter', () => {
|
||||
|
||||
// Iteration 1 already started by `start()`. Two more 'ended' events
|
||||
// should re-play, and the third 'ended' should finish.
|
||||
expect(audio.instances[0].play).toBeCalledTimes(1);
|
||||
expect(audio.instances[0].play).toHaveBeenCalledTimes(1);
|
||||
audio.instances[0].dispatchEvent(new Event('ended'));
|
||||
expect(audio.instances[0].play).toBeCalledTimes(2);
|
||||
expect(audio.instances[0].play).toHaveBeenCalledTimes(2);
|
||||
audio.instances[0].dispatchEvent(new Event('ended'));
|
||||
expect(audio.instances[0].play).toBeCalledTimes(3);
|
||||
expect(onFinished).not.toBeCalled();
|
||||
expect(audio.instances[0].play).toHaveBeenCalledTimes(3);
|
||||
expect(onFinished).not.toHaveBeenCalled();
|
||||
audio.instances[0].dispatchEvent(new Event('ended'));
|
||||
|
||||
expect(onFinished).toBeCalledTimes(1);
|
||||
expect(onFinished).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should ignore ended events after stop', () => {
|
||||
@@ -150,7 +150,7 @@ describe('repeat counter', () => {
|
||||
// no-op as far as the source is concerned.
|
||||
element.dispatchEvent(new Event('ended'));
|
||||
|
||||
expect(onFinished).not.toBeCalled();
|
||||
expect(onFinished).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -162,11 +162,11 @@ describe('stop', () => {
|
||||
|
||||
tone.stop();
|
||||
|
||||
expect(element.pause).toBeCalled();
|
||||
expect(element.pause).toHaveBeenCalled();
|
||||
// Confirm the 'ended' listener is gone: dispatching it must not re-play.
|
||||
vi.mocked(HTMLMediaElement.prototype.play).mockClear();
|
||||
element.dispatchEvent(new Event('ended'));
|
||||
expect(element.play).not.toBeCalled();
|
||||
expect(element.play).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not fire finishedHandler on external stop', () => {
|
||||
@@ -176,7 +176,7 @@ describe('stop', () => {
|
||||
|
||||
tone.stop();
|
||||
|
||||
expect(onFinished).not.toBeCalled();
|
||||
expect(onFinished).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should be safe to call before start', () => {
|
||||
|
||||
@@ -22,8 +22,8 @@ describe('MelodyTone', () => {
|
||||
expect(audio.oscillators[2].frequency.value).toBe(659.25);
|
||||
expect(audio.oscillators[3].frequency.value).toBe(783.99);
|
||||
expect(audio.oscillators[4].frequency.value).toBe(261.63);
|
||||
expect(audio.oscillators[0].start).toBeCalledWith(0);
|
||||
expect(audio.oscillators[4].start).toBeCalledWith(0);
|
||||
expect(audio.oscillators[0].start).toHaveBeenCalledWith(0);
|
||||
expect(audio.oscillators[4].start).toHaveBeenCalledWith(0);
|
||||
|
||||
// --- V chord (G major) at t=1: sparkle D6, G4 + B4 + D5, hum G3. ---
|
||||
expect(audio.oscillators[5].frequency.value).toBe(1174.66);
|
||||
@@ -31,8 +31,8 @@ describe('MelodyTone', () => {
|
||||
expect(audio.oscillators[7].frequency.value).toBe(493.88);
|
||||
expect(audio.oscillators[8].frequency.value).toBe(587.33);
|
||||
expect(audio.oscillators[9].frequency.value).toBe(196.0);
|
||||
expect(audio.oscillators[5].start).toBeCalledWith(1);
|
||||
expect(audio.oscillators[9].start).toBeCalledWith(1);
|
||||
expect(audio.oscillators[5].start).toHaveBeenCalledWith(1);
|
||||
expect(audio.oscillators[9].start).toHaveBeenCalledWith(1);
|
||||
|
||||
// --- I chord (resolution, an octave higher) at t=2. ---
|
||||
expect(audio.oscillators[10].frequency.value).toBe(2093.0);
|
||||
@@ -40,21 +40,21 @@ describe('MelodyTone', () => {
|
||||
expect(audio.oscillators[12].frequency.value).toBe(783.99);
|
||||
expect(audio.oscillators[13].frequency.value).toBe(1046.5);
|
||||
expect(audio.oscillators[14].frequency.value).toBe(329.63);
|
||||
expect(audio.oscillators[10].start).toBeCalledWith(2);
|
||||
expect(audio.oscillators[14].start).toBeCalledWith(2);
|
||||
expect(audio.oscillators[10].start).toHaveBeenCalledWith(2);
|
||||
expect(audio.oscillators[14].start).toHaveBeenCalledWith(2);
|
||||
});
|
||||
|
||||
it('should give the resolving chord a longer tail than the I and V chords', () => {
|
||||
new MelodyTone(0).start();
|
||||
|
||||
// I and V chords use default fundDecay=0.6, humDecay=1.1.
|
||||
expect(audio.gainParams[1].setTargetAtTime).toBeCalledWith(0, 0.005, 0.6);
|
||||
expect(audio.gainParams[4].setTargetAtTime).toBeCalledWith(0, 0.005, 1.1);
|
||||
expect(audio.gainParams[6].setTargetAtTime).toBeCalledWith(0, 1.005, 0.6);
|
||||
expect(audio.gainParams[9].setTargetAtTime).toBeCalledWith(0, 1.005, 1.1);
|
||||
expect(audio.gainParams[1].setTargetAtTime).toHaveBeenCalledWith(0, 0.005, 0.6);
|
||||
expect(audio.gainParams[4].setTargetAtTime).toHaveBeenCalledWith(0, 0.005, 1.1);
|
||||
expect(audio.gainParams[6].setTargetAtTime).toHaveBeenCalledWith(0, 1.005, 0.6);
|
||||
expect(audio.gainParams[9].setTargetAtTime).toHaveBeenCalledWith(0, 1.005, 1.1);
|
||||
|
||||
// Final I chord overrides to fundDecay=0.9, humDecay=1.4.
|
||||
expect(audio.gainParams[11].setTargetAtTime).toBeCalledWith(0, 2.005, 0.9);
|
||||
expect(audio.gainParams[14].setTargetAtTime).toBeCalledWith(0, 2.005, 1.4);
|
||||
expect(audio.gainParams[11].setTargetAtTime).toHaveBeenCalledWith(0, 2.005, 0.9);
|
||||
expect(audio.gainParams[14].setTargetAtTime).toHaveBeenCalledWith(0, 2.005, 1.4);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -19,30 +19,38 @@ describe('WestminsterTone', () => {
|
||||
|
||||
// E5 (659.25) at t=0.
|
||||
expect(audio.oscillators[1].frequency.value).toBe(659.25);
|
||||
expect(audio.oscillators[1].start).toBeCalledWith(0);
|
||||
expect(audio.oscillators[1].start).toHaveBeenCalledWith(0);
|
||||
|
||||
// D5 (587.33) at t=0.55.
|
||||
expect(audio.oscillators[4].frequency.value).toBe(587.33);
|
||||
expect(audio.oscillators[4].start).toBeCalledWith(0.55);
|
||||
expect(audio.oscillators[4].start).toHaveBeenCalledWith(0.55);
|
||||
|
||||
// C5 (523.25) at t=1.1.
|
||||
expect(audio.oscillators[7].frequency.value).toBe(523.25);
|
||||
expect(audio.oscillators[7].start).toBeCalledWith(1.1);
|
||||
expect(audio.oscillators[7].start).toHaveBeenCalledWith(1.1);
|
||||
|
||||
// G4 (392.0) at t=1.65 -- the resolution.
|
||||
expect(audio.oscillators[10].frequency.value).toBe(392.0);
|
||||
expect(audio.oscillators[10].start).toBeCalledWith(1.65);
|
||||
expect(audio.oscillators[10].start).toHaveBeenCalledWith(1.65);
|
||||
});
|
||||
|
||||
it('should give the resolving G4 a longer bell tail than the other strikes', () => {
|
||||
new WestminsterTone(0).start();
|
||||
|
||||
// First three strikes use default decay (fundDecay=0.6, humDecay=1.0).
|
||||
expect(audio.gainParams[1].setTargetAtTime).toBeCalledWith(0, 0.005, 0.6);
|
||||
expect(audio.gainParams[2].setTargetAtTime).toBeCalledWith(0, 0.005, 1.0);
|
||||
expect(audio.gainParams[1].setTargetAtTime).toHaveBeenCalledWith(0, 0.005, 0.6);
|
||||
expect(audio.gainParams[2].setTargetAtTime).toHaveBeenCalledWith(0, 0.005, 1.0);
|
||||
|
||||
// G4 (final strike) overrides to fundDecay=0.9, humDecay=1.4.
|
||||
expect(audio.gainParams[10].setTargetAtTime).toBeCalledWith(0, 1.65 + 0.005, 0.9);
|
||||
expect(audio.gainParams[11].setTargetAtTime).toBeCalledWith(0, 1.65 + 0.005, 1.4);
|
||||
expect(audio.gainParams[10].setTargetAtTime).toHaveBeenCalledWith(
|
||||
0,
|
||||
1.65 + 0.005,
|
||||
0.9,
|
||||
);
|
||||
expect(audio.gainParams[11].setTargetAtTime).toHaveBeenCalledWith(
|
||||
0,
|
||||
1.65 + 0.005,
|
||||
1.4,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,17 +7,18 @@ import type { CardController } from '../../src/card-controller/controller';
|
||||
import type { AdvancedCameraCardView } from '../../src/config/schema/common/const';
|
||||
import { triggersSchema, type TriggersOptions } from '../../src/config/schema/view';
|
||||
import {
|
||||
createCameraConfig,
|
||||
createCameraManager,
|
||||
createCapabilities,
|
||||
createStore,
|
||||
} from '../camera-manager/test-utils';
|
||||
import { createCameraConfig, createConfig } from '../config/test-utils';
|
||||
import {
|
||||
createCardAPI,
|
||||
createConfig,
|
||||
createHASS,
|
||||
createStateEntity,
|
||||
createStore,
|
||||
createView,
|
||||
flushPromises,
|
||||
} from '../test-utils';
|
||||
import { createView } from '../view/test-utils';
|
||||
|
||||
vi.mock('lodash-es', async () => ({
|
||||
...(await vi.importActual('lodash-es')),
|
||||
@@ -117,7 +118,7 @@ describe('CameraTriggersManager', () => {
|
||||
});
|
||||
|
||||
expect(manager.isTriggered()).toBeTruthy();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not trigger if there is no config', async () => {
|
||||
@@ -156,7 +157,7 @@ describe('CameraTriggersManager', () => {
|
||||
});
|
||||
|
||||
expect(manager.isTriggered()).toBeTruthy();
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).toBeCalledWith({
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).toHaveBeenCalledWith({
|
||||
queryExecutorOptions: { useCache: false },
|
||||
});
|
||||
});
|
||||
@@ -181,7 +182,7 @@ describe('CameraTriggersManager', () => {
|
||||
});
|
||||
|
||||
expect(manager.isTriggered()).toBeTruthy();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).toBeCalledWith({
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).toHaveBeenCalledWith({
|
||||
params: {
|
||||
camera: 'camera_1',
|
||||
},
|
||||
@@ -208,7 +209,7 @@ describe('CameraTriggersManager', () => {
|
||||
});
|
||||
|
||||
expect(manager.isTriggered()).toBeTruthy();
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).toBeCalledWith({
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).toHaveBeenCalledWith({
|
||||
params: {
|
||||
view: 'live',
|
||||
camera: 'camera_1',
|
||||
@@ -257,10 +258,12 @@ describe('CameraTriggersManager', () => {
|
||||
if (!viewName) {
|
||||
expect(
|
||||
api.getViewManager().setViewByParametersWithNewQuery,
|
||||
).not.toBeCalled();
|
||||
).not.toHaveBeenCalled();
|
||||
} else {
|
||||
expect(manager.isTriggered()).toBeTruthy();
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).toBeCalledWith({
|
||||
expect(
|
||||
api.getViewManager().setViewByParametersWithNewQuery,
|
||||
).toHaveBeenCalledWith({
|
||||
params: {
|
||||
camera: 'camera_1',
|
||||
view: viewName,
|
||||
@@ -291,8 +294,10 @@ describe('CameraTriggersManager', () => {
|
||||
});
|
||||
|
||||
expect(manager.isTriggered()).toBeTruthy();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).not.toHaveBeenCalled();
|
||||
expect(
|
||||
api.getViewManager().setViewByParametersWithNewQuery,
|
||||
).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should handle trigger action set to call', async () => {
|
||||
@@ -313,11 +318,13 @@ describe('CameraTriggersManager', () => {
|
||||
expect(manager.isTriggered()).toBeTruthy();
|
||||
// `start()` is called with the triggered camera and the inbound flag --
|
||||
// view navigation is delegated to CallManager itself.
|
||||
expect(api.getCallManager().start).toBeCalledWith({
|
||||
expect(api.getCallManager().start).toHaveBeenCalledWith({
|
||||
cameraID: 'camera_1',
|
||||
inbound: true,
|
||||
});
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).not.toBeCalled();
|
||||
expect(
|
||||
api.getViewManager().setViewByParametersWithNewQuery,
|
||||
).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should start a call on a high-fidelity event with no media', async () => {
|
||||
@@ -338,7 +345,7 @@ describe('CameraTriggersManager', () => {
|
||||
fidelity: 'high',
|
||||
});
|
||||
|
||||
expect(api.getCallManager().start).toBeCalledWith({
|
||||
expect(api.getCallManager().start).toHaveBeenCalledWith({
|
||||
cameraID: 'camera_1',
|
||||
inbound: true,
|
||||
});
|
||||
@@ -376,8 +383,10 @@ describe('CameraTriggersManager', () => {
|
||||
|
||||
expect(manager.isTriggered()).toBeFalsy();
|
||||
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).not.toHaveBeenCalled();
|
||||
expect(
|
||||
api.getViewManager().setViewByParametersWithNewQuery,
|
||||
).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should handle untrigger action set to default', async () => {
|
||||
@@ -410,7 +419,7 @@ describe('CameraTriggersManager', () => {
|
||||
|
||||
expect(manager.isTriggered()).toBeFalsy();
|
||||
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).toBeCalled();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should handle untrigger action set to call', async () => {
|
||||
@@ -437,12 +446,12 @@ describe('CameraTriggersManager', () => {
|
||||
await flushPromises();
|
||||
|
||||
expect(manager.isTriggered()).toBeFalsy();
|
||||
expect(api.getCallManager().endIf).toBeCalledWith({
|
||||
expect(api.getCallManager().endIf).toHaveBeenCalledWith({
|
||||
cameraID: 'camera_1',
|
||||
inbound: true,
|
||||
answered: false,
|
||||
});
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should handle untrigger call with no state', async () => {
|
||||
@@ -455,7 +464,7 @@ describe('CameraTriggersManager', () => {
|
||||
type: 'end',
|
||||
});
|
||||
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not untrigger if other sources are still active', async () => {
|
||||
@@ -531,7 +540,7 @@ describe('CameraTriggersManager', () => {
|
||||
|
||||
// Should still be triggered because the second 'new' event should have cancelled the first timer.
|
||||
expect(manager.isTriggered()).toBeTruthy();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should untrigger each camera independently', async () => {
|
||||
@@ -580,7 +589,7 @@ describe('CameraTriggersManager', () => {
|
||||
await flushPromises();
|
||||
|
||||
// Camera 1 untriggered: setViewDefaultWithNewQuery is called.
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).toBeCalledTimes(1);
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).toHaveBeenCalledTimes(1);
|
||||
// Camera 2 is still triggered.
|
||||
expect(manager.getTriggeredCameraIDs()).toEqual(new Set(['camera_2']));
|
||||
|
||||
@@ -596,7 +605,7 @@ describe('CameraTriggersManager', () => {
|
||||
await flushPromises();
|
||||
|
||||
// Camera 2 untriggered: setViewDefaultWithNewQuery is called again.
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).toBeCalledTimes(2);
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).toHaveBeenCalledTimes(2);
|
||||
expect(manager.getTriggeredCameraIDs()).toEqual(new Set());
|
||||
});
|
||||
|
||||
@@ -696,7 +705,7 @@ describe('CameraTriggersManager', () => {
|
||||
await flushPromises();
|
||||
|
||||
expect(manager.isTriggered()).toBeFalsy();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).toBeCalled();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should force untrigger when untrigger_force_seconds expires', async () => {
|
||||
@@ -718,7 +727,7 @@ describe('CameraTriggersManager', () => {
|
||||
await flushPromises();
|
||||
|
||||
expect(manager.isTriggered()).toBeFalsy();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).toBeCalledTimes(1);
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should not reset force timer on source update', async () => {
|
||||
@@ -750,7 +759,7 @@ describe('CameraTriggersManager', () => {
|
||||
vi.advanceTimersByTime(100);
|
||||
await flushPromises();
|
||||
expect(manager.isTriggered()).toBeFalsy();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).toBeCalledTimes(1);
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should force untrigger all sources when one force timer expires', async () => {
|
||||
@@ -777,7 +786,7 @@ describe('CameraTriggersManager', () => {
|
||||
await flushPromises();
|
||||
|
||||
expect(manager.isTriggered()).toBeFalsy();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).toBeCalledTimes(1);
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should not extend force timer when a second source triggers later', async () => {
|
||||
@@ -809,7 +818,7 @@ describe('CameraTriggersManager', () => {
|
||||
vi.advanceTimersByTime(100);
|
||||
await flushPromises();
|
||||
expect(manager.isTriggered()).toBeFalsy();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).toBeCalledTimes(1);
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should auto-untrigger after the delay on a momentary event', async () => {
|
||||
@@ -827,14 +836,14 @@ describe('CameraTriggersManager', () => {
|
||||
});
|
||||
|
||||
expect(manager.isTriggered()).toBeTruthy();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).not.toHaveBeenCalled();
|
||||
|
||||
vi.setSystemTime(add(start, { seconds: 10 }));
|
||||
vi.runOnlyPendingTimers();
|
||||
await flushPromises();
|
||||
|
||||
expect(manager.isTriggered()).toBeFalsy();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).toBeCalled();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should auto-untrigger immediately on a momentary event when delay is 0', async () => {
|
||||
@@ -854,7 +863,7 @@ describe('CameraTriggersManager', () => {
|
||||
await flushPromises();
|
||||
|
||||
expect(manager.isTriggered()).toBeFalsy();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).toBeCalled();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not auto-untrigger from a momentary event while a continuous source remains active', async () => {
|
||||
@@ -885,7 +894,7 @@ describe('CameraTriggersManager', () => {
|
||||
|
||||
// Continuous source keeps the trigger alive.
|
||||
expect(manager.isTriggered()).toBeTruthy();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should add event_hold_seconds on top of untrigger_delay_seconds for momentary events', async () => {
|
||||
@@ -915,7 +924,7 @@ describe('CameraTriggersManager', () => {
|
||||
vi.advanceTimersByTime(1_000);
|
||||
await flushPromises();
|
||||
expect(manager.isTriggered()).toBeFalsy();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).toBeCalled();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not apply event_hold_seconds to non-momentary events', async () => {
|
||||
@@ -1018,8 +1027,10 @@ describe('CameraTriggersManager', () => {
|
||||
fidelity: 'high',
|
||||
});
|
||||
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).not.toHaveBeenCalled();
|
||||
expect(
|
||||
api.getViewManager().setViewByParametersWithNewQuery,
|
||||
).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should ignore high-fidelity events when default view is not live', async () => {
|
||||
@@ -1043,8 +1054,10 @@ describe('CameraTriggersManager', () => {
|
||||
fidelity: 'high',
|
||||
});
|
||||
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).not.toHaveBeenCalled();
|
||||
expect(
|
||||
api.getViewManager().setViewByParametersWithNewQuery,
|
||||
).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1063,8 +1076,8 @@ describe('CameraTriggersManager', () => {
|
||||
|
||||
expect(manager.isTriggered()).toBeTruthy();
|
||||
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).not.toHaveBeenCalled();
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).not.toHaveBeenCalled();
|
||||
|
||||
await manager.handleCameraEvent({
|
||||
cameraID: 'camera_1',
|
||||
@@ -1077,8 +1090,8 @@ describe('CameraTriggersManager', () => {
|
||||
|
||||
expect(manager.isTriggered()).toBeFalsy();
|
||||
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).not.toHaveBeenCalled();
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should take no actions when actions are set to none', async () => {
|
||||
@@ -1098,8 +1111,8 @@ describe('CameraTriggersManager', () => {
|
||||
type: 'new',
|
||||
});
|
||||
expect(manager.isTriggered()).toBeTruthy();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).not.toHaveBeenCalled();
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).not.toHaveBeenCalled();
|
||||
|
||||
await manager.handleCameraEvent({
|
||||
cameraID: 'camera_1',
|
||||
@@ -1111,8 +1124,8 @@ describe('CameraTriggersManager', () => {
|
||||
vi.runOnlyPendingTimers();
|
||||
|
||||
expect(manager.isTriggered()).toBeFalsy();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).not.toHaveBeenCalled();
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should take actions with human interactions when interaction mode is active', async () => {
|
||||
@@ -1136,7 +1149,7 @@ describe('CameraTriggersManager', () => {
|
||||
});
|
||||
|
||||
expect(manager.isTriggered()).toBeTruthy();
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).toBeCalledWith({
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).toHaveBeenCalledWith({
|
||||
params: {
|
||||
view: 'live' as const,
|
||||
camera: 'camera_1' as const,
|
||||
@@ -1155,7 +1168,7 @@ describe('CameraTriggersManager', () => {
|
||||
|
||||
expect(manager.isTriggered()).toBeFalsy();
|
||||
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).toBeCalled();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should report multiple triggered cameras', async () => {
|
||||
@@ -1354,7 +1367,7 @@ describe('CameraTriggersManager', () => {
|
||||
await flushPromises();
|
||||
|
||||
expect(manager.isTriggered()).toBeFalsy();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).toBeCalled();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1475,7 +1488,9 @@ describe('CameraTriggersManager', () => {
|
||||
|
||||
expect(result).toBeTruthy();
|
||||
expect(manager.isTriggered()).toBeTruthy();
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).toBeCalledTimes(1);
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).toHaveBeenCalledTimes(
|
||||
1,
|
||||
);
|
||||
});
|
||||
|
||||
it('should prioritize the first triggered camera action at startup', async () => {
|
||||
@@ -1522,7 +1537,9 @@ describe('CameraTriggersManager', () => {
|
||||
|
||||
expect(result).toBeTruthy();
|
||||
expect(manager.getTriggeredCameraIDs()).toEqual(new Set(['camera_1', 'camera_2']));
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).toBeCalledTimes(1);
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).toHaveBeenCalledTimes(
|
||||
1,
|
||||
);
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).toHaveBeenCalledWith({
|
||||
params: {
|
||||
view: 'live',
|
||||
@@ -1564,8 +1581,10 @@ describe('CameraTriggersManager', () => {
|
||||
expect(result).toBeTruthy();
|
||||
// ...but the camera was filtered out, so no trigger state/action was applied.
|
||||
expect(manager.isTriggered()).toBeFalsy();
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).not.toBeCalled();
|
||||
expect(
|
||||
api.getViewManager().setViewByParametersWithNewQuery,
|
||||
).not.toHaveBeenCalled();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not trigger a camera without the trigger capability', async () => {
|
||||
@@ -1674,7 +1693,7 @@ describe('CameraTriggersManager', () => {
|
||||
});
|
||||
|
||||
expect(manager.isTriggered()).toBeTruthy();
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).toBeCalledWith({
|
||||
expect(api.getViewManager().setViewByParametersWithNewQuery).toHaveBeenCalledWith({
|
||||
params: {
|
||||
view: 'live' as const,
|
||||
camera: 'camera_1' as const,
|
||||
@@ -1693,7 +1712,7 @@ describe('CameraTriggersManager', () => {
|
||||
|
||||
expect(manager.isTriggered()).toBeFalsy();
|
||||
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).toBeCalled();
|
||||
expect(api.getViewManager().setViewDefaultWithNewQuery).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should ignore untrigger actions during non-allowable interaction but still untrigger camera', async () => {
|
||||
|
||||
@@ -3,7 +3,8 @@ import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { CameraURLManager } from '../../src/card-controller/camera-url-manager';
|
||||
import type { CardCameraURLAPI } from '../../src/card-controller/types';
|
||||
import type { Endpoint } from '../../src/types';
|
||||
import { createCardAPI, createViewWithMedia } from '../test-utils';
|
||||
import { createCardAPI } from '../test-utils';
|
||||
import { createViewWithMedia } from '../view/test-utils';
|
||||
|
||||
const createAPIWithMedia = (): CardCameraURLAPI => {
|
||||
const api = createCardAPI();
|
||||
@@ -34,7 +35,7 @@ describe('CameraURLManager', () => {
|
||||
|
||||
const windowSpy = vi.spyOn(window, 'open').mockReturnValue(null);
|
||||
manager.openURL();
|
||||
expect(windowSpy).toBeCalledWith('http://frigate');
|
||||
expect(windowSpy).toHaveBeenCalledWith('http://frigate');
|
||||
});
|
||||
|
||||
it('should not get URL without view', () => {
|
||||
@@ -43,7 +44,7 @@ describe('CameraURLManager', () => {
|
||||
|
||||
const windowSpy = vi.spyOn(window, 'open').mockReturnValue(null);
|
||||
manager.openURL();
|
||||
expect(windowSpy).not.toBeCalled();
|
||||
expect(windowSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not get URL without cameraManager endpoints', () => {
|
||||
|
||||
@@ -5,15 +5,14 @@ import { CardElementManager } from '../../src/card-controller/card-element-manag
|
||||
import type { StateWatcher } from '../../src/card-controller/hass/state-watcher';
|
||||
import { QueryResults } from '../../src/view/query-results';
|
||||
import { View } from '../../src/view/view';
|
||||
import { createConfig } from '../config/test-utils';
|
||||
import {
|
||||
callStateWatcherCallback,
|
||||
createCardAPI,
|
||||
createCardHTMLElement,
|
||||
createConfig,
|
||||
createStateEntity,
|
||||
createView,
|
||||
TestViewMedia,
|
||||
} from '../test-utils';
|
||||
import { createView, TestViewMedia } from '../view/test-utils';
|
||||
|
||||
// @vitest-environment jsdom
|
||||
describe('CardElementManager', () => {
|
||||
@@ -62,7 +61,7 @@ describe('CardElementManager', () => {
|
||||
|
||||
manager.scrollReset();
|
||||
|
||||
expect(callback).toBeCalled();
|
||||
expect(callback).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should toggle menu', () => {
|
||||
@@ -76,7 +75,7 @@ describe('CardElementManager', () => {
|
||||
|
||||
manager.toggleMenu();
|
||||
|
||||
expect(callback).toBeCalled();
|
||||
expect(callback).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should update', () => {
|
||||
@@ -89,7 +88,7 @@ describe('CardElementManager', () => {
|
||||
);
|
||||
|
||||
manager.update();
|
||||
expect(element.requestUpdate).toBeCalled();
|
||||
expect(element.requestUpdate).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should get hasUpdated', () => {
|
||||
@@ -124,45 +123,48 @@ describe('CardElementManager', () => {
|
||||
|
||||
expect(element.getAttribute('panel')).toBeNull();
|
||||
expect(element.getAttribute('casted')).toBeNull();
|
||||
expect(api.getFullscreenManager().connect).toBeCalled();
|
||||
expect(api.getFullscreenManager().connect).toHaveBeenCalled();
|
||||
|
||||
expect(addEventListener).toBeCalledWith(
|
||||
expect(addEventListener).toHaveBeenCalledWith(
|
||||
'mousemove',
|
||||
api.getInteractionManager().reportInteraction,
|
||||
);
|
||||
expect(addEventListener).toBeCalledWith(
|
||||
expect(addEventListener).toHaveBeenCalledWith(
|
||||
'll-custom',
|
||||
api.getActionsManager().handleCustomActionEvent,
|
||||
);
|
||||
expect(addEventListener).toBeCalledWith(
|
||||
expect(addEventListener).toHaveBeenCalledWith(
|
||||
'action',
|
||||
api.getActionsManager().handleInteractionEvent,
|
||||
);
|
||||
expect(addEventListener).toBeCalledWith(
|
||||
expect(addEventListener).toHaveBeenCalledWith(
|
||||
'action',
|
||||
api.getInteractionManager().reportInteraction,
|
||||
);
|
||||
expect(addEventListener).toBeCalledWith(
|
||||
expect(addEventListener).toHaveBeenCalledWith(
|
||||
'touchstart',
|
||||
api.getInteractionManager().reportInteraction,
|
||||
);
|
||||
expect(addEventListener).toBeCalledWith(
|
||||
expect(addEventListener).toHaveBeenCalledWith(
|
||||
'touchmove',
|
||||
api.getInteractionManager().reportInteraction,
|
||||
);
|
||||
expect(windowAddEventListener).toBeCalledWith('location-changed', expect.anything());
|
||||
expect(windowAddEventListener).toBeCalledWith('popstate', expect.anything());
|
||||
expect(windowAddEventListener).toBeCalledWith(
|
||||
expect(windowAddEventListener).toHaveBeenCalledWith(
|
||||
'location-changed',
|
||||
expect.anything(),
|
||||
);
|
||||
expect(windowAddEventListener).toHaveBeenCalledWith('popstate', expect.anything());
|
||||
expect(windowAddEventListener).toHaveBeenCalledWith(
|
||||
'advanced-camera-card:editor:diagnostics',
|
||||
expect.anything(),
|
||||
);
|
||||
|
||||
expect(api.getInteractionManager().initialize).toBeCalled();
|
||||
expect(api.getFullscreenManager().initialize).toBeCalled();
|
||||
expect(api.getExpandManager().initialize).toBeCalled();
|
||||
expect(api.getMediaLoadedInfoManager().initialize).toBeCalled();
|
||||
expect(api.getMicrophoneManager().initialize).toBeCalled();
|
||||
expect(api.getCallManager().initialize).toBeCalled();
|
||||
expect(api.getInteractionManager().initialize).toHaveBeenCalled();
|
||||
expect(api.getFullscreenManager().initialize).toHaveBeenCalled();
|
||||
expect(api.getExpandManager().initialize).toHaveBeenCalled();
|
||||
expect(api.getMediaLoadedInfoManager().initialize).toHaveBeenCalled();
|
||||
expect(api.getMicrophoneManager().initialize).toHaveBeenCalled();
|
||||
expect(api.getCallManager().initialize).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should disconnect', () => {
|
||||
@@ -188,49 +190,52 @@ describe('CardElementManager', () => {
|
||||
|
||||
expect(element.getAttribute('panel')).toBeNull();
|
||||
expect(element.getAttribute('casted')).toBeNull();
|
||||
expect(api.getMediaLoadedInfoManager().clear).toBeCalled();
|
||||
expect(api.getFullscreenManager().disconnect).toBeCalled();
|
||||
expect(api.getMediaLoadedInfoManager().clear).toHaveBeenCalled();
|
||||
expect(api.getFullscreenManager().disconnect).toHaveBeenCalled();
|
||||
|
||||
expect(removeEventListener).toBeCalledWith(
|
||||
expect(removeEventListener).toHaveBeenCalledWith(
|
||||
'mousemove',
|
||||
api.getInteractionManager().reportInteraction,
|
||||
);
|
||||
expect(removeEventListener).toBeCalledWith(
|
||||
expect(removeEventListener).toHaveBeenCalledWith(
|
||||
'll-custom',
|
||||
api.getActionsManager().handleCustomActionEvent,
|
||||
);
|
||||
expect(removeEventListener).toBeCalledWith(
|
||||
expect(removeEventListener).toHaveBeenCalledWith(
|
||||
'action',
|
||||
api.getActionsManager().handleInteractionEvent,
|
||||
);
|
||||
expect(removeEventListener).toBeCalledWith(
|
||||
expect(removeEventListener).toHaveBeenCalledWith(
|
||||
'action',
|
||||
api.getInteractionManager().reportInteraction,
|
||||
);
|
||||
expect(removeEventListener).toBeCalledWith(
|
||||
expect(removeEventListener).toHaveBeenCalledWith(
|
||||
'touchstart',
|
||||
api.getInteractionManager().reportInteraction,
|
||||
);
|
||||
expect(removeEventListener).toBeCalledWith(
|
||||
expect(removeEventListener).toHaveBeenCalledWith(
|
||||
'touchmove',
|
||||
api.getInteractionManager().reportInteraction,
|
||||
);
|
||||
expect(windowRemoveEventListener).toBeCalledWith(
|
||||
expect(windowRemoveEventListener).toHaveBeenCalledWith(
|
||||
'location-changed',
|
||||
expect.anything(),
|
||||
);
|
||||
expect(windowRemoveEventListener).toBeCalledWith('popstate', expect.anything());
|
||||
expect(windowRemoveEventListener).toBeCalledWith(
|
||||
expect(windowRemoveEventListener).toHaveBeenCalledWith(
|
||||
'popstate',
|
||||
expect.anything(),
|
||||
);
|
||||
expect(windowRemoveEventListener).toHaveBeenCalledWith(
|
||||
'advanced-camera-card:editor:diagnostics',
|
||||
expect.anything(),
|
||||
);
|
||||
|
||||
expect(api.getMediaLoadedInfoManager().clear).toBeCalled();
|
||||
expect(api.getFullscreenManager().disconnect).toBeCalled();
|
||||
expect(api.getKeyboardStateManager().uninitialize).toBeCalled();
|
||||
expect(api.getActionsManager().uninitialize).toBeCalled();
|
||||
expect(api.getCallManager().uninitialize).toBeCalled();
|
||||
expect(api.getInitializationManager().uninitialize).toBeCalledWith('cameras');
|
||||
expect(api.getMediaLoadedInfoManager().clear).toHaveBeenCalled();
|
||||
expect(api.getFullscreenManager().disconnect).toHaveBeenCalled();
|
||||
expect(api.getKeyboardStateManager().uninitialize).toHaveBeenCalled();
|
||||
expect(api.getActionsManager().uninitialize).toHaveBeenCalled();
|
||||
expect(api.getCallManager().uninitialize).toHaveBeenCalled();
|
||||
expect(api.getInitializationManager().uninitialize).toHaveBeenCalledWith('cameras');
|
||||
});
|
||||
|
||||
describe('should update card when', () => {
|
||||
@@ -263,7 +268,7 @@ describe('CardElementManager', () => {
|
||||
};
|
||||
callStateWatcherCallback(stateWatcher, diff);
|
||||
|
||||
expect(element.requestUpdate).toBeCalled();
|
||||
expect(element.requestUpdate).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('media player entity changes', () => {
|
||||
@@ -291,7 +296,7 @@ describe('CardElementManager', () => {
|
||||
};
|
||||
callStateWatcherCallback(stateWatcher, diff);
|
||||
|
||||
expect(element.requestUpdate).toBeCalled();
|
||||
expect(element.requestUpdate).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('selected media review status changes', () => {
|
||||
@@ -325,7 +330,7 @@ describe('CardElementManager', () => {
|
||||
}),
|
||||
);
|
||||
|
||||
expect(element.requestUpdate).toBeCalled();
|
||||
expect(element.requestUpdate).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('non-selected media review status changes does not update', () => {
|
||||
@@ -361,7 +366,7 @@ describe('CardElementManager', () => {
|
||||
);
|
||||
|
||||
// Should NOT update because the reviewed item is not the selected item.
|
||||
expect(element.requestUpdate).not.toBeCalled();
|
||||
expect(element.requestUpdate).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -406,7 +411,7 @@ describe('CardElementManager', () => {
|
||||
|
||||
fireFromDialog(dialog);
|
||||
|
||||
expect(api.getViewManager().setViewByParameters).toBeCalledWith({
|
||||
expect(api.getViewManager().setViewByParameters).toHaveBeenCalledWith({
|
||||
params: { view: 'diagnostics' },
|
||||
});
|
||||
});
|
||||
@@ -431,7 +436,7 @@ describe('CardElementManager', () => {
|
||||
|
||||
fireFromDialog(dialog);
|
||||
|
||||
expect(api.getViewManager().setViewDefault).toBeCalled();
|
||||
expect(api.getViewManager().setViewDefault).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not set view to diagnostics if card is not in editor', () => {
|
||||
@@ -452,7 +457,7 @@ describe('CardElementManager', () => {
|
||||
document.body.append(otherDialog);
|
||||
fireFromDialog(otherDialog);
|
||||
|
||||
expect(api.getViewManager().setViewByParameters).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewByParameters).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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', () => {
|
||||
|
||||
@@ -113,7 +113,7 @@ describe('CardController', () => {
|
||||
|
||||
const controller = new CardController(element, scrollCallback, menuToggleCallback);
|
||||
|
||||
expect(CardElementManager).toBeCalledWith(
|
||||
expect(CardElementManager).toHaveBeenCalledWith(
|
||||
controller,
|
||||
element,
|
||||
scrollCallback,
|
||||
@@ -137,7 +137,9 @@ describe('CardController', () => {
|
||||
const csmListener = calls[0][0];
|
||||
const hass = {} as Parameters<typeof csmListener>[0];
|
||||
csmListener(hass, null);
|
||||
expect(vi.mocked(ConditionStateManager).mock.instances[0].setState).toBeCalledWith({
|
||||
expect(
|
||||
vi.mocked(ConditionStateManager).mock.instances[0].setState,
|
||||
).toHaveBeenCalledWith({
|
||||
hass,
|
||||
});
|
||||
});
|
||||
@@ -372,14 +374,14 @@ describe('CardController', () => {
|
||||
createController().hostConnected();
|
||||
expect(
|
||||
vi.mocked(CardElementManager).mock.instances[0].elementConnected,
|
||||
).toBeCalled();
|
||||
).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should handle hostDisconnected', () => {
|
||||
createController().hostDisconnected();
|
||||
expect(
|
||||
vi.mocked(CardElementManager).mock.instances[0].elementDisconnected,
|
||||
).toBeCalled();
|
||||
).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,10 +4,10 @@ import { mock } from 'vitest-mock-extended';
|
||||
import type { CardController } from '../../src/card-controller/controller';
|
||||
import { DefaultManager } from '../../src/card-controller/default-manager';
|
||||
import type { StateWatcherSubscriptionInterface } from '../../src/card-controller/hass/state-watcher';
|
||||
import { createConfig } from '../config/test-utils';
|
||||
import {
|
||||
callStateWatcherCallback,
|
||||
createCardAPI,
|
||||
createConfig,
|
||||
createHASS,
|
||||
createStateEntity,
|
||||
} from '../test-utils';
|
||||
@@ -46,21 +46,21 @@ describe('DefaultManager', () => {
|
||||
const manager = new DefaultManager(api);
|
||||
await manager.initialize();
|
||||
|
||||
expect(api.getViewManager().setViewDefault).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewDefault).not.toHaveBeenCalled();
|
||||
|
||||
vi.runOnlyPendingTimers();
|
||||
|
||||
expect(api.getViewManager().setViewDefault).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewDefault).not.toHaveBeenCalled();
|
||||
|
||||
vi.mocked(api.getInteractionManager().hasInteraction).mockReturnValue(false);
|
||||
vi.runOnlyPendingTimers();
|
||||
|
||||
expect(api.getViewManager().setViewDefault).toBeCalledTimes(1);
|
||||
expect(api.getViewManager().setViewDefault).toHaveBeenCalledTimes(1);
|
||||
|
||||
manager.uninitialize();
|
||||
vi.runOnlyPendingTimers();
|
||||
|
||||
expect(api.getViewManager().setViewDefault).toBeCalledTimes(1);
|
||||
expect(api.getViewManager().setViewDefault).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should not set default view when not configured', () => {
|
||||
@@ -82,11 +82,11 @@ describe('DefaultManager', () => {
|
||||
const manager = new DefaultManager(api);
|
||||
manager.initialize();
|
||||
|
||||
expect(api.getViewManager().setViewDefault).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewDefault).not.toHaveBeenCalled();
|
||||
|
||||
vi.runOnlyPendingTimers();
|
||||
|
||||
expect(api.getViewManager().setViewDefault).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewDefault).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should restart timer when reconfigured', async () => {
|
||||
@@ -108,14 +108,14 @@ describe('DefaultManager', () => {
|
||||
const manager = new DefaultManager(api);
|
||||
|
||||
await manager.initialize();
|
||||
expect(api.getViewManager().setViewDefault).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewDefault).not.toHaveBeenCalled();
|
||||
|
||||
await manager.initialize();
|
||||
expect(api.getViewManager().setViewDefault).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewDefault).not.toHaveBeenCalled();
|
||||
|
||||
vi.runOnlyPendingTimers();
|
||||
|
||||
expect(api.getViewManager().setViewDefault).toBeCalled();
|
||||
expect(api.getViewManager().setViewDefault).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -146,7 +146,7 @@ describe('DefaultManager', () => {
|
||||
newState: createStateEntity({ state: 'on' }),
|
||||
});
|
||||
|
||||
expect(api.getViewManager().setViewDefault).toBeCalled();
|
||||
expect(api.getViewManager().setViewDefault).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('interaction based', () => {
|
||||
@@ -166,7 +166,7 @@ describe('DefaultManager', () => {
|
||||
const manager = new DefaultManager(api);
|
||||
await manager.initialize();
|
||||
|
||||
expect(api.getAutomationsManager().addAutomations).not.toBeCalled();
|
||||
expect(api.getAutomationsManager().addAutomations).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should register automation on initialization', async () => {
|
||||
@@ -185,7 +185,7 @@ describe('DefaultManager', () => {
|
||||
const manager = new DefaultManager(api);
|
||||
await manager.initialize();
|
||||
|
||||
expect(api.getAutomationsManager().addAutomations).toBeCalledWith([
|
||||
expect(api.getAutomationsManager().addAutomations).toHaveBeenCalledWith([
|
||||
{
|
||||
actions: [
|
||||
{
|
||||
@@ -209,7 +209,9 @@ describe('DefaultManager', () => {
|
||||
const manager = new DefaultManager(api);
|
||||
manager.uninitialize();
|
||||
|
||||
expect(api.getAutomationsManager().deleteAutomations).toBeCalledWith(manager);
|
||||
expect(api.getAutomationsManager().deleteAutomations).toHaveBeenCalledWith(
|
||||
manager,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -241,18 +243,18 @@ describe('DefaultManager', () => {
|
||||
await manager.initializeIfNecessary(null);
|
||||
|
||||
vi.runOnlyPendingTimers();
|
||||
expect(api.getViewManager().setViewDefault).toBeCalledTimes(1);
|
||||
expect(api.getViewManager().setViewDefault).toHaveBeenCalledTimes(1);
|
||||
|
||||
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(configOff);
|
||||
await manager.initializeIfNecessary(configOn);
|
||||
|
||||
vi.runOnlyPendingTimers();
|
||||
expect(api.getViewManager().setViewDefault).toBeCalledTimes(1);
|
||||
expect(api.getViewManager().setViewDefault).toHaveBeenCalledTimes(1);
|
||||
|
||||
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(configOff);
|
||||
await manager.initializeIfNecessary(configOff);
|
||||
|
||||
vi.runOnlyPendingTimers();
|
||||
expect(api.getViewManager().setViewDefault).toBeCalledTimes(1);
|
||||
expect(api.getViewManager().setViewDefault).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16,7 +16,9 @@ describe('ExpandManager', () => {
|
||||
const manager = new ExpandManager(api);
|
||||
|
||||
manager.initialize();
|
||||
expect(api.getConditionStateManager().setState).toBeCalledWith({ expand: false });
|
||||
expect(api.getConditionStateManager().setState).toHaveBeenCalledWith({
|
||||
expand: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('should set expanded', () => {
|
||||
@@ -29,9 +31,11 @@ describe('ExpandManager', () => {
|
||||
manager.setExpanded(true);
|
||||
|
||||
expect(manager.isExpanded()).toBeTruthy();
|
||||
expect(api.getFullscreenManager().setFullscreen).toBeCalledWith(false);
|
||||
expect(api.getConditionStateManager().setState).toBeCalledWith({ expand: true });
|
||||
expect(api.getCardElementManager().update).toBeCalled();
|
||||
expect(api.getFullscreenManager().setFullscreen).toHaveBeenCalledWith(false);
|
||||
expect(api.getConditionStateManager().setState).toHaveBeenCalledWith({
|
||||
expand: true,
|
||||
});
|
||||
expect(api.getCardElementManager().update).toHaveBeenCalled();
|
||||
expect(element.hasAttribute('expanded')).toBeTruthy();
|
||||
});
|
||||
|
||||
@@ -44,7 +48,7 @@ describe('ExpandManager', () => {
|
||||
|
||||
manager.setExpanded(true);
|
||||
|
||||
expect(api.getFullscreenManager().setFullscreen).not.toBeCalled();
|
||||
expect(api.getFullscreenManager().setFullscreen).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should toggle expanded', () => {
|
||||
|
||||
@@ -9,7 +9,8 @@ import type { FolderConfig } from '../../../src/config/schema/folders';
|
||||
import { QuerySource } from '../../../src/query-source';
|
||||
import type { Endpoint } from '../../../src/types';
|
||||
import { ViewFolder } from '../../../src/view/item';
|
||||
import { createFolder, createHASS, TestViewMedia } from '../../test-utils';
|
||||
import { createFolder, createHASS } from '../../test-utils';
|
||||
import { TestViewMedia } from '../../view/test-utils';
|
||||
|
||||
vi.mock('../../../src/card-controller/folders/ha/engine');
|
||||
vi.mock('../../../../src/utils/ha/download');
|
||||
@@ -134,7 +135,7 @@ describe('FoldersExecutor', () => {
|
||||
|
||||
await executor.favorite(hass, item, true);
|
||||
|
||||
expect(haFolderEngine.favorite).toBeCalledWith(hass, item, true);
|
||||
expect(haFolderEngine.favorite).toHaveBeenCalledWith(hass, item, true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -153,7 +154,10 @@ describe('FoldersExecutor', () => {
|
||||
const executor = new FoldersExecutor(templateManager, { ha: haFolderEngine });
|
||||
|
||||
expect(executor.generateChildFolderQuery(query, viewFolder)).toEqual(query);
|
||||
expect(haFolderEngine.generateChildFolderQuery).toBeCalledWith(query, viewFolder);
|
||||
expect(haFolderEngine.generateChildFolderQuery).toHaveBeenCalledWith(
|
||||
query,
|
||||
viewFolder,
|
||||
);
|
||||
});
|
||||
|
||||
it('should return null for non-existent folder engine', () => {
|
||||
|
||||
@@ -11,12 +11,8 @@ import { homeAssistantWSRequest } from '../../../../src/ha/ws-request';
|
||||
import { QuerySource } from '../../../../src/query-source';
|
||||
import type { Endpoint } from '../../../../src/types';
|
||||
import { ViewFolder, ViewMedia } from '../../../../src/view/item';
|
||||
import {
|
||||
createBrowseMedia,
|
||||
createFolder,
|
||||
createHASS,
|
||||
TestViewMedia,
|
||||
} from '../../../test-utils';
|
||||
import { createBrowseMedia, createFolder, createHASS } from '../../../test-utils';
|
||||
import { TestViewMedia } from '../../../view/test-utils';
|
||||
|
||||
vi.mock('../../../../src/ha/download');
|
||||
vi.mock('../../../../src/ha/ws-request');
|
||||
@@ -143,11 +139,11 @@ describe('HAFoldersEngine', () => {
|
||||
expect(results?.[0]).toBeInstanceOf(ViewMedia);
|
||||
expect(results?.[1]).toBeInstanceOf(ViewFolder);
|
||||
|
||||
expect(homeAssistantWSRequest).toBeCalledTimes(1);
|
||||
expect(homeAssistantWSRequest).toHaveBeenCalledTimes(1);
|
||||
|
||||
// Expanding the folder again should use the cache.
|
||||
await engine.expandFolder(createHASS(), query);
|
||||
expect(homeAssistantWSRequest).toBeCalledTimes(1);
|
||||
expect(homeAssistantWSRequest).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should expand folder without cache when requested', async () => {
|
||||
@@ -190,11 +186,11 @@ describe('HAFoldersEngine', () => {
|
||||
expect(results?.[0]).toBeInstanceOf(ViewMedia);
|
||||
expect(results?.[1]).toBeInstanceOf(ViewFolder);
|
||||
|
||||
expect(homeAssistantWSRequest).toBeCalledTimes(1);
|
||||
expect(homeAssistantWSRequest).toHaveBeenCalledTimes(1);
|
||||
|
||||
// Expanding the folder again should use the cache.
|
||||
await engine.expandFolder(createHASS(), query);
|
||||
expect(homeAssistantWSRequest).toBeCalledTimes(2);
|
||||
expect(homeAssistantWSRequest).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('should use id from browsemedia in folder in query', async () => {
|
||||
@@ -225,7 +221,7 @@ describe('HAFoldersEngine', () => {
|
||||
const engine = new HAFoldersEngine(templateManager);
|
||||
await engine.expandFolder(hass, query);
|
||||
|
||||
expect(homeAssistantWSRequest).toBeCalledWith(hass, browseMediaSchema, {
|
||||
expect(homeAssistantWSRequest).toHaveBeenCalledWith(hass, browseMediaSchema, {
|
||||
type: 'media_source/browse_media',
|
||||
media_content_id: 'media-source://id',
|
||||
});
|
||||
|
||||
@@ -13,12 +13,8 @@ import { QuerySource } from '../../../src/query-source';
|
||||
import type { Endpoint } from '../../../src/types';
|
||||
import { ViewFolder } from '../../../src/view/item';
|
||||
import type { ViewItemCapabilities } from '../../../src/view/types';
|
||||
import {
|
||||
createCardAPI,
|
||||
createFolder,
|
||||
createHASS,
|
||||
TestViewMedia,
|
||||
} from '../../test-utils';
|
||||
import { createCardAPI, createFolder, createHASS } from '../../test-utils';
|
||||
import { TestViewMedia } from '../../view/test-utils';
|
||||
|
||||
describe('FoldersManager', () => {
|
||||
it('should initialize with no folders', () => {
|
||||
@@ -74,7 +70,7 @@ describe('FoldersManager', () => {
|
||||
const folder_1 = createFolder({ id: 'DUP' });
|
||||
const folder_2 = createFolder({ id: 'DUP' });
|
||||
|
||||
expect(() => manager.addFolders([folder_1, folder_2])).toThrowError(
|
||||
expect(() => manager.addFolders([folder_1, folder_2])).toThrow(
|
||||
/Duplicate folder id/,
|
||||
);
|
||||
});
|
||||
@@ -119,7 +115,7 @@ describe('FoldersManager', () => {
|
||||
executor.getDefaultQueryParameters.mockReturnValue(query);
|
||||
|
||||
expect(manager.getDefaultQueryParameters(folder)).toEqual(query);
|
||||
expect(executor.getDefaultQueryParameters).toBeCalledWith(folder);
|
||||
expect(executor.getDefaultQueryParameters).toHaveBeenCalledWith(folder);
|
||||
});
|
||||
|
||||
it('should fallback to default folder if none provided', () => {
|
||||
@@ -133,7 +129,9 @@ describe('FoldersManager', () => {
|
||||
executor.getDefaultQueryParameters.mockReturnValue(query);
|
||||
|
||||
expect(manager.getDefaultQueryParameters()).toEqual(query);
|
||||
expect(executor.getDefaultQueryParameters).toBeCalledWith(manager.getFolder());
|
||||
expect(executor.getDefaultQueryParameters).toHaveBeenCalledWith(
|
||||
manager.getFolder(),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -186,7 +184,7 @@ describe('FoldersManager', () => {
|
||||
const manager = new FoldersManager(createCardAPI(), executor);
|
||||
|
||||
expect(manager.generateChildFolderQuery(query, viewFolder)).toEqual(query);
|
||||
expect(executor.generateChildFolderQuery).toBeCalledWith(query, viewFolder);
|
||||
expect(executor.generateChildFolderQuery).toHaveBeenCalledWith(query, viewFolder);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -215,7 +213,7 @@ describe('FoldersManager', () => {
|
||||
media,
|
||||
]);
|
||||
|
||||
expect(executor.expandFolder).toBeCalledWith(
|
||||
expect(executor.expandFolder).toHaveBeenCalledWith(
|
||||
hass,
|
||||
query,
|
||||
conditionState,
|
||||
@@ -237,7 +235,7 @@ describe('FoldersManager', () => {
|
||||
}),
|
||||
).toBeNull();
|
||||
|
||||
expect(executor.expandFolder).not.toBeCalled();
|
||||
expect(executor.expandFolder).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should return null for query with unsupported filters', async () => {
|
||||
@@ -257,7 +255,7 @@ describe('FoldersManager', () => {
|
||||
};
|
||||
|
||||
expect(await manager.expandFolder(query)).toBeNull();
|
||||
expect(executor.expandFolder).not.toBeCalled();
|
||||
expect(executor.expandFolder).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -275,7 +273,7 @@ describe('FoldersManager', () => {
|
||||
const manager = new FoldersManager(api, executor);
|
||||
|
||||
expect(manager.getItemCapabilities(item)).toEqual(capabilities);
|
||||
expect(executor.getItemCapabilities).toBeCalledWith(item);
|
||||
expect(executor.getItemCapabilities).toHaveBeenCalledWith(item);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -294,7 +292,7 @@ describe('FoldersManager', () => {
|
||||
|
||||
const manager = new FoldersManager(api, executor);
|
||||
expect(await manager.getDownloadPath(item)).toEqual(endpoint);
|
||||
expect(executor.getDownloadPath).toBeCalledWith(hass, item, {
|
||||
expect(executor.getDownloadPath).toHaveBeenCalledWith(hass, item, {
|
||||
resolvedMediaCache: cache,
|
||||
});
|
||||
});
|
||||
@@ -311,7 +309,7 @@ describe('FoldersManager', () => {
|
||||
|
||||
const manager = new FoldersManager(api, executor);
|
||||
await manager.favorite(item, true);
|
||||
expect(executor.favorite).toBeCalledWith(hass, item, true);
|
||||
expect(executor.favorite).toHaveBeenCalledWith(hass, item, true);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ describe('FullscreenManager', () => {
|
||||
const manager = new FullscreenManager(api, mock<FullscreenProvider>());
|
||||
|
||||
manager.initialize();
|
||||
expect(api.getConditionStateManager().setState).toBeCalledWith({
|
||||
expect(api.getConditionStateManager().setState).toHaveBeenCalledWith({
|
||||
fullscreen: false,
|
||||
});
|
||||
});
|
||||
@@ -49,7 +49,7 @@ describe('FullscreenManager', () => {
|
||||
|
||||
manager.toggleFullscreen();
|
||||
|
||||
expect(provider.setFullscreen).toBeCalledWith(expected);
|
||||
expect(provider.setFullscreen).toHaveBeenCalledWith(expected);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -60,7 +60,7 @@ describe('FullscreenManager', () => {
|
||||
|
||||
manager.setFullscreen(fullscreen);
|
||||
|
||||
expect(provider.setFullscreen).toBeCalledWith(fullscreen);
|
||||
expect(provider.setFullscreen).toHaveBeenCalledWith(fullscreen);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -70,7 +70,7 @@ describe('FullscreenManager', () => {
|
||||
|
||||
manager.connect();
|
||||
|
||||
expect(provider.connect).toBeCalled();
|
||||
expect(provider.connect).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should disconnect', () => {
|
||||
@@ -79,7 +79,7 @@ describe('FullscreenManager', () => {
|
||||
|
||||
manager.disconnect();
|
||||
|
||||
expect(provider.disconnect).toBeCalled();
|
||||
expect(provider.disconnect).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('should confirm whether fullscreen is supported', () => {
|
||||
@@ -137,7 +137,7 @@ describe('FullscreenManager', () => {
|
||||
|
||||
handler();
|
||||
|
||||
expect(api.getConditionStateManager().setState).toBeCalledWith({
|
||||
expect(api.getConditionStateManager().setState).toHaveBeenCalledWith({
|
||||
fullscreen: fullscreen,
|
||||
});
|
||||
});
|
||||
@@ -148,6 +148,9 @@ describe('FullscreenManager', () => {
|
||||
|
||||
new FullscreenManager(api);
|
||||
|
||||
expect(FullscreenProviderFactory.create).toBeCalledWith(api, expect.anything());
|
||||
expect(FullscreenProviderFactory.create).toHaveBeenCalledWith(
|
||||
api,
|
||||
expect.anything(),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -41,7 +41,7 @@ describe('ScreenfullFullScreenProvider', () => {
|
||||
|
||||
provider.connect();
|
||||
|
||||
expect(on).toBeCalledWith('change', expect.anything());
|
||||
expect(on).toHaveBeenCalledWith('change', expect.anything());
|
||||
});
|
||||
|
||||
it('should not connect if not enabled', () => {
|
||||
@@ -52,7 +52,7 @@ describe('ScreenfullFullScreenProvider', () => {
|
||||
|
||||
provider.connect();
|
||||
|
||||
expect(on).not.toBeCalled();
|
||||
expect(on).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -65,7 +65,7 @@ describe('ScreenfullFullScreenProvider', () => {
|
||||
|
||||
provider.disconnect();
|
||||
|
||||
expect(off).toBeCalledWith('change', expect.anything());
|
||||
expect(off).toHaveBeenCalledWith('change', expect.anything());
|
||||
});
|
||||
|
||||
it('should not disconnect if not enabled', () => {
|
||||
@@ -76,7 +76,7 @@ describe('ScreenfullFullScreenProvider', () => {
|
||||
|
||||
provider.disconnect();
|
||||
|
||||
expect(off).not.toBeCalled();
|
||||
expect(off).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -138,7 +138,7 @@ describe('ScreenfullFullScreenProvider', () => {
|
||||
|
||||
provider.setFullscreen(true);
|
||||
|
||||
expect(screenfull.request).toBeCalledWith(element);
|
||||
expect(screenfull.request).toHaveBeenCalledWith(element);
|
||||
});
|
||||
|
||||
it('should exit fullscreen if fullscreen is false', () => {
|
||||
@@ -148,7 +148,7 @@ describe('ScreenfullFullScreenProvider', () => {
|
||||
|
||||
provider.setFullscreen(false);
|
||||
|
||||
expect(screenfull.exit).toBeCalled();
|
||||
expect(screenfull.exit).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should take no action if not supported', () => {
|
||||
@@ -162,8 +162,8 @@ describe('ScreenfullFullScreenProvider', () => {
|
||||
provider.setFullscreen(true);
|
||||
provider.setFullscreen(false);
|
||||
|
||||
expect(screenfull.request).not.toBeCalled();
|
||||
expect(screenfull.exit).not.toBeCalled();
|
||||
expect(screenfull.request).not.toHaveBeenCalled();
|
||||
expect(screenfull.exit).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should swallow a rejected fullscreen request', async () => {
|
||||
@@ -177,7 +177,7 @@ describe('ScreenfullFullScreenProvider', () => {
|
||||
provider.setFullscreen(true);
|
||||
await flushPromises();
|
||||
|
||||
expect(screenfull.request).toBeCalledWith(element);
|
||||
expect(screenfull.request).toHaveBeenCalledWith(element);
|
||||
});
|
||||
|
||||
it('should swallow a rejected fullscreen exit', async () => {
|
||||
@@ -188,7 +188,7 @@ describe('ScreenfullFullScreenProvider', () => {
|
||||
provider.setFullscreen(false);
|
||||
await flushPromises();
|
||||
|
||||
expect(screenfull.exit).toBeCalled();
|
||||
expect(screenfull.exit).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -40,7 +40,9 @@ describe('WebkitFullScreenProvider', () => {
|
||||
|
||||
provider.connect();
|
||||
|
||||
expect(api.getConditionStateManager().addListener).toBeCalledWith(expect.anything());
|
||||
expect(api.getConditionStateManager().addListener).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
);
|
||||
});
|
||||
|
||||
it('should disconnect', () => {
|
||||
@@ -49,7 +51,7 @@ describe('WebkitFullScreenProvider', () => {
|
||||
|
||||
provider.disconnect();
|
||||
|
||||
expect(api.getConditionStateManager().removeListener).toBeCalledWith(
|
||||
expect(api.getConditionStateManager().removeListener).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
);
|
||||
});
|
||||
@@ -110,7 +112,7 @@ describe('WebkitFullScreenProvider', () => {
|
||||
|
||||
provider.setFullscreen(true);
|
||||
|
||||
expect(element.webkitEnterFullscreen).toBeCalled();
|
||||
expect(element.webkitEnterFullscreen).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should exit fullscreen if fullscreen is true', () => {
|
||||
@@ -130,7 +132,7 @@ describe('WebkitFullScreenProvider', () => {
|
||||
|
||||
provider.setFullscreen(false);
|
||||
|
||||
expect(element.webkitExitFullscreen).toBeCalled();
|
||||
expect(element.webkitExitFullscreen).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should take no action if not supported', () => {
|
||||
@@ -152,8 +154,8 @@ describe('WebkitFullScreenProvider', () => {
|
||||
provider.setFullscreen(true);
|
||||
provider.setFullscreen(false);
|
||||
|
||||
expect(element.webkitEnterFullscreen).not.toBeCalled();
|
||||
expect(element.webkitExitFullscreen).not.toBeCalled();
|
||||
expect(element.webkitEnterFullscreen).not.toHaveBeenCalled();
|
||||
expect(element.webkitExitFullscreen).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should take no action if element is not a video', () => {
|
||||
@@ -175,8 +177,8 @@ describe('WebkitFullScreenProvider', () => {
|
||||
provider.setFullscreen(true);
|
||||
provider.setFullscreen(false);
|
||||
|
||||
expect(element.webkitEnterFullscreen).not.toBeCalled();
|
||||
expect(element.webkitExitFullscreen).not.toBeCalled();
|
||||
expect(element.webkitEnterFullscreen).not.toHaveBeenCalled();
|
||||
expect(element.webkitExitFullscreen).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -205,7 +207,7 @@ describe('WebkitFullScreenProvider', () => {
|
||||
|
||||
element_1.dispatchEvent(new Event(event));
|
||||
|
||||
expect(handler).toBeCalledTimes(1);
|
||||
expect(handler).toHaveBeenCalledTimes(1);
|
||||
|
||||
const element_2 = createWebkitVideoElement();
|
||||
const mediaPlayerController_2 = mock<MediaPlayerController>();
|
||||
@@ -218,12 +220,12 @@ describe('WebkitFullScreenProvider', () => {
|
||||
|
||||
element_2.dispatchEvent(new Event(event));
|
||||
|
||||
expect(handler).toBeCalledTimes(2);
|
||||
expect(handler).toHaveBeenCalledTimes(2);
|
||||
|
||||
// Events on the old element should be ignored.
|
||||
element_1.dispatchEvent(new Event(event));
|
||||
|
||||
expect(handler).toBeCalledTimes(2);
|
||||
expect(handler).toHaveBeenCalledTimes(2);
|
||||
|
||||
// Test the media loaded info changing, but the player not changing.
|
||||
stateManager.setState({
|
||||
@@ -233,7 +235,7 @@ describe('WebkitFullScreenProvider', () => {
|
||||
// Events on the new element should still be handled.
|
||||
element_2.dispatchEvent(new Event(event));
|
||||
|
||||
expect(handler).toBeCalledTimes(3);
|
||||
expect(handler).toHaveBeenCalledTimes(3);
|
||||
},
|
||||
);
|
||||
});
|
||||
@@ -265,11 +267,11 @@ describe('WebkitFullScreenProvider', () => {
|
||||
|
||||
element.dispatchEvent(new Event('webkitendfullscreen'));
|
||||
|
||||
expect(element.play).not.toBeCalled();
|
||||
expect(element.play).not.toHaveBeenCalled();
|
||||
|
||||
vi.runOnlyPendingTimers();
|
||||
|
||||
expect(element.play).toBeCalled();
|
||||
expect(element.play).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should swallow a rejected video replay after fullscreen ends', async () => {
|
||||
@@ -295,6 +297,6 @@ describe('WebkitFullScreenProvider', () => {
|
||||
vi.runOnlyPendingTimers();
|
||||
await flushPromises();
|
||||
|
||||
expect(element.play).toBeCalled();
|
||||
expect(element.play).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -35,7 +35,7 @@ describe('EventWatcher', () => {
|
||||
watcher.subscribe({ event_type: 'zha_event', callback: vi.fn() });
|
||||
await flushPromises();
|
||||
|
||||
expect(hass.connection.subscribeEvents).toBeCalledTimes(1);
|
||||
expect(hass.connection.subscribeEvents).toHaveBeenCalledTimes(1);
|
||||
expect(vi.mocked(hass.connection.subscribeEvents).mock.calls[0][1]).toBe(
|
||||
'zha_event',
|
||||
);
|
||||
@@ -50,7 +50,7 @@ describe('EventWatcher', () => {
|
||||
watcher.subscribe({ event_type: 'zha_event', callback: vi.fn() });
|
||||
await flushPromises();
|
||||
|
||||
expect(hass.connection.subscribeEvents).toBeCalledTimes(1);
|
||||
expect(hass.connection.subscribeEvents).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should open separate WS subscriptions for distinct event_types', async () => {
|
||||
@@ -62,7 +62,7 @@ describe('EventWatcher', () => {
|
||||
watcher.subscribe({ event_type: 'deconz_event', callback: vi.fn() });
|
||||
await flushPromises();
|
||||
|
||||
expect(hass.connection.subscribeEvents).toBeCalledTimes(2);
|
||||
expect(hass.connection.subscribeEvents).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('should dispatch to every subscriber whose event_type matches', async () => {
|
||||
@@ -79,8 +79,8 @@ describe('EventWatcher', () => {
|
||||
|
||||
fireEvent(hass, event);
|
||||
|
||||
expect(cb1).toBeCalledWith(event);
|
||||
expect(cb2).toBeCalledWith(event);
|
||||
expect(cb1).toHaveBeenCalledWith(event);
|
||||
expect(cb2).toHaveBeenCalledWith(event);
|
||||
});
|
||||
|
||||
it('should gate dispatch on the request matcher when provided', async () => {
|
||||
@@ -98,9 +98,9 @@ describe('EventWatcher', () => {
|
||||
fireEvent(hass, matching);
|
||||
fireEvent(hass, nonMatching);
|
||||
|
||||
expect(matcher).toBeCalledTimes(2);
|
||||
expect(cb).toBeCalledTimes(1);
|
||||
expect(cb).toBeCalledWith(matching);
|
||||
expect(matcher).toHaveBeenCalledTimes(2);
|
||||
expect(cb).toHaveBeenCalledTimes(1);
|
||||
expect(cb).toHaveBeenCalledWith(matching);
|
||||
});
|
||||
|
||||
it('should tear down the WS subscription only when the last subscriber unsubscribes', async () => {
|
||||
@@ -118,11 +118,11 @@ describe('EventWatcher', () => {
|
||||
|
||||
watcher.unsubscribe(req1);
|
||||
await flushPromises();
|
||||
expect(unsub).not.toBeCalled();
|
||||
expect(unsub).not.toHaveBeenCalled();
|
||||
|
||||
watcher.unsubscribe(req2);
|
||||
await flushPromises();
|
||||
expect(unsub).toBeCalledTimes(1);
|
||||
expect(unsub).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should drop events from an old-connection subscription after a swap', async () => {
|
||||
@@ -147,7 +147,7 @@ describe('EventWatcher', () => {
|
||||
// Old dispatcher fires: guard.isConnected() is now false, callback must NOT
|
||||
// receive the event.
|
||||
oldDispatcher?.(createHASSEvent('zha_event', { command: 'press' }));
|
||||
expect(cb).not.toBeCalled();
|
||||
expect(cb).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not dispatch to a subscriber that registers mid-dispatch', async () => {
|
||||
@@ -164,8 +164,8 @@ describe('EventWatcher', () => {
|
||||
|
||||
fireEvent(hass, createHASSEvent('zha_event', { command: 'press' }));
|
||||
|
||||
expect(reentrantCallback).toBeCalledTimes(1);
|
||||
expect(lateCallback).not.toBeCalled();
|
||||
expect(reentrantCallback).toHaveBeenCalledTimes(1);
|
||||
expect(lateCallback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('subscription health monitoring', () => {
|
||||
|
||||
@@ -4,16 +4,10 @@ import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { EventWatcher } from '../../../src/card-controller/hass/event-watcher';
|
||||
import { HASSManager } from '../../../src/card-controller/hass/hass-manager';
|
||||
import { StateWatcher } from '../../../src/card-controller/hass/state-watcher';
|
||||
import {
|
||||
createCameraConfig,
|
||||
createCameraManager,
|
||||
createCardAPI,
|
||||
createConfig,
|
||||
createHASS,
|
||||
createStateEntity,
|
||||
createStore,
|
||||
createView,
|
||||
} from '../../test-utils';
|
||||
import { createCameraManager, createStore } from '../../camera-manager/test-utils';
|
||||
import { createCameraConfig, createConfig } from '../../config/test-utils';
|
||||
import { createCardAPI, createHASS, createStateEntity } from '../../test-utils';
|
||||
import { createView } from '../../view/test-utils';
|
||||
|
||||
describe('HASSManager', () => {
|
||||
beforeEach(() => {
|
||||
@@ -53,11 +47,11 @@ describe('HASSManager', () => {
|
||||
|
||||
const hass1 = createHASS();
|
||||
manager.setHASS(hass1);
|
||||
expect(listener).toBeCalledWith(hass1, null);
|
||||
expect(listener).toHaveBeenCalledWith(hass1, null);
|
||||
|
||||
const hass2 = createHASS();
|
||||
manager.setHASS(hass2);
|
||||
expect(listener).toBeCalledWith(hass2, hass1);
|
||||
expect(listener).toHaveBeenCalledWith(hass2, hass1);
|
||||
});
|
||||
|
||||
it('should call listeners in insertion order on every fan-out', () => {
|
||||
@@ -79,7 +73,7 @@ describe('HASSManager', () => {
|
||||
unlisten();
|
||||
manager.setHASS(createHASS());
|
||||
|
||||
expect(listener).not.toBeCalled();
|
||||
expect(listener).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not fan out on null/undefined hass', () => {
|
||||
@@ -90,7 +84,7 @@ describe('HASSManager', () => {
|
||||
manager.setHASS(null);
|
||||
manager.setHASS();
|
||||
|
||||
expect(listener).not.toBeCalled();
|
||||
expect(listener).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should expose current hass via getHASS for source consumers', () => {
|
||||
@@ -128,10 +122,12 @@ describe('HASSManager', () => {
|
||||
// Cameras and view should be uninitialized so they get re-subscribed
|
||||
// to event sources (e.g. Frigate WebSocket events) on the next
|
||||
// render cycle.
|
||||
expect(api.getInitializationManager().uninitialize).toBeCalledWith('cameras');
|
||||
expect(api.getCameraManager().destroy).toBeCalled();
|
||||
expect(api.getInitializationManager().uninitialize).toBeCalledWith('view');
|
||||
expect(api.getInitializationManager().uninitialize).toBeCalledWith(
|
||||
expect(api.getInitializationManager().uninitialize).toHaveBeenCalledWith(
|
||||
'cameras',
|
||||
);
|
||||
expect(api.getCameraManager().destroy).toHaveBeenCalled();
|
||||
expect(api.getInitializationManager().uninitialize).toHaveBeenCalledWith('view');
|
||||
expect(api.getInitializationManager().uninitialize).toHaveBeenCalledWith(
|
||||
'initial-trigger',
|
||||
);
|
||||
});
|
||||
@@ -147,8 +143,8 @@ describe('HASSManager', () => {
|
||||
manager.setHASS(startingHASS);
|
||||
|
||||
// No reinit yet -- HA isn't fully ready.
|
||||
expect(api.getInitializationManager().uninitialize).not.toBeCalled();
|
||||
expect(api.getCameraManager().destroy).not.toBeCalled();
|
||||
expect(api.getInitializationManager().uninitialize).not.toHaveBeenCalled();
|
||||
expect(api.getCameraManager().destroy).not.toHaveBeenCalled();
|
||||
|
||||
// HA finishes booting.
|
||||
const readyHASS = createHASS();
|
||||
@@ -156,10 +152,12 @@ describe('HASSManager', () => {
|
||||
readyHASS.config.state = STATE_RUNNING;
|
||||
manager.setHASS(readyHASS);
|
||||
|
||||
expect(api.getInitializationManager().uninitialize).toBeCalledWith('cameras');
|
||||
expect(api.getCameraManager().destroy).toBeCalled();
|
||||
expect(api.getInitializationManager().uninitialize).toBeCalledWith('view');
|
||||
expect(api.getInitializationManager().uninitialize).toBeCalledWith(
|
||||
expect(api.getInitializationManager().uninitialize).toHaveBeenCalledWith(
|
||||
'cameras',
|
||||
);
|
||||
expect(api.getCameraManager().destroy).toHaveBeenCalled();
|
||||
expect(api.getInitializationManager().uninitialize).toHaveBeenCalledWith('view');
|
||||
expect(api.getInitializationManager().uninitialize).toHaveBeenCalledWith(
|
||||
'initial-trigger',
|
||||
);
|
||||
});
|
||||
@@ -178,8 +176,8 @@ describe('HASSManager', () => {
|
||||
manager.setHASS(startingHASS);
|
||||
|
||||
// WS came back but integrations still loading -- wait for RUNNING.
|
||||
expect(api.getInitializationManager().uninitialize).not.toBeCalled();
|
||||
expect(api.getCameraManager().destroy).not.toBeCalled();
|
||||
expect(api.getInitializationManager().uninitialize).not.toHaveBeenCalled();
|
||||
expect(api.getCameraManager().destroy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not reinitialize on first hass set (no previous hass)', () => {
|
||||
@@ -194,8 +192,8 @@ describe('HASSManager', () => {
|
||||
// First-ever hass set -- there's no "previous not-ready state" to
|
||||
// transition from, so the normal first-load init flow applies and we must
|
||||
// not blow away cameras.
|
||||
expect(api.getInitializationManager().uninitialize).not.toBeCalled();
|
||||
expect(api.getCameraManager().destroy).not.toBeCalled();
|
||||
expect(api.getInitializationManager().uninitialize).not.toHaveBeenCalled();
|
||||
expect(api.getCameraManager().destroy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not reinitialize on ready → ready (no transition)', () => {
|
||||
@@ -212,8 +210,8 @@ describe('HASSManager', () => {
|
||||
anotherReadyHASS.config.state = STATE_RUNNING;
|
||||
manager.setHASS(anotherReadyHASS);
|
||||
|
||||
expect(api.getInitializationManager().uninitialize).not.toBeCalled();
|
||||
expect(api.getCameraManager().destroy).not.toBeCalled();
|
||||
expect(api.getInitializationManager().uninitialize).not.toHaveBeenCalled();
|
||||
expect(api.getCameraManager().destroy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not crash when hass is null', () => {
|
||||
@@ -257,7 +255,7 @@ describe('HASSManager', () => {
|
||||
|
||||
manager.setHASS(hass);
|
||||
|
||||
expect(api.getViewManager().setViewDefault).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewDefault).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not set default view when there is card interaction', () => {
|
||||
@@ -280,7 +278,7 @@ describe('HASSManager', () => {
|
||||
|
||||
manager.setHASS(hass);
|
||||
|
||||
expect(api.getViewManager().setViewDefault).not.toBeCalled();
|
||||
expect(api.getViewManager().setViewDefault).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user