816 lines
23 KiB
TypeScript
816 lines
23 KiB
TypeScript
import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest';
|
|
import { mock } from 'vitest-mock-extended';
|
|
|
|
import { Capabilities } from '../../../../src/camera-manager/capabilities';
|
|
import { PTZAction } from '../../../../src/card-controller/actions/actions/ptz';
|
|
import type { Action } from '../../../../src/card-controller/actions/types';
|
|
import { PTZMovementType } from '../../../../src/types';
|
|
import { createCameraManager, createStore } from '../../../camera-manager/test-utils';
|
|
import { createCameraConfig } from '../../../config/test-utils';
|
|
import { createCardAPI } from '../../../test-utils';
|
|
import { createView } from '../../../view/test-utils';
|
|
|
|
describe('should handle ptz action', () => {
|
|
it('should execute simple action', async () => {
|
|
const api = createCardAPI();
|
|
vi.mocked(api.getViewManager().getView).mockReturnValue(
|
|
createView({
|
|
camera: 'camera.office',
|
|
}),
|
|
);
|
|
const store = createStore([
|
|
{
|
|
cameraID: 'camera.office',
|
|
capabilities: new Capabilities({ ptz: { left: [PTZMovementType.Relative] } }),
|
|
},
|
|
]);
|
|
vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager(store));
|
|
|
|
const action = new PTZAction(
|
|
{},
|
|
{
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'ptz',
|
|
ptz_action: 'left',
|
|
camera: 'camera.office',
|
|
},
|
|
);
|
|
|
|
await action.execute(api);
|
|
|
|
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledWith(
|
|
'camera.office',
|
|
'left',
|
|
{
|
|
phase: undefined,
|
|
preset: undefined,
|
|
},
|
|
);
|
|
});
|
|
|
|
describe('without explicit camera', () => {
|
|
it('when current camera supports PTZ', async () => {
|
|
const api = createCardAPI();
|
|
const store = createStore([
|
|
{
|
|
cameraID: 'camera.office',
|
|
capabilities: new Capabilities({ ptz: { left: [PTZMovementType.Relative] } }),
|
|
},
|
|
]);
|
|
vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager(store));
|
|
vi.mocked(api.getViewManager().getView).mockReturnValue(
|
|
createView({ camera: 'camera.office' }),
|
|
);
|
|
|
|
const action = new PTZAction(
|
|
{},
|
|
{
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'ptz',
|
|
ptz_action: 'left',
|
|
},
|
|
);
|
|
|
|
await action.execute(api);
|
|
|
|
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledWith(
|
|
'camera.office',
|
|
'left',
|
|
{
|
|
phase: undefined,
|
|
preset: undefined,
|
|
},
|
|
);
|
|
});
|
|
|
|
it('when substream supports PTZ', async () => {
|
|
const api = createCardAPI();
|
|
const store = createStore([
|
|
{
|
|
cameraID: 'camera.office',
|
|
config: createCameraConfig({
|
|
dependencies: { cameras: ['camera.office_hd'] },
|
|
}),
|
|
},
|
|
{
|
|
cameraID: 'camera.office_hd',
|
|
capabilities: new Capabilities({ ptz: { left: [PTZMovementType.Relative] } }),
|
|
},
|
|
]);
|
|
vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager(store));
|
|
vi.mocked(api.getViewManager().getView).mockReturnValue(
|
|
createView({
|
|
camera: 'camera.office',
|
|
context: {
|
|
live: {
|
|
overrides: new Map([['camera.office', 'camera.office_hd']]),
|
|
},
|
|
},
|
|
}),
|
|
);
|
|
|
|
const action = new PTZAction(
|
|
{},
|
|
{
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'ptz',
|
|
ptz_action: 'left',
|
|
},
|
|
);
|
|
|
|
await action.execute(api);
|
|
|
|
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledWith(
|
|
'camera.office_hd',
|
|
'left',
|
|
{
|
|
phase: undefined,
|
|
preset: undefined,
|
|
},
|
|
);
|
|
});
|
|
|
|
it('when no camera supports PTZ', async () => {
|
|
const api = createCardAPI();
|
|
vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager());
|
|
vi.mocked(api.getViewManager().getView).mockReturnValue(
|
|
createView({ camera: 'camera.office' }),
|
|
);
|
|
|
|
const action = new PTZAction(
|
|
{},
|
|
{
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'ptz',
|
|
ptz_action: 'left',
|
|
},
|
|
);
|
|
|
|
await action.execute(api);
|
|
|
|
expect(api.getCameraManager().executePTZAction).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
it('when there is no view', async () => {
|
|
const api = createCardAPI();
|
|
vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager());
|
|
|
|
const action = new PTZAction(
|
|
{},
|
|
{
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'ptz',
|
|
ptz_action: 'left',
|
|
},
|
|
);
|
|
|
|
await action.execute(api);
|
|
|
|
expect(api.getCameraManager().executePTZAction).not.toHaveBeenCalled();
|
|
});
|
|
|
|
describe('when there is no action', () => {
|
|
it('should call first preset', async () => {
|
|
const api = createCardAPI();
|
|
const store = createStore([
|
|
{
|
|
cameraID: 'camera.office',
|
|
capabilities: new Capabilities({ ptz: { presets: ['home'] } }),
|
|
},
|
|
]);
|
|
vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager(store));
|
|
vi.mocked(api.getViewManager().getView).mockReturnValue(
|
|
createView({ camera: 'camera.office' }),
|
|
);
|
|
|
|
const action = new PTZAction(
|
|
{},
|
|
{
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'ptz',
|
|
},
|
|
);
|
|
|
|
await action.execute(api);
|
|
|
|
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledWith(
|
|
'camera.office',
|
|
'preset',
|
|
{
|
|
phase: undefined,
|
|
preset: 'home',
|
|
},
|
|
);
|
|
});
|
|
|
|
it('should call configured home preset in preference to first preset', async () => {
|
|
// See: https://github.com/dermotduffy/advanced-camera-card/issues/2525
|
|
const api = createCardAPI();
|
|
const store = createStore([
|
|
{
|
|
cameraID: 'camera.office',
|
|
config: createCameraConfig({
|
|
ptz: {
|
|
presets: {
|
|
home: {
|
|
action: 'perform-action',
|
|
perform_action: 'button.press',
|
|
data: { entity_id: 'button.office_guard' },
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
// An engine (e.g. Reolink) auto-detects presets that would otherwise
|
|
// shadow the configured home action.
|
|
capabilities: new Capabilities({
|
|
ptz: { presets: ['Staw', 'Piwnica'] },
|
|
}),
|
|
},
|
|
]);
|
|
vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager(store));
|
|
vi.mocked(api.getViewManager().getView).mockReturnValue(
|
|
createView({ camera: 'camera.office' }),
|
|
);
|
|
|
|
const action = new PTZAction(
|
|
{},
|
|
{
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'ptz',
|
|
},
|
|
);
|
|
|
|
await action.execute(api);
|
|
|
|
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledWith(
|
|
'camera.office',
|
|
'preset',
|
|
{
|
|
phase: undefined,
|
|
preset: 'home',
|
|
},
|
|
);
|
|
});
|
|
|
|
it('should call first preset when no home preset is configured', async () => {
|
|
const api = createCardAPI();
|
|
const store = createStore([
|
|
{
|
|
cameraID: 'camera.office',
|
|
config: createCameraConfig({
|
|
ptz: {
|
|
presets: {
|
|
window: {
|
|
action: 'perform-action',
|
|
perform_action: 'button.press',
|
|
data: { entity_id: 'button.office_window' },
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
capabilities: new Capabilities({
|
|
ptz: { presets: ['Staw', 'Piwnica'] },
|
|
}),
|
|
},
|
|
]);
|
|
vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager(store));
|
|
vi.mocked(api.getViewManager().getView).mockReturnValue(
|
|
createView({ camera: 'camera.office' }),
|
|
);
|
|
|
|
const action = new PTZAction(
|
|
{},
|
|
{
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'ptz',
|
|
},
|
|
);
|
|
|
|
await action.execute(api);
|
|
|
|
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledWith(
|
|
'camera.office',
|
|
'preset',
|
|
{
|
|
phase: undefined,
|
|
preset: 'Staw',
|
|
},
|
|
);
|
|
});
|
|
|
|
it('should not call preset when there are no presets', async () => {
|
|
const api = createCardAPI();
|
|
const store = createStore([
|
|
{
|
|
cameraID: 'camera.office',
|
|
capabilities: new Capabilities({
|
|
ptz: {
|
|
left: [PTZMovementType.Relative],
|
|
presets: [],
|
|
},
|
|
}),
|
|
},
|
|
]);
|
|
vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager(store));
|
|
vi.mocked(api.getViewManager().getView).mockReturnValue(
|
|
createView({ camera: 'camera.office' }),
|
|
);
|
|
|
|
const action = new PTZAction(
|
|
{},
|
|
{
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'ptz',
|
|
},
|
|
);
|
|
|
|
await action.execute(api);
|
|
|
|
expect(api.getCameraManager().executePTZAction).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
it('should execute preset', async () => {
|
|
const api = createCardAPI();
|
|
const store = createStore([
|
|
{
|
|
cameraID: 'camera.office',
|
|
capabilities: new Capabilities({
|
|
ptz: {
|
|
presets: ['window'],
|
|
},
|
|
}),
|
|
},
|
|
]);
|
|
vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager(store));
|
|
vi.mocked(api.getViewManager().getView).mockReturnValue(
|
|
createView({ camera: 'camera.office' }),
|
|
);
|
|
|
|
const action = new PTZAction(
|
|
{},
|
|
{
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'ptz',
|
|
ptz_action: 'preset',
|
|
ptz_preset: 'window',
|
|
},
|
|
);
|
|
|
|
await action.execute(api);
|
|
|
|
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledWith(
|
|
'camera.office',
|
|
'preset',
|
|
{
|
|
phase: undefined,
|
|
preset: 'window',
|
|
},
|
|
);
|
|
});
|
|
|
|
it('should execute action with phase', async () => {
|
|
const api = createCardAPI();
|
|
const store = createStore([
|
|
{
|
|
cameraID: 'camera.office',
|
|
capabilities: new Capabilities({
|
|
ptz: {
|
|
left: [PTZMovementType.Continuous],
|
|
},
|
|
}),
|
|
},
|
|
]);
|
|
vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager(store));
|
|
vi.mocked(api.getViewManager().getView).mockReturnValue(
|
|
createView({ camera: 'camera.office' }),
|
|
);
|
|
|
|
const action = new PTZAction(
|
|
{},
|
|
{
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'ptz',
|
|
ptz_action: 'left',
|
|
ptz_phase: 'start',
|
|
},
|
|
);
|
|
|
|
await action.execute(api);
|
|
|
|
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledWith(
|
|
'camera.office',
|
|
'left',
|
|
{
|
|
phase: 'start',
|
|
},
|
|
);
|
|
});
|
|
|
|
// @vitest-environment jsdom
|
|
describe('when relative is requested but unsupported', () => {
|
|
beforeAll(() => {
|
|
vi.useFakeTimers();
|
|
});
|
|
|
|
afterAll(() => {
|
|
vi.useRealTimers();
|
|
});
|
|
|
|
it('should emulate relative', async () => {
|
|
const api = createCardAPI();
|
|
const store = createStore([
|
|
{
|
|
cameraID: 'camera.office',
|
|
capabilities: new Capabilities({
|
|
ptz: {
|
|
left: [PTZMovementType.Continuous],
|
|
},
|
|
}),
|
|
},
|
|
]);
|
|
vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager(store));
|
|
vi.mocked(api.getViewManager().getView).mockReturnValue(
|
|
createView({ camera: 'camera.office' }),
|
|
);
|
|
|
|
const action = new PTZAction(
|
|
{},
|
|
{
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'ptz',
|
|
ptz_action: 'left',
|
|
},
|
|
);
|
|
|
|
await action.execute(api);
|
|
|
|
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledWith(
|
|
'camera.office',
|
|
'left',
|
|
{
|
|
phase: 'start',
|
|
},
|
|
);
|
|
|
|
vi.runOnlyPendingTimers();
|
|
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledWith(
|
|
'camera.office',
|
|
'left',
|
|
{
|
|
phase: 'stop',
|
|
},
|
|
);
|
|
});
|
|
|
|
it('should honor stop', async () => {
|
|
const api = createCardAPI();
|
|
const store = createStore([
|
|
{
|
|
cameraID: 'camera.office',
|
|
capabilities: new Capabilities({
|
|
ptz: {
|
|
left: [PTZMovementType.Continuous],
|
|
},
|
|
}),
|
|
},
|
|
]);
|
|
vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager(store));
|
|
vi.mocked(api.getViewManager().getView).mockReturnValue(
|
|
createView({ camera: 'camera.office' }),
|
|
);
|
|
|
|
const context = {};
|
|
const action = new PTZAction(context, {
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'ptz',
|
|
ptz_action: 'left',
|
|
});
|
|
|
|
await action.execute(api);
|
|
|
|
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledTimes(1);
|
|
|
|
action.stop();
|
|
vi.runOnlyPendingTimers();
|
|
|
|
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledTimes(1);
|
|
});
|
|
});
|
|
|
|
describe('when continuous is requested but unsupported', () => {
|
|
beforeAll(() => {
|
|
vi.useFakeTimers();
|
|
});
|
|
|
|
afterAll(() => {
|
|
vi.useRealTimers();
|
|
});
|
|
|
|
it('should emulate continuous', async () => {
|
|
const api = createCardAPI();
|
|
const store = createStore([
|
|
{
|
|
cameraID: 'camera.office',
|
|
capabilities: new Capabilities({
|
|
ptz: {
|
|
left: [PTZMovementType.Relative],
|
|
},
|
|
}),
|
|
},
|
|
]);
|
|
vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager(store));
|
|
vi.mocked(api.getViewManager().getView).mockReturnValue(
|
|
createView({ camera: 'camera.office' }),
|
|
);
|
|
|
|
const context = {};
|
|
const startAction = new PTZAction(context, {
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'ptz',
|
|
ptz_action: 'left',
|
|
ptz_phase: 'start',
|
|
});
|
|
await startAction.execute(api);
|
|
|
|
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledWith(
|
|
'camera.office',
|
|
'left',
|
|
{
|
|
phase: undefined,
|
|
},
|
|
);
|
|
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledTimes(1);
|
|
|
|
await vi.runOnlyPendingTimersAsync();
|
|
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledTimes(2);
|
|
|
|
await vi.runOnlyPendingTimersAsync();
|
|
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledTimes(3);
|
|
|
|
const stopAction = new PTZAction(context, {
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'ptz',
|
|
ptz_action: 'left',
|
|
ptz_phase: 'stop',
|
|
});
|
|
await stopAction.execute(api);
|
|
|
|
// There should be no additional calls.
|
|
await vi.runOnlyPendingTimersAsync();
|
|
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledTimes(3);
|
|
});
|
|
|
|
it('should honor stop', async () => {
|
|
const api = createCardAPI();
|
|
const store = createStore([
|
|
{
|
|
cameraID: 'camera.office',
|
|
capabilities: new Capabilities({
|
|
ptz: {
|
|
left: [PTZMovementType.Relative],
|
|
},
|
|
}),
|
|
},
|
|
]);
|
|
const cameraManager = createCameraManager(store);
|
|
vi.mocked(api.getCameraManager).mockReturnValue(cameraManager);
|
|
vi.mocked(api.getViewManager().getView).mockReturnValue(
|
|
createView({ camera: 'camera.office' }),
|
|
);
|
|
|
|
const context = {};
|
|
const action = new PTZAction(context, {
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'ptz',
|
|
ptz_action: 'left',
|
|
ptz_phase: 'start',
|
|
});
|
|
|
|
await action.execute(api);
|
|
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledTimes(1);
|
|
|
|
await vi.runOnlyPendingTimersAsync();
|
|
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledTimes(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).toHaveBeenCalledTimes(3);
|
|
|
|
action.stop();
|
|
|
|
resolve();
|
|
await vi.runOnlyPendingTimersAsync();
|
|
|
|
// There should be no additional calls.
|
|
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledTimes(3);
|
|
});
|
|
|
|
it('should only move for the latest of two concurrent starts', async () => {
|
|
const api = createCardAPI();
|
|
const store = createStore([
|
|
{
|
|
cameraID: 'camera.office',
|
|
capabilities: new Capabilities({
|
|
ptz: {
|
|
left: [PTZMovementType.Relative],
|
|
up: [PTZMovementType.Relative],
|
|
},
|
|
}),
|
|
},
|
|
]);
|
|
vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager(store));
|
|
vi.mocked(api.getViewManager().getView).mockReturnValue(
|
|
createView({ camera: 'camera.office' }),
|
|
);
|
|
|
|
const context = {};
|
|
const createStartAction = (ptzAction: 'left' | 'up'): PTZAction =>
|
|
new PTZAction(context, {
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'ptz',
|
|
ptz_action: ptzAction,
|
|
ptz_phase: 'start',
|
|
});
|
|
|
|
await Promise.all([
|
|
createStartAction('left').execute(api),
|
|
createStartAction('up').execute(api),
|
|
]);
|
|
|
|
// The 'up' start replaces the 'left' start before the 'left' start has
|
|
// made its first move, so only the 'up' start moves.
|
|
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledTimes(1);
|
|
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledWith(
|
|
'camera.office',
|
|
'up',
|
|
{ preset: undefined },
|
|
);
|
|
|
|
const stopAction = new PTZAction(context, {
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'ptz',
|
|
ptz_action: 'up',
|
|
ptz_phase: 'stop',
|
|
});
|
|
await stopAction.execute(api);
|
|
|
|
await vi.runOnlyPendingTimersAsync();
|
|
|
|
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('should continue movement when a stop for a different movement arrives', async () => {
|
|
const api = createCardAPI();
|
|
const store = createStore([
|
|
{
|
|
cameraID: 'camera.office',
|
|
capabilities: new Capabilities({
|
|
ptz: {
|
|
left: [PTZMovementType.Relative],
|
|
up: [PTZMovementType.Relative],
|
|
},
|
|
}),
|
|
},
|
|
]);
|
|
vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager(store));
|
|
vi.mocked(api.getViewManager().getView).mockReturnValue(
|
|
createView({ camera: 'camera.office' }),
|
|
);
|
|
|
|
const context = {};
|
|
await new PTZAction(context, {
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'ptz',
|
|
ptz_action: 'left',
|
|
ptz_phase: 'start',
|
|
}).execute(api);
|
|
|
|
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledTimes(1);
|
|
|
|
// A stop for a movement that is not in progress leaves the 'left'
|
|
// movement running.
|
|
await new PTZAction(context, {
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'ptz',
|
|
ptz_action: 'up',
|
|
ptz_phase: 'stop',
|
|
}).execute(api);
|
|
|
|
await vi.runOnlyPendingTimersAsync();
|
|
|
|
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledTimes(2);
|
|
expect(api.getCameraManager().executePTZAction).toHaveBeenLastCalledWith(
|
|
'camera.office',
|
|
'left',
|
|
{ preset: undefined },
|
|
);
|
|
|
|
await new PTZAction(context, {
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'ptz',
|
|
ptz_action: 'left',
|
|
ptz_phase: 'stop',
|
|
}).execute(api);
|
|
|
|
await vi.runOnlyPendingTimersAsync();
|
|
|
|
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledTimes(2);
|
|
});
|
|
|
|
it('should not stop an in-progress action that is not a PTZ action', async () => {
|
|
const api = createCardAPI();
|
|
const store = createStore([
|
|
{
|
|
cameraID: 'camera.office',
|
|
capabilities: new Capabilities({
|
|
ptz: {
|
|
left: [PTZMovementType.Relative],
|
|
},
|
|
}),
|
|
},
|
|
]);
|
|
vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager(store));
|
|
vi.mocked(api.getViewManager().getView).mockReturnValue(
|
|
createView({ camera: 'camera.office' }),
|
|
);
|
|
|
|
const incumbent = mock<Action>();
|
|
const context = { ptz: { 'camera.office': { inProgressAction: incumbent } } };
|
|
|
|
const stopAction = new PTZAction(context, {
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'ptz',
|
|
ptz_action: 'left',
|
|
ptz_phase: 'stop',
|
|
});
|
|
await stopAction.execute(api);
|
|
|
|
expect(incumbent.stop).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should continue movement when a start is concurrent with a stop', async () => {
|
|
const api = createCardAPI();
|
|
const store = createStore([
|
|
{
|
|
cameraID: 'camera.office',
|
|
capabilities: new Capabilities({
|
|
ptz: {
|
|
left: [PTZMovementType.Relative],
|
|
up: [PTZMovementType.Relative],
|
|
},
|
|
}),
|
|
},
|
|
]);
|
|
vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager(store));
|
|
vi.mocked(api.getViewManager().getView).mockReturnValue(
|
|
createView({ camera: 'camera.office' }),
|
|
);
|
|
|
|
const context = {};
|
|
await new PTZAction(context, {
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'ptz',
|
|
ptz_action: 'left',
|
|
ptz_phase: 'start',
|
|
}).execute(api);
|
|
|
|
const stopAction = new PTZAction(context, {
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'ptz',
|
|
ptz_action: 'left',
|
|
ptz_phase: 'stop',
|
|
});
|
|
const upAction = new PTZAction(context, {
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'ptz',
|
|
ptz_action: 'up',
|
|
ptz_phase: 'start',
|
|
});
|
|
|
|
// The left key is released as the up key is pressed.
|
|
await Promise.all([stopAction.execute(api), upAction.execute(api)]);
|
|
|
|
// One move for the left start, one for the up start.
|
|
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledTimes(2);
|
|
|
|
await vi.runOnlyPendingTimersAsync();
|
|
|
|
expect(api.getCameraManager().executePTZAction).toHaveBeenCalledTimes(3);
|
|
expect(api.getCameraManager().executePTZAction).toHaveBeenLastCalledWith(
|
|
'camera.office',
|
|
'up',
|
|
{ preset: undefined },
|
|
);
|
|
});
|
|
});
|
|
});
|