94 lines
5.3 KiB
JavaScript
94 lines
5.3 KiB
JavaScript
import test from 'node:test'
|
|
import assert from 'node:assert/strict'
|
|
import { readFile } from 'node:fs/promises'
|
|
|
|
const read = (path) => readFile(new URL(path, import.meta.url), 'utf8')
|
|
const template = (source) => source.match(/<template>([\s\S]*?)<\/template>/)?.[1] || ''
|
|
const interpolations = (source) => [...template(source).matchAll(/\{\{([\s\S]*?)\}\}/g)].map((match) => match[1]).join('\n')
|
|
|
|
test('all registered user-facing pages avoid rendering internal identifiers', async () => {
|
|
const paths = [
|
|
'../src/pages/login/login.vue', '../src/pages/home/home.vue', '../src/pages/module/module.vue',
|
|
'../src/pages/operation/operation.vue', '../src/pages/pallet/pallet.vue', '../src/pages/profile/profile.vue',
|
|
'../src/pages/dispatch/dispatch.vue', '../src/pages/outbound/outbound.vue',
|
|
'../src/pages/stocktake/stocktake.vue', '../src/pages/move/move.vue', '../src/pages/relabel/relabel.vue', '../src/pages/query/query.vue',
|
|
'../src/pages/return-receipt/return-receipt.vue',
|
|
'../src/pages/return-packing/return-packing.vue',
|
|
'../src/pages/history/history.vue', '../src/pages/scanner-test/scanner-test.vue',
|
|
'../src/components/PortalHeader.vue', '../src/components/PopupHeader.vue',
|
|
'../src/components/ReceivingSessionSummary.vue', '../src/components/ScanTargetInput.vue'
|
|
]
|
|
const visibleExpressions = (await Promise.all(paths.map(read))).map(interpolations).join('\n')
|
|
for (const field of [
|
|
'orderId', 'inboundId', 'planId', 'containerBookingId', 'sourceContainerBookingId',
|
|
'warehouseId', 'palletId', 'locationId', 'positionId', 'user.id'
|
|
]) assert.doesNotMatch(visibleExpressions, new RegExp(field.replace('.', '\\.')))
|
|
})
|
|
|
|
test('operator and warehouse cards never fall back to internal IDs', async () => {
|
|
const [home, profile, session] = await Promise.all([
|
|
read('../src/pages/home/home.vue'),
|
|
read('../src/pages/profile/profile.vue'),
|
|
read('../src/stores/session.js')
|
|
])
|
|
|
|
assert.doesNotMatch(template(home), /warehouseId|warehouseCode|user\.warehouse/)
|
|
assert.doesNotMatch(home, /warehouseId\.slice|当前作业仓\s*·/)
|
|
assert.match(home, /warehouseName \|\| ''[\s\S]*海外仓未关联/)
|
|
assert.doesNotMatch(template(profile), /user\.id|user\.role|warehouseId|warehouseCode|user\.warehouse/)
|
|
assert.match(profile, /roleLabel\(\) \{ return '海外仓作业员' \}/)
|
|
assert.match(profile, /warehouseName \|\| ''[\s\S]*海外仓未关联/)
|
|
assert.doesNotMatch(session, /海外仓 #\$\{|warehouse:\s*profile\.warehouseCode/)
|
|
})
|
|
|
|
test('operation templates expose business references only and keep diagnostic evidence', async () => {
|
|
const [operation, pallet, summary, stocktake, move, relabel, query, returnReceipt, returnPacking, apiFiles] = await Promise.all([
|
|
read('../src/pages/operation/operation.vue'),
|
|
read('../src/pages/pallet/pallet.vue'),
|
|
read('../src/components/ReceivingSessionSummary.vue'),
|
|
read('../src/pages/stocktake/stocktake.vue'), read('../src/pages/move/move.vue'),
|
|
read('../src/pages/relabel/relabel.vue'), read('../src/pages/query/query.vue'),
|
|
read('../src/pages/return-receipt/return-receipt.vue'),
|
|
read('../src/pages/return-packing/return-packing.vue'),
|
|
Promise.all([
|
|
read('../src/api/inbound.js'), read('../src/api/pallet.js'),
|
|
read('../src/api/overseas.js'), read('../src/api/receiving-adapter.js'),
|
|
read('../src/api/warehouse-operations.js'), read('../src/api/relabel.js')
|
|
]).then((values) => values.join('\n'))
|
|
])
|
|
|
|
const forbiddenDisplayFields = [
|
|
'orderId', 'inboundId', 'planId', 'containerBookingId', 'sourceContainerBookingId',
|
|
'warehouseId', 'palletId', 'locationId', 'positionId'
|
|
]
|
|
for (const field of forbiddenDisplayFields) {
|
|
assert.doesNotMatch(template(operation), new RegExp(`\\b${field}\\b`))
|
|
assert.doesNotMatch(template(summary), new RegExp(`\\b${field}\\b`))
|
|
}
|
|
for (const field of ['orderId', 'inboundId', 'planId', 'containerBookingId', 'sourceContainerBookingId', 'warehouseId', 'palletId', 'locationId']) {
|
|
assert.doesNotMatch(template(pallet), new RegExp(`\\b${field}\\b`))
|
|
for (const page of [stocktake, move, relabel, query]) assert.doesNotMatch(template(page), new RegExp(`\\b${field}\\b`))
|
|
}
|
|
for (const field of [...forbiddenDisplayFields, 'customerId']) assert.doesNotMatch(template(returnReceipt), new RegExp(`\\b${field}\\b`))
|
|
for (const field of [...forbiddenDisplayFields, 'customerId']) assert.doesNotMatch(template(returnPacking), new RegExp(`\\b${field}\\b`))
|
|
|
|
for (const businessField of ['containerNo', 'inboundCode', 'cartonMark', 'palletCode']) {
|
|
assert.match(operation + pallet + summary, new RegExp(businessField))
|
|
}
|
|
assert.match(operation, /requestId[\s\S]*traceId/)
|
|
assert.match(pallet, /requestId[\s\S]*traceId/)
|
|
for (const page of [stocktake, move, relabel, query, returnReceipt, returnPacking]) assert.match(page, /requestId[\s\S]*traceId/)
|
|
assert.doesNotMatch(apiFiles, /\/api\/platform\/v1\/|inbound-code-relationships/)
|
|
})
|
|
|
|
test('missing user-visible relationships use explicit empty labels instead of ID-shaped fallbacks', async () => {
|
|
const [summary, pallet] = await Promise.all([
|
|
read('../src/components/ReceivingSessionSummary.vue'),
|
|
read('../src/pages/pallet/pallet.vue')
|
|
])
|
|
assert.match(summary, /overseasWarehouseCode[\s\S]*overseasWarehouseName/)
|
|
assert.match(summary, /unique\.length \? unique : \['—'\]/)
|
|
assert.match(pallet, /inboundCode \|\| '无入仓码'/)
|
|
assert.match(pallet, /locationCode \|\| '未绑定库位'/)
|
|
})
|