mirror of
https://github.com/docker/docs.git
synced 2026-10-23 18:09:02 +03:00
154 lines
4.9 KiB
JavaScript
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");
|
|
});
|