import assert from 'node:assert/strict'; import test from 'node:test'; import { FmodeRequestError, FmodeVocEcommerceClient } from '../src/modules/domestic-voc/upstream/fmode-client.js'; test('Fmode client sends credentials in a header and never in the URL', async () => { const calls: Array<{ url: string; authorization: string | null }> = []; const client = new FmodeVocEcommerceClient({ baseUrl: 'http://127.0.0.1:3000/api/voc-e-commerce', apiKey: 'private-test-key', timeoutMs: 1_000, retries: 0, fetch: async (input, init) => { calls.push({ url: String(input), authorization: new Headers(init?.headers).get('authorization'), }); return new Response(JSON.stringify({ code: 200, data: { items: [] } }), { status: 200 }); }, }); await client.request('jd/search-item-list/v1', { params: { keyword: 'test' } }); assert.equal(calls.length, 1); assert.equal(calls[0]?.authorization, 'Bearer private-test-key'); assert.doesNotMatch(calls[0]?.url ?? '', /private-test-key/); assert.match(calls[0]?.url ?? '', /keyword=test/); }); test('Fmode client retries transient gateway failures', async () => { let attempts = 0; const client = new FmodeVocEcommerceClient({ baseUrl: 'http://127.0.0.1:3000/api/voc-e-commerce', apiKey: 'test-key', timeoutMs: 1_000, retries: 2, sleep: async () => undefined, fetch: async () => { attempts += 1; if (attempts === 1) return new Response('{}', { status: 503 }); return new Response(JSON.stringify({ code: 200, data: { ok: true } }), { status: 200 }); }, }); const response = await client.request<{ data: { ok: boolean } }>('jd/product-detail/v1'); assert.equal(attempts, 2); assert.equal(response.data.ok, true); }); test('Fmode client aborts timed out requests without leaking the key', async () => { const client = new FmodeVocEcommerceClient({ baseUrl: 'http://127.0.0.1:3000/api/voc-e-commerce', apiKey: 'secret-value-that-must-not-appear', timeoutMs: 5, retries: 0, fetch: async (_input, init) => new Promise((_resolve, reject) => { init?.signal?.addEventListener('abort', () => { const error = new Error('aborted'); error.name = 'AbortError'; reject(error); }); }), }); await assert.rejects( () => client.request('jd/product-detail/v1'), (error: unknown) => { assert.ok(error instanceof FmodeRequestError); assert.match(error.message, /timed out/); assert.doesNotMatch(error.message, /secret-value/); return true; }, ); });