1
0
mirror of https://github.com/home-assistant/frontend.git synced 2026-07-04 04:55:09 +01:00
Files
frontend/test/common/url/query-params.test.ts
Aidan Timson 8a85d1cf31 Use typed query param handling in todo and refactor handler typing (#52505)
* Use typed query param handlers for todo

* Refactor to query param config obj

* Remove type casts

* Use main window

Co-authored-by: Petar Petrov <MindFreeze@users.noreply.github.com>

* Fix import

---------

Co-authored-by: Petar Petrov <MindFreeze@users.noreply.github.com>
2026-06-09 11:40:45 +00:00

243 lines
6.5 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
createHistoryLogbookUrl,
decodeHistoryLogbookQueryParams,
historyLogbookQueryParamConfig,
historyLogbookTargetParamKeys,
historyLogbookTargetFromQueryParams,
} from "../../../src/common/url/history-logbook-query-params";
import {
createQueryString,
decodeQueryParams,
queryParamsFromServiceTarget,
serviceTargetFromQueryParams,
type QueryParamConfig,
} from "../../../src/common/url/query-params";
import {
createTodoQueryString,
decodeTodoQueryParams,
} from "../../../src/common/url/todo-query-params";
const panelQueryParams = [
{
type: "history",
path: "/history",
},
{
type: "logbook",
path: "/logbook",
},
] as const;
describe.each(panelQueryParams)("$type query params", (panel) => {
it("decodes target and date params", () => {
const params = decodeQueryParams(
"?entity_id=light.kitchen,switch.fan&device_id=device-1&area_id=kitchen&floor_id=downstairs&label_id=important&start_date=2026-06-05T10:00:00.000Z&end_date=2026-06-05T11:00:00.000Z&back=1",
historyLogbookQueryParamConfig
);
expect(params).toEqual({
entity_id: ["light.kitchen", "switch.fan"],
label_id: ["important"],
floor_id: ["downstairs"],
area_id: ["kitchen"],
device_id: ["device-1"],
start_date: new Date("2026-06-05T10:00:00.000Z"),
end_date: new Date("2026-06-05T11:00:00.000Z"),
back: true,
});
});
it("creates target picker values only when target params are present", () => {
expect(
serviceTargetFromQueryParams(
decodeQueryParams(
"?start_date=2026-06-05T10:00:00.000Z",
historyLogbookQueryParamConfig
),
historyLogbookTargetParamKeys
)
).toBeUndefined();
expect(
serviceTargetFromQueryParams(
decodeQueryParams(
"?entity_id=light.kitchen&area_id=kitchen",
historyLogbookQueryParamConfig
),
historyLogbookTargetParamKeys
)
).toEqual({
entity_id: ["light.kitchen"],
area_id: ["kitchen"],
});
});
it("ignores empty target values", () => {
expect(
serviceTargetFromQueryParams(
decodeQueryParams(
"?entity_id=&device_id=",
historyLogbookQueryParamConfig
),
historyLogbookTargetParamKeys
)
).toBeUndefined();
});
it("encodes target picker values", () => {
expect(
queryParamsFromServiceTarget(
{
entity_id: ["light.kitchen", "switch.fan"],
area_id: "kitchen",
},
historyLogbookTargetParamKeys
)
).toEqual({
entity_id: ["light.kitchen", "switch.fan"],
area_id: ["kitchen"],
});
});
it("creates deterministic query strings", () => {
expect(
createQueryString(
{
device_id: ["device-1"],
entity_id: ["light.kitchen"],
start_date: new Date("2026-06-05T10:00:00.000Z"),
end_date: new Date("2026-06-05T11:00:00.000Z"),
},
historyLogbookQueryParamConfig
)
).toBe(
"entity_id=light.kitchen&device_id=device-1&start_date=2026-06-05T10%3A00%3A00.000Z&end_date=2026-06-05T11%3A00%3A00.000Z"
);
});
it("creates typed URLs", () => {
expect(
createHistoryLogbookUrl(
panel.path,
{ entity_id: ["light.kitchen"] },
new Date("2026-06-05T10:00:00.000Z"),
new Date("2026-06-05T11:00:00.000Z")
)
).toBe(
`${panel.path}?entity_id=light.kitchen&start_date=2026-06-05T10%3A00%3A00.000Z&end_date=2026-06-05T11%3A00%3A00.000Z`
);
});
});
describe("history logbook query params", () => {
it("decodes query params", () => {
expect(
decodeHistoryLogbookQueryParams("?entity_id=light.kitchen&back=1")
).toEqual({
entity_id: ["light.kitchen"],
back: true,
});
});
it("creates target picker values only when target params are present", () => {
expect(
historyLogbookTargetFromQueryParams(
decodeHistoryLogbookQueryParams("?start_date=2026-06-05T10:00:00.000Z")
)
).toBeUndefined();
});
});
describe("string params", () => {
const stringConfig = {
string: ["name", "color"],
} as const satisfies QueryParamConfig;
it("decodes scalar string params", () => {
expect(decodeQueryParams("?name=hello&color=blue", stringConfig)).toEqual({
name: "hello",
color: "blue",
});
});
it("ignores empty string values", () => {
expect(decodeQueryParams("?name=&color=blue", stringConfig)).toEqual({
color: "blue",
});
});
it("ignores missing string params", () => {
expect(decodeQueryParams("?color=green", stringConfig)).toEqual({
color: "green",
});
});
it("encodes scalar string params", () => {
expect(
createQueryString({ name: "hello", color: "blue" }, stringConfig)
).toBe("name=hello&color=blue");
});
it("omits undefined string values from encoding", () => {
expect(createQueryString({ name: "hello" }, stringConfig)).toBe(
"name=hello"
);
});
});
describe("todo query params", () => {
it("decodes entity_id", () => {
expect(decodeTodoQueryParams("?entity_id=todo.shopping")).toEqual({
entity_id: "todo.shopping",
});
});
it("decodes entity_id with add_item", () => {
expect(
decodeTodoQueryParams("?entity_id=todo.shopping&add_item=true")
).toEqual({
entity_id: "todo.shopping",
add_item: true,
});
});
it("ignores add_item with non-true value", () => {
expect(
decodeTodoQueryParams("?entity_id=todo.shopping&add_item=false")
).toEqual({
entity_id: "todo.shopping",
});
});
it("returns empty for no params", () => {
expect(decodeTodoQueryParams("")).toEqual({});
});
it("creates query string with entity_id only", () => {
expect(createTodoQueryString({ entity_id: "todo.shopping" })).toBe(
"entity_id=todo.shopping"
);
});
it("creates query string with entity_id and add_item", () => {
expect(
createTodoQueryString({ entity_id: "todo.shopping", add_item: true })
).toBe("add_item=true&entity_id=todo.shopping");
});
it("omits add_item when false or undefined", () => {
expect(
createTodoQueryString({ entity_id: "todo.shopping", add_item: false })
).toBe("entity_id=todo.shopping");
});
it("round-trips decode and encode", () => {
const original = "?entity_id=todo.tasks&add_item=true";
const decoded = decodeTodoQueryParams(original);
const encoded = createTodoQueryString(decoded);
expect(encoded).toBe("add_item=true&entity_id=todo.tasks");
});
});