93 lines
4.3 KiB
JavaScript
93 lines
4.3 KiB
JavaScript
import assert from 'node:assert/strict'
|
|
import test from 'node:test'
|
|
import { readFileSync } from 'node:fs'
|
|
import { run } from './appointment-work.mjs'
|
|
|
|
const entry = readFileSync(new URL('../admin-test-env-acceptance.mjs', import.meta.url), 'utf8')
|
|
const moduleSource = readFileSync(new URL('./appointment-work.mjs', import.meta.url), 'utf8')
|
|
|
|
function fakeContext(overrides = {}) {
|
|
const calls = []
|
|
const gaps = []
|
|
const steps = []
|
|
const context = {
|
|
marker: 'ADMIN-API-OFFLINE',
|
|
calls,
|
|
gaps,
|
|
steps,
|
|
async request(method, path, body) {
|
|
calls.push({ method, path, body })
|
|
const url = new URL(path, 'https://offline.invalid')
|
|
if (url.pathname.endsWith('/calendar')) {
|
|
const from = url.searchParams.get('from')
|
|
const to = url.searchParams.get('to')
|
|
return { http: 200, body: { code: '200', data: { from, to, total: 2, days: [
|
|
{ date: from, total: 1, typeCounts: { DELIVERY: 1 } },
|
|
{ date: to, total: 1, typeCounts: { PICKUP: 1 } },
|
|
] } } }
|
|
}
|
|
if (url.pathname.endsWith('/summary')) {
|
|
return { http: 200, body: { code: '200', data: { all: 2, followToday: 1, overdue: 0, undated: 1, review: 0 } } }
|
|
}
|
|
if (url.pathname.endsWith('/items')) {
|
|
return { http: 200, body: { code: '200', data: overrides.emptyPage
|
|
? { records: [], page: 1, size: 20, total: 0, pages: 0 }
|
|
: { records: [{ workItemKey: 'WORK-1', type: 'DELIVERY', flow: 'TRANSFER' }], page: 1, size: 20, total: 1, pages: 1 } } }
|
|
}
|
|
if (url.pathname.includes('/items/WORK-1')) {
|
|
return { http: 200, body: { code: '200', data: {
|
|
item: { workItemKey: 'WORK-1', type: 'DELIVERY', flow: 'TRANSFER', containers: [{ containerBookingId: 'C-1' }], allowedActions: [] },
|
|
references: [], history: [],
|
|
} } }
|
|
}
|
|
if (url.pathname.endsWith('/commands')) {
|
|
return { http: 200, body: { code: 'A0404', message: '工作事项不存在' } }
|
|
}
|
|
throw new Error(`unexpected offline request ${method} ${path}`)
|
|
},
|
|
apiSuccess(module, name, response) {
|
|
assert.equal(response.http, 200)
|
|
assert.equal(String(response.body?.code), '200')
|
|
steps.push({ module, name, passed: true })
|
|
return response.body.data
|
|
},
|
|
assert(module, name, response, condition, evidence) {
|
|
assert.equal(Boolean(condition), true, `${name}: ${evidence}`)
|
|
steps.push({ module, name, passed: true })
|
|
return true
|
|
},
|
|
addCoverageGap(module, scenario, name, reason, category, metadata) {
|
|
gaps.push({ module, scenario, name, reason, category, metadata })
|
|
},
|
|
}
|
|
return context
|
|
}
|
|
|
|
test('预约工作模块在默认全量中注册且只读查询官方工作事项接口', () => {
|
|
assert.match(entry, /const CONFIGURED_MODULES = \[[^\n]*'appointment-work'/)
|
|
assert.match(moduleSource, /\/api\/platform\/v1\/last-leg\/appointment-work/)
|
|
for (const path of ['/calendar', '/summary', '/items', '/commands']) assert.match(moduleSource, new RegExp(path.replace('/', '\\/')))
|
|
assert.match(moduleSource, /command: 'SAVE_FOLLOWUP'/)
|
|
assert.doesNotMatch(moduleSource, /this\.addStep|writeFileSync|execSync/)
|
|
})
|
|
|
|
test('预约工作只读链按日历、汇总、分页、详情顺序调用,唯一写入是不存在事项的拒绝命令', async () => {
|
|
const context = fakeContext()
|
|
await run(context)
|
|
assert.deepEqual(context.calls.map((row) => row.method), ['GET', 'GET', 'GET', 'GET', 'POST'])
|
|
assert.ok(context.calls[0].path.includes('/calendar?'))
|
|
assert.ok(context.calls[1].path.endsWith('/summary'))
|
|
assert.ok(context.calls[2].path.includes('/items?view=ALL&page=1&size=20'))
|
|
assert.ok(context.calls[3].path.includes('/items/WORK-1'))
|
|
assert.ok(context.calls[4].path.includes('/items/FULL-ACCEPTANCE-MISSING-WORK-ITEM/commands'))
|
|
assert.equal(context.calls[4].body.command, 'SAVE_FOLLOWUP')
|
|
assert.ok(context.gaps.some((gap) => gap.name === '预约写命令正向链路' && gap.metadata.blocking === false))
|
|
})
|
|
|
|
test('无本轮工作事项时记录非阻断覆盖缺口而不是虚构详情或命令结果', async () => {
|
|
const context = fakeContext({ emptyPage: true })
|
|
await run(context)
|
|
assert.equal(context.calls.length, 3)
|
|
assert.ok(context.gaps.some((gap) => gap.name === '预约工作项详情与命令' && gap.metadata.blocking === false))
|
|
})
|