1
0
mirror of https://github.com/docker/docs.git synced 2026-10-23 18:09:02 +03:00
Files
docs/hack/releaser/cloudfront-lambda-redirects.test.js
2026-08-03 14:12:21 +00:00

154 lines
4.9 KiB
JavaScript

"use strict";
// Tests for cloudfront-lambda-redirects.js.
//
// The function source is a Go text/template (see aws.go) with two
// placeholders that are filled with JSON at build time. These tests render
// the template the same way aws.go does, then load and exercise the handler.
//
// Run with: node --test hack/releaser/cloudfront-lambda-redirects.test.js
const { test } = require("node:test");
const assert = require("node:assert/strict");
const fs = require("node:fs");
const path = require("node:path");
const Module = require("node:module");
const SRC = path.join(__dirname, "cloudfront-lambda-redirects.js");
const REDIRECTS = {
"/learn": "/learn/",
"/old/page/": "/new/page/",
"/target-with-query/": "/dest/?ref=docs",
"/target-with-fragment/": "/dest/?ref=docs#install",
"/external-target/": "https://www.docker.com/example?ref=docs#install",
};
const REDIRECTS_PREFIXES = [
{ prefix: "keep/", strip: false },
{ prefix: "strip/", strip: true },
];
// Render the template the same way getLambdaFunctionZip in aws.go does, then
// evaluate it as a CommonJS module so we can call handler() directly.
function loadHandler() {
const rendered = fs
.readFileSync(SRC, "utf8")
// Function replacers avoid String.replace's special handling of `$`
// sequences in the replacement, in case a redirect target contains one.
.replace("{{.RedirectsJSON}}", () => JSON.stringify(REDIRECTS))
.replace("{{.RedirectsPrefixesJSON}}", () =>
JSON.stringify(REDIRECTS_PREFIXES),
);
const m = new Module(SRC);
m._compile(rendered, SRC);
return m.exports.handler;
}
const handler = loadHandler();
// invoke wraps the callback-style handler in a promise.
function invoke({ uri, querystring = "", accept = "text/html" }) {
const request = {
uri,
querystring,
headers: { accept: [{ key: "Accept", value: accept }] },
};
const event = { Records: [{ cf: { request } }] };
return new Promise((resolve, reject) => {
handler(event, {}, (err, result) => {
if (err) return reject(err);
resolve({ result, request });
});
});
}
function locationOf(result) {
return result.headers.location[0].value;
}
test("exact redirect preserves the query string", async () => {
const { result } = await invoke({
uri: "/old/page/",
querystring: "utm_source=newsletter&utm_campaign=launch",
});
assert.equal(result.status, "301");
assert.equal(
locationOf(result),
"/new/page/?utm_source=newsletter&utm_campaign=launch",
);
});
test("exact redirect without a query string is unchanged", async () => {
const { result } = await invoke({ uri: "/old/page/" });
assert.equal(result.status, "301");
assert.equal(locationOf(result), "/new/page/");
});
test("bare path redirects without redirecting the canonical target to itself", async () => {
const { result: bareResult } = await invoke({ uri: "/learn" });
assert.equal(bareResult.status, "301");
assert.equal(locationOf(bareResult), "/learn/");
const { result: canonicalResult, request } = await invoke({ uri: "/learn/" });
assert.equal(canonicalResult, request);
assert.equal(request.uri, "/learn/index.html");
});
test("exact redirect appends with & when target already has a query string", async () => {
const { result } = await invoke({
uri: "/target-with-query/",
querystring: "utm_medium=email",
});
assert.equal(locationOf(result), "/dest/?ref=docs&utm_medium=email");
});
test("exact redirect inserts the query string before a fragment", async () => {
const { result } = await invoke({
uri: "/target-with-fragment/",
querystring: "utm_medium=email",
});
assert.equal(locationOf(result), "/dest/?ref=docs&utm_medium=email#install");
});
test("exact redirect preserves an absolute target URL", async () => {
const { result } = await invoke({
uri: "/external-target/",
querystring: "utm_medium=email",
});
assert.equal(
locationOf(result),
"https://www.docker.com/example?ref=docs&utm_medium=email#install",
);
});
test("prefix redirect (strip) preserves the query string", async () => {
const { result } = await invoke({
uri: "/strip/some/path",
querystring: "utm_source=x",
});
assert.equal(result.status, "301");
assert.equal(locationOf(result), "/some/path?utm_source=x");
});
test("prefix redirect (no strip) preserves the query string", async () => {
const { result } = await invoke({
uri: "/keep/anything",
querystring: "utm_source=x",
});
assert.equal(result.status, "301");
assert.equal(locationOf(result), "/?utm_source=x");
});
test("directory rewrite passes the request through with query string intact", async () => {
const { result, request } = await invoke({
uri: "/some/page",
querystring: "utm_source=x",
});
// No redirect response: the handler forwards the (mutated) request.
assert.equal(result, request);
assert.equal(request.uri, "/some/page/index.html");
assert.equal(request.querystring, "utm_source=x");
});