Files
client-web/src/modules/first-leg/views/QuickOrderView.test.mjs
T

103 lines
6.3 KiB
JavaScript
Raw Normal View History

2026-08-13 09:48:51 +08:00
import assert from 'node:assert/strict'
import { readFileSync } from 'node:fs'
import test from 'node:test'
const source = readFileSync(new URL('./QuickOrderView.vue', import.meta.url), 'utf8')
const routesSource = readFileSync(new URL('../routes.ts', import.meta.url), 'utf8')
const contractsSource = readFileSync(new URL('../../tenant-management/contracts.ts', import.meta.url), 'utf8')
const orderViewSource = readFileSync(new URL('./FirstLegOrdersView.vue', import.meta.url), 'utf8')
test('exposes quick order as an active first-leg route with its dedicated permission', () => {
assert.match(routesSource, /path: 'first-leg\/quick-order'[\s\S]*?release: 'active'[\s\S]*?permission: 'order:first-leg:quick-create'/)
assert.match(contractsSource, /code: 'order:first-leg:quick-create'[\s\S]*?label: '快速下单'/)
assert.match(contractsSource, /'order:first-leg:quick-create': \['merchant:order:quick-create', 'merchant:order:create'\]/)
assert.match(contractsSource, /FRONTEND_PERMISSIONS_REQUIRING_ALL_BACKEND_CODES[\s\S]*?'order:first-leg:quick-create'/)
assert.match(routesSource, /path: 'orders\/first-leg\/:draftId\/edit'[\s\S]*?name: 'first-leg-order-edit'[\s\S]*?permission: 'order:first-leg:edit'/)
assert.match(orderViewSource, /store\.loadDraftDetail\(id\)/)
})
2026-08-18 11:32:58 +08:00
test('keeps the primary quick-order table focused on inbound code policy, channel, destination and cargo', () => {
2026-08-13 09:48:51 +08:00
for (const label of ['选择渠道', '目的仓', '产品信息:产品 SKU / 箱数', '新增一行', '生成草稿单']) {
assert.match(source, new RegExp(label))
}
assert.match(source, /getMerchantPricingChannels/)
assert.match(source, /destinationType: 'FBA'/)
assert.match(source, /function createProduct\(\): QuickOrderProduct/)
assert.match(source, /products: \[createProduct\(\)\]/)
2026-08-18 11:32:58 +08:00
assert.match(source, /getMerchantInboundCodePolicy/)
assert.match(source, /manualInboundCodeRequired/)
assert.match(source, /v-if="manualInboundCodeRequired"[^>]*>旧系统入仓码/)
assert.match(source, /inboundCode: row\.inboundCode\.trim\(\) \|\| undefined/)
2026-08-13 09:48:51 +08:00
})
test('creates one real backend draft per order row and keeps its products together', () => {
assert.match(source, /function buildOrderDraft\(row: QuickOrderRow, channel: QuickChannelOption\)/)
assert.match(source, /items: row\.products\.map/)
assert.match(source, /const drafts = rows\.flatMap\(\(row\) =>/)
assert.match(source, /clientRowId: row\.id, draft: buildOrderDraft\(row, channel\)/)
assert.match(source, /store\.saveDraftBatch\(drafts, customerName, activeBatchKey\.value\)/)
assert.match(source, /response\.items\.flatMap/)
2026-08-18 11:32:58 +08:00
assert.match(source, /inboundCode: item\.inboundCode\?\.trim\(\) \?\? ''/)
2026-08-13 09:48:51 +08:00
assert.match(source, /已生成 \$\{successes\.length\} 张草稿单/)
assert.match(source, /successfulIds\.has\(rows\[index\]\.id\)/)
assert.match(source, /response\.items\.filter/)
assert.match(source, /activeBatchKey\.value/)
assert.match(source, /name: 'first-leg-order-edit'/)
assert.match(source, /params: \{ draftId: result\.draftId \}/)
assert.doesNotMatch(source, /getMerchantUnifiedOrder/)
assert.doesNotMatch(source, /store\.saveDraft\(/)
assert.doesNotMatch(source, /store\.submit\(|store\.submitSavedDraft\(|submitMerchantFirstLegOrder/)
assert.doesNotMatch(source, /name: 'first-leg-order-create'/)
})
2026-08-18 11:32:58 +08:00
test('requires the old inbound code globally only while legacy manual mode is active', () => {
assert.match(source, /manualInboundCodeRequired\.value[\s\S]*?rows\.findIndex\(\(row\) => !row\.inboundCode\.trim\(\)\)/)
assert.match(source, /请填写第 \$\{missingInboundCodeIndex \+ 1\} 行的旧系统入仓码/)
2026-08-13 09:48:51 +08:00
assert.match(source, /!row\.channelKey \|\| !row\.destinationWarehouseName/)
assert.match(source, /!product\.sku\.trim\(\) \|\| product\.packageCount < 1/)
assert.match(source, /渠道、目的仓、产品 SKU 和箱数/)
assert.match(source, /createEmptyCargoItem/)
assert.match(source, /packageCount: product\.packageCount/)
assert.match(source, /sku: product\.sku\.trim\(\)/)
assert.match(source, /destinationWarehouseId: row\.destinationWarehouseId/)
assert.match(source, /destinationWarehouseName: row\.destinationWarehouseName/)
assert.match(source, /destinationCountryCode: row\.destinationCountryCode/)
assert.doesNotMatch(source, /mixedChannel/)
assert.doesNotMatch(source, /confirmationDialogOpen|QuickCargoConfirmation|confirmAndCreateQuickDraft/)
assert.doesNotMatch(source, /确认草稿资料|确认并生成草稿/)
assert.doesNotMatch(source, /validateFirstLegOrderDraft/)
assert.match(source, /@click="submitQuickOrder"/)
assert.ok(
source.indexOf('async function submitQuickOrder()') < source.indexOf('store.saveDraftBatch(drafts'),
'the primary quick-order action must save drafts directly',
)
})
test('shows every created draft and keeps failed rows available for retry', () => {
assert.match(source, /v-for="result in draftResults"/)
2026-08-18 11:32:58 +08:00
assert.match(source, /入仓码将在提交订单时生成/)
2026-08-13 09:48:51 +08:00
assert.match(source, /@click="editDraft\(result\)"/)
assert.match(source, /if \(rows\.length === 0\) rows\.push\(createRow\(\)\)/)
assert.match(source, /resultDialogOpen\.value = successes\.length > 0/)
})
test('adds products inside one order row and only the footer adds a new draft row', () => {
assert.match(source, /function addProduct\(row: QuickOrderRow\)[\s\S]*?row\.products\.push\(createProduct\(\)\)/)
assert.match(source, /function addOrderRow\(\)[\s\S]*?rows\.push\(createRow\(\)\)/)
assert.match(source, /@click="addProduct\(row\)"[^>]*><Plus[^>]*\/>添加产品行/)
assert.match(source, /@click="addOrderRow"[^>]*><Plus[^>]*\/>新增一行/)
assert.match(source, /v-for="\(product, productIndex\) in row\.products"/)
assert.match(source, /@click="removeProduct\(row, productIndex\)"/)
})
test('binds exactly one destination warehouse through a destination dialog', () => {
assert.match(source, /<el-dialog v-model="destinationDialogOpen"/)
assert.match(source, /function bindDestination\(\)/)
assert.match(source, /availableDestinationWarehouses\.value\.find/)
assert.match(source, /destinationWarehouseId: warehouse\.id/)
assert.match(source, /destinationWarehouseId: ''/)
assert.match(source, /const required = \[destinationForm\.privateName, destinationForm\.countryCode\]/)
assert.match(source, /hasCompletePrivateContact\(row\)/)
assert.match(source, /确认绑定/)
})