Testing and demo data
You never need a Home Assistant to work on a control. @dashhaus/core/testing puts a real store over a fake
transport for tests, and @dashhaus/core/demo puts it over a whole demo house for stories and trying things out.
Test a connected control
Section titled “Test a connected control”renderConnected renders your component under a real store and HaProvider, on a transport that serves the entities
you give it and records every service call. Your component goes through the real hook, mapper and actions; only Home
Assistant is fake.
import { useHaLight } from "@dashhaus/core";
export function LightButton({ entityId }: { entityId: string }) { const { entity, actions } = useHaLight(entityId, { loadHistory: false }); return ( <button type="button" aria-pressed={entity.state === "on"} disabled={entity.state === "unavailable"} onClick={actions.onToggle}> {entity.name} </button> );}import { act, fireEvent, screen } from "@testing-library/react";import { describe, expect, it } from "vitest";import { renderConnected } from "@dashhaus/core/testing";import { LightButton } from "./LightButton";
const entities = { "light.desk": { entity_id: "light.desk", state: "off", attributes: { friendly_name: "Desk" } },};
describe("LightButton", () => { it("toggles the light through Home Assistant", async () => { const { calls } = renderConnected(<LightButton entityId="light.desk" />, entities); fireEvent.click(await screen.findByRole("button", { name: "Desk" })); expect(calls).toEqual([{ domain: "light", service: "toggle", data: { entity_id: "light.desk" } }]); });
it("follows the entity as Home Assistant changes it", async () => { const { emitEntity } = renderConnected(<LightButton entityId="light.desk" />, entities); const button = await screen.findByRole("button", { name: "Desk" }); act(() => emitEntity("light.desk", { state: "on" })); expect(button.getAttribute("aria-pressed")).toBe("true"); act(() => emitEntity("light.desk", { state: "unavailable" })); expect(button).toHaveProperty("disabled", true); });});calls is every callService in order, as { domain, service, data }. emitEntity patches one entity the way Home
Assistant would report a change: top-level fields replace, attributes merge. emit replaces the whole set. These
tests run with the rest of Dashhaus’s on every change, so the sample above is known to pass.
fakeTransport(initialEntities: HassEntities): { transport, callService, calls, emit, emitEntity }renderConnected(ui: ReactNode, entities: HassEntities): { transport, callService, calls, emit, emitEntity, container, baseElement, debug, … }@dashhaus/core/testing needs Vitest and Testing Library in your project; the rest of the package doesn’t.
fakeTransport on its own gives you the transport to put behind createHaStore when you render some other way.
Test a card on its own
Section titled “Test a card on its own”A skin’s card takes its model as props, so it needs no store at all: render it with an entity object you write. The raw
Home Assistant states the package’s own tests use are in @dashhaus/core/fixtures/*, if you’d rather start from real
attribute shapes, and the mappers (lightFromHass) turn them into models.
The demo house
Section titled “The demo house”createDemoStore() is the store over a demo house: every kind of entity, with an area, today’s history, and actions
that answer the way Home Assistant would. Storybook’s connected stories run on these demo transports.
import { HaProvider } from "@dashhaus/core";import { createDemoCoverHaTransport, createDemoStore } from "@dashhaus/core/demo";import { HaCoverTile } from "@dashhaus/orb";
/** The whole demo house, as Storybook and the docs' live dashboards run it. */export const house = createDemoStore();
/** One domain's demo on its own: a smaller seed, for a story or a test about covers. */export const covers = createDemoStore(createDemoCoverHaTransport());
export function CoverPlayground() { return ( <HaProvider store={covers}> <HaCoverTile entityId="cover.living_room" /> </HaProvider> );}Each domain also has a smaller transport of its own (createDemoHaTransport for lights, createDemoCoverHaTransport,
createDemoAlarmHaTransport and so on) for a story about one thing.
The demo’s entities and their states can change in any release. Test against entities you write, not against the demo.