331 files

This commit is contained in:
Home Assistant Version Control
2026-10-04 05:26:42 +00:00
parent 22ba8b4648
commit c4d601bfba
331 changed files with 10227 additions and 50159 deletions
@@ -47,6 +47,21 @@ function setInput(el: MaintenanceCompleteDialog, index: number, value: string) {
input.dispatchEvent(new Event("input"));
}
/** The cost has its own element (#200: Cost | Credit and the amount). */
function costInput(el: MaintenanceCompleteDialog) {
return el.shadowRoot!.querySelector("ms-cost-input")! as HTMLElement & { value: string; updateComplete: Promise<unknown> };
}
function costAmount(el: MaintenanceCompleteDialog): HTMLInputElement {
return costInput(el).shadowRoot!.querySelector<HTMLInputElement>("input.amount")!;
}
function setCost(el: MaintenanceCompleteDialog, value: string) {
const input = costAmount(el);
input.value = value;
input.dispatchEvent(new Event("input"));
}
function clickComplete(el: MaintenanceCompleteDialog) {
const buttons = [...el.shadowRoot!.querySelectorAll(".dialog-actions ha-button")];
(buttons[buttons.length - 1] as HTMLElement).click();
@@ -60,8 +75,8 @@ describe("complete-dialog", () => {
});
setInput(el, 0, "oil changed");
setInput(el, 1, "12.5");
setInput(el, 2, "30");
setCost(el, "12.5");
setInput(el, 1, "30");
// Tick the second checklist step (click the checkbox; the event bubbles
// to the row's toggle handler exactly once).
const boxes = [...el.shadowRoot!.querySelectorAll<HTMLInputElement>(".checklist-item input")];
@@ -105,6 +120,34 @@ describe("complete-dialog", () => {
expect("completed_at" in msg).to.be.false;
});
it("a credit goes out as a negative cost (#200)", async () => {
// The old unit sold for 150: Credit, then the amount — a phone keypad
// has no minus key, so the switch carries the sign.
const { el, sent } = await mount();
const cost = costInput(el);
await cost.updateComplete;
cost.shadowRoot!.querySelector<HTMLButtonElement>(".kind.credit")!.click();
await cost.updateComplete;
expect(cost.shadowRoot!.querySelector(".hint")!.textContent).to.include("Money back");
setCost(el, "150");
clickComplete(el);
await new Promise((r) => setTimeout(r, 10));
const msg = sent.find((m) => m.type === "maintenance_supporter/task/complete")!;
expect(msg.cost).to.equal(-150);
});
it("notes may run over several lines (#202): a text area, sent trimmed, no Markdown promise", async () => {
const { el, sent } = await mount();
expect(el.shadowRoot!.querySelector("textarea.field-input"), "the notes field is a text area").to.exist;
// The history and the printouts show notes as plain text.
expect(el.shadowRoot!.textContent).not.to.include("Markdown");
setInput(el, 0, "Filter changed\nSeal checked\n");
clickComplete(el);
await new Promise((r) => setTimeout(r, 10));
const msg = sent.find((m) => m.type === "maintenance_supporter/task/complete")!;
expect(msg.notes, "the line break inside stays, the one at the end goes").to.equal("Filter changed\nSeal checked");
});
/** The optional backdate starts as a "Set date & time" button (#163): the
* HA datetime selector has no empty state, so the field only appears once
* the user asks for it, seeded with the current minute. */
@@ -396,10 +439,9 @@ describe("complete-dialog parts cost (#104)", () => {
expect(chip(el)!.textContent).to.include("18");
chip(el)!.click();
await el.updateComplete;
// Buy task: restock qty, notes, cost.
const cost = [...el.shadowRoot!.querySelectorAll<HTMLInputElement>(".field-input")][2];
await costInput(el).updateComplete;
// Machine value for the <input type="number"> — never profile-formatted.
expect(cost.value).to.equal("18");
expect(costAmount(el).value).to.equal("18");
expect(chip(el), "chip hides once cost is set").to.equal(null);
});
@@ -423,7 +465,7 @@ describe("complete-dialog parts cost (#104)", () => {
it("buy task: no chip once the user typed a cost themselves", async () => {
const el = await mountWithParts({ restockDefault: 1, restockUnitCost: 5 });
expect(chip(el)).to.exist;
setInput(el, 2, "3.10");
setCost(el, "3.10");
await el.updateComplete;
expect(chip(el)).to.equal(null);
});
@@ -128,8 +128,10 @@ describe("task-dialog completion-actions sections", () => {
"ms-textfield",
);
expect(qcInputs[0]?.value, "qc notes").to.equal("Quick note");
expect(qcInputs[1]?.value, "qc cost").to.equal("4.5");
expect(qcInputs[2]?.value, "qc duration").to.equal("10");
// The cost has its own element (#200: Cost | Credit and the amount).
const qcCost = sections[1].querySelector<HTMLElement & { value: string }>("ms-cost-input");
expect(qcCost?.value, "qc cost").to.equal("4.5");
expect(qcInputs[1]?.value, "qc duration").to.equal("10");
const qcSelect = sections[1].querySelector<HTMLSelectElement>("select.qc-feedback");
expect(qcSelect?.value, "qc feedback").to.equal("needed");