/** * Unit tests for useTranslateSession logic. * * We extract and test the pure session orchestration logic — the fetch orchestration, * pipeline path selection, and error sanitization — without mounting React hooks. * The hook wraps this logic in useState/useCallback; the logic itself is testable * in isolation by replicating the core run() body. */ import { describe, it, beforeEach } from "node:test"; import assert from "node:assert/strict"; // ─── Types (mirroring types.ts) ─────────────────────────────────────────────── type FormatId = "openai" | "openai-responses" | "claude" | "gemini" | "antigravity" | "kiro" | "cursor"; type TranslateMode = "preview" | "send"; interface TranslateNarratedResult { detected: FormatId | null; target: FormatId; status: "idle" | "translating" | "sending" | "ok" | "error"; responsePreview: string | null; translatedJson: string | null; pipelinePath: "direct" | "hub-and-spoke" | "passthrough" | null; intermediateJson: string | null; errorMessage: string | null; latencyMs: number | null; } interface RunInput { source: FormatId; target: FormatId; provider: string; inputText: string; mode: TranslateMode; } // ─── Extracted sanitizeError logic ─────────────────────────────────────────── function sanitizeError(raw: unknown): string { const text = raw instanceof Error ? raw.message : typeof raw === "string" ? raw : "Unknown error"; return text .replace(/\sat\s\/[^\s]+/g, "") .replace(/sk-[A-Za-z0-9_-]{16,}/g, "[REDACTED]") .replace(/Bearer\s+[A-Za-z0-9_.-]+/g, "Bearer [REDACTED]"); } // ─── Extracted run() logic (mirrors useTranslateSession hook implementation) ─ type FetchFn = (url: string, init?: RequestInit) => Promise; async function runSession( input: RunInput, fetchImpl: FetchFn ): Promise { const { source, target, provider, inputText, mode } = input; const target_: FormatId = target; let detected: FormatId | null = null; let translatedJson: string | null = null; let intermediateJson: string | null = null; let pipelinePath: TranslateNarratedResult["pipelinePath"] = "passthrough"; let translatedResult: Record; let responsePreview: string | null = null; // 1. Parse input let parsed: Record; try { parsed = JSON.parse(inputText); } catch { parsed = { messages: [{ role: "user", content: inputText }] }; } // 2. Detect format try { const detectRes = await fetchImpl("/api/translator/detect", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ body: parsed }), }); const detectData = (await detectRes.json()) as { success: boolean; format?: string }; if (detectData.success) detected = detectData.format as FormatId; } catch { /* non-fatal */ } // 3. Translate translatedResult = parsed; if (source !== target) { const needsHub = source !== "openai" && target !== "openai"; if (needsHub) { const step1 = await fetchImpl("/api/translator/translate", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ step: "direct", sourceFormat: source, targetFormat: "openai", body: parsed }), }); const step1Data = (await step1.json()) as { success: boolean; result?: Record; error?: string }; if (!step1Data.success) throw new Error(step1Data.error ?? "Translate step 1 failed"); intermediateJson = JSON.stringify(step1Data.result, null, 2); const step2 = await fetchImpl("/api/translator/translate", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ step: "direct", sourceFormat: "openai", targetFormat: target, body: step1Data.result }), }); const step2Data = (await step2.json()) as { success: boolean; result?: Record; error?: string }; if (!step2Data.success) throw new Error(step2Data.error ?? "Translate step 2 failed"); translatedResult = step2Data.result as Record; translatedJson = JSON.stringify(step2Data.result, null, 2); pipelinePath = "hub-and-spoke"; } else { const stepDirect = await fetchImpl("/api/translator/translate", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ step: "direct", sourceFormat: source, targetFormat: target, body: parsed }), }); const stepData = (await stepDirect.json()) as { success: boolean; result?: Record; error?: string }; if (!stepData.success) throw new Error(stepData.error ?? "Translate failed"); translatedResult = stepData.result as Record; translatedJson = JSON.stringify(stepData.result, null, 2); pipelinePath = "direct"; } } else { translatedJson = JSON.stringify(parsed, null, 2); } // 4. Optional send if (mode === "send") { const sendRes = await fetchImpl("/api/translator/send", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ provider, body: translatedResult }), }); if (!sendRes.ok) { const errorBody = (await sendRes.json().catch(() => ({ error: `HTTP ${sendRes.status}` }))) as { error?: unknown }; throw new Error(typeof errorBody.error === "string" ? errorBody.error : "Send failed"); } const reader = sendRes.body?.getReader(); if (reader) { const decoder = new TextDecoder(); let buf = ""; while (buf.length < 500) { const { done, value } = await reader.read(); if (done) break; buf += decoder.decode(value, { stream: true }); } responsePreview = buf.slice(0, 500); } } return { detected, target: target_, status: "ok", responsePreview, translatedJson, pipelinePath, intermediateJson, errorMessage: null, latencyMs: 0, }; } // ─── Fetch call tracker ─────────────────────────────────────────────────────── interface FetchCall { url: string; body: unknown; } let fetchCalls: FetchCall[] = []; beforeEach(() => { fetchCalls = []; }); function makeBody(body: unknown): ReadableStream | null { const text = typeof body === "string" ? body : JSON.stringify(body); const encoder = new TextEncoder(); const bytes = encoder.encode(text); return new ReadableStream({ start(controller) { controller.enqueue(bytes); controller.close(); }, }); } // ─── Tests ──────────────────────────────────────────────────────────────────── describe("mode=preview, source === target (passthrough)", () => { it("pipelinePath is passthrough, no translate fetch", async () => { const fetchMock: FetchFn = async (url, init) => { const body = init?.body ? JSON.parse(init.body as string) : null; fetchCalls.push({ url, body }); if (url.includes("detect")) { return new Response(JSON.stringify({ success: true, format: "openai" }), { status: 200 }); } throw new Error(`Unexpected fetch: ${url}`); }; const result = await runSession( { source: "openai", target: "openai", provider: "openai", inputText: '{"messages":[]}', mode: "preview" }, fetchMock ); assert.equal(result.pipelinePath, "passthrough"); assert.equal(result.status, "ok"); const translateCalls = fetchCalls.filter((c) => c.url.includes("translate")); assert.equal(translateCalls.length, 0); const sendCalls = fetchCalls.filter((c) => c.url.includes("send")); assert.equal(sendCalls.length, 0); }); }); describe("mode=preview, claude → gemini (hub-and-spoke)", () => { it("calls translate twice (step1: claude→openai, step2: openai→gemini), pipelinePath=hub-and-spoke", async () => { const fetchMock: FetchFn = async (url, init) => { const body = init?.body ? JSON.parse(init.body as string) : null; fetchCalls.push({ url, body }); if (url.includes("detect")) { return new Response(JSON.stringify({ success: true, format: "claude" }), { status: 200 }); } if (url.includes("translate")) { const b = body as { targetFormat?: string }; if (b.targetFormat === "openai") { return new Response(JSON.stringify({ success: true, result: { intermediate: true } }), { status: 200 }); } return new Response(JSON.stringify({ success: true, result: { gemini: true } }), { status: 200 }); } throw new Error(`Unexpected fetch: ${url}`); }; const result = await runSession( { source: "claude", target: "gemini", provider: "gemini", inputText: '{"messages":[]}', mode: "preview" }, fetchMock ); assert.equal(result.pipelinePath, "hub-and-spoke"); assert.equal(result.status, "ok"); assert.ok(result.intermediateJson !== null, "intermediateJson should be set"); assert.ok(result.translatedJson !== null, "translatedJson should be set"); const translateCalls = fetchCalls.filter((c) => c.url.includes("translate")); assert.equal(translateCalls.length, 2); const sendCalls = fetchCalls.filter((c) => c.url.includes("send")); assert.equal(sendCalls.length, 0); }); }); describe("mode=preview, openai → claude (direct)", () => { it("calls translate once, pipelinePath=direct", async () => { const fetchMock: FetchFn = async (url, init) => { const body = init?.body ? JSON.parse(init.body as string) : null; fetchCalls.push({ url, body }); if (url.includes("detect")) { return new Response(JSON.stringify({ success: true, format: "openai" }), { status: 200 }); } if (url.includes("translate")) { return new Response(JSON.stringify({ success: true, result: { claude: true } }), { status: 200 }); } throw new Error(`Unexpected fetch: ${url}`); }; const result = await runSession( { source: "openai", target: "claude", provider: "claude", inputText: '{"messages":[]}', mode: "preview" }, fetchMock ); assert.equal(result.pipelinePath, "direct"); assert.equal(result.status, "ok"); const translateCalls = fetchCalls.filter((c) => c.url.includes("translate")); assert.equal(translateCalls.length, 1); }); }); describe("mode=send happy path", () => { it("calls detect + translate + send; status=ok, responsePreview populated", async () => { const fetchMock: FetchFn = async (url, init) => { const body = init?.body ? JSON.parse(init.body as string) : null; fetchCalls.push({ url, body }); if (url.includes("detect")) { return new Response(JSON.stringify({ success: true, format: "openai" }), { status: 200 }); } if (url.includes("translate")) { return new Response(JSON.stringify({ success: true, result: { openai: true } }), { status: 200 }); } if (url.includes("send")) { return new Response(makeBody("hello from provider"), { status: 200, headers: { "Content-Type": "text/event-stream" }, }); } throw new Error(`Unexpected fetch: ${url}`); }; const result = await runSession( { source: "openai", target: "claude", provider: "claude", inputText: '{"messages":[]}', mode: "send" }, fetchMock ); assert.equal(result.status, "ok"); const detectCalls = fetchCalls.filter((c) => c.url.includes("detect")); const translateCalls = fetchCalls.filter((c) => c.url.includes("translate")); const sendCalls = fetchCalls.filter((c) => c.url.includes("send")); assert.equal(detectCalls.length, 1); assert.equal(translateCalls.length, 1); assert.equal(sendCalls.length, 1); assert.ok(result.responsePreview !== null, "responsePreview should be populated"); }); }); describe("error path — sanitization", () => { it("error message does not contain stack trace ('at /')", async () => { const fakeStack = "Translate failed at /home/user/foo.ts:42:10 sk-abcdefghijklmnopqrstuvwxyz1234567890"; const sanitized = sanitizeError(new Error(fakeStack)); assert.ok(!sanitized.includes("at /"), `Expected no stack trace in: ${sanitized}`); assert.ok(!sanitized.includes("sk-"), `Expected no API key in: ${sanitized}`); }); it("error with Bearer token is redacted", () => { const msg = "Auth failed: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.somepayload.signature"; const sanitized = sanitizeError(new Error(msg)); assert.ok(!sanitized.includes("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"), `Token not redacted in: ${sanitized}`); assert.ok(sanitized.includes("Bearer [REDACTED]"), `Expected Bearer [REDACTED] in: ${sanitized}`); }); it("translate fetch 500 with stack trace in error body does not leak", async () => { const fetchMock: FetchFn = async (url, init) => { const body = init?.body ? JSON.parse(init.body as string) : null; fetchCalls.push({ url, body }); if (url.includes("detect")) { return new Response(JSON.stringify({ success: false, format: null }), { status: 200 }); } if (url.includes("translate")) { return new Response( JSON.stringify({ success: false, error: "internal error at /home/user/foo.ts:42 sk-abcdefghijklmnopqrstuvwxyz1234567890" }), { status: 500 } ); } throw new Error(`Unexpected fetch: ${url}`); }; let caught: string | null = null; try { await runSession( { source: "openai", target: "claude", provider: "claude", inputText: '{"messages":[]}', mode: "preview" }, fetchMock ); } catch (err) { caught = sanitizeError(err); } assert.ok(caught !== null, "should have thrown"); // The error message from the fake response is thrown as-is (not sanitized in run()) // but the hook's catch() applies sanitizeError. We verify the sanitizer works: assert.ok(!caught.includes("at /"), `Stack trace leaked: ${caught}`); assert.ok(!caught.includes("sk-"), `API key leaked: ${caught}`); }); it("non-Error thrown value → 'Unknown error'", () => { const sanitized = sanitizeError(42); assert.equal(sanitized, "Unknown error"); }); it("string error → sanitized", () => { const sanitized = sanitizeError("error at /opt/node/foo.ts:10"); assert.ok(!sanitized.includes("at /"), `Stack trace leaked: ${sanitized}`); }); }); describe("reset — returns idle state", () => { it("initialResult(openai) matches idle defaults", () => { // Replicate initialResult function const initial: TranslateNarratedResult = { detected: null, target: "openai", status: "idle", responsePreview: null, translatedJson: null, pipelinePath: null, intermediateJson: null, errorMessage: null, latencyMs: null, }; assert.equal(initial.status, "idle"); assert.equal(initial.detected, null); assert.equal(initial.responsePreview, null); assert.equal(initial.translatedJson, null); assert.equal(initial.pipelinePath, null); assert.equal(initial.errorMessage, null); assert.equal(initial.latencyMs, null); }); });