mirror of
https://github.com/cloudflare/vinext.git
synced 2026-09-14 19:04:59 +08:00
d85791c2fb
* feat(app-router): promote segment reset semantics Implements #726-CORE-11/12 from #726. Add typed App Router segment state-key derivation, wire template/loading/error/access boundaries to semantic reset keys, and preserve pathname fallback semantics for legacy boundary callers. Cover dynamic params, route groups, catch-all keys, template reset ownership, and boundary reset behavior. * fix(app-router): treat empty boundary reset keys as absent Empty segment identities can be produced for root, route-group-only, and default slot paths. Normalize empty reset keys to null so pathname fallback continues to clear caught boundary state. * fix(app-router): scope route reset keys to branches Use typed segment state identities and full visible route-state paths for route-wide wrappers so unrelated branches do not collide on the same leaf value. Add hostile unit and browser tests for dynamic and static branch collisions.
82 lines
2.5 KiB
TypeScript
82 lines
2.5 KiB
TypeScript
import { describe, expect, it } from "vite-plus/test";
|
|
import {
|
|
resolveAppPageLeafSegmentStateKey,
|
|
resolveAppPageRouteStateKey,
|
|
resolveAppPageSegmentStateKey,
|
|
} from "../packages/vinext/src/server/app-page-segment-state.js";
|
|
|
|
describe("app page segment state keys", () => {
|
|
// Mirrors Next.js createRouterCacheKey(..., true): the React state key is
|
|
// the active segment identity without search params, so search-only changes
|
|
// do not reset templates or boundaries.
|
|
it("resolves dynamic params into segment state keys without search params", () => {
|
|
expect(
|
|
resolveAppPageSegmentStateKey(["dashboard", "[team]", "settings"], 1, {
|
|
team: "alpha",
|
|
}),
|
|
).toBe("team|alpha|d");
|
|
});
|
|
|
|
it("skips route groups when selecting the state key below a tree position", () => {
|
|
expect(
|
|
resolveAppPageSegmentStateKey(["(marketing)", "blog", "[slug]"], 0, {
|
|
slug: "launch",
|
|
}),
|
|
).toBe("blog");
|
|
expect(
|
|
resolveAppPageSegmentStateKey(["(marketing)", "blog", "[slug]"], 1, {
|
|
slug: "launch",
|
|
}),
|
|
).toBe("blog");
|
|
expect(
|
|
resolveAppPageSegmentStateKey(["(marketing)", "blog", "[slug]"], 2, {
|
|
slug: "launch",
|
|
}),
|
|
).toBe("slug|launch|d");
|
|
});
|
|
|
|
it("keeps the leaf segment helper scoped to the active local segment", () => {
|
|
expect(
|
|
resolveAppPageLeafSegmentStateKey(["(marketing)", "blog", "[slug]"], {
|
|
slug: "launch",
|
|
}),
|
|
).toBe("slug|launch|d");
|
|
expect(resolveAppPageLeafSegmentStateKey(["(marketing)"], {})).toBe("");
|
|
});
|
|
|
|
it("uses the full visible segment-state path for route-wide reset keys", () => {
|
|
expect(
|
|
resolveAppPageRouteStateKey(["(marketing)", "blog", "[slug]"], {
|
|
slug: "launch",
|
|
}),
|
|
).toBe(JSON.stringify(["blog", "slug|launch|d"]));
|
|
|
|
expect(
|
|
resolveAppPageRouteStateKey(["posts", "[id]"], {
|
|
id: "123",
|
|
}),
|
|
).not.toBe(
|
|
resolveAppPageRouteStateKey(["photos", "[id]"], {
|
|
id: "123",
|
|
}),
|
|
);
|
|
|
|
expect(resolveAppPageRouteStateKey(["account", "settings"], {})).not.toBe(
|
|
resolveAppPageRouteStateKey(["admin", "settings"], {}),
|
|
);
|
|
});
|
|
|
|
it("keeps catch-all segment keys canonical", () => {
|
|
expect(
|
|
resolveAppPageSegmentStateKey(["docs", "[...parts]"], 1, {
|
|
parts: ["guides", "routing"],
|
|
}),
|
|
).toBe("parts|guides/routing|c");
|
|
expect(
|
|
resolveAppPageSegmentStateKey(["docs", "[[...parts]]"], 1, {
|
|
parts: [],
|
|
}),
|
|
).toBe("parts||oc");
|
|
});
|
|
});
|