import assert from 'node:assert/strict' import test from 'node:test' import { filterGroupsByPermission, filterWorkflowByPermission, TOOL_DETAILS, TOOL_GROUPS, TOOL_ICON_GRADIENTS, TOOL_ICON_SHAPES, TOOL_MAP, } from '../src/pages/amazon/tool-catalog.ts' test('工具目录:20 个工具 id 唯一且每个都有图标与渐变配色', () => { const ids = TOOL_GROUPS.flatMap((g) => g.tools.map((t) => t.id)) assert.equal(ids.length, 20, '工具总数应为 20(前端8 + 运营10 + 后勤2)') assert.equal(new Set(ids).size, ids.length, '工具 id 不应重复') for (const id of ids) { assert.ok(TOOL_ICON_SHAPES[id], `图标形状缺失: ${id}`) assert.ok(TOOL_ICON_GRADIENTS[id], `图标渐变缺失: ${id}`) assert.equal(TOOL_MAP.get(id)?.id, id, `TOOL_MAP 应覆盖: ${id}`) } }) test('工具目录:无页面的工具应在 catalog 里标记为未开通(无 href)', () => { const pending = TOOL_GROUPS.flatMap((g) => g.tools).filter((t) => !t.href) const pendingIds = pending.map((t) => t.id).sort() assert.deepEqual(pendingIds, ['erp', 'purchase', 'shop'], '只有 店铺状态查询/采购/ERP 未开通') }) test('权限过滤:组键命中整组保留,未命中按工具权限过滤并隐藏空组', () => { const allowedAll = ['brand_front_tools', 'brand_operation_tools', 'brand_logistics_tools'] const all = filterGroupsByPermission(TOOL_GROUPS, allowedAll) assert.equal(all.length, 3) assert.ok(all[0].tools.every((t) => t.permissionKeys.length > 0)) // 只给前端组键:仅前端工具整组可见 const frontOnly = filterGroupsByPermission(TOOL_GROUPS, ['brand_front_tools']) assert.equal(frontOnly.length, 1) assert.equal(frontOnly[0].key, 'front') assert.equal(frontOnly[0].tools.length, 8) // 无组键时按单个工具权限过滤 const partial = filterGroupsByPermission(TOOL_GROUPS, ['collect-data', 'publish']) const groups = new Map(partial.map((g) => [g.key, g])) assert.deepEqual(groups.get('front')?.tools.map((t) => t.id), ['collect']) assert.deepEqual(groups.get('ops')?.tools.map((t) => t.id), ['list']) assert.equal(groups.has('logi'), false, '后勤无可见工具应整体隐藏') // 无任何权限:全部隐藏 assert.equal(filterGroupsByPermission(TOOL_GROUPS, []).length, 0) }) test('权限过滤:工作流时间线按工具权限截断', () => { const front = TOOL_GROUPS.find((g) => g.key === 'front') assert.ok(front?.workflow?.length === 8) // 只允许 采集数据,时间线只剩它一步 const steps = filterWorkflowByPermission(front?.workflow ?? [], ['collect-data']) assert.equal(steps.length, 1) assert.equal(steps[0].name, '采集数据') // 无权限 → 空 assert.equal(filterWorkflowByPermission(front?.workflow ?? [], []).length, 0) }) test('工具目录:页面链接与现有 BrandTopBar 导航映射一致', () => { const expectHref = new Map([ ['collect', '/collect-data'], ['dedupe', '/dedupe'], ['source', '/similar-asin'], ['brand', '/brand'], ['list', '/publish'], ['follow', '/price-track'], ['scrape', '/shop-data-crawl'], ['cash', '/withdraw'], ]) for (const [id, href] of expectHref) { assert.equal(TOOL_MAP.get(id)?.href, href, `工具 ${id} 应指向 ${href}`) } }) test('工具目录:页头长描述(detail)只覆盖已知工具,且不为空', () => { for (const [id, detail] of Object.entries(TOOL_DETAILS)) { assert.ok(TOOL_MAP.has(id), `TOOL_DETAILS 引用了未知工具: ${id}`) assert.ok(detail.trim().length > 0, `工具 ${id} 的 detail 不应为空`) const toolsWithHref = TOOL_MAP.get(id) assert.ok(toolsWithHref?.href, `detail 只应用于有页面的工具: ${id}`) } })