Files
cloudflare__vinext/tests/cloudflare-version-deploy.test.ts
James Anderson f1efcc1e60 fix(cloudflare): harden canonical RSC warmup end to end (#3040)
* fix(cloudflare): validate reusable warm responses

* fix(cloudflare): retry staged warmup failures safely

* fix(cloudflare): extend staged propagation retries

* fix(build): filter Pages-owned RSC warm paths

* fix(cloudflare): keep CDN warmup correct with custom adapters and i18n

* fix(cloudflare): reject unusable CDN warm responses

* fix(cloudflare): keep CDN warmup bound to the deployed build

* fix(router): reuse warmed RSC on locale-prefixed hybrid routes

* fix(cloudflare): verify exact build and variant during CDN warmup

* fix(router): keep warmed RSC ownership rewrite-safe

* test(cloudflare): prove browser reuse of warmed RSC variants

* test(cloudflare): bind RSC warm proof to each deploy attempt

* fix(rsc): keep deferred loading shells contextual

* fix(build): keep CDN warm discovery route-correct

* fix(cache): preserve valid CDN policy during RSC warmup

* fix(cloudflare): warm the deployed Worker route host

* fix(cloudflare): preserve staged warmup guarantees

* fix(build): discover localized Pages warmup paths

* fix(cloudflare): wait for staged Worker before CDN warmup

* fix(cloudflare): preserve strict warmup deploy invariants

* fix(build): fail closed during CDN warm discovery
2026-08-24 23:03:14 +01:00

267 lines
8.9 KiB
TypeScript

import { afterEach, describe, expect, it, vi } from "vite-plus/test";
import {
buildWranglerDeploymentsStatusArgs,
buildWranglerTriggersDeployArgs,
buildWranglerVersionDeployArgs,
buildWranglerVersionUploadArgs,
parseVersionId,
parseWorkersDevUrl,
parseWranglerDeploymentStatusOutput,
parseWranglerVersionUploadOutput,
runWranglerVersionDeploy,
runWranglerVersionUpload,
} from "../packages/cloudflare/src/version-deploy.js";
describe("Cloudflare Wrangler version deployment helpers", () => {
afterEach(() => {
vi.restoreAllMocks();
});
it("builds version upload args for production", () => {
expect(buildWranglerVersionUploadArgs({})).toEqual({
args: ["versions", "upload"],
env: undefined,
});
});
it("builds version upload args for a named environment and preview alias", () => {
expect(buildWranglerVersionUploadArgs({ env: "staging", previewAlias: "warm-build" })).toEqual({
args: ["versions", "upload", "--env", "staging", "--preview-alias", "warm-build"],
env: "staging",
});
});
it("builds version upload args for an explicit Worker name", () => {
expect(
buildWranglerVersionUploadArgs({
name: "custom-worker",
env: "staging",
previewAlias: "warm-build",
}),
).toEqual({
args: [
"versions",
"upload",
"--name",
"custom-worker",
"--env",
"staging",
"--preview-alias",
"warm-build",
],
env: "staging",
});
});
it("builds version upload args for an explicit Wrangler config", () => {
expect(buildWranglerVersionUploadArgs({ config: "dist/server/wrangler.json" })).toEqual({
args: ["versions", "upload", "--config", "dist/server/wrangler.json"],
env: undefined,
});
});
it("builds non-interactive version deploy args for the uploaded version", () => {
expect(
buildWranglerVersionDeployArgs(
[{ versionId: "095f00a7-23a7-43b7-a227-e4c97cab5f22", percentage: 100 }],
{},
),
).toEqual({
args: ["versions", "deploy", "095f00a7-23a7-43b7-a227-e4c97cab5f22@100%", "--yes"],
env: undefined,
});
});
it("builds non-interactive split deployment args for staging a version", () => {
expect(
buildWranglerVersionDeployArgs(
[
{ versionId: "11111111-1111-4111-8111-111111111111", percentage: 100 },
{ versionId: "22222222-2222-4222-8222-222222222222", percentage: 0 },
],
{ env: "staging" },
),
).toEqual({
args: [
"versions",
"deploy",
"11111111-1111-4111-8111-111111111111@100%",
"22222222-2222-4222-8222-222222222222@0%",
"--yes",
"--env",
"staging",
],
env: "staging",
});
});
it("logs distinct labels for staged and promoted version deploys", () => {
const log = vi.spyOn(console, "log").mockImplementation(() => {});
const execute = vi.fn(() => "Deployed version\nhttps://app.example.workers.dev\n");
runWranglerVersionDeploy(
"/tmp/app",
[
{ versionId: "11111111-1111-4111-8111-111111111111", percentage: 100 },
{ versionId: "22222222-2222-4222-8222-222222222222", percentage: 0 },
],
{},
"stage",
execute as never,
);
runWranglerVersionDeploy(
"/tmp/app",
[{ versionId: "22222222-2222-4222-8222-222222222222", percentage: 100 }],
{},
"promote-warmed",
execute as never,
);
runWranglerVersionDeploy(
"/tmp/app",
[{ versionId: "22222222-2222-4222-8222-222222222222", percentage: 100 }],
{ env: "staging" },
"promote-uploaded",
execute as never,
);
expect(log).toHaveBeenCalledWith(
"\n Staging uploaded Worker version at 0% for CDN warmup in production...",
);
expect(log).toHaveBeenCalledWith("\n Promoting warmed Worker version to production...");
expect(log).toHaveBeenCalledWith("\n Promoting uploaded Worker version to env: staging...");
});
it("asks for an initial deploy without CDN pre-warm when the Worker does not exist yet", () => {
vi.spyOn(console, "log").mockImplementation(() => {});
const execute = vi.fn(() => {
throw Object.assign(new Error("Command failed"), {
stderr:
"✘ [ERROR] You cannot upload a new version of a Worker that does not yet exist. Please run the `deploy` command first.",
});
});
expect(() => runWranglerVersionUpload("/tmp/app", {}, execute as never)).toThrow(
"Run `vinext-cloudflare deploy` once without `--experimental-warm-cdn-cache` to create the Worker",
);
});
it("builds deployment status args for environments", () => {
expect(buildWranglerDeploymentsStatusArgs({ env: "preview" })).toEqual({
args: ["deployments", "status", "--json", "--env", "preview"],
env: "preview",
});
});
it("builds deployment status args for an explicit Worker name", () => {
expect(buildWranglerDeploymentsStatusArgs({ name: "custom-worker" })).toEqual({
args: ["deployments", "status", "--json", "--name", "custom-worker"],
env: undefined,
});
});
it("builds deployment status args for an explicit Wrangler config", () => {
expect(buildWranglerDeploymentsStatusArgs({ config: "dist/server/wrangler.json" })).toEqual({
args: ["deployments", "status", "--json", "--config", "dist/server/wrangler.json"],
env: undefined,
});
});
it("builds trigger deployment args for environments", () => {
expect(buildWranglerTriggersDeployArgs({ env: "preview" })).toEqual({
args: ["triggers", "deploy", "--env", "preview"],
env: "preview",
});
});
it("parses version IDs and preview URLs from Wrangler text output", () => {
const output = `
Uploaded app 095f00a7-23a7-43b7-a227-e4c97cab5f22
https://app-warm.example.workers.dev
`;
expect(parseVersionId(output)).toBe("095f00a7-23a7-43b7-a227-e4c97cab5f22");
expect(parseWorkersDevUrl(output)).toBe("https://app-warm.example.workers.dev");
expect(parseWranglerVersionUploadOutput(output)).toMatchObject({
versionId: "095f00a7-23a7-43b7-a227-e4c97cab5f22",
previewUrl: "https://app-warm.example.workers.dev",
});
});
it("parses workers.dev URLs without depending on a broad URL regex", () => {
expect(parseWorkersDevUrl("Preview: <https://app.example.workers.dev/path?x=1>.")).toBe(
"https://app.example.workers.dev/path?x=1",
);
expect(parseWorkersDevUrl(`https://${"a".repeat(2048)}.example.com`)).toBeNull();
});
it("parses version upload JSON output", () => {
expect(
parseWranglerVersionUploadOutput(
JSON.stringify({
version: { id: "095f00a7-23a7-43b7-a227-e4c97cab5f22" },
preview_url: "https://app-warm.example.workers.dev",
}),
),
).toMatchObject({
versionId: "095f00a7-23a7-43b7-a227-e4c97cab5f22",
previewUrl: "https://app-warm.example.workers.dev",
});
});
it("prefers Wrangler's labeled version ID over UUIDs in uploaded asset paths", () => {
const output = `
+ /_next/static/82859cda-4cfe-4924-96da-fe471138612a/_buildManifest.js
Uploaded rsc-prewarm-32362416100 (4.16 sec)
Worker Version ID: 7283300a-90b0-45d6-ba08-7c4b76797f38
Version Preview URL: https://7283300a-rsc-prewarm-32362416100.vinext.workers.dev
`;
expect(parseWranglerVersionUploadOutput(output)).toMatchObject({
versionId: "7283300a-90b0-45d6-ba08-7c4b76797f38",
workerName: "rsc-prewarm-32362416100",
previewUrl: "https://7283300a-rsc-prewarm-32362416100.vinext.workers.dev",
});
});
it("does not treat unrelated nested JSON IDs and URLs as upload metadata", () => {
expect(
parseWranglerVersionUploadOutput(
JSON.stringify({
version_id: "095f00a7-23a7-43b7-a227-e4c97cab5f22",
preview_url: "https://app-warm.example.workers.dev",
diagnostics: {
id: "not-the-version",
url: "https://not-preview.example.workers.dev",
},
}),
),
).toMatchObject({
versionId: "095f00a7-23a7-43b7-a227-e4c97cab5f22",
previewUrl: "https://app-warm.example.workers.dev",
});
});
it("throws when upload output lacks a version ID", () => {
expect(() => parseWranglerVersionUploadOutput("uploaded")).toThrow(
"Could not detect Worker version ID",
);
});
it("keeps the uploaded version when Wrangler does not return a preview URL", () => {
expect(parseWranglerVersionUploadOutput("095f00a7-23a7-43b7-a227-e4c97cab5f22")).toMatchObject({
versionId: "095f00a7-23a7-43b7-a227-e4c97cab5f22",
previewUrl: null,
});
});
it("parses current deployment version traffic", () => {
expect(
parseWranglerDeploymentStatusOutput(
JSON.stringify({
versions: [{ version_id: "11111111-1111-4111-8111-111111111111", percentage: 100 }],
}),
).versions,
).toEqual([{ versionId: "11111111-1111-4111-8111-111111111111", percentage: 100 }]);
});
});