145 lines
6.3 KiB
JavaScript
145 lines
6.3 KiB
JavaScript
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/)
|
|
})
|