优化
This commit is contained in:
@@ -8,7 +8,7 @@ const interpolations = (source) => [...template(source).matchAll(/\{\{([\s\S]*?)
|
||||
|
||||
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/login/login.vue', '../src/pages/home/home.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',
|
||||
@@ -86,7 +86,6 @@ test('missing user-visible relationships use explicit empty labels instead of ID
|
||||
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 \|\| '未绑定库位'/)
|
||||
|
||||
@@ -108,7 +108,7 @@ test('container UI locks and signs once, then renders the resolved destination g
|
||||
for (const fact of ['已分配', '未分配', '可合托·非强制', '不合托', '加急', '普通']) assert.match(summary, new RegExp(fact))
|
||||
assert.doesNotMatch(operation, /v-for="[^"]*inbound[^"]*"/)
|
||||
assert.match(operation, /v-if="activeInbound"[\s\S]*activeInbound\.inboundCodes[\s\S]*activeInbound\.pendingPackages/)
|
||||
assert.match(operation, /activeInbound\.operationMode === 'FBA_GROUP'[\s\S]*按 FBA 仓成组收货/)
|
||||
assert.match(operation, /class="mode-banner"[^\n]*activeInbound\.destinationType === 'FBA'[^\n]*FBA 按箱数收货[^\n]*海外仓逐箱收货/)
|
||||
assert.doesNotMatch(operation, /activeInbound\.customer|客户/)
|
||||
assert.match(operation, /resolveCurrentCarton\(cartonMark\)/)
|
||||
assert.match(operation, /operationMode !== 'DROPSHIP_PALLET'[\s\S]*receiveCurrentWholePallet/)
|
||||
@@ -121,7 +121,6 @@ test('container UI locks and signs once, then renders the resolved destination g
|
||||
assert.match(operation, /applyWarehouseProfile\(await getCurrentWarehouseProfile\(\)\)/)
|
||||
assert.match(operation, /values\.map\(\(item\) => this\.validateReceivingWarehouse/)
|
||||
assert.match(operation, /prepareReceivingContainer[\s\S]*validateReceivingWarehouse/)
|
||||
assert.match(summary, /overseasWarehouseCode[\s\S]*overseasWarehouseName/)
|
||||
for (const forbidden of ['customerId', 'planNo', 'allocationId', 'warehouseId', 'locationId']) {
|
||||
assert.doesNotMatch(inboundApi, new RegExp(forbidden))
|
||||
}
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import test from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
import { readFile } from 'node:fs/promises'
|
||||
import { MODULES } from '../src/data/overseas-workbench.js'
|
||||
import { navigateBackOr, navigateToUnique } from '../src/utils/navigation.js'
|
||||
|
||||
const read = (path) => readFile(new URL(path, import.meta.url), 'utf8')
|
||||
const component = (source, dependencies) => new Function(...Object.keys(dependencies), source.match(/<script>([\s\S]*?)<\/script>/)[1].replace(/^\s*import .*$/gm, '').replace('export default', 'return'))(...Object.values(dependencies))
|
||||
|
||||
test('navigateBackOr returns through the stack and falls back when the stack is empty', () => {
|
||||
const calls = []
|
||||
globalThis.uni = {
|
||||
@@ -36,3 +41,46 @@ test('navigateToUnique does not stack the current utility page twice', () => {
|
||||
navigateToUnique('/pages/history/history')
|
||||
assert.deepEqual(calls, [{ url: '/pages/history/history' }])
|
||||
})
|
||||
|
||||
test('every registered page header returns home after a reload without page history', async (t) => {
|
||||
const previousUni = globalThis.uni
|
||||
const previousPages = globalThis.getCurrentPages
|
||||
t.after(() => { globalThis.uni = previousUni; globalThis.getCurrentPages = previousPages })
|
||||
const { pages } = JSON.parse(await read('../src/pages.json'))
|
||||
const header = component(await read('../src/components/PortalHeader.vue'), { PopupHeader: {}, navigateBackOr, navigateToUnique })
|
||||
const calls = []
|
||||
globalThis.uni = { reLaunch: (options) => calls.push(options), navigateBack: () => assert.fail('a reloaded page has no back stack') }
|
||||
let checked = 0
|
||||
for (const { path } of pages) {
|
||||
const source = await read(`../src/${path}.vue`)
|
||||
const tag = source.match(/<PortalHeader\b[^>]*\/>/)?.[0]
|
||||
if (!tag) continue
|
||||
assert.doesNotMatch(tag, /:fallback-url=/, path)
|
||||
const fallbackUrl = tag.match(/\bfallback-url="([^"]*)"/)?.[1] || header.props.fallbackUrl.default
|
||||
assert.equal(fallbackUrl, '/pages/home/home', path)
|
||||
globalThis.getCurrentPages = () => [{ route: path }]
|
||||
header.methods.goBack.call({ fallbackUrl })
|
||||
assert.deepEqual(calls.at(-1), { url: '/pages/home/home' }, path)
|
||||
checked++
|
||||
}
|
||||
assert.ok(checked > 0)
|
||||
assert.equal(calls.length, checked)
|
||||
})
|
||||
|
||||
test('home opens every enabled operation directly on a registered page', async (t) => {
|
||||
const previousUni = globalThis.uni
|
||||
t.after(() => { globalThis.uni = previousUni })
|
||||
const { pages } = JSON.parse(await read('../src/pages.json'))
|
||||
const registered = new Set(pages.map(({ path }) => `/${path}`))
|
||||
const home = component(await read('../src/pages/home/home.vue'), { PortalHeader: {}, MODULES })
|
||||
const calls = []
|
||||
globalThis.uni = { navigateTo: (options) => calls.push(options) }
|
||||
for (const group of MODULES) {
|
||||
for (const operation of group.operations.filter((item) => item.available)) {
|
||||
const count = calls.length
|
||||
home.methods.openOperation.call({ groups: MODULES }, operation)
|
||||
assert.equal(calls.length, count + 1, operation.name)
|
||||
assert.ok(registered.has(calls.at(-1).url.split('?')[0]), operation.name)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -5,14 +5,13 @@ import { readFile } from 'node:fs/promises'
|
||||
const read = (path) => readFile(new URL(path, import.meta.url), 'utf8')
|
||||
|
||||
test('pallet management is enabled through its dedicated real PDA route', async () => {
|
||||
const [workbench, pages, home, module] = await Promise.all([
|
||||
const [workbench, pages, home] = await Promise.all([
|
||||
read('../src/data/overseas-workbench.js'), read('../src/pages.json'),
|
||||
read('../src/pages/home/home.vue'), read('../src/pages/module/module.vue')
|
||||
read('../src/pages/home/home.vue')
|
||||
])
|
||||
assert.match(workbench, /key: 'pallet'[\s\S]*available: true[\s\S]*route: '\/pages\/pallet\/pallet'/)
|
||||
assert.match(pages, /pages\/pallet\/pallet/)
|
||||
assert.match(home, /operation\.route \|\|/)
|
||||
assert.match(module, /operation\.route \|\|/)
|
||||
})
|
||||
|
||||
test('pallet API maps only the frozen overseas PDA operation endpoints', async () => {
|
||||
|
||||
@@ -90,9 +90,9 @@ test('login has no committed demo credentials and inbound operation implements t
|
||||
})
|
||||
|
||||
test('warehouse operations use dedicated real pages and contain no prototype task data', async () => {
|
||||
const [operation, home, module, workbench, pages] = await Promise.all([
|
||||
const [operation, home, workbench, pages] = await Promise.all([
|
||||
read('../src/pages/operation/operation.vue'), read('../src/pages/home/home.vue'),
|
||||
read('../src/pages/module/module.vue'), read('../src/data/overseas-workbench.js'), read('../src/pages.json')
|
||||
read('../src/data/overseas-workbench.js'), read('../src/pages.json')
|
||||
])
|
||||
assert.doesNotMatch(operation, /prototypeScan|prototypeInput/)
|
||||
assert.doesNotMatch(workbench, /PROTOTYPES|getOperationPrototype|模拟成功/)
|
||||
@@ -101,7 +101,7 @@ test('warehouse operations use dedicated real pages and contain no prototype tas
|
||||
}
|
||||
assert.doesNotMatch(workbench, /key: 'stocktake'/)
|
||||
for (const page of ['pages/stocktake/stocktake', 'pages/move/move', 'pages/relabel/relabel', 'pages/query/query']) assert.match(pages, new RegExp(page))
|
||||
assert.match(home + module, /operation\.route \|\|/)
|
||||
assert.match(home, /operation\.route \|\|/)
|
||||
})
|
||||
|
||||
test('receiving phases use a compiled container summary with cabinet and aggregate facts', async () => {
|
||||
@@ -130,7 +130,7 @@ test('candidate containers use compact card navigation and a small refresh actio
|
||||
assert.match(operation, /class="candidate-facts"[\s\S]*总订单[\s\S]*入仓码[\s\S]*已生成计划[\s\S]*未操作/)
|
||||
assert.match(operation, /class="candidate-destinations"/)
|
||||
assert.match(operation, /计划到仓:\{\{ formatPlannedArrival\(item\.plannedArrivalAt\) \}\}/)
|
||||
assert.match(operation, /item\.blockReason \|\| '当前柜入库计划尚未齐全'/)
|
||||
assert.match(operation, /selected\?\.blockReason \|\| '当前柜入库计划尚未齐全'/)
|
||||
assert.doesNotMatch(operation, /预计到港/)
|
||||
assert.doesNotMatch(operation, /item\.receivedPackages[\s\S]*item\.totalPackages[\s\S]*progress-fill/)
|
||||
})
|
||||
|
||||
@@ -126,7 +126,6 @@ test('relabel review opens a pending task as customer-confirmation read-only det
|
||||
assert.equal(visible.call({ ...context, candidates: [] }), false)
|
||||
assert.equal(visible.call({ ...context, stage: 'review', current: { ...context.current, taskStatus: 'WAIT_REVIEW' } }), true)
|
||||
assert.equal(visible.call({ ...context, current: { ...context.current, taskStatus: 'WAIT_REVIEW' } }), false)
|
||||
assert.match(page, /stageSubtitle\(\) \{ return this\.stage === 'review' \? '仅展示当前仓库已完成现场换标并等待客户或平台处理的单据'/)
|
||||
assert.match(page, /<view v-else class="task-list">[\s\S]*@tap="openReview\(item\)"/)
|
||||
assert.match(page, /查看并复核/)
|
||||
assert.match(page, /async openReview\(item\)/)
|
||||
@@ -145,8 +144,8 @@ test('relabel review opens a pending task as customer-confirmation read-only det
|
||||
|
||||
test('returned relabel tasks are highlighted, sorted first, and still obey the single active task lock', async () => {
|
||||
const page = await read('../src/pages/relabel/relabel.vue')
|
||||
assert.match(page, /item\.reviewDecision === 'REWORK'[\s\S]*退回重做[\s\S]*优先处理/)
|
||||
assert.match(page, /退回备注:\{\{ item\.reviewRemark \}\}/)
|
||||
assert.match(page, /item\.reviewDecision === 'REWORK'[\s\S]*退回重做/)
|
||||
assert.match(page, /current\.reviewDecision === 'REWORK' && current\.reviewRemark[\s\S]*\{\{ current\.reviewRemark \}\}/)
|
||||
assert.match(page, /\.sort\(\(left, right\) => Number\(right\.reviewDecision === 'REWORK'\) - Number\(left\.reviewDecision === 'REWORK'\)/)
|
||||
assert.match(page, /const active = this\.candidates\.find\(\(candidate\) => candidate\.taskStatus === 'PROCESSING' && candidate\.claimedByCurrentOperator === true\)/)
|
||||
assert.match(page, /if \(active && active\.relabelNo !== item\.relabelNo\) return this\.promptActiveTask\(active\)/)
|
||||
|
||||
Reference in New Issue
Block a user