test: Split test utilities to improve test times (#2622)
This commit is contained in:
@@ -44,7 +44,7 @@ describe('BrowseMediaWalker', () => {
|
||||
},
|
||||
]);
|
||||
|
||||
expect(homeAssistantWSRequest).toBeCalledWith(hass, browseMediaSchema, {
|
||||
expect(homeAssistantWSRequest).toHaveBeenCalledWith(hass, browseMediaSchema, {
|
||||
type: 'media_source/browse_media',
|
||||
media_content_id: 'media/parent',
|
||||
});
|
||||
@@ -80,7 +80,7 @@ describe('BrowseMediaWalker', () => {
|
||||
|
||||
const result = await walker.walk(hass, steps);
|
||||
|
||||
expect(homeAssistantWSRequest).toBeCalledWith(hass, browseMediaSchema, {
|
||||
expect(homeAssistantWSRequest).toHaveBeenCalledWith(hass, browseMediaSchema, {
|
||||
type: 'media_source/browse_media',
|
||||
media_content_id: 'media/parent',
|
||||
});
|
||||
@@ -330,8 +330,8 @@ describe('BrowseMediaWalker', () => {
|
||||
const result = await walker.walk(hass, steps);
|
||||
|
||||
expect(result).toEqual([child_1]);
|
||||
expect(homeAssistantWSRequest).toBeCalledTimes(1);
|
||||
expect(homeAssistantWSRequest).toBeCalledWith(hass, browseMediaSchema, {
|
||||
expect(homeAssistantWSRequest).toHaveBeenCalledTimes(1);
|
||||
expect(homeAssistantWSRequest).toHaveBeenCalledWith(hass, browseMediaSchema, {
|
||||
type: 'media_source/browse_media',
|
||||
media_content_id: 'media/parent-1',
|
||||
});
|
||||
@@ -418,14 +418,14 @@ describe('BrowseMediaWalker', () => {
|
||||
child,
|
||||
]);
|
||||
|
||||
expect(homeAssistantWSRequest).toBeCalledTimes(1);
|
||||
expect(homeAssistantWSRequest).toHaveBeenCalledTimes(1);
|
||||
expect(cache.has('media/parent')).toBe(true);
|
||||
expect(cache.get('media/parent')).toEqual(parent);
|
||||
|
||||
expect(await walker.walk(hass, [{ targets: ['media/parent'] }], { cache })).toEqual([
|
||||
child,
|
||||
]);
|
||||
expect(homeAssistantWSRequest).toBeCalledTimes(1);
|
||||
expect(homeAssistantWSRequest).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should process multiple targets and combine their children', async () => {
|
||||
|
||||
@@ -82,15 +82,15 @@ describe('SubscriptionHealthMonitor', () => {
|
||||
|
||||
// Healthy -> failing: one notification.
|
||||
monitor.update(status('failing', request, 'zha_event', { failureCount: 1 }));
|
||||
expect(listener).toBeCalledTimes(1);
|
||||
expect(listener).toHaveBeenCalledTimes(1);
|
||||
|
||||
// Still failing (next attempt, same key): no membership change, no notify.
|
||||
monitor.update(status('failing', request, 'zha_event', { failureCount: 2 }));
|
||||
expect(listener).toBeCalledTimes(1);
|
||||
expect(listener).toHaveBeenCalledTimes(1);
|
||||
|
||||
// Failing -> healthy: one more notification.
|
||||
monitor.update(status('subscribed', request, 'zha_event'));
|
||||
expect(listener).toBeCalledTimes(2);
|
||||
expect(listener).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('should stop notifying after the returned unsubscribe is called', () => {
|
||||
@@ -101,7 +101,7 @@ describe('SubscriptionHealthMonitor', () => {
|
||||
remove();
|
||||
monitor.update(status('failing', { id: 'a' }, 'zha_event', { failureCount: 1 }));
|
||||
|
||||
expect(listener).not.toBeCalled();
|
||||
expect(listener).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should retry one request per failing key and leave healthy keys alone', () => {
|
||||
@@ -120,7 +120,7 @@ describe('SubscriptionHealthMonitor', () => {
|
||||
|
||||
// Exactly one retry, for one of the failing key's requests; never the
|
||||
// healthy key.
|
||||
expect(retry).toBeCalledTimes(1);
|
||||
expect(retry).toHaveBeenCalledTimes(1);
|
||||
expect([failingA, failingB]).toContainEqual(retry.mock.calls[0][0]);
|
||||
});
|
||||
|
||||
@@ -136,8 +136,8 @@ describe('SubscriptionHealthMonitor', () => {
|
||||
|
||||
monitor.retry();
|
||||
|
||||
expect(retry).toBeCalledTimes(1);
|
||||
expect(retry).toBeCalledWith(failing);
|
||||
expect(retry).toHaveBeenCalledTimes(1);
|
||||
expect(retry).toHaveBeenCalledWith(failing);
|
||||
});
|
||||
|
||||
it('should retry one request for each distinct failing key', () => {
|
||||
@@ -151,7 +151,7 @@ describe('SubscriptionHealthMonitor', () => {
|
||||
|
||||
monitor.retry();
|
||||
|
||||
expect(retry).toBeCalledTimes(2);
|
||||
expect(retry).toHaveBeenCalledTimes(2);
|
||||
expect(retry.mock.calls.map((c) => c[0])).toEqual(expect.arrayContaining([a, b]));
|
||||
});
|
||||
|
||||
@@ -162,7 +162,7 @@ describe('SubscriptionHealthMonitor', () => {
|
||||
|
||||
monitor.update(status('unsubscribed', { id: 'a' }, 'zha_event'));
|
||||
|
||||
expect(listener).not.toBeCalled();
|
||||
expect(listener).not.toHaveBeenCalled();
|
||||
expect(monitor.getFailures()).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -189,7 +189,7 @@ describe('HASSConnectionSubscriptionManager', () => {
|
||||
await flushPromises();
|
||||
|
||||
// The old era's subscription is closed, not abandoned.
|
||||
expect(calls[0].unsub).toBeCalledTimes(1);
|
||||
expect(calls[0].unsub).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should close old-era subscriptions when HA goes not-ready', async () => {
|
||||
@@ -206,7 +206,7 @@ describe('HASSConnectionSubscriptionManager', () => {
|
||||
push(notReady);
|
||||
await flushPromises();
|
||||
|
||||
expect(calls[0].unsub).toBeCalledTimes(1);
|
||||
expect(calls[0].unsub).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should mint a fresh era when reanimating from a dead not-ready era, even with the same Connection', async () => {
|
||||
@@ -330,14 +330,14 @@ describe('HASSConnectionSubscriptionManager', () => {
|
||||
|
||||
manager.subscribe({ key: 'a' }, failing);
|
||||
await vi.advanceTimersByTimeAsync(0);
|
||||
expect(failing).toBeCalledTimes(1);
|
||||
expect(failing).toHaveBeenCalledTimes(1);
|
||||
|
||||
// HASS pushes do not retry while the retry-timer is scheduled.
|
||||
for (let i = 0; i < 10; i++) {
|
||||
push(hass);
|
||||
await vi.advanceTimersByTimeAsync(0);
|
||||
}
|
||||
expect(failing).toBeCalledTimes(1);
|
||||
expect(failing).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should retry after the backoff delay elapses', async () => {
|
||||
@@ -347,19 +347,19 @@ describe('HASSConnectionSubscriptionManager', () => {
|
||||
|
||||
manager.subscribe({ key: 'a' }, failing);
|
||||
await vi.advanceTimersByTimeAsync(0);
|
||||
expect(failing).toBeCalledTimes(1);
|
||||
expect(failing).toHaveBeenCalledTimes(1);
|
||||
|
||||
// 1st retry: ~1s.
|
||||
await vi.advanceTimersByTimeAsync(1000);
|
||||
expect(failing).toBeCalledTimes(2);
|
||||
expect(failing).toHaveBeenCalledTimes(2);
|
||||
|
||||
// 2nd retry: ~2s.
|
||||
await vi.advanceTimersByTimeAsync(2000);
|
||||
expect(failing).toBeCalledTimes(3);
|
||||
expect(failing).toHaveBeenCalledTimes(3);
|
||||
|
||||
// 3rd retry: ~4s.
|
||||
await vi.advanceTimersByTimeAsync(4000);
|
||||
expect(failing).toBeCalledTimes(4);
|
||||
expect(failing).toHaveBeenCalledTimes(4);
|
||||
});
|
||||
|
||||
it('should reset the backoff on a connection swap', async () => {
|
||||
@@ -434,13 +434,13 @@ describe('HASSConnectionSubscriptionManager', () => {
|
||||
|
||||
manager.subscribe({ key: 'a' }, openCallback);
|
||||
await flushPromises();
|
||||
expect(openCallback).toBeCalledTimes(1);
|
||||
expect(openCallback).toHaveBeenCalledTimes(1);
|
||||
|
||||
// Swap to a new connection BEFORE the first call settles.
|
||||
const hass2 = createSwappedHASS();
|
||||
push(hass2);
|
||||
await flushPromises();
|
||||
expect(openCallback).toBeCalledTimes(2);
|
||||
expect(openCallback).toHaveBeenCalledTimes(2);
|
||||
|
||||
// Now reject the stale first call. The catch must NOT wipe the marker for
|
||||
// the in-flight second submission, so the next same-connection push must
|
||||
@@ -450,7 +450,7 @@ describe('HASSConnectionSubscriptionManager', () => {
|
||||
|
||||
push(hass2);
|
||||
await flushPromises();
|
||||
expect(openCallback).toBeCalledTimes(2);
|
||||
expect(openCallback).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -474,7 +474,7 @@ describe('HASSConnectionSubscriptionManager', () => {
|
||||
manager.destroy();
|
||||
await flushPromises();
|
||||
|
||||
expect(failingUnsub).toBeCalled();
|
||||
expect(failingUnsub).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should detach source listener, drain KSM, clear state, and flip guards dead', async () => {
|
||||
@@ -511,7 +511,7 @@ describe('HASSConnectionSubscriptionManager', () => {
|
||||
await flushPromises();
|
||||
|
||||
expect(calls).toHaveLength(1);
|
||||
expect(calls[0].unsub).toBeCalledTimes(1);
|
||||
expect(calls[0].unsub).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -556,7 +556,7 @@ describe('HASSConnectionSubscriptionManager', () => {
|
||||
manager.unsubscribe(req);
|
||||
await flushPromises();
|
||||
|
||||
expect(failingUnsub).toBeCalled();
|
||||
expect(failingUnsub).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -730,17 +730,17 @@ describe('HASSConnectionSubscriptionManager', () => {
|
||||
|
||||
manager.subscribe(req, openCallback);
|
||||
await vi.advanceTimersByTimeAsync(0);
|
||||
expect(openCallback).toBeCalledTimes(1);
|
||||
expect(openCallback).toHaveBeenCalledTimes(1);
|
||||
|
||||
// Pending timer would fire ~1s from now. retry runs the second attempt
|
||||
// synchronously instead of waiting.
|
||||
manager.retry(req);
|
||||
await flushPromises();
|
||||
expect(openCallback).toBeCalledTimes(2);
|
||||
expect(openCallback).toHaveBeenCalledTimes(2);
|
||||
|
||||
// Advance well past the original 1s schedule: nothing further fires.
|
||||
await vi.advanceTimersByTimeAsync(10_000);
|
||||
expect(openCallback).toBeCalledTimes(2);
|
||||
expect(openCallback).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('should reset the backoff so the next failure schedules at the base delay', async () => {
|
||||
@@ -755,17 +755,17 @@ describe('HASSConnectionSubscriptionManager', () => {
|
||||
await vi.advanceTimersByTimeAsync(0);
|
||||
await vi.advanceTimersByTimeAsync(1000);
|
||||
await vi.advanceTimersByTimeAsync(2000);
|
||||
expect(failing).toBeCalledTimes(3);
|
||||
expect(failing).toHaveBeenCalledTimes(3);
|
||||
|
||||
// User clicks retry: counter resets. Next failure should schedule at ~1s
|
||||
// again, not ~8s.
|
||||
manager.retry(req);
|
||||
await flushPromises();
|
||||
expect(failing).toBeCalledTimes(4);
|
||||
expect(failing).toHaveBeenCalledTimes(4);
|
||||
await vi.advanceTimersByTimeAsync(999);
|
||||
expect(failing).toBeCalledTimes(4);
|
||||
expect(failing).toHaveBeenCalledTimes(4);
|
||||
await vi.advanceTimersByTimeAsync(1);
|
||||
expect(failing).toBeCalledTimes(5);
|
||||
expect(failing).toHaveBeenCalledTimes(5);
|
||||
});
|
||||
|
||||
it('should be a no-op for an unknown request', () => {
|
||||
@@ -785,18 +785,18 @@ describe('HASSConnectionSubscriptionManager', () => {
|
||||
|
||||
manager.subscribe(req, openCallback);
|
||||
await vi.advanceTimersByTimeAsync(0);
|
||||
expect(openCallback).not.toBeCalled();
|
||||
expect(openCallback).not.toHaveBeenCalled();
|
||||
|
||||
manager.retry(req);
|
||||
await flushPromises();
|
||||
expect(openCallback).not.toBeCalled();
|
||||
expect(openCallback).not.toHaveBeenCalled();
|
||||
|
||||
// Era starts; the request submits.
|
||||
const ready = createHASS();
|
||||
ready.config.state = STATE_RUNNING;
|
||||
push(ready);
|
||||
await flushPromises();
|
||||
expect(openCallback).toBeCalledTimes(1);
|
||||
expect(openCallback).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -45,6 +45,6 @@ describe('getMediaDownloadPath', () => {
|
||||
expect(await getMediaDownloadPath(hass, 'id-1', resolvedMediaCache)).toEqual({
|
||||
endpoint: 'canonicalized:/media/path.mp4',
|
||||
});
|
||||
expect(resolveMedia).toBeCalledWith(hass, 'id-1', resolvedMediaCache);
|
||||
expect(resolveMedia).toHaveBeenCalledWith(hass, 'id-1', resolvedMediaCache);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,7 +15,7 @@ describe('fireHASSEvent', () => {
|
||||
|
||||
fireHASSEvent(target, type, detail);
|
||||
|
||||
expect(handler).toBeCalledWith(
|
||||
expect(handler).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
detail,
|
||||
}),
|
||||
|
||||
@@ -20,6 +20,6 @@ describe('forwardHaptic', () => {
|
||||
])('should call fireHASSEvent with %s', (hapticType: HapticType) => {
|
||||
forwardHaptic(hapticType);
|
||||
|
||||
expect(fireHASSEvent).toBeCalledWith(window, 'haptic', hapticType);
|
||||
expect(fireHASSEvent).toHaveBeenCalledWith(window, 'haptic', hapticType);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,20 +1,23 @@
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { getIntegrationManifest } from '../../../src/ha/integration';
|
||||
import { integrationManifestSchema } from '../../../src/ha/integration/types';
|
||||
import { homeAssistantWSRequest } from '../../../src/ha/ws-request.js';
|
||||
import { createHASS } from '../../test-utils';
|
||||
|
||||
vi.mock('../../../src/ha/ws-request.js');
|
||||
|
||||
describe('getIntegrationManifest', () => {
|
||||
it('should get integration manifest', async () => {
|
||||
const hass = createHASS();
|
||||
await getIntegrationManifest(hass, 'INTEGRATION');
|
||||
expect(homeAssistantWSRequest).toHaveBeenCalledWith(
|
||||
hass,
|
||||
integrationManifestSchema,
|
||||
{ type: 'manifest/get', integration: 'INTEGRATION' },
|
||||
);
|
||||
vi.mocked(hass.callWS).mockResolvedValue({
|
||||
domain: 'INTEGRATION',
|
||||
version: '1.0',
|
||||
});
|
||||
|
||||
expect(await getIntegrationManifest(hass, 'INTEGRATION')).toEqual({
|
||||
domain: 'INTEGRATION',
|
||||
version: '1.0',
|
||||
});
|
||||
expect(hass.callWS).toHaveBeenCalledWith({
|
||||
type: 'manifest/get',
|
||||
integration: 'INTEGRATION',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -21,7 +21,7 @@ describe('isHassDifferent', () => {
|
||||
const entities = ['light.office'];
|
||||
|
||||
expect(isHassDifferent(newHass, oldHass, entities)).toBe(true);
|
||||
expect(getHassDifferences).toBeCalledWith(newHass, oldHass, entities, {
|
||||
expect(getHassDifferences).toHaveBeenCalledWith(newHass, oldHass, entities, {
|
||||
firstOnly: true,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,10 +2,9 @@ import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { DeviceRegistryManager } from '../../../../src/ha/registry/device';
|
||||
import { DeviceCache } from '../../../../src/ha/registry/device/types';
|
||||
import { homeAssistantWSRequest } from '../../../../src/ha/ws-request';
|
||||
import { AdvancedCameraCardError } from '../../../../src/types';
|
||||
import { createHASS, createRegistryDevice } from '../../../test-utils.js';
|
||||
|
||||
vi.mock('../../../../src/ha/ws-request');
|
||||
vi.spyOn(global.console, 'warn').mockImplementation(() => true);
|
||||
|
||||
describe('DeviceRegistryManager', () => {
|
||||
@@ -20,37 +19,43 @@ describe('DeviceRegistryManager', () => {
|
||||
|
||||
cache.set('test', testDevice);
|
||||
|
||||
const hass = createHASS();
|
||||
const manager = new DeviceRegistryManager(cache);
|
||||
expect(await manager.getDevice(createHASS(), 'test')).toEqual(testDevice);
|
||||
expect(await manager.getDevice(hass, 'test')).toEqual(testDevice);
|
||||
|
||||
expect(homeAssistantWSRequest).not.toHaveBeenCalled();
|
||||
expect(hass.callWS).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should fetch and cache when not cached', async () => {
|
||||
const testDevice = createRegistryDevice({ id: 'test' });
|
||||
|
||||
const hass = createHASS();
|
||||
const manager = new DeviceRegistryManager(new DeviceCache());
|
||||
vi.mocked(homeAssistantWSRequest).mockResolvedValueOnce([testDevice]);
|
||||
vi.mocked(hass.callWS).mockResolvedValueOnce([testDevice]);
|
||||
|
||||
expect(await manager.getDevice(createHASS(), 'test')).toEqual(testDevice);
|
||||
expect(homeAssistantWSRequest).toBeCalledTimes(1);
|
||||
expect(await manager.getDevice(hass, 'test')).toEqual(testDevice);
|
||||
expect(hass.callWS).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(await manager.getDevice(createHASS(), 'test')).toEqual(testDevice);
|
||||
expect(homeAssistantWSRequest).toBeCalledTimes(1);
|
||||
expect(await manager.getDevice(hass, 'test')).toEqual(testDevice);
|
||||
expect(hass.callWS).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(await manager.getDevice(createHASS(), 'missing')).toBeNull();
|
||||
expect(await manager.getDevice(hass, 'missing')).toBeNull();
|
||||
|
||||
// The fetch call is called exactly once.
|
||||
expect(homeAssistantWSRequest).toBeCalledTimes(1);
|
||||
expect(hass.callWS).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should return null when fetch fails', async () => {
|
||||
vi.mocked(homeAssistantWSRequest).mockRejectedValueOnce(new Error('Fetch error'));
|
||||
const hass = createHASS();
|
||||
vi.mocked(hass.callWS).mockRejectedValueOnce(new Error('Fetch error'));
|
||||
|
||||
const manager = new DeviceRegistryManager(new DeviceCache());
|
||||
expect(await manager.getDevice(createHASS(), 'test')).toBeNull();
|
||||
expect(await manager.getDevice(hass, 'test')).toBeNull();
|
||||
|
||||
vi.mocked(expect(console.warn)).toBeCalledWith('Fetch error');
|
||||
expect(console.warn).toHaveBeenCalledWith(
|
||||
expect.any(AdvancedCameraCardError),
|
||||
expect.anything(),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -59,10 +64,7 @@ describe('DeviceRegistryManager', () => {
|
||||
const notMatchingDevice = createRegistryDevice({ id: 'not-matching' });
|
||||
const hass = createHASS();
|
||||
|
||||
vi.mocked(homeAssistantWSRequest).mockResolvedValueOnce([
|
||||
matchingDevice,
|
||||
notMatchingDevice,
|
||||
]);
|
||||
vi.mocked(hass.callWS).mockResolvedValueOnce([matchingDevice, notMatchingDevice]);
|
||||
|
||||
const manager = new DeviceRegistryManager(new DeviceCache());
|
||||
expect(
|
||||
|
||||
@@ -2,10 +2,9 @@ import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { EntityRegistryManagerLive } from '../../../../src/ha/registry/entity';
|
||||
import { EntityCache } from '../../../../src/ha/registry/entity/types';
|
||||
import { homeAssistantWSRequest } from '../../../../src/ha/ws-request';
|
||||
import { AdvancedCameraCardError } from '../../../../src/types';
|
||||
import { createHASS, createRegistryEntity } from '../../../test-utils.js';
|
||||
|
||||
vi.mock('../../../../src/ha/ws-request');
|
||||
vi.spyOn(global.console, 'warn').mockImplementation(() => true);
|
||||
|
||||
describe('EntityRegistryManager', () => {
|
||||
@@ -20,32 +19,38 @@ describe('EntityRegistryManager', () => {
|
||||
|
||||
cache.set('test', testEntity);
|
||||
|
||||
const hass = createHASS();
|
||||
const manager = new EntityRegistryManagerLive(cache);
|
||||
expect(await manager.getEntity(createHASS(), 'test')).toEqual(testEntity);
|
||||
expect(await manager.getEntity(hass, 'test')).toEqual(testEntity);
|
||||
|
||||
expect(homeAssistantWSRequest).not.toHaveBeenCalled();
|
||||
expect(hass.callWS).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should fetch and cache when not cached', async () => {
|
||||
const testEntity = createRegistryEntity({ entity_id: 'test' });
|
||||
|
||||
const hass = createHASS();
|
||||
const manager = new EntityRegistryManagerLive(new EntityCache());
|
||||
vi.mocked(homeAssistantWSRequest).mockResolvedValueOnce(testEntity);
|
||||
vi.mocked(hass.callWS).mockResolvedValueOnce(testEntity);
|
||||
|
||||
expect(await manager.getEntity(createHASS(), 'test')).toEqual(testEntity);
|
||||
expect(homeAssistantWSRequest).toBeCalledTimes(1);
|
||||
expect(await manager.getEntity(hass, 'test')).toEqual(testEntity);
|
||||
expect(hass.callWS).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(await manager.getEntity(createHASS(), 'test')).toEqual(testEntity);
|
||||
expect(homeAssistantWSRequest).toBeCalledTimes(1);
|
||||
expect(await manager.getEntity(hass, 'test')).toEqual(testEntity);
|
||||
expect(hass.callWS).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should return null when entity does not exist', async () => {
|
||||
vi.mocked(homeAssistantWSRequest).mockRejectedValueOnce(new Error('Not found'));
|
||||
const hass = createHASS();
|
||||
vi.mocked(hass.callWS).mockRejectedValueOnce(new Error('Not found'));
|
||||
|
||||
const manager = new EntityRegistryManagerLive(new EntityCache());
|
||||
expect(await manager.getEntity(createHASS(), 'missing')).toBeNull();
|
||||
expect(await manager.getEntity(hass, 'missing')).toBeNull();
|
||||
|
||||
vi.mocked(expect(console.warn)).toBeCalledWith('Not found');
|
||||
expect(console.warn).toHaveBeenCalledWith(
|
||||
expect.any(AdvancedCameraCardError),
|
||||
expect.anything(),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -56,57 +61,58 @@ describe('EntityRegistryManager', () => {
|
||||
const cache = new EntityCache();
|
||||
cache.set('cached', cachedEntity);
|
||||
|
||||
const hass = createHASS();
|
||||
const manager = new EntityRegistryManagerLive(cache);
|
||||
vi.mocked(homeAssistantWSRequest).mockResolvedValueOnce(notCachedEntity);
|
||||
vi.mocked(homeAssistantWSRequest).mockRejectedValueOnce(new Error('Not found'));
|
||||
vi.mocked(hass.callWS).mockResolvedValueOnce(notCachedEntity);
|
||||
vi.mocked(hass.callWS).mockRejectedValueOnce(new Error('Not found'));
|
||||
|
||||
expect(
|
||||
await manager.getEntities(createHASS(), ['cached', 'not-cached', 'missing']),
|
||||
).toEqual(
|
||||
expect(await manager.getEntities(hass, ['cached', 'not-cached', 'missing'])).toEqual(
|
||||
new Map([
|
||||
['cached', cachedEntity],
|
||||
['not-cached', notCachedEntity],
|
||||
]),
|
||||
);
|
||||
|
||||
vi.mocked(expect(console.warn)).toBeCalledWith('Not found');
|
||||
expect(console.warn).toHaveBeenCalledWith(
|
||||
expect.any(AdvancedCameraCardError),
|
||||
expect.anything(),
|
||||
);
|
||||
});
|
||||
|
||||
describe('fetchEntityList', async () => {
|
||||
it('should fetch entire entity list once', async () => {
|
||||
const hass = createHASS();
|
||||
const entity = createRegistryEntity({ entity_id: 'cached' });
|
||||
vi.mocked(homeAssistantWSRequest).mockResolvedValueOnce([entity]);
|
||||
vi.mocked(hass.callWS).mockResolvedValueOnce([entity]);
|
||||
|
||||
const manager = new EntityRegistryManagerLive(new EntityCache());
|
||||
|
||||
await manager.fetchEntityList(hass);
|
||||
|
||||
expect(homeAssistantWSRequest).toBeCalledTimes(1);
|
||||
expect(homeAssistantWSRequest).toBeCalledWith(
|
||||
expect.anything(),
|
||||
expect.anything(),
|
||||
{
|
||||
type: 'config/entity_registry/list',
|
||||
},
|
||||
);
|
||||
expect(hass.callWS).toHaveBeenCalledTimes(1);
|
||||
expect(hass.callWS).toHaveBeenCalledWith({
|
||||
type: 'config/entity_registry/list',
|
||||
});
|
||||
|
||||
expect(await manager.getEntity(hass, 'cached')).toEqual(entity);
|
||||
expect(homeAssistantWSRequest).toBeCalledTimes(1);
|
||||
expect(hass.callWS).toHaveBeenCalledTimes(1);
|
||||
|
||||
await manager.fetchEntityList(hass);
|
||||
expect(homeAssistantWSRequest).toBeCalledTimes(1);
|
||||
expect(hass.callWS).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should log to console on error', async () => {
|
||||
const hass = createHASS();
|
||||
vi.mocked(homeAssistantWSRequest).mockRejectedValueOnce(new Error('Fetch error'));
|
||||
vi.mocked(hass.callWS).mockRejectedValueOnce(new Error('Fetch error'));
|
||||
|
||||
const manager = new EntityRegistryManagerLive(new EntityCache());
|
||||
|
||||
await manager.fetchEntityList(hass);
|
||||
|
||||
vi.mocked(expect(console.warn)).toBeCalledWith('Fetch error');
|
||||
expect(console.warn).toHaveBeenCalledWith(
|
||||
expect.any(AdvancedCameraCardError),
|
||||
expect.anything(),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -115,10 +121,7 @@ describe('EntityRegistryManager', () => {
|
||||
const notMatchingEntity = createRegistryEntity({ entity_id: 'not-matching' });
|
||||
const hass = createHASS();
|
||||
|
||||
vi.mocked(homeAssistantWSRequest).mockResolvedValueOnce([
|
||||
matchingEntity,
|
||||
notMatchingEntity,
|
||||
]);
|
||||
vi.mocked(hass.callWS).mockResolvedValueOnce([matchingEntity, notMatchingEntity]);
|
||||
|
||||
const manager = new EntityRegistryManagerLive(new EntityCache());
|
||||
expect(
|
||||
|
||||
@@ -58,7 +58,7 @@ describe('resolveMedia', () => {
|
||||
const cache = new ResolvedMediaCache();
|
||||
const result = await resolveMedia(hass, mediaContentID, cache);
|
||||
|
||||
expect(homeAssistantWSRequest).toBeCalledWith(
|
||||
expect(homeAssistantWSRequest).toHaveBeenCalledWith(
|
||||
hass,
|
||||
resolvedMediaSchema,
|
||||
expect.objectContaining({
|
||||
@@ -77,7 +77,7 @@ describe('resolveMedia', () => {
|
||||
const cache = new ResolvedMediaCache();
|
||||
const result = await resolveMedia(createHASS(), mediaContentID, cache);
|
||||
expect(result).toBeNull();
|
||||
expect(errorToConsole).toBeCalledWith(error);
|
||||
expect(errorToConsole).toHaveBeenCalledWith(error);
|
||||
});
|
||||
|
||||
it('does not cache null results', async () => {
|
||||
|
||||
+24
-20
@@ -4,12 +4,9 @@ import {
|
||||
homeAssistantGetSignedURLIfNecessary,
|
||||
homeAssistantSignPath,
|
||||
} from '../../src/ha/sign-path';
|
||||
import { homeAssistantWSRequest } from '../../src/ha/ws-request.js';
|
||||
import { signedPathSchema } from '../../src/types';
|
||||
import { AdvancedCameraCardError } from '../../src/types';
|
||||
import { createHASS } from '../test-utils';
|
||||
|
||||
vi.mock('../../src/ha/ws-request.js');
|
||||
|
||||
describe('homeAssistantSignPath', () => {
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
@@ -20,7 +17,7 @@ describe('homeAssistantSignPath', () => {
|
||||
const unsignedPath = 'unsigned/path';
|
||||
const expires = 42;
|
||||
|
||||
vi.mocked(homeAssistantWSRequest).mockResolvedValue({
|
||||
vi.mocked(hass.callWS).mockResolvedValue({
|
||||
path: 'signed/path',
|
||||
});
|
||||
vi.mocked(hass.hassUrl).mockImplementation((url) => 'hass:' + url);
|
||||
@@ -28,16 +25,20 @@ describe('homeAssistantSignPath', () => {
|
||||
expect(await homeAssistantSignPath(hass, unsignedPath, expires)).toEqual(
|
||||
'hass:signed/path',
|
||||
);
|
||||
expect(homeAssistantWSRequest).toBeCalledWith(hass, signedPathSchema, {
|
||||
expect(hass.callWS).toHaveBeenCalledWith({
|
||||
type: 'auth/sign_path',
|
||||
path: unsignedPath,
|
||||
expires,
|
||||
});
|
||||
});
|
||||
|
||||
it('should return null for null response', async () => {
|
||||
vi.mocked(homeAssistantWSRequest).mockResolvedValue(null);
|
||||
expect(await homeAssistantSignPath(createHASS(), 'unsigned/path', 42)).toBeNull();
|
||||
it('should throw for empty response', async () => {
|
||||
const hass = createHASS();
|
||||
vi.mocked(hass.callWS).mockResolvedValue(null);
|
||||
|
||||
await expect(homeAssistantSignPath(hass, 'unsigned/path', 42)).rejects.toThrow(
|
||||
AdvancedCameraCardError,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -47,24 +48,26 @@ describe('homeAssistantSignEndpoint', () => {
|
||||
});
|
||||
|
||||
it('should return endpoint URL without signing when sign is false', async () => {
|
||||
const hass = createHASS();
|
||||
const endpoint = { endpoint: 'http://example.com', sign: false };
|
||||
expect(await homeAssistantGetSignedURLIfNecessary(createHASS(), endpoint)).toBe(
|
||||
expect(await homeAssistantGetSignedURLIfNecessary(hass, endpoint)).toBe(
|
||||
'http://example.com',
|
||||
);
|
||||
expect(homeAssistantWSRequest).not.toHaveBeenCalled();
|
||||
expect(hass.callWS).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should return endpoint URL without signing when sign is undefined', async () => {
|
||||
const hass = createHASS();
|
||||
const endpoint = { endpoint: 'http://example.com' };
|
||||
expect(await homeAssistantGetSignedURLIfNecessary(createHASS(), endpoint)).toBe(
|
||||
expect(await homeAssistantGetSignedURLIfNecessary(hass, endpoint)).toBe(
|
||||
'http://example.com',
|
||||
);
|
||||
expect(homeAssistantWSRequest).not.toHaveBeenCalled();
|
||||
expect(hass.callWS).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should sign endpoint when sign is true', async () => {
|
||||
const hass = createHASS();
|
||||
vi.mocked(homeAssistantWSRequest).mockResolvedValue({
|
||||
vi.mocked(hass.callWS).mockResolvedValue({
|
||||
path: 'signed/path',
|
||||
});
|
||||
vi.mocked(hass.hassUrl).mockImplementation((url) => 'hass:' + url);
|
||||
@@ -73,19 +76,20 @@ describe('homeAssistantSignEndpoint', () => {
|
||||
expect(await homeAssistantGetSignedURLIfNecessary(hass, endpoint, 60)).toBe(
|
||||
'hass:signed/path',
|
||||
);
|
||||
expect(homeAssistantWSRequest).toHaveBeenCalledWith(hass, signedPathSchema, {
|
||||
expect(hass.callWS).toHaveBeenCalledWith({
|
||||
type: 'auth/sign_path',
|
||||
path: 'http://example.com',
|
||||
expires: 60,
|
||||
});
|
||||
});
|
||||
|
||||
it('should return null when signing fails', async () => {
|
||||
vi.mocked(homeAssistantWSRequest).mockResolvedValue(null);
|
||||
it('should throw when signing fails', async () => {
|
||||
const hass = createHASS();
|
||||
vi.mocked(hass.callWS).mockRejectedValue(new Error('connection lost'));
|
||||
|
||||
const endpoint = { endpoint: 'http://example.com', sign: true };
|
||||
expect(
|
||||
await homeAssistantGetSignedURLIfNecessary(createHASS(), endpoint),
|
||||
).toBeNull();
|
||||
await expect(homeAssistantGetSignedURLIfNecessary(hass, endpoint)).rejects.toThrow(
|
||||
AdvancedCameraCardError,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -38,7 +38,7 @@ describe('homeAssistantWSRequest', () => {
|
||||
|
||||
await expect(
|
||||
homeAssistantWSRequest(hass, resolvedMediaSchema, request),
|
||||
).rejects.toThrowError(/Failed to receive response/);
|
||||
).rejects.toThrow(/Failed to receive response/);
|
||||
});
|
||||
|
||||
it('should throw on empty response', async () => {
|
||||
@@ -47,7 +47,7 @@ describe('homeAssistantWSRequest', () => {
|
||||
|
||||
await expect(
|
||||
homeAssistantWSRequest(hass, resolvedMediaSchema, request),
|
||||
).rejects.toThrowError(/Received empty response/);
|
||||
).rejects.toThrow(/Received empty response/);
|
||||
});
|
||||
|
||||
it('should throw error on parse failure', async () => {
|
||||
@@ -56,7 +56,7 @@ describe('homeAssistantWSRequest', () => {
|
||||
|
||||
await expect(
|
||||
homeAssistantWSRequest(hass, resolvedMediaSchema, request),
|
||||
).rejects.toThrowError(/Received invalid response/);
|
||||
).rejects.toThrow(/Received invalid response/);
|
||||
});
|
||||
|
||||
it('should throw on JSON parse failure', async () => {
|
||||
@@ -67,6 +67,6 @@ describe('homeAssistantWSRequest', () => {
|
||||
|
||||
await expect(
|
||||
homeAssistantWSRequest(hass, resolvedMediaSchema, request, true),
|
||||
).rejects.toThrowError(/Received invalid response/);
|
||||
).rejects.toThrow(/Received invalid response/);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user