mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-28 03:36:44 +00:00
Add more unit tests for common/entity (#24182)
* Add new entity tests * Improve canToggleDomain test
This commit is contained in:
parent
7369b7e0d5
commit
63a98155cd
45
test/common/entity/battery_icon.test.ts
Normal file
45
test/common/entity/battery_icon.test.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import {
|
||||
batteryIcon,
|
||||
batteryLevelIcon,
|
||||
} from "../../../src/common/entity/battery_icon";
|
||||
|
||||
describe("batteryIcon", () => {
|
||||
it("should return correct icon for battery level", () => {
|
||||
const stateObj: HassEntity = { state: "50" } as HassEntity;
|
||||
expect(batteryIcon(stateObj)).toBe("mdi:battery-50");
|
||||
});
|
||||
|
||||
it("should return correct icon for battery level with state", () => {
|
||||
const stateObj: HassEntity = { state: "50" } as HassEntity;
|
||||
expect(batteryIcon(stateObj, "20")).toBe("mdi:battery-20");
|
||||
});
|
||||
});
|
||||
|
||||
describe("batteryLevelIcon", () => {
|
||||
it("should return correct icon for battery level", () => {
|
||||
expect(batteryLevelIcon(50)).toBe("mdi:battery-50");
|
||||
});
|
||||
|
||||
it("should return correct icon for charging battery", () => {
|
||||
expect(batteryLevelIcon(50, true)).toBe("mdi:battery-charging-50");
|
||||
});
|
||||
|
||||
it("should return charging outline icon for charging battery with 9%", () => {
|
||||
expect(batteryLevelIcon(9, true)).toBe("mdi:battery-charging-outline");
|
||||
});
|
||||
|
||||
it("should return alert icon for low battery", () => {
|
||||
expect(batteryLevelIcon(5)).toBe("mdi:battery-alert-variant-outline");
|
||||
});
|
||||
|
||||
it("should return unknown icon for invalid battery level", () => {
|
||||
expect(batteryLevelIcon("invalid")).toBe("mdi:battery-unknown");
|
||||
});
|
||||
|
||||
it("should return battery icon for on/off", () => {
|
||||
expect(batteryLevelIcon("off")).toBe("mdi:battery");
|
||||
expect(batteryLevelIcon("on")).toBe("mdi:battery-alert");
|
||||
});
|
||||
});
|
@ -1,6 +1,7 @@
|
||||
import { assert, describe, it } from "vitest";
|
||||
|
||||
import { canToggleDomain } from "../../../src/common/entity/can_toggle_domain";
|
||||
import type { HomeAssistant } from "../../../src/types";
|
||||
|
||||
describe("canToggleDomain", () => {
|
||||
const hass: any = {
|
||||
@ -9,10 +10,6 @@ describe("canToggleDomain", () => {
|
||||
turn_on: null, // Service keys only need to be present for test
|
||||
turn_off: null,
|
||||
},
|
||||
lock: {
|
||||
lock: null,
|
||||
unlock: null,
|
||||
},
|
||||
sensor: {
|
||||
custom_service: null,
|
||||
},
|
||||
@ -23,10 +20,6 @@ describe("canToggleDomain", () => {
|
||||
assert.isTrue(canToggleDomain(hass, "light"));
|
||||
});
|
||||
|
||||
it("Detects locks toggle", () => {
|
||||
assert.isTrue(canToggleDomain(hass, "lock"));
|
||||
});
|
||||
|
||||
it("Detects sensors do not toggle", () => {
|
||||
assert.isFalse(canToggleDomain(hass, "sensor"));
|
||||
});
|
||||
@ -34,4 +27,58 @@ describe("canToggleDomain", () => {
|
||||
it("Detects binary sensors do not toggle", () => {
|
||||
assert.isFalse(canToggleDomain(hass, "binary_sensor"));
|
||||
});
|
||||
|
||||
it("Detects covers toggle", () => {
|
||||
assert.isTrue(
|
||||
canToggleDomain(
|
||||
{
|
||||
services: {
|
||||
cover: {
|
||||
open_cover: null,
|
||||
},
|
||||
},
|
||||
} as unknown as HomeAssistant,
|
||||
"cover"
|
||||
)
|
||||
);
|
||||
assert.isFalse(
|
||||
canToggleDomain(
|
||||
{
|
||||
services: {
|
||||
cover: {
|
||||
open: null,
|
||||
},
|
||||
},
|
||||
} as unknown as HomeAssistant,
|
||||
"cover"
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
it("Detects lock toggle", () => {
|
||||
assert.isTrue(
|
||||
canToggleDomain(
|
||||
{
|
||||
services: {
|
||||
lock: {
|
||||
lock: null,
|
||||
},
|
||||
},
|
||||
} as unknown as HomeAssistant,
|
||||
"lock"
|
||||
)
|
||||
);
|
||||
assert.isFalse(
|
||||
canToggleDomain(
|
||||
{
|
||||
services: {
|
||||
lock: {
|
||||
unlock: null,
|
||||
},
|
||||
},
|
||||
} as unknown as HomeAssistant,
|
||||
"lock"
|
||||
)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
31
test/common/entity/color/battery_color.test.ts
Normal file
31
test/common/entity/color/battery_color.test.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { batteryStateColorProperty } from "../../../../src/common/entity/color/battery_color";
|
||||
|
||||
describe("battery_color", () => {
|
||||
it("should return green for high battery level", () => {
|
||||
let color = batteryStateColorProperty("70");
|
||||
expect(color).toBe("--state-sensor-battery-high-color");
|
||||
color = batteryStateColorProperty("200");
|
||||
expect(color).toBe("--state-sensor-battery-high-color");
|
||||
});
|
||||
|
||||
it("should return yellow for medium battery level", () => {
|
||||
let color = batteryStateColorProperty("69.99");
|
||||
expect(color).toBe("--state-sensor-battery-medium-color");
|
||||
color = batteryStateColorProperty("30");
|
||||
expect(color).toBe("--state-sensor-battery-medium-color");
|
||||
});
|
||||
|
||||
it("should return red for low battery level", () => {
|
||||
let color = batteryStateColorProperty("29.999");
|
||||
expect(color).toBe("--state-sensor-battery-low-color");
|
||||
color = batteryStateColorProperty("-20");
|
||||
expect(color).toBe("--state-sensor-battery-low-color");
|
||||
});
|
||||
|
||||
// add nan test
|
||||
it("should return undefined for non-numeric state", () => {
|
||||
const color = batteryStateColorProperty("not a number");
|
||||
expect(color).toBe(undefined);
|
||||
});
|
||||
});
|
56
test/common/entity/compute_state_name.test.ts
Normal file
56
test/common/entity/compute_state_name.test.ts
Normal file
@ -0,0 +1,56 @@
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import {
|
||||
computeStateName,
|
||||
computeStateNameFromEntityAttributes,
|
||||
} from "../../../src/common/entity/compute_state_name";
|
||||
|
||||
describe("computeStateName", () => {
|
||||
it("should return friendly_name if it exists", () => {
|
||||
const stateObj = {
|
||||
entity_id: "light.living_room",
|
||||
attributes: { friendly_name: "Living Room Light" },
|
||||
} as HassEntity;
|
||||
expect(computeStateName(stateObj)).toBe("Living Room Light");
|
||||
});
|
||||
|
||||
it("should return object id if friendly_name does not exist", () => {
|
||||
const stateObj = {
|
||||
entity_id: "light.living_room",
|
||||
attributes: {},
|
||||
} as HassEntity;
|
||||
expect(computeStateName(stateObj)).toBe("living room");
|
||||
});
|
||||
});
|
||||
|
||||
describe("computeStateNameFromEntityAttributes", () => {
|
||||
it("should return friendly_name if it exists", () => {
|
||||
const entityId = "light.living_room";
|
||||
const attributes = { friendly_name: "Living Room Light" };
|
||||
expect(computeStateNameFromEntityAttributes(entityId, attributes)).toBe(
|
||||
"Living Room Light"
|
||||
);
|
||||
});
|
||||
|
||||
it("should return friendly_name 0", () => {
|
||||
const entityId = "light.living_room";
|
||||
const attributes = { friendly_name: 0 };
|
||||
expect(computeStateNameFromEntityAttributes(entityId, attributes)).toBe(
|
||||
"0"
|
||||
);
|
||||
});
|
||||
|
||||
it("should return empty if friendly_name is null", () => {
|
||||
const entityId = "light.living_room";
|
||||
const attributes = { friendly_name: null };
|
||||
expect(computeStateNameFromEntityAttributes(entityId, attributes)).toBe("");
|
||||
});
|
||||
|
||||
it("should return object id if friendly_name does not exist", () => {
|
||||
const entityId = "light.living_room";
|
||||
const attributes = {};
|
||||
expect(computeStateNameFromEntityAttributes(entityId, attributes)).toBe(
|
||||
"living room"
|
||||
);
|
||||
});
|
||||
});
|
54
test/common/entity/cover_icon.test.ts
Normal file
54
test/common/entity/cover_icon.test.ts
Normal file
@ -0,0 +1,54 @@
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import {
|
||||
mdiArrowCollapseHorizontal,
|
||||
mdiArrowDown,
|
||||
mdiArrowExpandHorizontal,
|
||||
mdiArrowUp,
|
||||
} from "@mdi/js";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import {
|
||||
computeOpenIcon,
|
||||
computeCloseIcon,
|
||||
} from "../../../src/common/entity/cover_icon";
|
||||
|
||||
describe("computeOpenIcon", () => {
|
||||
it("returns mdiArrowExpandHorizontal for awning, door, gate, and curtain", () => {
|
||||
const stateObj = { attributes: { device_class: "awning" } } as HassEntity;
|
||||
expect(computeOpenIcon(stateObj)).toBe(mdiArrowExpandHorizontal);
|
||||
|
||||
stateObj.attributes.device_class = "door";
|
||||
expect(computeOpenIcon(stateObj)).toBe(mdiArrowExpandHorizontal);
|
||||
|
||||
stateObj.attributes.device_class = "gate";
|
||||
expect(computeOpenIcon(stateObj)).toBe(mdiArrowExpandHorizontal);
|
||||
|
||||
stateObj.attributes.device_class = "curtain";
|
||||
expect(computeOpenIcon(stateObj)).toBe(mdiArrowExpandHorizontal);
|
||||
});
|
||||
|
||||
it("returns mdiArrowUp for other device classes", () => {
|
||||
const stateObj = { attributes: { device_class: "window" } } as HassEntity;
|
||||
expect(computeOpenIcon(stateObj)).toBe(mdiArrowUp);
|
||||
});
|
||||
});
|
||||
|
||||
describe("computeCloseIcon", () => {
|
||||
it("returns mdiArrowCollapseHorizontal for awning, door, gate, and curtain", () => {
|
||||
const stateObj = { attributes: { device_class: "awning" } } as HassEntity;
|
||||
expect(computeCloseIcon(stateObj)).toBe(mdiArrowCollapseHorizontal);
|
||||
|
||||
stateObj.attributes.device_class = "door";
|
||||
expect(computeCloseIcon(stateObj)).toBe(mdiArrowCollapseHorizontal);
|
||||
|
||||
stateObj.attributes.device_class = "gate";
|
||||
expect(computeCloseIcon(stateObj)).toBe(mdiArrowCollapseHorizontal);
|
||||
|
||||
stateObj.attributes.device_class = "curtain";
|
||||
expect(computeCloseIcon(stateObj)).toBe(mdiArrowCollapseHorizontal);
|
||||
});
|
||||
|
||||
it("returns mdiArrowDown for other device classes", () => {
|
||||
const stateObj = { attributes: { device_class: "window" } } as HassEntity;
|
||||
expect(computeCloseIcon(stateObj)).toBe(mdiArrowDown);
|
||||
});
|
||||
});
|
194
test/common/entity/delete_entity.test.ts
Normal file
194
test/common/entity/delete_entity.test.ts
Normal file
@ -0,0 +1,194 @@
|
||||
import { describe, it, expect, vi } from "vitest";
|
||||
import {
|
||||
isDeletableEntity,
|
||||
deleteEntity,
|
||||
} from "../../../src/common/entity/delete_entity";
|
||||
import type { HomeAssistant } from "../../../src/types";
|
||||
import type { EntityRegistryEntry } from "../../../src/data/entity_registry";
|
||||
import type { IntegrationManifest } from "../../../src/data/integration";
|
||||
import type { ConfigEntry } from "../../../src/data/config_entries";
|
||||
import type { Helper } from "../../../src/panels/config/helpers/const";
|
||||
|
||||
describe("isDeletableEntity", () => {
|
||||
it("should return true for restored entities", () => {
|
||||
const hass = {
|
||||
states: { "light.test": { attributes: { restored: true } } },
|
||||
} as unknown as HomeAssistant;
|
||||
const result = isDeletableEntity(hass, "light.test", [], [], [], []);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false for non-restored entities without config entry", () => {
|
||||
const hass = {
|
||||
states: { "light.test": { attributes: {} } },
|
||||
} as unknown as HomeAssistant;
|
||||
const entityRegistry = [
|
||||
{ entity_id: "light.test" },
|
||||
] as EntityRegistryEntry[];
|
||||
const result = isDeletableEntity(
|
||||
hass,
|
||||
"light.test",
|
||||
[],
|
||||
entityRegistry,
|
||||
[],
|
||||
[]
|
||||
);
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it("should return true for helper domain entities", () => {
|
||||
const hass = {
|
||||
states: { "input_boolean.test": { attributes: {} } },
|
||||
config: { components: ["input_boolean"] },
|
||||
} as unknown as HomeAssistant;
|
||||
const entityRegistry = [
|
||||
{ entity_id: "input_boolean.test", unique_id: "123" },
|
||||
] as EntityRegistryEntry[];
|
||||
const fetchedHelpers = [{ id: "123" }] as Helper[];
|
||||
const result = isDeletableEntity(
|
||||
hass,
|
||||
"input_boolean.test",
|
||||
[],
|
||||
entityRegistry,
|
||||
[],
|
||||
fetchedHelpers
|
||||
);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false for non-helper domain entities without restored attribute", () => {
|
||||
const hass = {
|
||||
states: { "light.test": { attributes: {} } },
|
||||
} as unknown as HomeAssistant;
|
||||
const entityRegistry = [
|
||||
{ entity_id: "light.test" },
|
||||
] as EntityRegistryEntry[];
|
||||
const result = isDeletableEntity(
|
||||
hass,
|
||||
"light.test",
|
||||
[],
|
||||
entityRegistry,
|
||||
[],
|
||||
[]
|
||||
);
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it("should return true for entities with helper integration type", () => {
|
||||
const hass = {
|
||||
states: { "light.test": { attributes: {} } },
|
||||
} as unknown as HomeAssistant;
|
||||
const entityRegistry = [
|
||||
{ entity_id: "light.test", config_entry_id: "config_1" },
|
||||
] as EntityRegistryEntry[];
|
||||
const configEntries = [
|
||||
{ entry_id: "config_1", domain: "light" },
|
||||
] as ConfigEntry[];
|
||||
const manifests = [
|
||||
{ domain: "light", integration_type: "helper" },
|
||||
] as IntegrationManifest[];
|
||||
const result = isDeletableEntity(
|
||||
hass,
|
||||
"light.test",
|
||||
manifests,
|
||||
entityRegistry,
|
||||
configEntries,
|
||||
[]
|
||||
);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("deleteEntity", () => {
|
||||
it("should call removeEntityRegistryEntry for restored entities", () => {
|
||||
const removeEntityRegistryEntry = vi.fn();
|
||||
const hass = {
|
||||
states: { "light.test": { attributes: { restored: true } } },
|
||||
callWS: removeEntityRegistryEntry,
|
||||
} as unknown as HomeAssistant;
|
||||
const entityRegistry = [
|
||||
{ entity_id: "light.test" },
|
||||
] as EntityRegistryEntry[];
|
||||
deleteEntity(hass, "light.test", [], entityRegistry, [], []);
|
||||
expect(removeEntityRegistryEntry).toHaveBeenCalledWith({
|
||||
type: "config/entity_registry/remove",
|
||||
entity_id: "light.test",
|
||||
});
|
||||
});
|
||||
|
||||
it("should call deleteConfigEntry for entities with helper integration type", () => {
|
||||
const deleteConfigEntry = vi.fn();
|
||||
const hass = {
|
||||
states: { "light.test": { attributes: {} } },
|
||||
callApi: deleteConfigEntry,
|
||||
} as unknown as HomeAssistant;
|
||||
const entityRegistry = [
|
||||
{ entity_id: "light.test", config_entry_id: "config_1" },
|
||||
] as EntityRegistryEntry[];
|
||||
const configEntries = [
|
||||
{ entry_id: "config_1", domain: "light" },
|
||||
] as ConfigEntry[];
|
||||
const manifests = [
|
||||
{ domain: "light", integration_type: "helper" },
|
||||
] as IntegrationManifest[];
|
||||
deleteEntity(
|
||||
hass,
|
||||
"light.test",
|
||||
manifests,
|
||||
entityRegistry,
|
||||
configEntries,
|
||||
[]
|
||||
);
|
||||
expect(deleteConfigEntry).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it("should call HELPERS_CRUD.delete for helper domain entities", () => {
|
||||
const deleteCall = vi.fn();
|
||||
const hass = {
|
||||
states: { "input_boolean.test": { attributes: {} } },
|
||||
config: { components: ["input_boolean"] },
|
||||
callWS: deleteCall,
|
||||
} as unknown as HomeAssistant;
|
||||
const entityRegistry = [
|
||||
{ entity_id: "input_boolean.test", unique_id: "123" },
|
||||
] as EntityRegistryEntry[];
|
||||
const fetchedHelpers = [{ id: "123" }] as Helper[];
|
||||
deleteEntity(
|
||||
hass,
|
||||
"input_boolean.test",
|
||||
[],
|
||||
entityRegistry,
|
||||
[],
|
||||
fetchedHelpers
|
||||
);
|
||||
expect(deleteCall).toHaveBeenCalledWith({
|
||||
type: "input_boolean/delete",
|
||||
input_boolean_id: "123",
|
||||
});
|
||||
});
|
||||
|
||||
it("should call removeEntityRegistryEntry for helper domain entities", () => {
|
||||
const removeEntityRegistryEntry = vi.fn();
|
||||
const hass = {
|
||||
states: { "input_boolean.test": { attributes: { restored: true } } },
|
||||
config: { components: ["input_boolean"] },
|
||||
callWS: removeEntityRegistryEntry,
|
||||
} as unknown as HomeAssistant;
|
||||
const entityRegistry = [
|
||||
{ entity_id: "input_boolean.test", unique_id: "124" },
|
||||
] as EntityRegistryEntry[];
|
||||
const fetchedHelpers = [{ id: "123" }] as Helper[];
|
||||
deleteEntity(
|
||||
hass,
|
||||
"input_boolean.test",
|
||||
[],
|
||||
entityRegistry,
|
||||
[],
|
||||
fetchedHelpers
|
||||
);
|
||||
expect(removeEntityRegistryEntry).toHaveBeenCalledWith({
|
||||
type: "config/entity_registry/remove",
|
||||
entity_id: "input_boolean.test",
|
||||
});
|
||||
});
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user