fix: Ensure a bare ptz_digital action resets the zoom (#2635)

- Closes: #2632
This commit is contained in:
Dermot Duffy
2026-07-29 23:18:06 -07:00
committed by GitHub
parent e9e6d9f833
commit a736f3dfaf
14 changed files with 258 additions and 113 deletions
@@ -0,0 +1,46 @@
import { expect, it } from 'vitest';
import { ZoomRequestViewModifier } from '../../../../src/card-controller/view/modifiers/zoom-request';
import { createView } from '../../../view/test-utils';
it('should write a request when the target has no zoom context', () => {
const view = createView();
new ZoomRequestViewModifier('target', { zoom: 3 }).modify(view);
expect(view.context?.zoom?.target.requested).toEqual({ zoom: 3 });
});
it('should preserve the observed settings of the target', () => {
const observed = {
pan: { x: 1, y: 2 },
zoom: 3,
isDefault: false,
unzoomed: false,
};
const view = createView({ context: { zoom: { target: { observed } } } });
new ZoomRequestViewModifier('target', { zoom: 4 }).modify(view);
expect(view.context?.zoom?.target.observed).toEqual(observed);
});
it('should replace an earlier request rather than merge into it', () => {
const view = createView({
context: { zoom: { target: { requested: { zoom: 3, pan: { x: 1, y: 2 } } } } },
});
new ZoomRequestViewModifier('target', { pan: { x: 5, y: 6 } }).modify(view);
expect(view.context?.zoom?.target.requested).toEqual({ pan: { x: 5, y: 6 } });
});
it('should allow an empty request to erase an earlier request', () => {
const view = createView({
context: { zoom: { target: { requested: { zoom: 3 } } } },
});
new ZoomRequestViewModifier('target', {}).modify(view);
expect(view.context?.zoom?.target.requested).toEqual({});
});
+16 -1
View File
@@ -1,7 +1,10 @@
import { vi } from 'vitest';
import { expect, vi } from 'vitest';
import type { CardController } from '../../../src/card-controller/controller';
import { applyViewModifiers } from '../../../src/card-controller/view/modifiers';
import type { ViewManagerInterface } from '../../../src/card-controller/view/types';
import type { RawAdvancedCameraCardConfig } from '../../../src/config/types';
import type { View } from '../../../src/view/view';
import {
createCameraManager,
createCapabilities,
@@ -42,3 +45,15 @@ export const createPopulatedAPI = (
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig(config));
return api;
};
// Apply the modifiers from the nth `setViewWithModifiers` call to the given
// view, so that a caller can assert on the resulting view.
export const applySetViewModifiers = (
viewManager: ViewManagerInterface,
view: View,
n = 0,
): View => {
const mock = vi.mocked(viewManager.setViewWithModifiers).mock;
expect(mock.calls.length).greaterThan(n);
return applyViewModifiers(view, mock.calls[n][0]);
};
@@ -4,6 +4,7 @@ import { mock } from 'vitest-mock-extended';
import type { CardController } from '../../../src/card-controller/controller';
import type { ViewFactory } from '../../../src/card-controller/view/factory';
import { MergeContextViewModifier } from '../../../src/card-controller/view/modifiers/merge-context';
import { SetQueryViewModifier } from '../../../src/card-controller/view/modifiers/set-query';
import type {
QueryExecutorOptions,
@@ -131,6 +132,26 @@ it('should set view with merged context', () => {
expect(manager.getView()?.context).toEqual(context);
});
it('should set view with modifiers', () => {
const api = createInitializedCardAPI();
const factory = mock<ViewFactory>();
const manager = new ViewManager(api, { viewFactory: factory });
const modifier = new MergeContextViewModifier({ timeline: {} });
// Applying modifiers with no existing view does nothing.
manager.setViewWithModifiers([modifier]);
expect(manager.getView()).toBeNull();
factory.getViewDefault.mockReturnValue(createView({ view: 'live', camera: 'camera' }));
manager.setViewDefault();
manager.setViewWithModifiers([modifier]);
expect(manager.getView()?.camera).toBe('camera');
expect(manager.getView()?.view).toBe('live');
expect(manager.getView()?.context).toEqual({ timeline: {} });
});
it('should return epoch', () => {
const factory = mock<ViewFactory>();
const manager = new ViewManager(createCardAPI(), { viewFactory: factory });