import assert from 'node:assert/strict'; import type { AddressInfo } from 'node:net'; import test from 'node:test'; import { createLocalDemoApp } from '../src/local-app.js'; import type { DomesticDataset, DomesticMetricSummary } from '../src/types/domestic-dataset.js'; const emptyMetrics: DomesticMetricSummary = { gmv: 0, soldUnits: 0, transactionOrders: 0, transactionCustomers: 0, impressions: 0, clicks: 0, views: 0, visitors: 0, cartUnits: 0, orderAmount: 0, orderUnits: 0, orderCount: 0, refundAmount: 0, refundUnits: 0, refundOrders: 0, conversionRate: 0, clickThroughRate: 0, averageUnitPrice: 0, refundToGmvRate: 0, }; const dataset: DomesticDataset = { schemaVersion: 1, generatedAt: '2026-07-23T00:00:00.000Z', caseName: 'Demashi', platform: 'jd', source: { sourceFile: 'demashi-summary.json', sourceHash: 'test', sheets: [], dateRange: { start: '2026-07-01', end: '2026-07-23' }, }, summary: { metricRows: 0, metricProducts: 1, mappingRows: 0, relations: 0, uniqueCompetitorProducts: 0, category2Count: 0, category3Count: 0, reviewCount: 0, }, dailyTotals: [], products: [{ platform: 'jd', productId: '11266507445', productKey: 'jd:11266507445', asin: '11266507445', role: 'own', brand: 'Demashi', title: 'Local demo product', model: '', category1: '', category2: '', category3: '', source: 'excel', relationCount: 0, summary: emptyMetrics, trend: [], }], mappingGroups: [], relations: [], reviews: [], quality: { orphanMappings: [], mappingsWithoutCompetitor: [], brandWithoutProductId: [], }, }; test('local demo serves a snapshot and queryable completed sync jobs without a database', async () => { const app = createLocalDemoApp({ dataset, corsOrigins: ['http://localhost:4200'] }); const server = await new Promise>((resolve) => { const listening = app.listen(0, '127.0.0.1', () => resolve(listening)); }); try { const address = server.address() as AddressInfo; const baseUrl = `http://127.0.0.1:${address.port}`; const health = await fetch(`${baseUrl}/health`); assert.equal(health.status, 200); const healthBody = await health.json() as { mode: string; database: string; dataset: { products: number; reviews: number }; }; assert.equal(healthBody.mode, 'local-demo'); assert.equal(healthBody.database, 'deferred'); assert.deepEqual(healthBody.dataset, { caseName: 'Demashi', platform: 'jd', products: 1, reviews: 0 }); const snapshot = await fetch(`${baseUrl}/api/domestic-voc/snapshot?workspaceId=demashi&platform=jd`); assert.equal(snapshot.status, 200); assert.equal((await snapshot.json() as DomesticDataset).products[0]?.productId, '11266507445'); const syncResponse = await fetch(`${baseUrl}/api/domestic-voc/sync`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Idempotency-Key': 'local-demo-sync-11266507445' }, body: JSON.stringify({ productIds: ['11266507445'] }), }); assert.equal(syncResponse.status, 202); const syncBody = await syncResponse.json() as { job: { id: string; status: string; progress: number } }; assert.equal(syncBody.job.status, 'completed'); assert.equal(syncBody.job.progress, 100); const jobResponse = await fetch(`${baseUrl}/api/domestic-voc/jobs/${syncBody.job.id}`); assert.equal(jobResponse.status, 200); assert.equal((await jobResponse.json() as { job: { status: string } }).job.status, 'completed'); } finally { await new Promise((resolve, reject) => server.close((error) => error ? reject(error) : resolve())); } });