test/shared/cookies.test.ts
Rama main · réplica de lectura del repositorio original.
import { assert, assertStringIncludes } from "@std/assert";
import { expect } from "@std/expect";
import { afterEach, describe, it as test } from "@std/testing/bdd";
import { parseCookies } from "#routes/url.ts";
import {
isSecureMode,
resetEffectiveDomain,
seedEffectiveDomainHost,
setEffectiveDomainForTest,
} from "#shared/config.ts";
import {
buildFlashCookie,
buildSessionCookie,
clearFlashCookie,
clearSessionCookie,
getSessionCookieName,
parseFlashValue,
} from "#shared/cookies.ts";
import { expectIncludesAll } from "#test-utils/assertions.ts";
/** Assert common cookie attributes for dev (localhost) mode */
const expectDevCookieAttributes = (cookie: string) => {
assertStringIncludes(cookie, "HttpOnly");
assert(!cookie.includes("; Secure;"));
expectIncludesAll(cookie, ["SameSite=Strict", "Path=/"]);
};
/** Assert common cookie attributes for secure (non-localhost) mode */
const expectSecureCookieAttributes = (cookie: string) => {
expectIncludesAll(cookie, [
"HttpOnly",
"; Secure;",
"SameSite=Strict",
"Path=/",
]);
};
describe("isSecureMode", () => {
afterEach(() => resetEffectiveDomain());
test("returns true for non-localhost domains", () => {
setEffectiveDomainForTest("example.com");
expect(isSecureMode()).toBe(true);
});
test("returns false for localhost", () => {
setEffectiveDomainForTest("localhost");
expect(isSecureMode()).toBe(false);
});
test("returns false for loopback IP hosts", () => {
setEffectiveDomainForTest("127.0.0.1");
expect(isSecureMode()).toBe(false);
setEffectiveDomainForTest("[::1]");
expect(isSecureMode()).toBe(false);
});
});
describe("getSessionCookieName", () => {
afterEach(() => resetEffectiveDomain());
test("returns __Host-session in secure mode", () => {
setEffectiveDomainForTest("example.com");
expect(getSessionCookieName()).toBe("__Host-session");
});
test("returns 'session' in dev mode", () => {
setEffectiveDomainForTest("localhost");
expect(getSessionCookieName()).toBe("session");
});
});
describe("buildSessionCookie", () => {
afterEach(() => resetEffectiveDomain());
test("includes __Host-session in secure mode with all required attributes", () => {
setEffectiveDomainForTest("example.com");
const cookie = buildSessionCookie("test-token");
assertStringIncludes(cookie, "__Host-session=test-token");
expectSecureCookieAttributes(cookie);
assertStringIncludes(cookie, "Max-Age=86400");
});
test("includes 'session' in dev mode without Secure flag", () => {
setEffectiveDomainForTest("localhost");
const cookie = buildSessionCookie("test-token");
assertStringIncludes(cookie, "session=test-token");
expectDevCookieAttributes(cookie);
assertStringIncludes(cookie, "Max-Age=86400");
});
test("keeps loopback request hosts in dev cookie mode", () => {
seedEffectiveDomainHost(new URL("http://127.0.0.1:38123/admin/"));
const cookie = buildSessionCookie("test-token");
assertStringIncludes(cookie, "session=test-token");
expectDevCookieAttributes(cookie);
});
test("respects custom maxAge", () => {
setEffectiveDomainForTest("example.com");
const cookie = buildSessionCookie("test-token", { maxAge: 3600 });
assertStringIncludes(cookie, "Max-Age=3600");
});
});
describe("clearSessionCookie", () => {
afterEach(() => resetEffectiveDomain());
test("includes __Host-session in secure mode with Max-Age=0", () => {
setEffectiveDomainForTest("example.com");
const cookie = clearSessionCookie();
assertStringIncludes(cookie, "__Host-session=");
expectSecureCookieAttributes(cookie);
assertStringIncludes(cookie, "Max-Age=0");
});
test("includes 'session' in dev mode without Secure flag", () => {
setEffectiveDomainForTest("localhost");
const cookie = clearSessionCookie();
assertStringIncludes(cookie, "session=");
expectDevCookieAttributes(cookie);
assertStringIncludes(cookie, "Max-Age=0");
});
});
describe("buildFlashCookie", () => {
afterEach(() => resetEffectiveDomain());
test("keys cookie name by flash ID", () => {
setEffectiveDomainForTest("localhost");
const cookie = buildFlashCookie("abc123", "Saved", true);
expect(cookie).toMatch(/^flash_abc123=/);
});
test("encodes success message as JSON", () => {
setEffectiveDomainForTest("localhost");
const cookie = buildFlashCookie("abc123", "Saved", true);
assertStringIncludes(
cookie,
encodeURIComponent(JSON.stringify({ m: "Saved", t: "s" })),
);
});
test("encodes error message as JSON", () => {
setEffectiveDomainForTest("localhost");
const cookie = buildFlashCookie("abc123", "Failed", false);
assertStringIncludes(
cookie,
encodeURIComponent(JSON.stringify({ m: "Failed", t: "e" })),
);
});
test("sets short Max-Age", () => {
setEffectiveDomainForTest("localhost");
const cookie = buildFlashCookie("abc123", "Saved", true);
assertStringIncludes(cookie, "Max-Age=10");
});
test("embeds the form re-fill token when provided", () => {
setEffectiveDomainForTest("localhost");
const cookie = buildFlashCookie(
"abc123",
"Saved",
true,
undefined,
undefined,
"stash-token",
);
assertStringIncludes(
cookie,
encodeURIComponent(
JSON.stringify({ f: "stash-token", m: "Saved", t: "s" }),
),
);
});
});
describe("clearFlashCookie", () => {
afterEach(() => resetEffectiveDomain());
test("clears the keyed cookie with Max-Age=0", () => {
setEffectiveDomainForTest("localhost");
const cookie = clearFlashCookie("abc123");
expect(cookie).toMatch(/^flash_abc123=/);
assertStringIncludes(cookie, "Max-Age=0");
});
});
describe("parseFlashValue", () => {
test("parses success flash value", () => {
const encoded = JSON.stringify({ m: "Listing created", t: "s" });
expect(parseFlashValue(encoded)).toEqual({
error: undefined,
formToken: undefined,
info: undefined,
result: undefined,
success: "Listing created",
});
});
test("parses error flash value", () => {
const encoded = JSON.stringify({ m: "Something went wrong", t: "e" });
expect(parseFlashValue(encoded)).toEqual({
error: "Something went wrong",
formToken: undefined,
info: undefined,
result: undefined,
success: undefined,
});
});
test("parses info flash value", () => {
const encoded = JSON.stringify({ m: "You've unsubscribed", t: "i" });
expect(parseFlashValue(encoded)).toEqual({
error: undefined,
formToken: undefined,
info: "You've unsubscribed",
result: undefined,
success: undefined,
});
});
test("decodes URL-encoded values", () => {
const encoded = encodeURIComponent(
JSON.stringify({ m: "Hello world", t: "s" }),
);
expect(parseFlashValue(encoded)).toEqual({
error: undefined,
formToken: undefined,
info: undefined,
result: undefined,
success: "Hello world",
});
});
test("parses flash with result", () => {
const encoded = JSON.stringify({ m: "Created", r: "abc123", t: "s" });
expect(parseFlashValue(encoded)).toEqual({
error: undefined,
formToken: undefined,
info: undefined,
result: "abc123",
success: "Created",
});
});
test("surfaces the form re-fill token when present", () => {
const encoded = JSON.stringify({ f: "stash-token", m: "Failed", t: "e" });
expect(parseFlashValue(encoded).formToken).toBe("stash-token");
});
test("throws for invalid format", () => {
expect(() => parseFlashValue("invalid")).toThrow();
});
});
describe("parseCookies", () => {
const reqWithCookies = (cookie: string) =>
new Request("http://localhost/", { headers: { cookie } });
test("parses simple key=value pairs", () => {
const cookies = parseCookies(reqWithCookies("session=abc; lang=en"));
expect(cookies.get("session")).toBe("abc");
expect(cookies.get("lang")).toBe("en");
});
test("returns empty map for no cookie header", () => {
const cookies = parseCookies(new Request("http://localhost/"));
expect(cookies.size).toBe(0);
});
test("preserves equals signs in cookie values", () => {
const cookies = parseCookies(
reqWithCookies("token=eyJhbGci.payload.sig=="),
);
expect(cookies.get("token")).toBe("eyJhbGci.payload.sig==");
});
test("handles URI-encoded flash cookie values", () => {
const payload = encodeURIComponent(JSON.stringify({ m: "Saved", t: "s" }));
const cookies = parseCookies(reqWithCookies(`flash_abc=${payload}`));
expect(cookies.get("flash_abc")).toBe(payload);
});
});