607 lines
16 KiB
TypeScript
607 lines
16 KiB
TypeScript
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
import { mock } from 'vitest-mock-extended';
|
|
|
|
import { INTERNAL_CALLBACK_ACTION } from '../../src/config/schema/actions/custom/internal.js';
|
|
import { ActionConfig } from '../../src/config/schema/actions/types.js';
|
|
import {
|
|
createCallAnswerAction,
|
|
createCallEndAction,
|
|
createCallStartAction,
|
|
createCameraAction,
|
|
createDisplayModeAction,
|
|
createEffectAction,
|
|
createGeneralAction,
|
|
createInternalCallbackAction,
|
|
createLogAction,
|
|
createMediaPlayerAction,
|
|
createNotificationAction,
|
|
createPerformAction,
|
|
createPTZAction,
|
|
createPTZControlsAction,
|
|
createPTZDigitalAction,
|
|
createPTZMultiAction,
|
|
createSelectOptionAction,
|
|
createSetReviewAction,
|
|
createSubstreamOffAction,
|
|
createSubstreamOnAction,
|
|
createViewAction,
|
|
getActionConfigGivenAction,
|
|
getActionName,
|
|
hasAction,
|
|
isIfAction,
|
|
stopEventFromActivatingCardWideActions,
|
|
} from '../../src/utils/action.js';
|
|
|
|
describe('createGeneralAction', () => {
|
|
it('should create general action', () => {
|
|
expect(
|
|
createGeneralAction('camera_ui', {
|
|
cardID: 'card_id',
|
|
}),
|
|
).toEqual({
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'camera_ui',
|
|
card_id: 'card_id',
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('createViewAction', () => {
|
|
it('should create view action', () => {
|
|
expect(
|
|
createViewAction('clips', {
|
|
cardID: 'card_id',
|
|
}),
|
|
).toEqual({
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'clips',
|
|
card_id: 'card_id',
|
|
});
|
|
});
|
|
|
|
it.each([['folder' as const], ['folders' as const]])(
|
|
'%s',
|
|
(viewName: 'folder' | 'folders') => {
|
|
expect(
|
|
createViewAction(viewName, { folderID: 'folderID', cardID: 'card_id' }),
|
|
).toEqual({
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: viewName,
|
|
card_id: 'card_id',
|
|
folder: 'folderID',
|
|
});
|
|
},
|
|
);
|
|
});
|
|
|
|
describe('createCameraAction', () => {
|
|
it('should create camera_select action', () => {
|
|
expect(createCameraAction('camera', { cardID: 'card_id' })).toEqual({
|
|
action: 'fire-dom-event',
|
|
camera: 'camera',
|
|
advanced_camera_card_action: 'camera_select',
|
|
card_id: 'card_id',
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('createMediaPlayerAction', () => {
|
|
it('should create media_player action', () => {
|
|
expect(
|
|
createMediaPlayerAction('device', 'play', {
|
|
cardID: 'card_id',
|
|
}),
|
|
).toEqual({
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'media_player',
|
|
media_player: 'device',
|
|
media_player_action: 'play',
|
|
card_id: 'card_id',
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('createDisplayModeAction', () => {
|
|
it('should create display mode action', () => {
|
|
expect(
|
|
createDisplayModeAction('grid', {
|
|
cardID: 'card_id',
|
|
}),
|
|
).toEqual({
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'display_mode_select',
|
|
display_mode: 'grid',
|
|
card_id: 'card_id',
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('createPTZControlsAction', () => {
|
|
it('should create PTZ controls action with enabled', () => {
|
|
expect(
|
|
createPTZControlsAction({
|
|
enabled: true,
|
|
cardID: 'card_id',
|
|
}),
|
|
).toEqual({
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'ptz_controls',
|
|
enabled: true,
|
|
card_id: 'card_id',
|
|
});
|
|
});
|
|
|
|
it('should create PTZ controls action with type', () => {
|
|
expect(
|
|
createPTZControlsAction({
|
|
type: 'gestures',
|
|
}),
|
|
).toEqual({
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'ptz_controls',
|
|
type: 'gestures',
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('createPTZAction', () => {
|
|
it('should create ptz action without parameters', () => {
|
|
expect(
|
|
createPTZAction({
|
|
cardID: 'card_id',
|
|
}),
|
|
).toEqual({
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'ptz',
|
|
card_id: 'card_id',
|
|
});
|
|
});
|
|
|
|
it('should create ptz action with parameters', () => {
|
|
expect(
|
|
createPTZAction({
|
|
cardID: 'card_id',
|
|
ptzAction: 'right',
|
|
ptzPhase: 'start',
|
|
ptzPreset: 'preset',
|
|
cameraID: 'camera_id',
|
|
}),
|
|
).toEqual({
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'ptz',
|
|
card_id: 'card_id',
|
|
camera: 'camera_id',
|
|
ptz_action: 'right',
|
|
ptz_phase: 'start',
|
|
ptz_preset: 'preset',
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('createPTZDigitalAction', () => {
|
|
it('should create ptz digital without parameters', () => {
|
|
expect(
|
|
createPTZDigitalAction({
|
|
cardID: 'card_id',
|
|
}),
|
|
).toEqual({
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'ptz_digital',
|
|
card_id: 'card_id',
|
|
});
|
|
});
|
|
|
|
it('should create ptz digital with parameters', () => {
|
|
expect(
|
|
createPTZDigitalAction({
|
|
cardID: 'card_id',
|
|
targetID: 'target_id',
|
|
absolute: {
|
|
pan: { x: 1, y: 2 },
|
|
zoom: 3,
|
|
},
|
|
ptzAction: 'right',
|
|
ptzPhase: 'start',
|
|
}),
|
|
).toEqual({
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'ptz_digital',
|
|
card_id: 'card_id',
|
|
target_id: 'target_id',
|
|
absolute: {
|
|
pan: { x: 1, y: 2 },
|
|
zoom: 3,
|
|
},
|
|
ptz_action: 'right',
|
|
ptz_phase: 'start',
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('createPTZMultiAction', () => {
|
|
it('should create ptz multi with parameters', () => {
|
|
expect(
|
|
createPTZMultiAction({
|
|
cardID: 'card_id',
|
|
ptzAction: 'right',
|
|
ptzPreset: 'preset',
|
|
}),
|
|
).toEqual({
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'ptz_multi',
|
|
card_id: 'card_id',
|
|
ptz_action: 'right',
|
|
ptz_preset: 'preset',
|
|
});
|
|
});
|
|
|
|
it('should create ptz multi without parameters', () => {
|
|
expect(
|
|
createPTZMultiAction({
|
|
cardID: 'card_id',
|
|
ptzAction: 'right',
|
|
ptzPhase: 'start',
|
|
targetID: 'target_id',
|
|
}),
|
|
).toEqual({
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'ptz_multi',
|
|
card_id: 'card_id',
|
|
ptz_action: 'right',
|
|
ptz_phase: 'start',
|
|
target_id: 'target_id',
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('createLogAction', () => {
|
|
it('should create log action', () => {
|
|
expect(
|
|
createLogAction('Hello, world!', {
|
|
cardID: 'card_id',
|
|
}),
|
|
).toEqual({
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'log',
|
|
message: 'Hello, world!',
|
|
card_id: 'card_id',
|
|
level: 'info',
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('createInternalCallbackAction', () => {
|
|
it('should create internal callback action', () => {
|
|
const callback = vi.fn();
|
|
expect(
|
|
createInternalCallbackAction(callback, {
|
|
cardID: 'card_id',
|
|
}),
|
|
).toEqual({
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: INTERNAL_CALLBACK_ACTION,
|
|
callback: callback,
|
|
card_id: 'card_id',
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('createPerformAction', () => {
|
|
it('should create perform action', () => {
|
|
expect(
|
|
createPerformAction('toggle', {
|
|
cardID: 'card_id',
|
|
target: { entity_id: 'light.office_main_lights' },
|
|
data: {},
|
|
}),
|
|
).toEqual({
|
|
action: 'perform-action',
|
|
perform_action: 'toggle',
|
|
card_id: 'card_id',
|
|
target: { entity_id: 'light.office_main_lights' },
|
|
data: {},
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('createSelectOptionAction', () => {
|
|
it('should create select option action', () => {
|
|
expect(
|
|
createSelectOptionAction('select', 'select.foo', 'option', {
|
|
cardID: 'card_id',
|
|
}),
|
|
).toEqual({
|
|
action: 'perform-action',
|
|
perform_action: 'select.select_option',
|
|
card_id: 'card_id',
|
|
target: { entity_id: 'select.foo' },
|
|
data: {
|
|
option: 'option',
|
|
},
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('createEffectAction', () => {
|
|
it('should create effect action', () => {
|
|
expect(
|
|
createEffectAction('snow', 'start', {
|
|
cardID: 'card_id',
|
|
}),
|
|
).toEqual({
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'effect',
|
|
effect: 'snow',
|
|
effect_action: 'start',
|
|
card_id: 'card_id',
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('createSetReviewAction', () => {
|
|
it('should create set review action', () => {
|
|
expect(createSetReviewAction(true)).toEqual({
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'set_review',
|
|
reviewed: true,
|
|
});
|
|
});
|
|
|
|
it('should create set review action with false', () => {
|
|
expect(createSetReviewAction(false)).toEqual({
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'set_review',
|
|
reviewed: false,
|
|
});
|
|
});
|
|
|
|
it('should create set review action with undefined', () => {
|
|
expect(createSetReviewAction()).toEqual({
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'set_review',
|
|
reviewed: undefined,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('createCallStartAction', () => {
|
|
it('should create call start action without a camera', () => {
|
|
expect(createCallStartAction()).toEqual({
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'call_start',
|
|
});
|
|
});
|
|
|
|
it('should create call start action with a camera, stream and cardID', () => {
|
|
expect(
|
|
createCallStartAction({
|
|
camera: 'camera.front',
|
|
stream: 'camera.front_doorbell',
|
|
cardID: 'card_id',
|
|
}),
|
|
).toEqual({
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'call_start',
|
|
camera: 'camera.front',
|
|
stream: 'camera.front_doorbell',
|
|
card_id: 'card_id',
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('createSubstreamOnAction', () => {
|
|
it('should create substream_on action without options', () => {
|
|
expect(createSubstreamOnAction()).toEqual({
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'substream_on',
|
|
});
|
|
});
|
|
|
|
it('should create substream_on action with camera, stream, and cardID', () => {
|
|
expect(
|
|
createSubstreamOnAction({
|
|
camera: 'camera.front',
|
|
stream: 'camera.front_hd',
|
|
cardID: 'card_id',
|
|
}),
|
|
).toEqual({
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'substream_on',
|
|
camera: 'camera.front',
|
|
stream: 'camera.front_hd',
|
|
card_id: 'card_id',
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('createSubstreamOffAction', () => {
|
|
it('should create substream_off action without options', () => {
|
|
expect(createSubstreamOffAction()).toEqual({
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'substream_off',
|
|
});
|
|
});
|
|
|
|
it('should create substream_off action with camera and cardID', () => {
|
|
expect(
|
|
createSubstreamOffAction({ camera: 'camera.front', cardID: 'card_id' }),
|
|
).toEqual({
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'substream_off',
|
|
camera: 'camera.front',
|
|
card_id: 'card_id',
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('createCallAnswerAction', () => {
|
|
it('should create call answer action', () => {
|
|
expect(createCallAnswerAction()).toEqual({
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'call_answer',
|
|
});
|
|
});
|
|
|
|
it('should create call answer action with a cardID', () => {
|
|
expect(createCallAnswerAction({ cardID: 'card_id' })).toEqual({
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'call_answer',
|
|
card_id: 'card_id',
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('createCallEndAction', () => {
|
|
it('should create call end action', () => {
|
|
expect(createCallEndAction()).toEqual({
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'call_end',
|
|
});
|
|
});
|
|
|
|
it('should create call end action with a cardID', () => {
|
|
expect(createCallEndAction({ cardID: 'card_id' })).toEqual({
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'call_end',
|
|
card_id: 'card_id',
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('createNotificationAction', () => {
|
|
it('should create notification action', () => {
|
|
const notification = { body: { text: 'test' } };
|
|
expect(createNotificationAction(notification)).toEqual({
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'notification',
|
|
notification,
|
|
});
|
|
});
|
|
|
|
it('should create notification action with cardID', () => {
|
|
const notification = { body: { text: 'test' } };
|
|
expect(createNotificationAction(notification, { cardID: 'card_id' })).toEqual({
|
|
action: 'fire-dom-event',
|
|
advanced_camera_card_action: 'notification',
|
|
notification,
|
|
card_id: 'card_id',
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('getActionConfigGivenAction', () => {
|
|
const action = createViewAction('clips');
|
|
|
|
it('should not handle undefined arguments', () => {
|
|
expect(getActionConfigGivenAction()).toBeNull();
|
|
});
|
|
|
|
it('should not handle unknown interactions', () => {
|
|
expect(
|
|
getActionConfigGivenAction('triple_poke', { triple_poke_action: action }),
|
|
).toBeNull();
|
|
});
|
|
|
|
it('should handle tap actions', () => {
|
|
expect(getActionConfigGivenAction('tap', { tap_action: action })).toBe(action);
|
|
});
|
|
|
|
it('should handle default tap action without an entity', () => {
|
|
expect(getActionConfigGivenAction('tap', {})).toBeNull();
|
|
});
|
|
|
|
it('should handle default tap action with an entity', () => {
|
|
expect(
|
|
getActionConfigGivenAction('tap', { entity: 'light.office_main_lights' }),
|
|
).toEqual({
|
|
action: 'more-info',
|
|
});
|
|
});
|
|
|
|
it('should handle hold actions', () => {
|
|
expect(getActionConfigGivenAction('hold', { hold_action: action })).toBe(action);
|
|
});
|
|
|
|
it('should handle double_tap actions', () => {
|
|
expect(getActionConfigGivenAction('double_tap', { double_tap_action: action })).toBe(
|
|
action,
|
|
);
|
|
});
|
|
|
|
it('should handle end_tap actions', () => {
|
|
expect(getActionConfigGivenAction('end_tap', { end_tap_action: action })).toBe(
|
|
action,
|
|
);
|
|
});
|
|
|
|
it('should handle start_tap actions', () => {
|
|
expect(getActionConfigGivenAction('start_tap', { start_tap_action: action })).toBe(
|
|
action,
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('hasAction', () => {
|
|
const realAction = createViewAction('clips');
|
|
const noneAction: ActionConfig = {
|
|
action: 'none',
|
|
};
|
|
|
|
afterEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
it('should return true for real action', () => {
|
|
expect(hasAction(realAction)).toBeTruthy();
|
|
});
|
|
|
|
it('should return false for none action', () => {
|
|
expect(hasAction(noneAction)).toBeFalsy();
|
|
});
|
|
|
|
it('should return true with an array of actions some real', () => {
|
|
expect(hasAction([noneAction, noneAction, realAction])).toBeTruthy();
|
|
});
|
|
|
|
it('should return false with an array of actions none real', () => {
|
|
expect(hasAction([noneAction, noneAction, noneAction])).toBeFalsy();
|
|
});
|
|
|
|
it('should return true for an if action', () => {
|
|
expect(hasAction({ if: [], then: [] })).toBeTruthy();
|
|
});
|
|
});
|
|
|
|
describe('isIfAction', () => {
|
|
it('should return true for an if action', () => {
|
|
expect(isIfAction({ if: [], then: [] })).toBeTruthy();
|
|
});
|
|
|
|
it('should return false for a stock action', () => {
|
|
expect(isIfAction({ action: 'none' })).toBeFalsy();
|
|
});
|
|
});
|
|
|
|
describe('getActionName', () => {
|
|
it('should name an if action', () => {
|
|
expect(getActionName({ if: [], then: [] })).toBe('if');
|
|
});
|
|
|
|
it('should name a custom action', () => {
|
|
expect(getActionName(createViewAction('clips'))).toBe('clips');
|
|
});
|
|
|
|
it('should name a stock action', () => {
|
|
expect(getActionName({ action: 'more-info' })).toBe('more-info');
|
|
});
|
|
});
|
|
|
|
// @vitest-environment jsdom
|
|
describe('stopEventFromActivatingCardWideActions', () => {
|
|
it('should stop event from propogating', () => {
|
|
const event = mock<Event>();
|
|
stopEventFromActivatingCardWideActions(event);
|
|
expect(event.stopPropagation).toBeCalled();
|
|
});
|
|
});
|