import { describe, expect, it } from "vitest"; import { sceneEntityStateObj } from "../../src/data/scene"; describe("sceneEntityStateObj", () => { it("builds a state object from string shorthand", () => { expect(sceneEntityStateObj("light.kitchen", "on")).toEqual({ entity_id: "light.kitchen", state: "on", attributes: {}, }); }); it("builds a state object from the dict form", () => { expect( sceneEntityStateObj("light.kitchen", { state: "on", brightness: 180, rgb_color: [255, 64, 112], }) ).toEqual({ entity_id: "light.kitchen", state: "on", attributes: { brightness: 180, rgb_color: [255, 64, 112] }, }); }); it("strips media-derived entity pictures but keeps other attributes", () => { const sceneEntity = { state: "playing", entity_picture: "/api/media_player_proxy/x?token=stale", entity_picture_local: "/local/x.jpg", friendly_name: "Player", }; expect(sceneEntityStateObj("media_player.x", sceneEntity)).toEqual({ entity_id: "media_player.x", state: "playing", attributes: { friendly_name: "Player" }, }); // The input scene config must not be mutated. expect(sceneEntity.entity_picture).toBe( "/api/media_player_proxy/x?token=stale" ); }); it("keeps a stable entity picture on other domains", () => { expect( sceneEntityStateObj("vacuum.robot", { state: "cleaning", entity_picture: "/local/robot.png", })?.attributes.entity_picture ).toBe("/local/robot.png"); }); it("returns undefined for null and undefined values", () => { // An entity left without a value in the YAML editor parses as null. expect(sceneEntityStateObj("light.kitchen", null)).toBeUndefined(); expect(sceneEntityStateObj("light.kitchen", undefined)).toBeUndefined(); }); it("returns undefined for an array value", () => { expect(sceneEntityStateObj("light.kitchen", [255, 100])).toBeUndefined(); }); it("returns undefined for a numeric value", () => { // The backend only accepts string and boolean states, so a number never // becomes a target the scene can apply. expect(sceneEntityStateObj("input_number.x", 23)).toBeUndefined(); expect( sceneEntityStateObj("input_number.x", { state: 23 }) ).toBeUndefined(); }); it("returns undefined when the dict holds no usable state", () => { expect( sceneEntityStateObj("light.kitchen", { brightness: 100 }) ).toBeUndefined(); expect( sceneEntityStateObj("light.kitchen", { state: null }) ).toBeUndefined(); expect( sceneEntityStateObj("light.kitchen", { state: { brightness: 100 } }) ).toBeUndefined(); }); it("normalizes boolean shorthand to on/off like the backend does", () => { // YAML 1.1 parses unquoted on/off in scenes.yaml as booleans. expect(sceneEntityStateObj("light.kitchen", true)?.state).toBe("on"); expect(sceneEntityStateObj("light.kitchen", false)?.state).toBe("off"); }); it("normalizes a boolean state in the dict form", () => { expect(sceneEntityStateObj("light.kitchen", { state: true })).toEqual({ entity_id: "light.kitchen", state: "on", attributes: {}, }); }); it("drops color attributes for an inactive target", () => { // A live entity never carries these while off, and state-badge applies // them without checking activity. expect( sceneEntityStateObj("light.kitchen", { state: "off", brightness: 180, rgb_color: [255, 0, 0], friendly_name: "Kitchen", }) ).toEqual({ entity_id: "light.kitchen", state: "off", attributes: { friendly_name: "Kitchen" }, }); }); });