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

This commit is contained in:
Dermot Duffy
2026-07-26 16:29:53 -07:00
committed by GitHub
parent 8d44fcecf1
commit ad89aa9538
234 changed files with 2730 additions and 2516 deletions
+6 -6
View File
@@ -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);
});
});
});
+1 -1
View File
@@ -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);
});
});
+1 -1
View File
@@ -15,7 +15,7 @@ describe('fireHASSEvent', () => {
fireHASSEvent(target, type, detail);
expect(handler).toBeCalledWith(
expect(handler).toHaveBeenCalledWith(
expect.objectContaining({
detail,
}),
+1 -1
View File
@@ -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);
});
});
+13 -10
View File
@@ -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',
});
});
});
+1 -1
View File
@@ -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,
});
});
+20 -18
View File
@@ -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(
+38 -35
View File
@@ -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(
+2 -2
View File
@@ -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
View File
@@ -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,
);
});
});
+4 -4
View File
@@ -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/);
});
});