fix(self-operated): render dashboard KPIs with omitted unknown values

This commit is contained in:
2026-10-14 11:22:59 +08:00
parent d8a4160bc7
commit 6a905419fc
3 changed files with 25 additions and 7 deletions
@@ -32,24 +32,41 @@ beforeEach(() => {
})
afterEach(() => { wrappers.splice(0).forEach(wrapper => wrapper.unmount()); vi.useRealTimers(); vi.restoreAllMocks() })
describe('warehouse operating dashboard', () => {
it.each(['PARTIAL', 'UNKNOWN'])('renders omitted nullable KPI fields for %s instead of rejecting the dashboard', async status => {
const response = structuredClone(dashboardFixture)
for (const metric of Object.values(response.kpis)) {
metric.value = null; metric.knownSubtotal = null; metric.unknownSkuCount = null
metric.outboundQuantity = null; metric.observedQuantity = null; metric.dataStatus = status
}
response.kpis.intervalOutboundQuantity.observedQuantity = '8'
response.kpis.physicalQuantity.knownSubtotal = '128'
// Match a server response serialized with NON_NULL, not an explicit-null fixture.
mocks.dashboard.mockResolvedValue(JSON.parse(JSON.stringify(response, (_, value) => value === null ? undefined : value)))
const wrapper = page(); await choose(wrapper, { warehouseCode: 'WH-A' })
expect(wrapper.text()).not.toContain('指标结构不完整')
expect(wrapper.findAll('.dashboard-kpis strong').map(node => node.text())).toEqual(['8', '—', '—', '—', '—', '—'])
expect(wrapper.text()).toContain('已知小计 128')
expect(wrapper.findAllComponents(DashboardBars)).toHaveLength(4)
})
it.each(['intervalOutboundQuantity', 'averageDailyOutboundQuantity', 'physicalQuantity', 'availableQuantity', 'physicalSkuCount', 'noOutboundSkuCount'] as const)('keeps the page usable when the response omits %s and recovers after refresh', async key => {
const invalid = structuredClone(dashboardFixture)
delete (invalid.kpis as Partial<typeof invalid.kpis>)[key]
mocks.dashboard.mockResolvedValue(invalid)
const wrapper = page(); await choose(wrapper, { warehouseCode: 'WH-A' })
expect(wrapper.text()).toContain('经营总览指标返回不完整')
expect(wrapper.text()).toContain('经营总览返回的指标结构不完整')
expect(wrapper.find('.dashboard-kpis').exists()).toBe(false)
expect(wrapper.findComponent(query).exists()).toBe(true)
mocks.dashboard.mockResolvedValue(dashboardFixture)
await findButton(wrapper, '整体刷新').trigger('click'); await flushPromises()
expect(wrapper.findAll('.dashboard-kpis section')).toHaveLength(6)
expect(wrapper.text()).not.toContain('经营总览指标返回不完整')
expect(wrapper.text()).not.toContain('经营总览返回的指标结构不完整')
})
it('preserves the last valid result when a refreshed response has a null KPI', async () => {
const wrapper = page(); await choose(wrapper, { warehouseCode: 'WH-A' })
mocks.dashboard.mockResolvedValue({ ...dashboardFixture, kpis: { ...dashboardFixture.kpis, averageDailyOutboundQuantity: null } })
await findButton(wrapper, '整体刷新').trigger('click'); await flushPromises()
expect(wrapper.text()).toContain('经营总览指标返回不完整,请更新服务后重新查询;展示上次查询')
expect(wrapper.text()).toContain('经营总览返回的指标结构不完整,请重试或联系管理员;展示上次查询')
expect(wrapper.findAll('.dashboard-kpis section')).toHaveLength(6)
})