| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374 |
- 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;
- },
- );
- });
|