import assert from 'node:assert/strict' import { readFileSync } from 'node:fs' import test from 'node:test' import { loadDashboardOverview } from './overview.ts' const dashboardView = readFileSync(new URL('./views/DashboardView.vue', import.meta.url), 'utf8') const profile = 'company:profile:view' const list = 'order:first-leg:list' const edit = 'order:first-leg:edit' const company = { tenantName: '示例企业', status: 'ACTIVE' } function order(overrides = {}) { return { orderId: 101, orderNo: 'ORDER-101', inboundCode: 'INBOUND-101', destinationWarehouseName: '示例目的仓', channelName: '示例渠道', mainStatus: 'WAIT_MEASURE', customerFeeConfirmationRequired: false, createdAt: '2026-09-18T08:00:00Z', ...overrides, } } function draft(overrides = {}) { return { ...order(), status: 'DRAFT', ...overrides } } function requests(overrides = {}) { return { company: async () => company, orders: async () => ({ records: [order()] }), drafts: async () => ({ records: [draft()] }), ...overrides, } } test('only calls sources allowed by their complete permission requirements', async (t) => { const cases = [ { permissions: [], expected: [] }, { permissions: [profile], expected: ['company'] }, { permissions: [list], expected: ['orders'] }, { permissions: [edit], expected: [] }, { permissions: [list, edit], expected: ['orders', 'drafts'] }, { permissions: [profile, list, edit], expected: ['company', 'orders', 'drafts'] }, ] for (const { permissions, expected } of cases) { await t.test(permissions.join(',') || 'no permissions', async () => { const calls = [] const result = await loadDashboardOverview(permissions, requests({ company: async () => { calls.push('company'); return company }, orders: async () => { calls.push('orders'); return { records: [order()] } }, drafts: async () => { calls.push('drafts'); return { records: [draft()] } }, })) assert.deepEqual(calls, expected) assert.equal(result.company, expected.includes('company') ? company : null) assert.equal(result.orders.length, expected.includes('orders') ? 1 : 0) assert.equal(result.drafts.length, expected.includes('drafts') ? 1 : 0) assert.deepEqual(result.errors, {}) }) } }) test('one failed source preserves successful sources and exposes its error', async (t) => { for (const failedSource of ['company', 'orders', 'drafts']) { await t.test(failedSource, async () => { const result = await loadDashboardOverview([profile, list, edit], requests({ [failedSource]: async () => { throw new Error(`${failedSource} unavailable`) }, })) assert.deepEqual(result.errors, { [failedSource]: `${failedSource} unavailable` }) assert.equal(result.company, failedSource === 'company' ? null : company) assert.equal(result.orders.length, failedSource === 'orders' ? 0 : 1) assert.equal(result.drafts.length, failedSource === 'drafts' ? 0 : 1) }) } }) test('loads sources concurrently and distinguishes a failed source from an empty result', async () => { const pending = new Map() const operation = loadDashboardOverview([profile, list, edit], requests(Object.fromEntries( ['company', 'orders', 'drafts'].map((source) => [source, () => new Promise((resolve, reject) => pending.set(source, { resolve, reject }))]), ))) assert.deepEqual([...pending.keys()], ['company', 'orders', 'drafts']) pending.get('company').resolve(company) pending.get('orders').resolve({ records: [] }) pending.get('drafts').reject(null) const result = await operation assert.deepEqual(result.orders, []) assert.equal(result.errors.orders, undefined) assert.deepEqual(result.drafts, []) assert.equal(result.errors.drafts, '订单草稿加载失败,请重试') }) test('sorts each source by creation time and includes only actual drafts', async () => { const orders = [ order({ orderId: 1, createdAt: '2026-09-16T08:00:00Z' }), order({ orderId: 2, createdAt: '2026-09-18T08:00:00Z', mainStatus: 'COMPLETED', customerFeeConfirmationRequired: true }), ] const drafts = [ draft({ orderId: 3, createdAt: '2026-09-15T08:00:00Z' }), draft({ orderId: 4, status: 'SUBMITTED', createdAt: '2026-09-19T08:00:00Z' }), draft({ orderId: 5, createdAt: '2026-09-17T08:00:00Z' }), ] const result = await loadDashboardOverview([list, edit], requests({ orders: async () => ({ records: orders }), drafts: async () => ({ records: drafts }), })) assert.deepEqual(result.orders.map(({ id }) => id), ['2', '1']) assert.deepEqual(result.drafts.map(({ id }) => id), ['5', '3']) assert.equal(result.orders[0].status, 'COMPLETED') assert.equal(result.orders[0].requiresFeeConfirmation, true) assert.ok(result.drafts.every(({ status, requiresFeeConfirmation }) => status === 'DRAFT' && !requiresFeeConfirmation)) assert.deepEqual(orders.map(({ orderId }) => orderId), [1, 2]) assert.deepEqual(drafts.map(({ orderId }) => orderId), [3, 4, 5]) }) test('keeps absent business numbers null and internal identifiers out of display fields', async () => { const missing = { orderId: 987654, orderNo: null, inboundCode: null, destinationWarehouseName: null, channelName: null } const result = await loadDashboardOverview([list, edit], requests({ orders: async () => ({ records: [order(missing)] }), drafts: async () => ({ records: [draft(missing)] }), })) for (const item of [...result.orders, ...result.drafts]) { assert.equal(item.id, '987654') assert.equal(item.orderNo, null) assert.equal(item.inboundCode, null) assert.equal(item.destination, null) assert.equal(item.channel, null) } }) test('matches the updated six-action icon and motion treatment', () => { assert.match(dashboardView, /icon: Forklift/) assert.doesNotMatch(dashboardView, /PanelsTopLeft/) assert.match(dashboardView, /featured: true/) assert.match(dashboardView, /quick-action--featured/) assert.match(dashboardView, /featured-aura 5s ease-in-out infinite/) assert.match(dashboardView, /featured-shine 3\.6s ease-in-out infinite/) assert.match(dashboardView, /\.quick-action:hover \{[^}]*border-color:[^}]*transform: translateY\(-9px\);/) assert.match(dashboardView, /prefers-reduced-motion: reduce/) assert.match(dashboardView, /\.client-dashboard a:focus-visible/) })