test: Split test utilities to improve test times (#2622)
This commit is contained in:
@@ -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();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -63,8 +63,8 @@ describe('StateWatcher', () => {
|
||||
}),
|
||||
);
|
||||
|
||||
expect(callback).toBeCalledTimes(1);
|
||||
expect(callback).toBeCalledWith(
|
||||
expect(callback).toHaveBeenCalledTimes(1);
|
||||
expect(callback).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
entityID: 'binary_sensor.bar',
|
||||
oldState: createStateEntity({ state: 'off' }),
|
||||
@@ -86,7 +86,7 @@ describe('StateWatcher', () => {
|
||||
}),
|
||||
);
|
||||
|
||||
expect(callback).not.toBeCalled();
|
||||
expect(callback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not call back without state change', () => {
|
||||
@@ -105,7 +105,7 @@ describe('StateWatcher', () => {
|
||||
}),
|
||||
);
|
||||
|
||||
expect(callback).not.toBeCalled();
|
||||
expect(callback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not call back when unsubscribed', () => {
|
||||
@@ -125,6 +125,6 @@ describe('StateWatcher', () => {
|
||||
}),
|
||||
);
|
||||
|
||||
expect(callback).not.toBeCalled();
|
||||
expect(callback).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user