Files
baiyue-firstleg/scripts/admin-test-env-modules/fleet-analytics-contract.test.mjs
T

91 lines
4.5 KiB
JavaScript
Raw Normal View History

2026-10-20 14:22:55 +08:00
import assert from 'node:assert/strict'
import test from 'node:test'
import { readFileSync } from 'node:fs'
import { run as runFleet } from './fleet-management.mjs'
import { run as runAnalytics } from './self-operated-analytics.mjs'
const entry = readFileSync(new URL('../admin-test-env-acceptance.mjs', import.meta.url), 'utf8')
function context(handler) {
const calls = []
const gaps = []
return {
marker: 'ADMIN-API-OFFLINE',
calls,
gaps,
async request(method, path) {
calls.push({ method, path })
return handler(method, path)
},
apiSuccess(_module, _name, response) {
assert.equal(response.http, 200)
assert.equal(String(response.body?.code), '200')
return response.body.data
},
assert(_module, name, _response, condition, evidence) {
assert.equal(Boolean(condition), true, `${name}: ${evidence}`)
return true
},
addCoverageGap(module, scenario, name, reason, category, metadata) {
gaps.push({ module, scenario, name, reason, category, metadata })
},
}
}
test('车队管理模块注册为默认模块并只读核对车次、出车、报价与拼车需求', async () => {
assert.match(entry, /const CONFIGURED_MODULES = \[[^\n]*'fleet-management'/)
const tripRow = { tripNo: 'TRIP-1', status: 'PLANNED', recordVersion: 0 }
const ctx = context((method, path) => {
if (path.endsWith('/fleet/trips/FLEET-MISSING-TRIP')) {
return { http: 200, body: { code: 'A0404', message: '车次不存在' } }
}
if (path.includes('/fleet/trips/TRIP-1')) {
return { http: 200, body: { code: '200', data: {
trip: tripRow, dispatches: [], loadingReview: { recordVersion: null }, previousDispatches: [] } } }
}
if (path.includes('/fleet/trips')) {
return { http: 200, body: { code: '200', data: { records: [tripRow], page: 1, size: 20, total: 1, pages: 1 } } }
}
if (path.includes('/fleet/operations')) {
return { http: 200, body: { code: '200', data: {
page: { records: [], page: 1, size: 20, total: 0, pages: 0 },
summary: { trips: 0, inTransit: 0, completed: 0, physicalPallets: 0, palletSpaces: 0, ownPackages: 0,
externalPackages: 0, externalAgreedAmounts: [], costs: { visible: true, unrecordedTrips: null, unallocatedTrips: null, totals: [] } },
charts: { physicalPallets: [], destinationTrips: [], externalAgreedAmounts: [], externalPalletRates: [] },
} } }
}
if (path.includes('/fleet/quotes')) {
return { http: 200, body: { code: '200', data: { records: [{ quoteNo: 'Q-1', status: 'ACTIVE', recordVersion: '0' }], page: 1, size: 20, total: 1, pages: 1 } } }
}
if (path.includes('/fleet/capacity-offers')) {
return { http: 200, body: { code: '200', data: { records: [{ status: 'OPEN' }], page: 1, size: 20, total: 1, pages: 1 } } }
}
if (path.endsWith('/fleet/trips/FLEET-MISSING-TRIP')) {
return { http: 200, body: { code: 'A0404', message: '车次不存在' } }
}
throw new Error(`unexpected ${method} ${path}`)
})
await runFleet(ctx)
assert.deepEqual(ctx.calls.map((row) => row.method), ['GET', 'GET', 'GET', 'GET', 'GET', 'GET'])
assert.ok(ctx.calls[0].path.includes('/fleet/trips?page=1&size=20'))
assert.ok(ctx.calls[2].path.includes('/fleet/operations?page=1&size=20&from='))
assert.ok(ctx.calls[4].path.includes('/fleet/capacity-offers'))
assert.ok(ctx.gaps.some((gap) => gap.name === '车次写命令' && gap.metadata.blocking === false))
})
test('自营分析模块注册为默认模块,空参不可用时记录缺口而不是虚构看板', async () => {
assert.match(entry, /const CONFIGURED_MODULES = \[[^\n]*'self-operated-analytics'/)
const unavailable = context(() => ({ http: 200, body: { code: 'A0400', message: '缺少采集账号' } }))
await runAnalytics(unavailable)
assert.equal(unavailable.calls.length, 2)
assert.ok(unavailable.gaps.some((gap) => gap.name === '经营看板' && gap.metadata.blocking === false))
assert.ok(unavailable.gaps.some((gap) => gap.name === '货主目录' && gap.metadata.blocking === false))
const available = context((_method, path) => path.endsWith('/dashboard')
? { http: 200, body: { code: '200', data: { metrics: [], trend: [] } } }
: { http: 200, body: { code: '200', data: { records: [], page: 1, size: 20, total: 0, pages: 0 } } })
await runAnalytics(available)
assert.equal(available.gaps.some((gap) => gap.name === '经营看板'), false)
assert.ok(available.gaps.some((gap) => gap.category === 'external-third-party' && gap.metadata.blocking === false))
})