one
Version:
One is a new React Framework that makes Vite serve both native and web.
210 lines (209 loc) • 7.48 kB
JavaScript
import { describe, expect, it } from "vitest";
import { setClientMatches } from "./useMatches";
describe("useMatches", () => {
describe("setClientMatches", () => {
it("should update client matches without errors", () => {
const matches = [
{
routeId: "/_layout",
pathname: "/",
params: {},
loaderData: { title: "Root" }
},
{
routeId: "/page",
pathname: "/page",
params: {},
loaderData: { content: "Page content" }
}
];
expect(() => setClientMatches(matches)).not.toThrow();
}), it("should accept empty matches array", () => {
expect(() => setClientMatches([])).not.toThrow();
});
}), describe("type safety", () => {
it("should have correct RouteMatch type", () => {
const match = {
routeId: "test",
pathname: "/test",
params: { id: "123" },
loaderData: { foo: "bar" }
};
expect(match.routeId).toBe("test"), expect(match.pathname).toBe("/test"), expect(match.params.id).toBe("123"), expect(match.loaderData).toEqual({ foo: "bar" });
}), it("should allow string[] params", () => {
expect({
routeId: "test",
pathname: "/test",
params: { slugs: ["a", "b", "c"] },
loaderData: null
}.params.slugs).toEqual(["a", "b", "c"]);
}), it("should allow undefined loaderData", () => {
expect({
routeId: "test",
pathname: "/test",
params: {},
loaderData: void 0
}.loaderData).toBeUndefined();
});
});
});
describe("RouteMatch ordering", () => {
it("matches should be ordered parent to child (root layout first)", () => {
const matches = [
{ routeId: "/_layout", pathname: "/", params: {}, loaderData: { level: "root" } },
{
routeId: "/docs/_layout",
pathname: "/docs",
params: {},
loaderData: { level: "docs" }
},
{
routeId: "/docs/intro",
pathname: "/docs/intro",
params: {},
loaderData: { level: "page" }
}
];
expect(matches[0].routeId).toBe("/_layout"), expect(matches[0].loaderData.level).toBe("root"), expect(matches[1].routeId).toBe("/docs/_layout"), expect(matches[1].loaderData.level).toBe("docs"), expect(matches[2].routeId).toBe("/docs/intro"), expect(matches[2].loaderData.level).toBe("page");
}), it("last match should be the current page", () => {
const matches = [
{ routeId: "/_layout", pathname: "/", params: {}, loaderData: {} },
{
routeId: "/page",
pathname: "/page",
params: { id: "123" },
loaderData: { title: "Page" }
}
], pageMatch = matches[matches.length - 1];
expect(pageMatch.routeId).toBe("/page"), expect(pageMatch.loaderData.title).toBe("Page");
});
});
describe("setClientMatches reactivity", () => {
it("should notify listeners when matches change", () => {
let notifyCount = 0;
const listener = () => {
notifyCount++;
}, matches1 = [
{ routeId: "/page1", pathname: "/page1", params: {}, loaderData: {} }
], matches2 = [
{ routeId: "/page2", pathname: "/page2", params: {}, loaderData: {} }
];
setClientMatches(matches1), setClientMatches(matches2), expect(notifyCount).toBe(0);
}), it("should handle multiple sequential updates", () => {
const matches1 = [
{ routeId: "/a", pathname: "/a", params: {}, loaderData: { n: 1 } }
], matches2 = [
{ routeId: "/b", pathname: "/b", params: {}, loaderData: { n: 2 } }
], matches3 = [
{ routeId: "/c", pathname: "/c", params: {}, loaderData: { n: 3 } }
];
expect(() => {
setClientMatches(matches1), setClientMatches(matches2), setClientMatches(matches3);
}).not.toThrow();
});
});
describe("RouteMatch with dynamic params", () => {
it("should handle single dynamic param", () => {
expect({
routeId: "/users/[id]",
pathname: "/users/123",
params: { id: "123" },
loaderData: { user: { name: "John" } }
}.params.id).toBe("123");
}), it("should handle multiple dynamic params", () => {
const match = {
routeId: "/users/[userId]/posts/[postId]",
pathname: "/users/123/posts/456",
params: { userId: "123", postId: "456" },
loaderData: { post: { title: "Hello" } }
};
expect(match.params.userId).toBe("123"), expect(match.params.postId).toBe("456");
}), it("should handle catch-all params", () => {
expect({
routeId: "/docs/[...slug]",
pathname: "/docs/getting-started/intro",
params: { slug: ["getting-started", "intro"] },
loaderData: { doc: { content: "Hello" } }
}.params.slug).toEqual(["getting-started", "intro"]);
});
});
describe("RouteMatch loaderData scenarios", () => {
it("should handle complex nested loaderData", () => {
const data = {
routeId: "/dashboard",
pathname: "/dashboard",
params: {},
loaderData: {
user: {
id: 1,
profile: {
name: "John",
settings: {
theme: "dark",
notifications: !0
}
}
},
posts: [
{ id: 1, title: "Post 1" },
{ id: 2, title: "Post 2" }
]
}
}.loaderData;
expect(data.user.profile.settings.theme).toBe("dark"), expect(data.posts).toHaveLength(2);
}), it("should handle null loaderData", () => {
expect({
routeId: "/empty",
pathname: "/empty",
params: {},
loaderData: null
}.loaderData).toBeNull();
}), it("should handle array loaderData", () => {
expect({
routeId: "/list",
pathname: "/list",
params: {},
loaderData: [1, 2, 3, 4, 5]
}.loaderData).toEqual([1, 2, 3, 4, 5]);
}), it("should handle primitive loaderData", () => {
expect({
routeId: "/count",
pathname: "/count",
params: {},
loaderData: 42
}.loaderData).toBe(42);
});
});
describe("finding matches", () => {
const createMatches = () => [
{ routeId: "/_layout", pathname: "/", params: {}, loaderData: { root: !0 } },
{
routeId: "/docs/_layout",
pathname: "/docs",
params: {},
loaderData: { navItems: ["intro", "guide"] }
},
{
routeId: "/docs/[slug]",
pathname: "/docs/intro",
params: { slug: "intro" },
loaderData: { title: "Introduction", headings: ["h1", "h2"] }
}
];
it("should find match by exact routeId", () => {
const found = createMatches().find((m) => m.routeId === "/docs/_layout");
expect(found).toBeDefined(), expect(found.loaderData.navItems).toEqual(["intro", "guide"]);
}), it("should find match by routeId pattern", () => {
const found = createMatches().find((m) => m.routeId.includes("_layout"));
expect(found).toBeDefined(), expect(found.routeId).toBe("/_layout");
}), it("should get page match (last in array)", () => {
const matches = createMatches(), pageMatch = matches[matches.length - 1];
expect(pageMatch.routeId).toBe("/docs/[slug]"), expect(pageMatch.loaderData.title).toBe("Introduction");
}), it("should get layout match for a page", () => {
const layoutMatch = createMatches().find(
(m) => m.routeId.includes("/docs/") && m.routeId.includes("_layout")
);
expect(layoutMatch).toBeDefined(), expect(layoutMatch.loaderData.navItems).toBeDefined();
});
});
//# sourceMappingURL=useMatches.test.js.map