style(tests): normalize platform command fixture line endings
This commit is contained in:
@@ -75,85 +75,85 @@ export async function verifyPlatformDraftEdit(context, tenantId, orderId, mercha
|
|||||||
context.assert(MODULE, 'Platform重放与拒绝不重复写入', null, orderPersistenceFacts(stable) === orderPersistenceFacts(edited), 'order/cargo/parties/history', CONTRACT_OPTIONS)
|
context.assert(MODULE, 'Platform重放与拒绝不重复写入', null, orderPersistenceFacts(stable) === orderPersistenceFacts(edited), 'order/cargo/parties/history', CONTRACT_OPTIONS)
|
||||||
return stable
|
return stable
|
||||||
}
|
}
|
||||||
export async function verifyPlatformSubmitCancel(context, tenantId, payload, policy) {
|
export async function verifyPlatformSubmitCancel(context, tenantId, payload, policy) {
|
||||||
const base = '/api/platform/v1/orders/first-leg'
|
const base = '/api/platform/v1/orders/first-leg'
|
||||||
const scope = `tenantId=${encodeURIComponent(tenantId)}`
|
const scope = `tenantId=${encodeURIComponent(tenantId)}`
|
||||||
const proofs = context.createdResources.orders.platformLifecycle = []
|
const proofs = context.createdResources.orders.platformLifecycle = []
|
||||||
for (const action of ['submit', 'cancel']) {
|
for (const action of ['submit', 'cancel']) {
|
||||||
const draftPayload = { ...structuredClone(payload), ...fixtureInboundCode(policy, `${context.marker}-PLATFORM-${action}`),
|
const draftPayload = { ...structuredClone(payload), ...fixtureInboundCode(policy, `${context.marker}-PLATFORM-${action}`),
|
||||||
customerRemark: `${context.marker} Platform ${action} independent draft` }
|
customerRemark: `${context.marker} Platform ${action} independent draft` }
|
||||||
const created = await context.request('POST', `${base}?${scope}`, draftPayload, context.token,
|
const created = await context.request('POST', `${base}?${scope}`, draftPayload, context.token,
|
||||||
{ 'Idempotency-Key': key(context, `platform-${action}-create`) })
|
{ 'Idempotency-Key': key(context, `platform-${action}-create`) })
|
||||||
const orderId = id(context.apiSuccess(MODULE, `Platform ${action} 创建本轮独立草稿`, created))
|
const orderId = id(context.apiSuccess(MODULE, `Platform ${action} 创建本轮独立草稿`, created))
|
||||||
if (!orderId) throw new Error(`Platform ${action} fixture order missing`)
|
if (!orderId) throw new Error(`Platform ${action} fixture order missing`)
|
||||||
const path = `${base}/${encodeURIComponent(orderId)}?${scope}`
|
const path = `${base}/${encodeURIComponent(orderId)}?${scope}`
|
||||||
const mutationPath = `${base}/${encodeURIComponent(orderId)}/${action}?${scope}`
|
const mutationPath = `${base}/${encodeURIComponent(orderId)}/${action}?${scope}`
|
||||||
const proof = { action, tenantId, orderId, commands: [], checks: [] }
|
const proof = { action, tenantId, orderId, commands: [], checks: [] }
|
||||||
proofs.push(proof)
|
proofs.push(proof)
|
||||||
const assertFact = (label, response, passed, evidence) => {
|
const assertFact = (label, response, passed, evidence) => {
|
||||||
context.assert(MODULE, `Platform ${action} ${label}`, response, passed, evidence, CONTRACT_OPTIONS)
|
context.assert(MODULE, `Platform ${action} ${label}`, response, passed, evidence, CONTRACT_OPTIONS)
|
||||||
if (!passed) throw new Error(`Platform ${action} ${label}`)
|
if (!passed) throw new Error(`Platform ${action} ${label}`)
|
||||||
}
|
}
|
||||||
const read = async label => {
|
const read = async label => {
|
||||||
const response = await context.request('GET', path)
|
const response = await context.request('GET', path)
|
||||||
const detail = context.apiSuccess(MODULE, `Platform ${action} ${label}`, response)
|
const detail = context.apiSuccess(MODULE, `Platform ${action} ${label}`, response)
|
||||||
assertFact('详情身份与完整事实集合', response, id(detail?.order?.id) === orderId && id(detail?.order?.tenantId) === id(tenantId)
|
assertFact('详情身份与完整事实集合', response, id(detail?.order?.id) === orderId && id(detail?.order?.tenantId) === id(tenantId)
|
||||||
&& Number.isSafeInteger(detail.order.version) && detail.order.version >= 0
|
&& Number.isSafeInteger(detail.order.version) && detail.order.version >= 0
|
||||||
&& ['cargoes','parties','internalNotes','statusHistory'].every(field => Array.isArray(detail[field])), 'exact-customer/order/version/aggregate')
|
&& ['cargoes','parties','internalNotes','statusHistory'].every(field => Array.isArray(detail[field])), 'exact-customer/order/version/aggregate')
|
||||||
return detail
|
return detail
|
||||||
}
|
}
|
||||||
const same = (label, before, after) => assertFact(label, null, orderPersistenceFacts(before) === orderPersistenceFacts(after), 'state/version/cargo/parties/notes/history unchanged')
|
const same = (label, before, after) => assertFact(label, null, orderPersistenceFacts(before) === orderPersistenceFacts(after), 'state/version/cargo/parties/notes/history unchanged')
|
||||||
const original = await read('冻结首次草稿版本')
|
const original = await read('冻结首次草稿版本')
|
||||||
assertFact('取消与提交前置仅为未履约草稿', created, original.order.status === 'DRAFT', 'DRAFT-only')
|
assertFact('取消与提交前置仅为未履约草稿', created, original.order.status === 'DRAFT', 'DRAFT-only')
|
||||||
// Advance through an actual edit, so stale version 0 remains valid input rather than Min(0) validation failure.
|
// Advance through an actual edit, so stale version 0 remains valid input rather than Min(0) validation failure.
|
||||||
const editCommand = freezeOrderCommand(original, key(context, `platform-${action}-prepare-edit`), { draft: draftPayload })
|
const editCommand = freezeOrderCommand(original, key(context, `platform-${action}-prepare-edit`), { draft: draftPayload })
|
||||||
context.apiSuccess(MODULE, `Platform ${action} 形成真实旧页面版本`,
|
context.apiSuccess(MODULE, `Platform ${action} 形成真实旧页面版本`,
|
||||||
await context.request('PUT', path, editCommand.body, context.token, editCommand.headers))
|
await context.request('PUT', path, editCommand.body, context.token, editCommand.headers))
|
||||||
const current = await read('冻结动作首次有效请求版本')
|
const current = await read('冻结动作首次有效请求版本')
|
||||||
assertFact('编辑后仍为草稿且版本增加', null, current.order.status === 'DRAFT' && current.order.version > original.order.version, 'old-page-version-created')
|
assertFact('编辑后仍为草稿且版本增加', null, current.order.status === 'DRAFT' && current.order.version > original.order.version, 'old-page-version-created')
|
||||||
const extra = action === 'cancel' ? { reason: `${context.marker} independent draft cancellation` } : {}
|
const extra = action === 'cancel' ? { reason: `${context.marker} independent draft cancellation` } : {}
|
||||||
const command = freezeOrderCommand(current, key(context, `platform-${action}-execute`), extra)
|
const command = freezeOrderCommand(current, key(context, `platform-${action}-execute`), extra)
|
||||||
proof.originalVersion = original.order.version
|
proof.originalVersion = original.order.version
|
||||||
proof.command = command
|
proof.command = command
|
||||||
const send = async (label, body, headers) => {
|
const send = async (label, body, headers) => {
|
||||||
proof.commands.push({ label, path: mutationPath, body: structuredClone(body), headers: structuredClone(headers) })
|
proof.commands.push({ label, path: mutationPath, body: structuredClone(body), headers: structuredClone(headers) })
|
||||||
return context.request('POST', mutationPath, body, context.token, headers)
|
return context.request('POST', mutationPath, body, context.token, headers)
|
||||||
}
|
}
|
||||||
const reject = async (label, body, headers, code, expected, statuses = [200]) => {
|
const reject = async (label, body, headers, code, expected, statuses = [200]) => {
|
||||||
const response = await send(label, body, headers)
|
const response = await send(label, body, headers)
|
||||||
assertFact(label, response, statuses.includes(response?.http) && String(response.body?.code) === code, `expected=${code}`)
|
assertFact(label, response, statuses.includes(response?.http) && String(response.body?.code) === code, `expected=${code}`)
|
||||||
same(`${label}后零漂移`, expected, await read(`${label}后回查`))
|
same(`${label}后零漂移`, expected, await read(`${label}后回查`))
|
||||||
proof.checks.push({ label, code })
|
proof.checks.push({ label, code })
|
||||||
}
|
}
|
||||||
await reject('首次旧页面版本拒绝', { ...extra, expectedVersion: original.order.version },
|
await reject('首次旧页面版本拒绝', { ...extra, expectedVersion: original.order.version },
|
||||||
{ 'Idempotency-Key': key(context, `platform-${action}-stale-first`) }, 'A0409', current)
|
{ 'Idempotency-Key': key(context, `platform-${action}-stale-first`) }, 'A0409', current)
|
||||||
await reject('首次缺版本拒绝', extra,
|
await reject('首次缺版本拒绝', extra,
|
||||||
{ 'Idempotency-Key': key(context, `platform-${action}-missing-version`) }, 'A0422', current)
|
{ 'Idempotency-Key': key(context, `platform-${action}-missing-version`) }, 'A0422', current)
|
||||||
await reject('首次缺幂等键拒绝', command.body, {}, 'A0400', current, [200,400])
|
await reject('首次缺幂等键拒绝', command.body, {}, 'A0400', current, [200,400])
|
||||||
context.apiSuccess(MODULE, `Platform ${action} 原版本原键成功`, await send('success', command.body, command.headers))
|
context.apiSuccess(MODULE, `Platform ${action} 原版本原键成功`, await send('success', command.body, command.headers))
|
||||||
const completed = await read('成功后的事实快照')
|
const completed = await read('成功后的事实快照')
|
||||||
const expectedStatus = action === 'submit' ? 'SUBMITTED' : 'CANCELLED'
|
const expectedStatus = action === 'submit' ? 'SUBMITTED' : 'CANCELLED'
|
||||||
const oldHistoryIds = new Set(current.statusHistory.map(row => id(row.id)))
|
const oldHistoryIds = new Set(current.statusHistory.map(row => id(row.id)))
|
||||||
const added = completed.statusHistory.filter(row => !oldHistoryIds.has(id(row.id)))
|
const added = completed.statusHistory.filter(row => !oldHistoryIds.has(id(row.id)))
|
||||||
assertFact('成功状态版本与唯一动作历史', null, completed.order.status === expectedStatus && completed.order.version > current.order.version
|
assertFact('成功状态版本与唯一动作历史', null, completed.order.status === expectedStatus && completed.order.version > current.order.version
|
||||||
&& added.length === 1 && added[0].action === expectedStatus && added[0].fromStatus === 'DRAFT' && added[0].toStatus === expectedStatus
|
&& added.length === 1 && added[0].action === expectedStatus && added[0].fromStatus === 'DRAFT' && added[0].toStatus === expectedStatus
|
||||||
&& Boolean(added[0].operatorId && added[0].occurredAt)
|
&& Boolean(added[0].operatorId && added[0].occurredAt)
|
||||||
&& (action !== 'cancel' || added[0].reason === extra.reason), 'one attributed lifecycle history')
|
&& (action !== 'cancel' || added[0].reason === extra.reason), 'one attributed lifecycle history')
|
||||||
assertFact('成功后货物旧历史及业务身份保留', null,
|
assertFact('成功后货物旧历史及业务身份保留', null,
|
||||||
['cargoes','parties','internalNotes'].every(field => JSON.stringify(current[field]) === JSON.stringify(completed[field]))
|
['cargoes','parties','internalNotes'].every(field => JSON.stringify(current[field]) === JSON.stringify(completed[field]))
|
||||||
&& JSON.stringify(current.statusHistory) === JSON.stringify(completed.statusHistory.filter(row => oldHistoryIds.has(id(row.id))))
|
&& JSON.stringify(current.statusHistory) === JSON.stringify(completed.statusHistory.filter(row => oldHistoryIds.has(id(row.id))))
|
||||||
&& ['id','tenantId','customerId','orderNo'].every(field => current.order[field] === completed.order[field]), 'no unrelated mutations')
|
&& ['id','tenantId','customerId','orderNo'].every(field => current.order[field] === completed.order[field]), 'no unrelated mutations')
|
||||||
context.apiSuccess(MODULE, `Platform ${action} 原键原版本精确重放成功`, await send('replay', command.body, command.headers))
|
context.apiSuccess(MODULE, `Platform ${action} 原键原版本精确重放成功`, await send('replay', command.body, command.headers))
|
||||||
same('成功重放后零漂移', completed, await read('原键重放后回查'))
|
same('成功重放后零漂移', completed, await read('原键重放后回查'))
|
||||||
const changed = action === 'submit' ? { expectedVersion: completed.order.version } : { ...command.body, reason: `${extra.reason}-changed` }
|
const changed = action === 'submit' ? { expectedVersion: completed.order.version } : { ...command.body, reason: `${extra.reason}-changed` }
|
||||||
await reject('原键异载荷拒绝', changed, command.headers, 'A0409', completed)
|
await reject('原键异载荷拒绝', changed, command.headers, 'A0409', completed)
|
||||||
await reject('新键重复动作拒绝', { ...extra, expectedVersion: completed.order.version },
|
await reject('新键重复动作拒绝', { ...extra, expectedVersion: completed.order.version },
|
||||||
{ 'Idempotency-Key': key(context, `platform-${action}-repeat-new-key`) }, 'A0409', completed)
|
{ 'Idempotency-Key': key(context, `platform-${action}-repeat-new-key`) }, 'A0409', completed)
|
||||||
proof.finalStatus = expectedStatus
|
proof.finalStatus = expectedStatus
|
||||||
proof.finalFactsSha256 = createHash('sha256').update(orderPersistenceFacts(completed)).digest('hex')
|
proof.finalFactsSha256 = createHash('sha256').update(orderPersistenceFacts(completed)).digest('hex')
|
||||||
}
|
}
|
||||||
return proofs
|
return proofs
|
||||||
}
|
}
|
||||||
export function fixtureInboundCode(policy, marker) {
|
export function fixtureInboundCode(policy, marker) {
|
||||||
if (policy?.mode === 'AUTO' && policy.manualEntryRequired === false) return {}
|
if (policy?.mode === 'AUTO' && policy.manualEntryRequired === false) return {}
|
||||||
if (policy?.mode !== 'LEGACY_MANUAL' || policy.manualEntryRequired !== true || !marker) {
|
if (policy?.mode !== 'LEGACY_MANUAL' || policy.manualEntryRequired !== true || !marker) {
|
||||||
|
|||||||
Reference in New Issue
Block a user