Files
edgeever/tests/deployment-verify.test.ts

157 lines
5.9 KiB
TypeScript

import { describe, expect, test } from "bun:test";
import {
buildSchemaVerificationSql,
normalizeDeploymentUrl,
parseCapturedDeploymentTargets,
parseCapturedDeploymentUrls,
parseD1Rows,
parseJsonOutput,
parseSecretNames,
REQUIRED_TABLES,
resolveDeploymentUrl,
verifyCloudflareWorkerHealth,
} from "../scripts/verify-deployment.mjs";
import {
parseWranglerDeploymentUrls,
parseWranglerDeploymentVersionId,
shouldCaptureDeploymentTargets,
} from "../scripts/wrangler-runner.mjs";
describe("deployment verification", () => {
test("checks the remote schema tables required by current application code", () => {
const sql = buildSchemaVerificationSql();
for (const table of REQUIRED_TABLES) {
expect(sql).toContain(`'${table}'`);
}
});
test("parses Wrangler D1 JSON output", () => {
expect(parseD1Rows(JSON.stringify([{ results: [{ name: "users" }] }]))).toEqual([{ name: "users" }]);
});
test("reports empty Wrangler JSON output clearly", () => {
expect(() => parseJsonOutput("", "the remote D1 schema")).toThrow(
"Wrangler returned no JSON while checking the remote D1 schema.",
);
});
test("treats an empty D1 result as zero rows", () => {
expect(parseD1Rows("")).toEqual([]);
});
test("parses current and wrapped Wrangler secret output", () => {
expect(parseSecretNames(JSON.stringify([{ name: "EDGE_EVER_AUTH_PASSWORD" }]))).toContain(
"EDGE_EVER_AUTH_PASSWORD",
);
expect(parseSecretNames(JSON.stringify({ result: [{ name: "EDGE_EVER_AUTH_PASSWORD_HASH" }] }))).toContain(
"EDGE_EVER_AUTH_PASSWORD_HASH",
);
});
test("captures public Workers and custom-domain URLs from Wrangler deploy output", () => {
expect(parseWranglerDeploymentUrls([
"Uploaded edgeever (2.1 sec)",
"Deployed edgeever triggers (0.4 sec)",
" https://edgeever.example.workers.dev",
" notes.example.com (custom domain)",
"Current Version ID: version-1",
].join("\n"))).toEqual([
"https://edgeever.example.workers.dev",
"https://notes.example.com",
]);
expect(parseWranglerDeploymentUrls("No targets deployed for edgeever")).toEqual([]);
expect(parseWranglerDeploymentVersionId([
"Uploaded edgeever (2.1 sec)",
"Current Version ID: version-1",
].join("\n"))).toBe("version-1");
});
test("captures deployment targets only in CI environments", () => {
expect(shouldCaptureDeploymentTargets({ WORKERS_CI: "1" })).toBe(true);
expect(shouldCaptureDeploymentTargets({ CI: " TRUE " })).toBe(true);
expect(shouldCaptureDeploymentTargets({})).toBe(false);
});
test("resolves an explicit or captured deployment URL without credentials or paths", () => {
expect(normalizeDeploymentUrl("notes.example.com/path")).toBe("https://notes.example.com");
expect(parseCapturedDeploymentUrls(JSON.stringify({
urls: ["https://edgeever.example.workers.dev"],
}))).toEqual(["https://edgeever.example.workers.dev"]);
expect(parseCapturedDeploymentTargets(JSON.stringify({
urls: ["https://edgeever.example.workers.dev"],
versionId: "version-1",
}))).toEqual({
urls: ["https://edgeever.example.workers.dev"],
versionId: "version-1",
});
expect(resolveDeploymentUrl({
env: { EDGE_EVER_DEPLOYMENT_URL: "https://notes.example.com/app" },
capturedUrls: ["https://edgeever.example.workers.dev"],
})).toBe("https://notes.example.com");
expect(resolveDeploymentUrl({
env: { EDGE_EVER_CUSTOM_DOMAIN: "notes.example.com" },
capturedUrls: [],
})).toBe("https://notes.example.com");
expect(() => normalizeDeploymentUrl("file:///tmp/edgeever")).toThrow("must use HTTP(S)");
});
test("verifies the live Worker health response", async () => {
let requestedUrl = "";
const result = await verifyCloudflareWorkerHealth({
deploymentUrl: "https://notes.example.com",
attempts: 1,
fetchImpl: async (url) => {
requestedUrl = String(url);
return Response.json({ ok: true, authMode: "required" });
},
});
expect(requestedUrl).toBe("https://notes.example.com/api/health");
expect(result.payload).toMatchObject({ ok: true });
});
test("requires a URL before requesting the live Worker", async () => {
expect(verifyCloudflareWorkerHealth({ deploymentUrl: "" })).rejects.toThrow(
"A deployment URL is required",
);
});
test("diagnoses a live Worker bound to a different unprepared D1 database", async () => {
expect(verifyCloudflareWorkerHealth({
deploymentUrl: "https://notes.example.com",
attempts: 1,
fetchImpl: async () => Response.json({
error: { code: "database_not_ready" },
}, { status: 503 }),
})).rejects.toThrow("may differ from the DB binding used by the live Worker");
});
test("diagnoses a live Worker without its R2 binding", async () => {
expect(verifyCloudflareWorkerHealth({
deploymentUrl: "https://notes.example.com",
attempts: 1,
fetchImpl: async () => Response.json({
error: { code: "object_storage_not_ready" },
}, { status: 503 }),
})).rejects.toThrow("RESOURCES binding points to the configured R2 bucket");
});
test("preserves Cloudflare runtime diagnostics for an unknown health failure", async () => {
const verification = verifyCloudflareWorkerHealth({
deploymentUrl: "https://notes.example.com",
deploymentVersionId: "version-1101",
attempts: 1,
fetchImpl: async () => new Response("error code: 1101", {
status: 500,
statusText: "Internal Server Error",
headers: { "CF-Ray": "ray-id-SJC" },
}),
});
await expect(verification).rejects.toThrow("response body: error code: 1101");
await expect(verification).rejects.toThrow("CF-Ray: ray-id-SJC");
await expect(verification).rejects.toThrow("Worker Version ID: version-1101");
await expect(verification).rejects.toThrow("Logs > Live");
});
});