159 lines
5.2 KiB
TypeScript
159 lines
5.2 KiB
TypeScript
import { describe, expect, it, vi, type Mock } from 'vitest';
|
|
|
|
import { ConditionStateManager } from '../../../../src/condition-trigger/conditions/state-manager';
|
|
import { CameraTrigger } from '../../../../src/condition-trigger/triggers/triggers/camera';
|
|
import type { TriggerOfType } from '../../../../src/condition-trigger/triggers/triggers/types';
|
|
import { createConfig } from '../../../config/test-utils';
|
|
import { createTriggerEvaluatorContext } from './test-utils';
|
|
|
|
describe('CameraTrigger', () => {
|
|
const create = (
|
|
trigger: TriggerOfType<'camera'>,
|
|
): {
|
|
cameraTrigger: CameraTrigger;
|
|
stateManager: ConditionStateManager;
|
|
callback: Mock;
|
|
} => {
|
|
const stateManager = new ConditionStateManager();
|
|
const callback = vi.fn();
|
|
const cameraTrigger = new CameraTrigger(
|
|
trigger,
|
|
createTriggerEvaluatorContext({ stateManager }),
|
|
);
|
|
return { cameraTrigger, stateManager, callback };
|
|
};
|
|
|
|
it('should trigger when the selected camera changes to a listed one', () => {
|
|
const { cameraTrigger, stateManager, callback } = create({
|
|
trigger: 'camera',
|
|
cameras: ['front', 'back'],
|
|
});
|
|
cameraTrigger.subscribe(callback);
|
|
|
|
// An unlisted camera does not trigger.
|
|
stateManager.setState({ camera: 'side' });
|
|
expect(callback).not.toHaveBeenCalled();
|
|
|
|
// Crossing to a listed camera triggers, with the before/after trigger data.
|
|
stateManager.setState({ camera: 'front' });
|
|
expect(callback).toHaveBeenCalledTimes(1);
|
|
expect(callback).toHaveBeenCalledWith({
|
|
platform: 'acc',
|
|
type: 'camera',
|
|
from_acc: { camera: 'side' },
|
|
to_acc: { camera: 'front' },
|
|
});
|
|
});
|
|
|
|
it('should trigger again when the camera changes between two listed cameras', () => {
|
|
const { cameraTrigger, stateManager, callback } = create({
|
|
trigger: 'camera',
|
|
cameras: ['front', 'back'],
|
|
});
|
|
cameraTrigger.subscribe(callback);
|
|
|
|
stateManager.setState({ camera: 'front' });
|
|
expect(callback).toHaveBeenCalledTimes(1);
|
|
|
|
// Still matching, but the camera moved: triggers again.
|
|
stateManager.setState({ camera: 'back' });
|
|
expect(callback).toHaveBeenCalledTimes(2);
|
|
expect(callback).toHaveBeenLastCalledWith({
|
|
platform: 'acc',
|
|
type: 'camera',
|
|
from_acc: { camera: 'front' },
|
|
to_acc: { camera: 'back' },
|
|
});
|
|
});
|
|
|
|
it('should not trigger on an unrelated state change while the camera is unchanged', () => {
|
|
const { cameraTrigger, stateManager, callback } = create({
|
|
trigger: 'camera',
|
|
cameras: ['front'],
|
|
});
|
|
cameraTrigger.subscribe(callback);
|
|
|
|
stateManager.setState({ camera: 'front' });
|
|
expect(callback).toHaveBeenCalledTimes(1);
|
|
|
|
stateManager.setState({ fullscreen: true });
|
|
expect(callback).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('should not trigger once the camera leaves the listed set', () => {
|
|
const { cameraTrigger, stateManager, callback } = create({
|
|
trigger: 'camera',
|
|
cameras: ['front'],
|
|
});
|
|
cameraTrigger.subscribe(callback);
|
|
|
|
stateManager.setState({ camera: 'front' });
|
|
expect(callback).toHaveBeenCalledTimes(1);
|
|
|
|
stateManager.setState({ camera: 'side' });
|
|
expect(callback).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('should trigger on any camera change without a listed set', () => {
|
|
const { cameraTrigger, stateManager, callback } = create({ trigger: 'camera' });
|
|
cameraTrigger.subscribe(callback);
|
|
|
|
stateManager.setState({ camera: 'side' });
|
|
expect(callback).toHaveBeenCalledTimes(1);
|
|
|
|
stateManager.setState({ camera: 'front' });
|
|
expect(callback).toHaveBeenCalledTimes(2);
|
|
|
|
// An unrelated change leaves the camera unchanged: no trigger.
|
|
stateManager.setState({ fullscreen: true });
|
|
expect(callback).toHaveBeenCalledTimes(2);
|
|
});
|
|
|
|
it('should trigger only when the camera becomes unselected for an empty list', () => {
|
|
const { cameraTrigger, stateManager, callback } = create({
|
|
trigger: 'camera',
|
|
cameras: [],
|
|
});
|
|
cameraTrigger.subscribe(callback);
|
|
|
|
// Changing between cameras does not trigger.
|
|
stateManager.setState({ camera: 'front' });
|
|
stateManager.setState({ camera: 'back' });
|
|
expect(callback).not.toHaveBeenCalled();
|
|
|
|
// Becoming unselected triggers.
|
|
stateManager.setState({ camera: undefined });
|
|
expect(callback).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('should include camera, view and config in the trigger data', () => {
|
|
const config = createConfig();
|
|
const { cameraTrigger, stateManager, callback } = create({
|
|
trigger: 'camera',
|
|
cameras: ['front'],
|
|
});
|
|
cameraTrigger.subscribe(callback);
|
|
|
|
stateManager.setState({ camera: 'side', view: 'live', config });
|
|
stateManager.setState({ camera: 'front' });
|
|
expect(callback).toHaveBeenLastCalledWith({
|
|
platform: 'acc',
|
|
type: 'camera',
|
|
from_acc: { camera: 'side', view: 'live', config },
|
|
to_acc: { camera: 'front', view: 'live', config },
|
|
});
|
|
});
|
|
|
|
it('should stop triggering after destroy', () => {
|
|
const { cameraTrigger, stateManager, callback } = create({
|
|
trigger: 'camera',
|
|
cameras: ['front'],
|
|
});
|
|
cameraTrigger.subscribe(callback);
|
|
cameraTrigger.destroy();
|
|
|
|
stateManager.setState({ camera: 'front' });
|
|
expect(callback).not.toHaveBeenCalled();
|
|
});
|
|
});
|