Files
order_site/apps/frontend/tests/consignment-matching-config.test.ts
T
zhaoxing 341f8b2000 feat(consignment): 自动匹配改为进入待抢单前一次性匹配
1) 配置改为开启自动匹配 + 匹配订单生效时间,移除内部匹配等待与定时轮询;2) 所有进入待抢单的路径统一先自动匹配一次,未命中进大厅;3) 手动匹配仅允许待抢单;4) 新增迁移 160 回填配置并迁移存量 internal_matching。
2026-11-13 13:25:05 +08:00

222 lines
11 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import assert from 'node:assert/strict'
import { readFileSync } from 'node:fs'
import { fileURLToPath } from 'node:url'
import test from 'node:test'
function read(relativePath: string) {
return readFileSync(fileURLToPath(new URL(relativePath, import.meta.url)), 'utf8')
}
test('管理端:订单服务之后必须存在寄卖配置 tab', () => {
const tabs = read('../src/utils/admin-worker-platform-tabs.ts')
assert.ok(tabs.includes("'consignment-config'"), '合法 tab 名单必须包含 consignment-config')
assert.ok(
tabs.includes("'consignment-config': [['admin-consignment-profiles']"),
'切到寄卖配置必须刷新配置查询',
)
const page = read('../src/pages/admin/AdminWorkerPlatformPage.tsx')
assert.ok(page.includes('ConsignmentConfigPanel'), '页面必须挂载寄卖配置面板')
const orderServiceIndex = page.indexOf("label: '订单服务'")
const consignmentIndex = page.indexOf("label: '寄卖配置'")
assert.ok(
orderServiceIndex > 0 && consignmentIndex > orderServiceIndex,
'寄卖配置必须在订单服务之后',
)
})
test('寄卖配置面板:必须覆盖保证金/服务费/数量限制/匹配/超时/降价', () => {
const panel = read('../src/pages/admin/panels/ConsignmentConfigPanel.tsx')
for (const label of [
'打手端 tab 名称',
'开启保证金',
'按数量',
'开启服务费',
'开启单人寄售上限',
'开启自动匹配',
'匹配订单生效时间',
'仅精确匹配',
'代练超时(小时)',
'重新匹配并退还押金',
'开启降价提示',
]) {
assert.ok(panel.includes(label), `寄卖配置面板缺少「${label}」`)
}
})
test('寄卖配置:旧配置缺少 autoMatchEnabled / orderEffectiveFrom 时不能崩溃', () => {
const panel = read('../src/pages/admin/panels/ConsignmentConfigPanel.tsx')
assert.ok(
panel.includes('Boolean(config.matching.autoMatchEnabled)'),
'缺少 autoMatchEnabled 时必须用 Boolean 容错',
)
assert.ok(
panel.includes('dayjs(config.matching.orderEffectiveFrom || undefined)'),
'缺少 orderEffectiveFrom 时必须回退到当前时间',
)
assert.ok(
panel.includes('values.matching.orderEffectiveFrom?.toISOString()'),
'保存时生效时间必须使用可选链',
)
assert.ok(panel.includes('staleTime: 0'), '配置查询必须每次重拉,避免旧缓存缺字段')
})
test('打手端:寄卖页必须按已发布配置动态生成 tab,并支持改价', () => {
const page = read('../src/pages/worker/WorkerConsignmentPage.tsx')
assert.ok(page.includes('fetchWorkerConsignmentProfiles'), '必须拉取已发布寄卖配置')
assert.ok(page.includes('profileTreeData'), '必须按配置生成 tab/分类树')
assert.ok(page.includes('修改售价'), '在售寄卖必须提供改价入口')
assert.ok(page.includes('updateWorkerConsignmentPrice'), '改价必须调用专用接口')
assert.ok(page.includes('priceDropSuggestion'), '必须展示降价建议')
assert.ok(page.includes('寄售数量'), '发布表单必须支持数量')
})
test('工单页:必须挂载内部库存匹配弹窗,并支持状态 internal_matching', () => {
const panel = read('../src/pages/admin/panels/WorkOrdersPanel.tsx')
assert.ok(panel.includes('ConsignmentWorkOrderMatchModal'), '工单页必须挂载内部匹配弹窗')
assert.ok(panel.includes("'internal_matching'"), '状态筛选必须支持内部匹配中')
const shared = read('../src/pages/admin/panels/shared.tsx')
assert.ok(shared.includes("internal_matching: '内部匹配中'"), '状态文案必须包含内部匹配中')
assert.ok(shared.includes("internal_matching: 'magenta'"), '状态配色必须包含内部匹配中')
})
test('寄卖配置面板:订单服务风格分类树、独立分区与价格配置', () => {
const panel = read('../src/pages/admin/panels/ConsignmentConfigPanel.tsx')
for (const label of [
'搜索分类',
'个分类已配置',
'规格字段',
'添加字段',
'基础信息',
'价格配置',
'履约保证金',
'服务费',
'库存数量限制',
'匹配设置',
'超时设置',
'降价提示',
'联系方式与游戏凭据',
'接单模板价打折',
'模板价固定下调',
'模板折扣',
'物品名模板',
]) {
assert.ok(panel.includes(label), `寄卖配置面板缺少「${label}」`)
}
assert.ok(panel.includes('order-service-category-group'), '分类必须按订单服务风格分组')
assert.ok(
panel.indexOf('title="规格字段"') < panel.indexOf('title="联系方式与游戏凭据"') &&
panel.indexOf('title="联系方式与游戏凭据"') < panel.indexOf('title="价格配置"'),
'联系方式与游戏凭据必须紧跟在规格字段之后、价格配置之前',
)
assert.ok(panel.includes('order-service-subcategory-list'), '二级分类必须缩进展示')
assert.ok(panel.includes('resolveInheritedProfileStatus'), '子分类必须展示继承父级状态')
assert.ok(panel.includes('order-service-save-bar'), '底部必须使用订单服务保存栏')
assert.ok(panel.includes('ConsignmentSectionTitle'), '配置分区必须使用编号标题')
assert.ok(!panel.includes('DEFAULT_SPEC_FIELDS'), '面板不能预置任何内置字段')
assert.ok(panel.includes('useState<ConsignmentSpecField[]>([])'), '规格字段初始必须为空')
assert.ok(panel.includes('specDrafts.map'), '规格字段必须可动态增删/排序')
assert.ok(panel.includes('SPEC_FIELD_TYPE_OPTIONS'), '字段类型必须支持 6 种选项')
assert.ok(panel.includes('addonBefore="选项"'), '下拉/单选项必须使用订单服务式逗号输入')
assert.ok(panel.includes('placeholder="选项1,选项2,选项3"'), '选项输入必须使用订单服务占位文案')
assert.ok(panel.includes('updateOptionText'), '选项编辑必须把逗号分隔文本解析为选项')
assert.ok(!panel.includes('添加选项'), '选项不再逐行编辑')
})
test('打手端:动态规格 + 系统建议价 + 改价不得高于建议价', () => {
const page = read('../src/pages/worker/WorkerConsignmentPage.tsx')
assert.ok(page.includes('selectedSpecs.map'), '规格必须按配置动态渲染')
assert.ok(page.includes('fetchWorkerConsignmentPricePreview'), '必须走动态价格预览')
assert.ok(page.includes('不能高于系统建议价'), '前端必须提示改价上限')
assert.ok(page.includes('specValues'), '发布必须提交动态规格值')
assert.ok(page.includes('config.pricing.allowWorkerPrice'), '改价能力必须按配置')
})
test('寄卖配置:未售出时长支持一位小数', () => {
const panel = read('../src/pages/admin/panels/ConsignmentConfigPanel.tsx')
const start = panel.indexOf("name={['priceDrop', 'hours']}")
assert.ok(start > 0, '必须存在未售出时长配置')
const block = panel.slice(start, panel.indexOf('</Form.Item>', start))
assert.ok(block.includes('precision={1}'), '未售出时长必须支持一位小数')
assert.ok(block.includes('min={0.1}'), '未售出时长下限应为 0.1 小时')
})
test('寄卖配置:保证金支持按数量(规格),弹窗内配置选项价格', () => {
const panel = read('../src/pages/admin/panels/ConsignmentConfigPanel.tsx')
assert.ok(
panel.includes("{ value: 'per_spec', label: '按数量(规格)' }"),
'保证金模式必须包含「按数量(规格)」',
)
assert.ok(panel.includes('title="按数量(规格)保证金"'), '必须提供规格价格配置弹窗')
assert.ok(panel.includes('specPricesYuan'), '选项价格必须写回配置')
assert.ok(panel.includes('填充全部选项'), '弹窗必须支持批量填充选项价格')
})
test('寄卖配置:规格字段与联系方式区块提供复制模板配置入口', () => {
const panel = read('../src/pages/admin/panels/ConsignmentConfigPanel.tsx')
assert.ok(panel.includes('复制模板配置'), '两个区块都要有复制模板配置按钮')
assert.ok(panel.includes("setCopyTemplateMode('specs')"), '规格字段入口必须打开规格复制')
assert.ok(panel.includes("setCopyTemplateMode('intake')"), '联系方式入口必须打开凭据复制')
assert.ok(panel.includes('ConsignmentTemplateCopyModal'), '必须挂载复制模板弹窗')
const modal = read('../src/components/admin/ConsignmentTemplateCopyModal.tsx')
assert.ok(modal.includes('已发布版本'), '复制来源必须支持已发布版本')
assert.ok(modal.includes('当前草稿'), '复制来源必须支持当前草稿')
assert.ok(modal.includes('publishedConfig'), '已发布版本必须读取发布快照配置')
assert.ok(modal.includes('不影响价格、保证金、服务费、匹配和超时设置'), '复制只替换当前区块')
assert.ok(modal.includes('ruleKey'), '模板驱动规格必须提示 ruleKey 仍指向来源模板')
assert.ok(modal.includes('TreeSelect'), '来源选择必须使用折叠树')
assert.ok(
modal.includes('treeDefaultExpandAll') && !modal.includes('treeDefaultExpandAll={false}'),
'来源树默认必须展开二级',
)
assert.ok(modal.includes('treeTitleRender'), '来源树必须自定义层级标题')
assert.ok(
!modal.includes('key: `') && modal.includes('.map((node) => node.value)'),
'展开键必须来自节点 value(rc-tree 内部 key 即 value),否则默认展开失效',
)
})
test('打手端:寄卖分类按一二级层级展示', () => {
const page = read('../src/pages/worker/WorkerConsignmentPage.tsx')
assert.ok(page.includes('categoryParentName'), '必须使用父分类名称')
assert.ok(page.includes('orderWorkerProfiles'), '必须按一级/二级排序')
assert.ok(page.includes('profileTreeData'), '必须构建一级/二级树')
assert.ok(page.includes('TreeSelect'), '必须使用可折叠的 TreeSelect')
assert.ok(
page.includes('treeDefaultExpandAll') && !page.includes('treeDefaultExpandAll={false}'),
'默认必须展开二级',
)
assert.ok(page.includes('treeTitleRender'), '必须自定义层级标题')
assert.ok(
!page.includes('key: `') && page.includes('.map((node) => node.value)'),
'展开键必须来自节点 value(rc-tree 内部 key 即 value),否则默认展开失效',
)
assert.ok(page.includes('二级'), '二级分类必须有层级标签')
})
test('寄售仓库:寄卖分类筛选按一二级层级展示', () => {
const panel = read('../src/pages/admin/panels/ConsignmentInventoryPanel.tsx')
assert.ok(panel.includes('categoryTreeData'), '必须构建一级/二级树')
assert.ok(panel.includes('TreeSelect'), '必须使用可折叠的 TreeSelect')
assert.ok(
panel.includes('treeDefaultExpandAll') && !panel.includes('treeDefaultExpandAll={false}'),
'默认必须展开二级',
)
assert.ok(panel.includes('treeTitleRender'), '必须自定义层级标题')
assert.ok(
!panel.includes('key: `') && panel.includes('.map((node) => node.value)'),
'展开键必须来自节点 value(rc-tree 内部 key 即 value),否则默认展开失效',
)
assert.ok(panel.includes('继承'), '继承型二级分类必须有继承标记')
})
test('寄卖配置:服务费提示修改后对在库商品立即生效', () => {
const panel = read('../src/pages/admin/panels/ConsignmentConfigPanel.tsx')
assert.ok(
panel.includes('服务费按匹配时的已发布配置计算:修改后对在库商品立即生效'),
'服务费区块必须提示:按匹配时已发布配置计算,修改后对在库商品立即生效',
)
})