Extract pure extractAuthTokenFromSetCookie from performLogin (behavior-identical) so cookie parsing is unit-testable without a network login. Add round-trip coverage for media attrs (width/height/align/drawio/escaping) the existing suite omitted; applyAnchorInDoc selection/ambiguity/atom-break cases; and a cross-copy drift guard proving the vendored editor-ext recreate-transform and the @fellow npm copy used by diff.ts emit identical steps (apply(diff)==target). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
94 lines
4.2 KiB
JavaScript
94 lines
4.2 KiB
JavaScript
// Cookie parsing for the login flow.
|
|
//
|
|
// `performLogin` in auth-utils.ts does a real network POST and then extracts the
|
|
// auth token from the response's Set-Cookie header. The cookie-parsing logic was
|
|
// extracted into the pure, exported helper `extractAuthTokenFromSetCookie` so it
|
|
// can be tested without network I/O; `performLogin` now delegates to it, so these
|
|
// tests cover the exact parsing path the login uses.
|
|
import { test } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
import { extractAuthTokenFromSetCookie } from "../../build/lib/auth-utils.js";
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Happy path: a single authToken cookie with attributes.
|
|
// ---------------------------------------------------------------------------
|
|
test("extracts the authToken value, ignoring trailing attributes", () => {
|
|
const cookies = [
|
|
"authToken=abc123; Path=/; HttpOnly; Secure; SameSite=Lax",
|
|
];
|
|
assert.equal(extractAuthTokenFromSetCookie(cookies), "abc123");
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// A base64/JWT value containing "=" padding must NOT be truncated: only the
|
|
// FIRST "=" separates name from value.
|
|
// ---------------------------------------------------------------------------
|
|
test("preserves an '=' inside the value (base64 padding is not truncated)", () => {
|
|
const jwt = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0=";
|
|
const cookies = [`authToken=${jwt}; Path=/`];
|
|
assert.equal(extractAuthTokenFromSetCookie(cookies), jwt);
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Exact-name match: a different cookie whose name merely STARTS WITH "authToken"
|
|
// (e.g. authTokenRefresh) must not be picked up; the real authToken wins.
|
|
// ---------------------------------------------------------------------------
|
|
test("matches the cookie name exactly, not by prefix (authTokenRefresh ignored)", () => {
|
|
const cookies = [
|
|
"authTokenRefresh=refreshvalue; Path=/; HttpOnly",
|
|
"authToken=realtoken; Path=/; HttpOnly",
|
|
];
|
|
assert.equal(extractAuthTokenFromSetCookie(cookies), "realtoken");
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Picks the authToken out of several unrelated cookies regardless of order.
|
|
// ---------------------------------------------------------------------------
|
|
test("selects authToken among multiple unrelated cookies", () => {
|
|
const cookies = [
|
|
"session=xyz; Path=/",
|
|
"authToken=tok-7; Path=/; HttpOnly",
|
|
"theme=dark",
|
|
];
|
|
assert.equal(extractAuthTokenFromSetCookie(cookies), "tok-7");
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// An empty value is valid and returns "".
|
|
// ---------------------------------------------------------------------------
|
|
test("returns an empty string when authToken has an empty value", () => {
|
|
assert.equal(extractAuthTokenFromSetCookie(["authToken=; Path=/"]), "");
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Missing Set-Cookie header -> documented error.
|
|
// ---------------------------------------------------------------------------
|
|
test("throws when there is no Set-Cookie header", () => {
|
|
assert.throws(
|
|
() => extractAuthTokenFromSetCookie(undefined),
|
|
/No Set-Cookie header/,
|
|
);
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Set-Cookie present but no authToken cookie -> documented error.
|
|
// ---------------------------------------------------------------------------
|
|
test("throws when no authToken cookie is present", () => {
|
|
assert.throws(
|
|
() => extractAuthTokenFromSetCookie(["session=xyz; Path=/", "theme=dark"]),
|
|
/No authToken cookie/,
|
|
);
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// An empty cookie array also yields the "no authToken" error (header exists but
|
|
// is empty), distinct from the "no Set-Cookie header" case above.
|
|
// ---------------------------------------------------------------------------
|
|
test("throws 'no authToken' (not 'no header') for an empty cookie array", () => {
|
|
assert.throws(
|
|
() => extractAuthTokenFromSetCookie([]),
|
|
/No authToken cookie/,
|
|
);
|
|
});
|