fix: Prevent "action loops" (#1978)

- Closes: #1967
- Closes: #1969
This commit is contained in:
Dermot Duffy
2025-03-22 18:39:36 -07:00
committed by GitHub
parent d6225fefda
commit 8512df1720
6 changed files with 75 additions and 15 deletions
@@ -206,7 +206,7 @@ describe('ActionsManager', () => {
vi.restoreAllMocks();
});
it('should handle event', async () => {
it('should handle advanced camera card event', async () => {
const action = createLogAction('Hello, world!');
const event = new CustomEvent('ll-custom', {
detail: action,
@@ -220,6 +220,27 @@ describe('ActionsManager', () => {
expect(consoleSpy).toBeCalled();
});
it('should not handle generic event', async () => {
const event = new CustomEvent('ll-custom', {
detail: {
type: 'fire-dom-event',
foo: 'bar',
},
});
const card = document.createElement('div');
const handler = vi.fn();
card.addEventListener('ll-custom', handler);
const api = createCardAPI();
vi.mocked(api.getCardElementManager().getElement).mockReturnValue(card);
const manager = new ActionsManager(api);
await manager.handleCustomActionEvent(event);
expect(handler).not.toBeCalled();
});
it('should not handle event without detail', async () => {
const manager = new ActionsManager(createCardAPI());
@@ -478,7 +478,8 @@ describe('should handle ptz action', () => {
}),
},
]);
vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager(store));
const cameraManager = createCameraManager(store);
vi.mocked(api.getCameraManager).mockReturnValue(cameraManager);
vi.mocked(api.getViewManager().getView).mockReturnValue(
createView({ camera: 'camera.office' }),
);
@@ -497,11 +498,24 @@ describe('should handle ptz action', () => {
await vi.runOnlyPendingTimersAsync();
expect(api.getCameraManager().executePTZAction).toBeCalledTimes(2);
// Emulate the stop being called while the action is running, but before
// the *next* timer is scheduled.
let resolve: () => void;
const promise: Promise<void> = new Promise((_resolve) => {
resolve = _resolve;
});
vi.mocked(cameraManager.executePTZAction).mockReturnValueOnce(promise);
await vi.runOnlyPendingTimersAsync();
expect(api.getCameraManager().executePTZAction).toBeCalledTimes(3);
action.stop();
resolve!();
await vi.runOnlyPendingTimersAsync();
// There should be no additional calls.
expect(api.getCameraManager().executePTZAction).toBeCalledTimes(2);
expect(api.getCameraManager().executePTZAction).toBeCalledTimes(3);
});
});
});