1
0
mirror of https://github.com/home-assistant/frontend.git synced 2026-07-02 03:55:52 +01:00
Files
frontend/test/resources/fuseMultiTerm.test.ts
2026-06-23 08:15:37 +03:00

159 lines
4.5 KiB
TypeScript

import Fuse from "fuse.js";
import { describe, expect, it } from "vitest";
import {
multiTermSortedSearch,
type FuseWeightedKey,
} from "../../src/resources/fuseMultiTerm";
interface Item {
id: string;
name: string;
description: string;
}
const keys: FuseWeightedKey[] = [
{ name: "name", weight: 10 },
{ name: "description", weight: 1 },
];
const getId = (i: Item) => i.id;
const search = (items: Item[], query: string) => {
const index = Fuse.createIndex(keys, items);
return multiTermSortedSearch(items, query, getId, index);
};
const ids = (items: Item[], query: string) => search(items, query).map(getId);
const item = (id: string, name: string, description = ""): Item => ({
id,
name,
description,
});
describe("multiTermSortedSearch", () => {
describe("filtering", () => {
it("returns all items for a blank search", () => {
const items = [item("1", "Alpha"), item("2", "Beta")];
expect(search(items, " ")).toEqual(items);
});
it("returns an empty array when there are no items", () => {
expect(search([], "alpha")).toEqual([]);
});
it("filters to matching items for a single term", () => {
const items = [item("match", "Apple pie"), item("miss", "Banana bread")];
expect(ids(items, "apple")).toEqual(["match"]);
});
it("keeps only items that match every term", () => {
const items = [item("both", "Red apple"), item("one", "Red onion")];
expect(ids(items, "red apple")).toEqual(["both"]);
});
it("returns nothing when a term matches no item", () => {
const items = [item("1", "Red apple"), item("2", "Green apple")];
expect(search(items, "apple zzzzz")).toEqual([]);
});
it("matches case-insensitively", () => {
const items = [item("1", "Red Apple")];
expect(ids(items, "RED apple")).toEqual(["1"]);
});
it("ignores diacritics", () => {
const items = [item("1", "Crème brûlée")];
expect(ids(items, "creme brulee")).toEqual(["1"]);
});
it("ignores extra whitespace between terms", () => {
const items = [item("both", "Red apple"), item("one", "Red onion")];
expect(ids(items, "red apple")).toEqual(["both"]);
});
it("tolerates a small typo", () => {
const items = [item("1", "Strawberry"), item("2", "Blueberry")];
expect(ids(items, "strawbery")).toEqual(["1"]);
});
});
describe("ranking", () => {
it("ranks a match in a higher-weighted field first", () => {
const inName = item("name", "ripe mango from the orchard");
const inDescription = item("description", "Smoothie", "ripe mango");
expect(ids([inDescription, inName], "ripe mango")[0]).toBe("name");
});
it("ranks the shorter match first when weights are equal", () => {
const short = item("short", "ripe mango");
const long = item("long", "ripe mango from the orchard");
expect(ids([long, short], "ripe mango")[0]).toBe("short");
});
it("ranks an exact match above a fuzzy one", () => {
const exact = item("exact", "Red apple");
const fuzzy = item("fuzzy", "Red aple");
expect(ids([fuzzy, exact], "red apple")[0]).toBe("exact");
});
});
describe("parameters", () => {
it("uses getItemId to aggregate an item across terms", () => {
const items = [item("both", "Red apple"), item("one", "Red onion")];
const result = multiTermSortedSearch(
items,
"red apple",
getId,
Fuse.createIndex(keys, items)
);
expect(result.map((i) => i.id)).toEqual(["both"]);
});
it("builds the index from keys passed in options when none is provided", () => {
const items = [item("1", "Red apple"), item("2", "Green apple")];
const result = multiTermSortedSearch(
items,
"red apple",
getId,
undefined,
{ keys }
);
expect(result.map((i) => i.id)).toEqual(["1"]);
});
it("returns nothing without an index or keys", () => {
const items = [item("1", "Red apple")];
expect(multiTermSortedSearch(items, "red apple", getId)).toEqual([]);
});
it("forwards Fuse options, like a stricter threshold", () => {
const items = [item("1", "Strawberry")];
const index = Fuse.createIndex(keys, items);
// The default threshold accepts this typo; a threshold of 0 rejects it.
expect(
multiTermSortedSearch(items, "strawbery", getId, index, {
threshold: 0,
})
).toEqual([]);
});
});
});