← Files Velox TriFit API DocsARCHIVED FILE
test/integration.test.mjs
4.87 KB · Nov 7, 2026 · 13:08 UTC
import assert from 'node:assert/strict';
import test from 'node:test';
import { randomUUID } from 'node:crypto';
import { get } from 'node:http';
import { DressMeClient } from '../src/client.mjs';
import { startMockApi, DUMMY, PLACEHOLDER } from '../src/mock-api.mjs';
async function inputs(api) {
const image = new Blob([PLACEHOLDER], { type: 'image/png' });
const reserved = [];
const product = await api.upload(image, { role: 'product', fileName: 'dummy-product.png', onReserved: id => reserved.push(id) });
const personal = await api.upload(image, { role: 'personal', fileName: 'dummy-person.png', onReserved: id => reserved.push(id) });
assert.equal(reserved.length, 2);
return { personalAssetId: personal.id, productAssetId: product.id };
}
test('local flow, storage credential isolation and idempotency', async () => {
const mock = await startMockApi();
try {
const api = new DressMeClient({ baseUrl: mock.baseUrl, ...DUMMY });
await api.verifyEnvironment('local-mock');
await assert.rejects(api.verifyEnvironment('production'), /mismatch/);
const payload = await inputs(api); const key = randomUUID();
const job = await api.createJob(payload, key);
assert.equal((await api.createJob(payload, key)).id, job.id);
assert.equal(mock.jobs.size, 1);
await assert.rejects(api.createJob({ ...payload, productAssetId: randomUUID() }, key), error => error.status === 409);
const states = [];
const done = await api.waitForJob(job.id, { intervalMs: 10, onStatus: s => states.push(s) });
assert.deepEqual(states, ['running', 'succeeded']);
assert.equal(done.simulated, true);
assert.deepEqual(Buffer.from(await (await fetch(done.result.url)).arrayBuffer()), PLACEHOLDER);
for (const h of mock.receivedStorageHeaders) for (const name of ['x-velox-integration-key', 'x-velox-client-id', 'x-velox-subject', 'authorization']) assert.equal(h[name], undefined);
} finally { await mock.close(); }
});
test('terminal failure is surfaced without another job', async () => {
const mock = await startMockApi({ failure: true });
try {
const api = new DressMeClient({ baseUrl: mock.baseUrl, ...DUMMY });
const job = await api.createJob(await inputs(api), randomUUID());
await assert.rejects(api.waitForJob(job.id, { intervalMs: 10 }), e => e.code === 'generation_failed');
assert.equal(mock.jobs.size, 1);
} finally { await mock.close(); }
});
test('invalid credentials, browser origins and public Host are rejected by mock', async () => {
const mock = await startMockApi();
try {
const api = new DressMeClient({ baseUrl: mock.baseUrl, ...DUMMY, applicationKey: 'va_BAD_DUMMY' });
await assert.rejects(api.verifyEnvironment('local-mock'), e => e.status === 401);
assert.equal((await fetch(`${mock.baseUrl}/me`, { headers: { Origin: 'https://example.com' } })).status, 403);
// Node fetch normalizes Host; use an HTTP request to exercise the server's Host guard.
const status = await new Promise((resolve, reject) => {
get(`${mock.baseUrl}/me`, { headers: { Host: 'example.com' } }, response => { response.resume(); resolve(response.statusCode); }).on('error', reject);
});
assert.equal(status, 403);
} finally { await mock.close(); }
});
test('client refuses unsafe setup and missing submission identity', () => {
for (const baseUrl of ['http://example.com/v1', 'https://user:pass@example.com/v1', 'https://example.com/v1?key=x']) assert.throws(() => new DressMeClient({ baseUrl, ...DUMMY }));
assert.throws(() => new DressMeClient({ baseUrl: 'https://example.com/v1', ...DUMMY, subject: 'person@example.com' }));
const api = new DressMeClient({ baseUrl: 'https://example.com/v1', ...DUMMY });
assert.throws(() => api.createJob({}, ''), /idempotency/);
});
test('429 metadata is surfaced; network uncertainty is never automatically replayed', async () => {
let calls = 0;
const api = new DressMeClient({ baseUrl: 'https://example.com/v1', ...DUMMY, fetch: async () => { calls++; return new Response(JSON.stringify({ error: { code: 'rate_limited', message: 'Wait.' } }), { status: 429, headers: { 'retry-after': '10', 'x-request-id': 'dummy-request' } }); } });
await assert.rejects(api.createJob({}, randomUUID()), e => e.status === 429 && e.retryAfter === '10' && e.requestId === 'dummy-request');
assert.equal(calls, 1);
api.fetch = async () => { calls++; throw new TypeError('Network failure'); };
await assert.rejects(api.createJob({}, randomUUID()), /Network failure/);
assert.equal(calls, 2);
});
test('polling has a deadline and never submits', async () => {
let calls = 0;
const api = new DressMeClient({ baseUrl: 'https://example.com/v1', ...DUMMY, fetch: async (_url, options) => { calls++; assert.equal(options.method, 'GET'); return Response.json({ status: 'running' }); } });
await assert.rejects(api.waitForJob('dummy-job', { timeoutMs: 40, intervalMs: 10 }), e => e.name === 'TimeoutError');
assert.ok(calls >= 1);
});
SHA-256: 7f93c666ad0d979c040f9cfcb975c69efd09fcf0504f87112f80c75a539067aa