import assert from "node:assert/strict";
import test from "node:test";
import { randomUUID } from "node:crypto";
import {
createAuthenticatedTestClient,
resolveApiUrl
} from "./authenticated-test-client.mjs";
test("resolveApiUrl keeps deployment path prefix", () => {
const url = resolveApiUrl("https://example.com/datafoundry", "api/v1/me");
assert.equal(url.href, "https://example.com/datafoundry/api/v1/me");
});
test("resolveApiUrl strips search and hash from base", () => {
const url = resolveApiUrl("https://example.com/datafoundry?x=1#frag", "/api/v1/me");
assert.equal(url.href, "https://example.com/datafoundry/api/v1/me");
});
test("resolveApiUrl preserves query from relative path", () => {
const url = resolveApiUrl("https://example.com/datafoundry", "/api/v1/sessions/s1/conversation?limit=10");
assert.equal(url.href, "https://example.com/datafoundry/api/v1/sessions/s1/conversation?limit=10");
});
test("adds cookie and csrf to unsafe requests", async () => {
const calls = [];
const client = createAuthenticatedTestClient({
baseUrl: "http://127.0.0.1:8787",
fetchImpl: async (url, init) => {
calls.push({ url, init });
return new Response("{}", { status: 200 });
}
});
client.cookies.replace({
df_session: "session-secret",
df_csrf: "csrf-secret"
});
await client.fetch("/api/v1/config", { method: "POST", body: "{}" });
assert.equal(calls[0].init.headers.get("cookie"), "df_session=session-secret; df_csrf=csrf-secret");
assert.equal(calls[0].init.headers.get("x-csrf-token"), "csrf-secret");
});
test("does not add csrf to safe GET requests", async () => {
const calls = [];
const client = createAuthenticatedTestClient({
baseUrl: "http://127.0.0.1:8787",
fetchImpl: async (url, init) => {
calls.push({ url, init });
return new Response("{}", { status: 200 });
}
});
client.cookies.replace({
df_session: "session-secret",
df_csrf: "csrf-secret"
});
await client.fetch("/api/v1/me");
assert.equal(calls[0].init.headers.get("cookie"), "df_session=session-secret; df_csrf=csrf-secret");
assert.equal(calls[0].init.headers.get("x-csrf-token"), null);
});
test("absorbs Set-Cookie from multiple headers", async () => {
const client = createAuthenticatedTestClient({
baseUrl: "http://127.0.0.1:8787",
fetchImpl: async () => {
const headers = new Headers();
headers.append("Set-Cookie", "df_session=session-a; Path=/; HttpOnly");
headers.append("Set-Cookie", "df_csrf=csrf-a; Path=/");
return new Response("{}", { status: 200, headers });
}
});
await client.fetch("/api/v1/auth/login", { method: "POST", body: "{}" });
assert.deepEqual(client.cookies.snapshot(), {
df_session: "session-a",
df_csrf: "csrf-a"
});
});
test("auth errors omit cookie secrets", async () => {
const client = createAuthenticatedTestClient({
baseUrl: "http://127.0.0.1:8787",
fetchImpl: async () =>
new Response(JSON.stringify({ error: { code: "UNAUTHORIZED", message: "nope" } }), {
status: 401,
headers: { "Content-Type": "application/json" }
})
});
client.cookies.replace({
df_session: "session-secret",
df_csrf: "csrf-secret"
});
await assert.rejects(
() => client.fetch("/api/v1/me", { expectOk: true }),
(error) => {
const text = String(error);
assert.equal(error.status, 401);
assert.equal(error.code, "UNAUTHORIZED");
assert.doesNotMatch(text, /session-secret|csrf-secret/);
return true;
}
);
});
test("verifyCurrentUser calls GET /api/v1/me only", async () => {
const calls = [];
const client = createAuthenticatedTestClient({
baseUrl: "http://127.0.0.1:8787/datafoundry",
fetchImpl: async (url, init) => {
calls.push({ url: String(url), method: init?.method ?? "GET" });
return new Response(
JSON.stringify({
data: {
user: { id: "u1", email: "a@example.test" },
workspace: { id: "w1" }
}
}),
{ status: 200, headers: { "Content-Type": "application/json" } }
);
}
});
client.cookies.replace({ df_session: "s", df_csrf: "c" });
const me = await client.verifyCurrentUser();
assert.equal(me.user.id, "u1");
assert.equal(calls.length, 1);
assert.equal(calls[0].url, "http://127.0.0.1:8787/datafoundry/api/v1/me");
assert.equal(calls[0].method, "GET");
assert.ok(!calls.some((call) => call.url.includes("/api/v1/auth/me")));
});
test("registerAndLogin walks register verify login and me", async () => {
const calls = [];
const email = `${randomUUID()}@example.test`;
const client = createAuthenticatedTestClient({
baseUrl: "http://127.0.0.1:8787",
fetchImpl: async (url, init) => {
const href = String(url);
const method = init?.method ?? "GET";
calls.push({ href, method, body: init?.body });
if (href.endsWith("/api/v1/auth/register") && method === "POST") {
return new Response(
JSON.stringify({
data: {
verificationToken: "verify-token",
user: { id: "user-1", email }
}
}),
{
status: 201,
headers: { "Content-Type": "application/json" }
}
);
}
if (href.endsWith("/api/v1/auth/verify-email") && method === "POST") {
return new Response(JSON.stringify({ data: { ok: true } }), {
status: 200,
headers: { "Content-Type": "application/json" }
});
}
if (href.endsWith("/api/v1/auth/login") && method === "POST") {
const headers = new Headers({ "Content-Type": "application/json" });
headers.append("Set-Cookie", "df_session=session-1; Path=/; HttpOnly");
headers.append("Set-Cookie", "df_csrf=csrf-1; Path=/");
return new Response(
JSON.stringify({
data: {
user: { id: "user-1", email },
workspace: { id: "personal-user-1" }
}
}),
{ status: 200, headers }
);
}
if (href.endsWith("/api/v1/me") && method === "GET") {
return new Response(
JSON.stringify({
data: {
user: { id: "user-1", email },
workspace: { id: "personal-user-1" }
}
}),
{ status: 200, headers: { "Content-Type": "application/json" } }
);
}
return new Response(JSON.stringify({ error: { code: "NOT_FOUND", message: href } }), {
status: 404,
headers: { "Content-Type": "application/json" }
});
}
});
const result = await client.registerAndLogin({
email,
password: "correct-horse-battery",
displayName: "Test User"
});
assert.equal(result.userId, "user-1");
assert.equal(result.workspaceId, "personal-user-1");
assert.equal(result.email, email);
assert.deepEqual(result.cookies, {
df_session: "session-1",
df_csrf: "csrf-1"
});
assert.deepEqual(
calls.map((call) => `${call.method} ${new URL(call.href).pathname}`),
[
"POST /api/v1/auth/register",
"POST /api/v1/auth/verify-email",
"POST /api/v1/auth/login",
"GET /api/v1/me"
]
);
assert.ok(!calls.some((call) => call.href.includes("/api/v1/auth/me")));
});