Add support for users and numeric_conditions.
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { CurrentUser } from '@dermotduffy/custom-card-helpers';
|
||||
import { HassEntities } from 'home-assistant-js-websocket';
|
||||
import merge from 'lodash-es/merge';
|
||||
import { copyConfig } from '../config-mgmt';
|
||||
@@ -22,6 +23,7 @@ interface ConditionState {
|
||||
triggered?: Set<string>;
|
||||
interaction?: boolean;
|
||||
microphone?: MicrophoneConditionState;
|
||||
user?: CurrentUser;
|
||||
}
|
||||
|
||||
export class ConditionEvaluateRequestEvent extends Event {
|
||||
@@ -174,7 +176,10 @@ export class ConditionsManager {
|
||||
|
||||
const conditions = getAllConditions();
|
||||
this._hasHAStateConditions = conditions.some(
|
||||
(condition) => !!condition.state?.length,
|
||||
(condition) =>
|
||||
!!condition.state?.length ||
|
||||
!!condition.numeric_state?.length ||
|
||||
!!condition.users?.length,
|
||||
);
|
||||
conditions.forEach((condition) => {
|
||||
if (condition.media_query) {
|
||||
@@ -235,11 +240,30 @@ export class ConditionsManager {
|
||||
((!stateTest.state && !stateTest.state_not) ||
|
||||
(stateTest.entity in state.state &&
|
||||
(!stateTest.state ||
|
||||
state.state[stateTest.entity].state === stateTest.state) &&
|
||||
(Array.isArray(stateTest.state)
|
||||
? stateTest.state.includes(state.state[stateTest.entity].state)
|
||||
: stateTest.state === state.state[stateTest.entity].state)) &&
|
||||
(!stateTest.state_not ||
|
||||
state.state[stateTest.entity].state !== stateTest.state_not)));
|
||||
(Array.isArray(stateTest.state_not)
|
||||
? !stateTest.state_not.includes(state.state[stateTest.entity].state)
|
||||
: stateTest.state_not !== state.state[stateTest.entity].state))));
|
||||
}
|
||||
}
|
||||
if (condition.numeric_state?.length) {
|
||||
for (const stateTest of condition.numeric_state) {
|
||||
result &&=
|
||||
!!state.state &&
|
||||
stateTest.entity in state.state &&
|
||||
state.state[stateTest.entity].state !== undefined &&
|
||||
(stateTest.above === undefined ||
|
||||
Number(state.state[stateTest.entity].state) > stateTest.above) &&
|
||||
(stateTest.below === undefined ||
|
||||
Number(state.state[stateTest.entity].state) < stateTest.below);
|
||||
}
|
||||
}
|
||||
if (condition.users?.length) {
|
||||
result &&= !!state.user && condition.users.includes(state.user.id);
|
||||
}
|
||||
if (condition.media_loaded !== undefined) {
|
||||
result &&=
|
||||
state.media_loaded !== undefined &&
|
||||
|
||||
@@ -66,7 +66,10 @@ export class HASSManager {
|
||||
}
|
||||
|
||||
if (this._api.getConditionsManager().hasHAStateConditions()) {
|
||||
this._api.getConditionsManager().setState({ state: this._hass.states });
|
||||
this._api.getConditionsManager().setState({
|
||||
state: this._hass.states,
|
||||
user: this._hass.user,
|
||||
});
|
||||
}
|
||||
|
||||
// Dark mode may depend on HASS.
|
||||
|
||||
+40
-11
@@ -400,20 +400,47 @@ const imageSchema = elementsBaseSchema.extend({
|
||||
aspect_ratio: z.string().optional(),
|
||||
});
|
||||
|
||||
// This state condition is used both for the Picture elements conditional
|
||||
// schema, and also in frigateCardConditionSchema.
|
||||
const stateConditions = z
|
||||
.object({
|
||||
// https://www.home-assistant.io/dashboards/conditional/#state
|
||||
const stateCondition = z.object({
|
||||
condition: z.literal('state'),
|
||||
entity: z.string(),
|
||||
state: z.string().optional(),
|
||||
state_not: z.string().optional(),
|
||||
})
|
||||
.array();
|
||||
state: z.string().or(z.string().array()).optional(),
|
||||
state_not: z.string().or(z.string().array()).optional(),
|
||||
});
|
||||
|
||||
// https://www.home-assistant.io/dashboards/conditional/#numeric-state
|
||||
const numericCondition = z.object({
|
||||
condition: z.literal('numeric_state'),
|
||||
entity: z.string(),
|
||||
above: z.number().optional(),
|
||||
below: z.number().optional(),
|
||||
});
|
||||
|
||||
const mediaQuerySchema = z.string();
|
||||
|
||||
// https://www.home-assistant.io/dashboards/conditional/#screen
|
||||
const screenCondition = z.object({
|
||||
condition: z.literal('screen'),
|
||||
media_query: mediaQuerySchema,
|
||||
});
|
||||
|
||||
// https://www.home-assistant.io/dashboards/conditional/#user
|
||||
const usersCondition = z.object({
|
||||
condition: z.literal('user'),
|
||||
users: z.string().array().min(1),
|
||||
});
|
||||
|
||||
const stockCondition = z.union([
|
||||
stateCondition,
|
||||
numericCondition,
|
||||
screenCondition,
|
||||
usersCondition,
|
||||
]);
|
||||
|
||||
// https://www.home-assistant.io/lovelace/picture-elements/#image-element
|
||||
export const conditionalSchema = z.object({
|
||||
type: z.literal('conditional'),
|
||||
conditions: stateConditions,
|
||||
conditions: stockCondition.array(),
|
||||
elements: z.lazy(() => pictureElementsSchema),
|
||||
});
|
||||
|
||||
@@ -501,12 +528,14 @@ export const frigateCardConditionSchema = z.object({
|
||||
expand: z.boolean().optional(),
|
||||
camera: z.string().array().optional(),
|
||||
media_loaded: z.boolean().optional(),
|
||||
state: stateConditions.optional(),
|
||||
media_query: z.string().optional(),
|
||||
state: stateCondition.array().optional(),
|
||||
numeric_state: numericCondition.array().optional(),
|
||||
media_query: mediaQuerySchema.optional(),
|
||||
display_mode: viewDisplayModeSchema.optional(),
|
||||
triggered: z.string().array().optional(),
|
||||
interaction: z.boolean().optional(),
|
||||
microphone: microphoneConditionSchema.optional(),
|
||||
users: z.string().array().optional()
|
||||
});
|
||||
export type FrigateCardCondition = z.infer<typeof frigateCardConditionSchema>;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { FrigateCardCondition } from '../../src/config/types';
|
||||
import {
|
||||
ConditionEvaluateRequestEvent,
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
createCondition,
|
||||
createConfig,
|
||||
createStateEntity,
|
||||
createUser,
|
||||
} from '../test-utils';
|
||||
|
||||
// @vitest-environment jsdom
|
||||
@@ -145,49 +146,6 @@ describe('getOverridesByKey', () => {
|
||||
});
|
||||
|
||||
describe('ConditionsManager', () => {
|
||||
const config = {
|
||||
type: 'custom:frigate-card',
|
||||
cameras: [],
|
||||
elements: [
|
||||
{
|
||||
type: 'custom:frigate-card-conditional',
|
||||
conditions: {
|
||||
fullscreen: true,
|
||||
},
|
||||
elements: [
|
||||
{
|
||||
type: 'custom:nested-unknown-object',
|
||||
unknown_key: {
|
||||
type: 'custom:frigate-card-conditional',
|
||||
conditions: {
|
||||
media_query: 'media query goes here',
|
||||
},
|
||||
elements: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
overrides: [
|
||||
{
|
||||
overrides: {
|
||||
menu: {
|
||||
style: 'overlay',
|
||||
},
|
||||
},
|
||||
conditions: {
|
||||
fullscreen: true,
|
||||
state: [
|
||||
{
|
||||
entity: 'binary_sensor.foo',
|
||||
state: 'on',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
@@ -214,26 +172,85 @@ describe('ConditionsManager', () => {
|
||||
expect(manager.getState()).toEqual(state);
|
||||
});
|
||||
|
||||
it('should not return hasHAStateConditions without HA state conditions', () => {
|
||||
const manager = new ConditionsManager(createCardAPI());
|
||||
expect(manager.hasHAStateConditions()).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should return hasHAStateConditions with HA state conditions', () => {
|
||||
describe('should handle hasHAStateConditions', () => {
|
||||
beforeEach(() => {
|
||||
vi.spyOn(window, 'matchMedia').mockReturnValueOnce({
|
||||
matches: false,
|
||||
addEventListener: vi.fn(),
|
||||
} as unknown as MediaQueryList);
|
||||
const api = createCardAPI();
|
||||
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig(config));
|
||||
const manager = new ConditionsManager(api);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
const createSuitableConfig = (conditions: FrigateCardCondition) => {
|
||||
return createConfig({
|
||||
overrides: [
|
||||
{
|
||||
overrides: {},
|
||||
conditions: conditions,
|
||||
},
|
||||
],
|
||||
});
|
||||
};
|
||||
|
||||
it('without HA state conditions', () => {
|
||||
const manager = new ConditionsManager(createCardAPI());
|
||||
expect(manager.hasHAStateConditions()).toBeFalsy();
|
||||
});
|
||||
|
||||
it('with HA state conditions', () => {
|
||||
const api = createCardAPI();
|
||||
const numericConfig = createSuitableConfig({
|
||||
state: [
|
||||
{
|
||||
condition: 'state',
|
||||
entity: 'binary_sensor.foo',
|
||||
state: 'on',
|
||||
},
|
||||
],
|
||||
});
|
||||
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(numericConfig);
|
||||
const manager = new ConditionsManager(api);
|
||||
manager.setConditionsFromConfig();
|
||||
|
||||
expect(manager.hasHAStateConditions()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should evaluate conditions with a view', () => {
|
||||
it('with HA numeric_state conditions', () => {
|
||||
const api = createCardAPI();
|
||||
const stateConfig = createSuitableConfig({
|
||||
numeric_state: [
|
||||
{
|
||||
entity: 'sensor.foo',
|
||||
condition: 'numeric_state' as const,
|
||||
above: 10,
|
||||
},
|
||||
],
|
||||
});
|
||||
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(stateConfig);
|
||||
const manager = new ConditionsManager(api);
|
||||
manager.setConditionsFromConfig();
|
||||
|
||||
expect(manager.hasHAStateConditions()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('with HA user conditions', () => {
|
||||
const api = createCardAPI();
|
||||
const userConfig = createSuitableConfig({
|
||||
users: ['user_1'],
|
||||
});
|
||||
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(userConfig);
|
||||
const manager = new ConditionsManager(api);
|
||||
manager.setConditionsFromConfig();
|
||||
|
||||
expect(manager.hasHAStateConditions()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('should evaluate conditions', () => {
|
||||
it('with a view', () => {
|
||||
const manager = new ConditionsManager(createCardAPI());
|
||||
const condition = { view: ['foo'] };
|
||||
expect(manager.evaluateCondition(condition)).toBeFalsy();
|
||||
@@ -241,7 +258,7 @@ describe('ConditionsManager', () => {
|
||||
expect(manager.evaluateCondition(condition)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should evaluate conditions with fullscreen', () => {
|
||||
it('with fullscreen', () => {
|
||||
const manager = new ConditionsManager(createCardAPI());
|
||||
const condition = { fullscreen: true };
|
||||
expect(manager.evaluateCondition(condition)).toBeFalsy();
|
||||
@@ -251,7 +268,7 @@ describe('ConditionsManager', () => {
|
||||
expect(manager.evaluateCondition(condition)).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should evaluate conditions with expand', () => {
|
||||
it('with expand', () => {
|
||||
const manager = new ConditionsManager(createCardAPI());
|
||||
const condition = { expand: true };
|
||||
expect(manager.evaluateCondition(condition)).toBeFalsy();
|
||||
@@ -261,7 +278,7 @@ describe('ConditionsManager', () => {
|
||||
expect(manager.evaluateCondition(condition)).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should evaluate conditions with camera', () => {
|
||||
it('camera', () => {
|
||||
const manager = new ConditionsManager(createCardAPI());
|
||||
const condition = { camera: ['bar'] };
|
||||
expect(manager.evaluateCondition(condition)).toBeFalsy();
|
||||
@@ -271,11 +288,15 @@ describe('ConditionsManager', () => {
|
||||
expect(manager.evaluateCondition(condition)).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should evaluate conditions with ha state positive check', () => {
|
||||
describe('with stock HA conditions', () => {
|
||||
describe('state check', () => {
|
||||
describe('positive', () => {
|
||||
it('single', () => {
|
||||
const manager = new ConditionsManager(createCardAPI());
|
||||
const condition = {
|
||||
state: [
|
||||
{
|
||||
condition: 'state' as const,
|
||||
entity: 'binary_sensor.foo',
|
||||
state: 'on',
|
||||
},
|
||||
@@ -290,11 +311,38 @@ describe('ConditionsManager', () => {
|
||||
expect(manager.evaluateCondition(condition)).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should evaluate conditions with ha state negative check', () => {
|
||||
it('multiple', () => {
|
||||
const manager = new ConditionsManager(createCardAPI());
|
||||
const condition = {
|
||||
state: [
|
||||
{
|
||||
condition: 'state' as const,
|
||||
entity: 'binary_sensor.foo',
|
||||
state: ['active', 'on'],
|
||||
},
|
||||
],
|
||||
};
|
||||
expect(manager.evaluateCondition(condition)).toBeFalsy();
|
||||
manager.setState({ state: { 'binary_sensor.foo': createStateEntity() } });
|
||||
expect(manager.evaluateCondition(condition)).toBeTruthy();
|
||||
manager.setState({
|
||||
state: { 'binary_sensor.foo': createStateEntity({ state: 'active' }) },
|
||||
});
|
||||
expect(manager.evaluateCondition(condition)).toBeTruthy();
|
||||
manager.setState({
|
||||
state: { 'binary_sensor.foo': createStateEntity({ state: 'off' }) },
|
||||
});
|
||||
expect(manager.evaluateCondition(condition)).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('negative', () => {
|
||||
it('single', () => {
|
||||
const manager = new ConditionsManager(createCardAPI());
|
||||
const condition = {
|
||||
state: [
|
||||
{
|
||||
condition: 'state' as const,
|
||||
entity: 'binary_sensor.foo',
|
||||
state_not: 'on',
|
||||
},
|
||||
@@ -308,8 +356,97 @@ describe('ConditionsManager', () => {
|
||||
});
|
||||
expect(manager.evaluateCondition(condition)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
it('should evaluate conditions with media_loaded', () => {
|
||||
it('multiple', () => {
|
||||
const manager = new ConditionsManager(createCardAPI());
|
||||
const condition = {
|
||||
state: [
|
||||
{
|
||||
condition: 'state' as const,
|
||||
entity: 'binary_sensor.foo',
|
||||
state_not: ['active', 'on'],
|
||||
},
|
||||
],
|
||||
};
|
||||
expect(manager.evaluateCondition(condition)).toBeFalsy();
|
||||
manager.setState({ state: { 'binary_sensor.foo': createStateEntity() } });
|
||||
expect(manager.evaluateCondition(condition)).toBeFalsy();
|
||||
manager.setState({
|
||||
state: { 'binary_sensor.foo': createStateEntity({ state: 'active' }) },
|
||||
});
|
||||
expect(manager.evaluateCondition(condition)).toBeFalsy();
|
||||
manager.setState({
|
||||
state: { 'binary_sensor.foo': createStateEntity({ state: 'off' }) },
|
||||
});
|
||||
expect(manager.evaluateCondition(condition)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('numeric state check', () => {
|
||||
it('above', () => {
|
||||
const manager = new ConditionsManager(createCardAPI());
|
||||
const condition = {
|
||||
numeric_state: [
|
||||
{
|
||||
condition: 'numeric_state' as const,
|
||||
entity: 'sensor.foo',
|
||||
above: 10,
|
||||
},
|
||||
],
|
||||
};
|
||||
expect(manager.evaluateCondition(condition)).toBeFalsy();
|
||||
manager.setState({
|
||||
state: { 'sensor.foo': createStateEntity({ state: '11' }) },
|
||||
});
|
||||
expect(manager.evaluateCondition(condition)).toBeTruthy();
|
||||
manager.setState({
|
||||
state: { 'binary_sensor.foo': createStateEntity({ state: '9' }) },
|
||||
});
|
||||
expect(manager.evaluateCondition(condition)).toBeFalsy();
|
||||
});
|
||||
|
||||
it('below', () => {
|
||||
const manager = new ConditionsManager(createCardAPI());
|
||||
const condition = {
|
||||
numeric_state: [
|
||||
{
|
||||
condition: 'numeric_state' as const,
|
||||
entity: 'sensor.foo',
|
||||
below: 10,
|
||||
},
|
||||
],
|
||||
};
|
||||
expect(manager.evaluateCondition(condition)).toBeFalsy();
|
||||
manager.setState({
|
||||
state: { 'sensor.foo': createStateEntity({ state: '11' }) },
|
||||
});
|
||||
expect(manager.evaluateCondition(condition)).toBeFalsy();
|
||||
manager.setState({
|
||||
state: { 'sensor.foo': createStateEntity({ state: '9' }) },
|
||||
});
|
||||
expect(manager.evaluateCondition(condition)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('with users', () => {
|
||||
const manager = new ConditionsManager(createCardAPI());
|
||||
const condition = {
|
||||
users: ['user_1', 'user_2'],
|
||||
};
|
||||
expect(manager.evaluateCondition(condition)).toBeFalsy();
|
||||
manager.setState({
|
||||
user: createUser({ id: 'user_1' }),
|
||||
});
|
||||
expect(manager.evaluateCondition(condition)).toBeTruthy();
|
||||
manager.setState({
|
||||
user: createUser({ id: 'user_WRONG' }),
|
||||
});
|
||||
expect(manager.evaluateCondition(condition)).toBeFalsy();
|
||||
});
|
||||
|
||||
it('with media_loaded', () => {
|
||||
const manager = new ConditionsManager(createCardAPI());
|
||||
const condition = { media_loaded: true };
|
||||
expect(manager.evaluateCondition(condition)).toBeFalsy();
|
||||
@@ -319,7 +456,33 @@ describe('ConditionsManager', () => {
|
||||
expect(manager.evaluateCondition(condition)).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should evaluate conditions with media query', () => {
|
||||
describe('with media query', () => {
|
||||
const mediaQueryConfig = {
|
||||
type: 'custom:frigate-card',
|
||||
cameras: [],
|
||||
elements: [
|
||||
{
|
||||
type: 'custom:frigate-card-conditional',
|
||||
conditions: {
|
||||
fullscreen: true,
|
||||
},
|
||||
elements: [
|
||||
{
|
||||
type: 'custom:nested-unknown-object',
|
||||
unknown_key: {
|
||||
type: 'custom:frigate-card-conditional',
|
||||
conditions: {
|
||||
media_query: 'media query goes here',
|
||||
},
|
||||
elements: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
it('on evaluation', () => {
|
||||
vi.spyOn(window, 'matchMedia')
|
||||
.mockReturnValueOnce(<MediaQueryList>{ matches: true })
|
||||
.mockReturnValueOnce(<MediaQueryList>{ matches: false });
|
||||
@@ -330,7 +493,7 @@ describe('ConditionsManager', () => {
|
||||
expect(manager.evaluateCondition(condition)).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should trigger on changes to media query conditions', () => {
|
||||
it('on trigger', () => {
|
||||
const addEventListener = vi.fn();
|
||||
const removeEventListener = vi.fn();
|
||||
vi.spyOn(window, 'matchMedia').mockReturnValueOnce({
|
||||
@@ -339,7 +502,9 @@ describe('ConditionsManager', () => {
|
||||
removeEventListener: removeEventListener,
|
||||
} as unknown as MediaQueryList);
|
||||
const api = createCardAPI();
|
||||
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig(config));
|
||||
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(
|
||||
createConfig(mediaQueryConfig),
|
||||
);
|
||||
const callback = vi.fn();
|
||||
const manager = new ConditionsManager(api, callback);
|
||||
|
||||
@@ -358,8 +523,9 @@ describe('ConditionsManager', () => {
|
||||
manager.removeConditions();
|
||||
expect(removeEventListener).toBeCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('should evaluate conditions with display mode', () => {
|
||||
it('with display mode', () => {
|
||||
const manager = new ConditionsManager(createCardAPI());
|
||||
const condition: FrigateCardCondition = { display_mode: 'grid' };
|
||||
expect(manager.evaluateCondition(condition)).toBeFalsy();
|
||||
@@ -369,7 +535,7 @@ describe('ConditionsManager', () => {
|
||||
expect(manager.evaluateCondition(condition)).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should evaluate conditions with triggers', () => {
|
||||
it('with triggers', () => {
|
||||
const manager = new ConditionsManager(createCardAPI());
|
||||
const condition: FrigateCardCondition = { triggered: ['camera_1', 'camera_2'] };
|
||||
expect(manager.evaluateCondition(condition)).toBeFalsy();
|
||||
@@ -381,7 +547,7 @@ describe('ConditionsManager', () => {
|
||||
expect(manager.evaluateCondition(condition)).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should evaluate conditions with interaction', () => {
|
||||
it('with interaction', () => {
|
||||
const manager = new ConditionsManager(createCardAPI());
|
||||
const condition: FrigateCardCondition = { interaction: true };
|
||||
expect(manager.evaluateCondition(condition)).toBeFalsy();
|
||||
@@ -391,7 +557,7 @@ describe('ConditionsManager', () => {
|
||||
expect(manager.evaluateCondition(condition)).toBeFalsy();
|
||||
});
|
||||
|
||||
describe('should evaluate conditions with microphone', () => {
|
||||
describe('with microphone', () => {
|
||||
it('empty', () => {
|
||||
const manager = new ConditionsManager(createCardAPI());
|
||||
const condition: FrigateCardCondition = { microphone: {} };
|
||||
@@ -462,4 +628,5 @@ describe('ConditionsManager', () => {
|
||||
expect(manager.evaluateCondition(condition)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
createHASS,
|
||||
createStateEntity,
|
||||
createStore,
|
||||
createUser,
|
||||
createView,
|
||||
} from '../test-utils';
|
||||
|
||||
@@ -44,13 +45,15 @@ describe('HASSManager', () => {
|
||||
vi.mocked(api.getConditionsManager().hasHAStateConditions).mockReturnValue(true);
|
||||
|
||||
const states = { 'switch.foo': createStateEntity() };
|
||||
const hass = createHASS(states);
|
||||
const user = createUser({ id: 'user_1' });
|
||||
const hass = createHASS(states, user);
|
||||
|
||||
manager.setHASS(hass);
|
||||
|
||||
expect(api.getConditionsManager().setState).toBeCalledWith(
|
||||
expect.objectContaining({
|
||||
state: states,
|
||||
user: user,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -381,6 +381,7 @@ describe('should lazy evaluate', () => {
|
||||
type: 'conditional',
|
||||
conditions: [
|
||||
{
|
||||
condition: 'state',
|
||||
entity: 'light.office_main_lights',
|
||||
state: 'on',
|
||||
state_not: 'off',
|
||||
@@ -401,6 +402,7 @@ describe('should lazy evaluate', () => {
|
||||
).toEqual({
|
||||
conditions: [
|
||||
{
|
||||
condition: 'state',
|
||||
entity: 'light.office_main_lights',
|
||||
state: 'on',
|
||||
state_not: 'off',
|
||||
|
||||
+15
-2
@@ -1,4 +1,4 @@
|
||||
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
|
||||
import { CurrentUser, HomeAssistant } from '@dermotduffy/custom-card-helpers';
|
||||
import { HassEntities, HassEntity } from 'home-assistant-js-websocket';
|
||||
import { expect, vi } from 'vitest';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
@@ -80,15 +80,28 @@ export const createCamera = (
|
||||
return new Camera(config, engine, { capabilities: capabilities });
|
||||
};
|
||||
|
||||
export const createHASS = (states?: HassEntities): ExtendedHomeAssistant => {
|
||||
export const createHASS = (states?: HassEntities, user?: CurrentUser): ExtendedHomeAssistant => {
|
||||
const hass = mock<ExtendedHomeAssistant>();
|
||||
if (states) {
|
||||
hass.states = states;
|
||||
}
|
||||
if (user) {
|
||||
hass.user = user;
|
||||
}
|
||||
hass.connection.subscribeMessage = vi.fn();
|
||||
return hass;
|
||||
};
|
||||
|
||||
export const createUser = (user?: Partial<CurrentUser>): CurrentUser => ({
|
||||
id: 'user',
|
||||
is_owner: false,
|
||||
is_admin: false,
|
||||
name: 'User',
|
||||
credentials: [],
|
||||
mfa_modules: [],
|
||||
...user,
|
||||
});
|
||||
|
||||
export const createRegistryEntity = (entity?: Partial<Entity>): Entity => {
|
||||
return {
|
||||
config_entry_id: entity?.config_entry_id ?? null,
|
||||
|
||||
Reference in New Issue
Block a user