Files
frontend/test/data/recorder-statistic-label.test.ts
T
Bram KragtenandClaude Opus 5 0ef3e9c71a Resolve statistic labels with structured entity names (#54202)
* Resolve statistic labels with structured entity names

getStatisticLabel resolved names through computeStateName, so every
statistic-shaped label — the energy dashboard cards, the sankey cards,
hui-statistic-card, chart series names and the energy configuration
dialogs — showed the flat friendly_name attribute while the rest of the
UI composed names from the device, area and floor.

It now asks hass.formatEntityName for the default composition, which
also makes the entity branch of computeEnergyLabel redundant.

The metadata fallback stays: external statistics have no entity to
resolve a name against.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* Keep the entity name shape out of the core chunk

recorder.ts sits in the core entry chunk, so importing DEFAULT_ENTITY_NAME
from compute_entity_name_display dragged the registry-aware formatters and
their dependencies in with it and blew the core bundle budget by 4.1%.

The constant and the name types have no runtime dependencies, so they move
to their own module; compute_entity_name_display re-exports them so nothing
else has to change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 09:59:12 +03:00

93 lines
2.6 KiB
TypeScript

import { describe, expect, it } from "vitest";
import type { StatisticsMetaData } from "../../src/data/recorder";
import { getStatisticLabel, StatisticMeanType } from "../../src/data/recorder";
import {
mockArea,
mockDevice,
mockEntity,
} from "../common/entity/context/context-mock";
import { createMockEntityState, createMockHass } from "../fixtures/hass";
const metadata = (
statistic_id: string,
name: string | null
): StatisticsMetaData => ({
statistic_id,
name,
source: "recorder",
statistics_unit_of_measurement: "kWh",
has_sum: true,
mean_type: StatisticMeanType.NONE,
unit_class: "energy",
});
// The friendly name deliberately differs from the composed name, so the
// assertions fail if the label is taken from the attribute again.
const hassWithRegistry = () =>
createMockHass(
{
"sensor.dishwasher_energy": createMockEntityState(
"sensor.dishwasher_energy",
"12",
{ friendly_name: "Smart plug 3 energy" }
),
},
{
entities: {
"sensor.dishwasher_energy": mockEntity({
entity_id: "sensor.dishwasher_energy",
device_id: "device_1",
name: "Energy",
}),
},
devices: {
device_1: mockDevice({
id: "device_1",
name: "Dishwasher",
area_id: "kitchen",
}),
},
areas: { kitchen: mockArea({ area_id: "kitchen", name: "Kitchen" }) },
}
);
describe("getStatisticLabel", () => {
it("composes the name from the registry rather than friendly_name", () => {
expect(
getStatisticLabel(
hassWithRegistry(),
"sensor.dishwasher_energy",
metadata("sensor.dishwasher_energy", "Recorder name")
)
).toBe("Dishwasher Energy");
});
// External statistics have no entity, so there is no registry context to
// compose a name from and the recorder metadata is all we have.
it("uses the metadata name when there is no entity", () => {
expect(
getStatisticLabel(
createMockHass(),
"energy:solar_production",
metadata("energy:solar_production", "Solar production")
)
).toBe("Solar production");
});
it("falls back to the statistic id when metadata has no name", () => {
expect(
getStatisticLabel(
createMockHass(),
"energy:solar_production",
metadata("energy:solar_production", null)
)
).toBe("energy:solar_production");
});
it("falls back to the statistic id when there is no metadata", () => {
expect(
getStatisticLabel(createMockHass(), "energy:solar_production", undefined)
).toBe("energy:solar_production");
});
});