mirror of
https://github.com/cloudflare/vinext.git
synced 2026-09-14 19:04:59 +08:00
8759b65c86
* fix(build): validate CDN warm path params * fix(build): exclude handlers from CDN warm paths * fix(build): resolve all CDN warm path owners * fix(build): preserve exact CDN warm path identity * fix(build): preserve encoded Pages warm paths * test(cloudflare): preserve encoded warm request URLs * fix(build): reject unsafe Pages warm paths * fix(router): match localized warm paths case-insensitively * fix(cache): honor build identity adapter capability * fix(build): reject normalized CDN warm paths * fix(build): discover dynamic MDX warm paths * fix(build): skip routes without static param generators * fix(cloudflare): validate warmup promotion delay
96 lines
4.1 KiB
TypeScript
96 lines
4.1 KiB
TypeScript
import { describe, expect, it, vi } from "vite-plus/test";
|
|
import { createAppPrerenderStaticParamsResolver } from "../packages/vinext/src/server/app-prerender-static-params.js";
|
|
|
|
describe("createAppPrerenderStaticParamsResolver", () => {
|
|
it("returns null when there are no sources at all", () => {
|
|
expect(createAppPrerenderStaticParamsResolver([])).toBeNull();
|
|
// An eager source that is not a function (e.g. `mod?.generateStaticParams`
|
|
// where the module has none) and no lazy sources → still null.
|
|
expect(createAppPrerenderStaticParamsResolver([undefined])).toBeNull();
|
|
});
|
|
|
|
it("resolves an eager generateStaticParams source", async () => {
|
|
const fn = () => [{ id: "a" }, { id: "b" }];
|
|
const resolver = createAppPrerenderStaticParamsResolver([fn]);
|
|
expect(resolver).not.toBeNull();
|
|
await expect(resolver!({ params: {} })).resolves.toEqual([{ id: "a" }, { id: "b" }]);
|
|
});
|
|
|
|
it("loads a lazy page source on demand and reads its generateStaticParams", async () => {
|
|
const load = vi.fn(async () => ({
|
|
generateStaticParams: () => [{ slug: "x" }, { slug: "y" }],
|
|
}));
|
|
const resolver = createAppPrerenderStaticParamsResolver([{ load }]);
|
|
expect(resolver).not.toBeNull();
|
|
// Not loaded until the resolver is actually invoked (prerender time).
|
|
expect(load).not.toHaveBeenCalled();
|
|
|
|
await expect(resolver!({ params: {} })).resolves.toEqual([{ slug: "x" }, { slug: "y" }]);
|
|
expect(load).toHaveBeenCalledTimes(1);
|
|
|
|
// Memoized: a second call does not re-import.
|
|
await resolver!({ params: {} });
|
|
expect(load).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it("returns the null sentinel when a lazy page has no generateStaticParams", async () => {
|
|
// A lazy page module with no generateStaticParams export. The resolver is
|
|
// non-null (there is a source) but must yield null so the prerender driver
|
|
// treats the route as having no static params (skip / output:export error).
|
|
const resolver = createAppPrerenderStaticParamsResolver([
|
|
{ load: async () => ({ default: () => null }) },
|
|
]);
|
|
expect(resolver).not.toBeNull();
|
|
await expect(resolver!({ params: {} })).resolves.toBeNull();
|
|
});
|
|
|
|
it("composes an eager layout source with a lazy page source", async () => {
|
|
const layout = () => [{ lang: "en" }, { lang: "fr" }];
|
|
const load = async () => ({ generateStaticParams: () => [{ slug: "post" }] });
|
|
const resolver = createAppPrerenderStaticParamsResolver([layout, { load }]);
|
|
|
|
await expect(resolver!({ params: {} })).resolves.toEqual([
|
|
{ lang: "en", slug: "post" },
|
|
{ lang: "fr", slug: "post" },
|
|
]);
|
|
});
|
|
|
|
it("composes sources in declared order regardless of eager/lazy kind", async () => {
|
|
// Lazy source first, eager second: composition order must follow `sources`
|
|
// order, not be reordered to eager-then-lazy.
|
|
const resolver = createAppPrerenderStaticParamsResolver([
|
|
{ load: async () => ({ generateStaticParams: () => [{ a: "1" }, { a: "2" }] }) },
|
|
() => [{ b: "x" }],
|
|
]);
|
|
|
|
await expect(resolver!({ params: {} })).resolves.toEqual([
|
|
{ a: "1", b: "x" },
|
|
{ a: "2", b: "x" },
|
|
]);
|
|
});
|
|
|
|
it("surfaces malformed results during CDN warm path discovery", async () => {
|
|
const previous = process.env.__VINEXT_PRERENDER_PATH_DISCOVERY;
|
|
process.env.__VINEXT_PRERENDER_PATH_DISCOVERY = "1";
|
|
try {
|
|
const nonArray = createAppPrerenderStaticParamsResolver([() => null]);
|
|
await expect(nonArray!({ params: {} })).rejects.toThrow(
|
|
"generateStaticParams must return an array",
|
|
);
|
|
|
|
const nonObjectEntry = createAppPrerenderStaticParamsResolver([() => ["slug"]]);
|
|
await expect(nonObjectEntry!({ params: {} })).rejects.toThrow(
|
|
"generateStaticParams must return an array of objects",
|
|
);
|
|
|
|
const nonPlainEntry = createAppPrerenderStaticParamsResolver([() => [new Date(0)]]);
|
|
await expect(nonPlainEntry!({ params: {} })).rejects.toThrow(
|
|
"generateStaticParams must return an array of objects",
|
|
);
|
|
} finally {
|
|
if (previous === undefined) delete process.env.__VINEXT_PRERENDER_PATH_DISCOVERY;
|
|
else process.env.__VINEXT_PRERENDER_PATH_DISCOVERY = previous;
|
|
}
|
|
});
|
|
});
|