278 files

This commit is contained in:
Home Assistant Version Control
2026-09-13 20:38:58 +00:00
parent d7a0a08372
commit 1b4f5f68c6
278 changed files with 36892 additions and 7150 deletions
@@ -65,7 +65,7 @@ export function obj(entryId: string, tasks: unknown[], name = "Pool Pump") {
export async function mountPanel(
objects: unknown[],
extraHandlers: Record<string, WsHandler> = {},
opts: { user?: { id: string; is_admin: boolean } } = {},
opts: { user?: { id: string; is_admin: boolean }; embedded?: boolean; presets?: { tab?: string; view?: string } } = {},
) {
const { hass, sent, subscriptions } = createMockHass({
handlers: {
@@ -90,6 +90,8 @@ export async function mountPanel(
const el = await fixture<HTMLElement & { updateComplete: Promise<unknown> }>(html`
<maintenance-supporter-panel
.hass=${hass}
.embedded=${opts.embedded ?? false}
.presets=${opts.presets ?? {}}
style="display:block; height: 600px;"
></maintenance-supporter-panel>
`);
@@ -362,7 +362,7 @@ describe("complete-dialog cost suggestion from parts (#104 follow-up)", () => {
});
const c = chip(el)!;
expect(c, "suggestion chip rendered").to.exist;
expect(c.textContent).to.include("17.00");
expect(c.textContent).to.include("17 €");
expect(c.textContent).to.include("€");
c.click();
await el.updateComplete;
@@ -375,7 +375,7 @@ describe("complete-dialog cost suggestion from parts (#104 follow-up)", () => {
it("buy task: restock qty x unit cost, follows the qty field", async () => {
const el = await mountWithParts({ restockDefault: 2, restockUnitCost: 4.5 });
expect(chip(el)!.textContent).to.include("9.00");
expect(chip(el)!.textContent).to.include("9");
});
it("no chip when no involved part carries a price", async () => {
@@ -0,0 +1,47 @@
{
"_comment": "Shared examples for the tolerant matcher (#171): __tests__/search-match.test.ts AND tests/test_search_match.py run every case here, so the panel's local groups and the server's document/history groups agree on what matches. Scores are named (EXACT/PREFIX/SUBSTRING/FUZZY/NONE) — each side maps them to its constants.",
"fold_length_preserving": ["Kühlschrank", "Straße", "Ærø", "ÉCOLE", "naïve café", "Łódź"],
"fold": [["Kühlschrank", "kuhlschrank"], ["Straße", "strase"], ["ÉCOLE", "ecole"], ["Łódź", "lodz"]],
"words": [["Fehler-Code E-24, Zulauf!", ["fehler", "code", "e", "24", "zulauf"]]],
"compact": [["E-24 / WM14T5", "e24wm14t5"]],
"query_tokens": [
["Spuel-Maschine", [["spuel", "spul"], ["maschine"]]],
["Strasse", [["strasse", "strase"]]],
["Bauer", [["bauer", "baur"]]],
[" ", []]
],
"within_one_edit": [
["abc", "abc", true],
["reinigen", "reinigne", true],
["filter", "fiter", true],
["filter", "fillter", true],
["filter", "filtar", true],
["filter", "flitre", false],
["abc", "abcde", false]
],
"word_score": [
[["filter"], "filter", "EXACT"],
[["filt"], "filter", "PREFIX"],
[["leitung"], "bedienungsanleitung", "SUBSTRING"],
[["reinigne"], "reinigen", "FUZZY"],
[["reinigugn"], "reinigungsmittel", "FUZZY"],
[["er"], "filter", "NONE"],
[["filt"], "fitler", "NONE"]
],
"field_score": [
[["kuhl"], "Kühlschrank", "PREFIX"],
[["spul"], "Spülmaschine", "PREFIX"],
[["e24"], "Fehlercode E-24", "SUBSTRING"]
],
"score_fields": {
"fields": [["Filter reinigen", 3], ["Spülmaschine", 2]],
"hits": ["spülm filt", "spuel filter"],
"misses": ["spülm garten"],
"order_independent": [["filt spülm", "spülm filt"]],
"name_outranks_notes": {
"query": "filter",
"in_name": [["Filter", 3], ["", 1]],
"in_notes": [["Pumpe", 3], ["Filter wechseln", 1]]
}
}
}
@@ -36,8 +36,8 @@ describe("budget KPI tiles: spent-only display (#104)", () => {
}));
const tiles = sr(el).querySelectorAll(".budget-tile");
expect(tiles.length).to.equal(2);
expect(tiles[0].textContent).to.contain("9.00 €");
expect(tiles[1].textContent).to.contain("429.60 €");
expect(tiles[0].textContent).to.contain("9 €");
expect(tiles[1].textContent).to.contain("430 €");
expect(sr(el).querySelectorAll(".budget-tile-bar").length).to.equal(0);
});
@@ -51,9 +51,9 @@ describe("budget KPI tiles: spent-only display (#104)", () => {
// 2026-08-24: the spent amount carries the full stat-value typography
// (same size as the other KPI chips); the "/ max" ratio is its own
// small line so it can't overflow the grid cell.
expect(tiles[0].querySelector(".stat-value")!.textContent).to.contain("9.00 €");
expect(tiles[0].querySelector(".stat-value")!.textContent).to.contain("9 €");
expect(tiles[0].querySelector(".budget-tile-max")!.textContent).to.contain("/ 150 €");
expect(tiles[1].textContent).to.contain("429.60 €");
expect(tiles[1].textContent).to.contain("430 €");
expect(tiles[1].querySelector(".budget-tile-max"), "spent-only tile has no ratio line").to.equal(null);
});
@@ -166,9 +166,11 @@ describe("panel deep links (QR scan routing)", () => {
);
await settleRaf(el);
await settleRaf(el);
expect((el as unknown as { _toastMessage: string })._toastMessage).to.equal(
"Earliest completion is 2026-09-01",
);
// The known code gives the localized headline; the server's detail
// (which says more than the code) follows in parentheses.
const toast = (el as unknown as { _toastMessage: string })._toastMessage;
expect(toast).to.match(/^Too early — /);
expect(toast).to.include("(Earliest completion is 2026-09-01)");
const dlg = completeDialog(el);
expect(dlg?.shadowRoot?.querySelector("ha-dialog") ?? null, "no dialog").to.be.null;
});
@@ -59,7 +59,7 @@ describe("parts-section", () => {
await el.updateComplete;
const chip = el.shadowRoot!.querySelector(".inventory-value")!;
expect(chip, "value chip rendered").to.exist;
expect(chip.textContent).to.include("37.50");
expect(chip.textContent).to.include("38");
expect(chip.textContent).to.include("€");
});