115 lines
6.8 KiB
TypeScript
115 lines
6.8 KiB
TypeScript
import { readFileSync } from 'node:fs'
|
|
import { resolve } from 'node:path'
|
|
import ElementPlus from 'element-plus'
|
|
import { enableAutoUnmount, flushPromises, mount } from '@vue/test-utils'
|
|
import { createMemoryHistory, createRouter } from 'vue-router'
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import { listPlatformTenants } from '@/modules/iam'
|
|
import { getReceivableStatistics } from '../api/finance'
|
|
import type { ReceivableStatisticsResult } from '../types'
|
|
import FinanceReceivableStatisticsView from './FinanceReceivableStatisticsView.vue'
|
|
|
|
const can = vi.hoisted(() => vi.fn((_permission: string) => true))
|
|
vi.mock('@/core/access/accessPreview', () => ({ useAccessPreviewStore: () => ({ can }) }))
|
|
vi.mock('@/modules/iam', () => ({ listPlatformTenants: vi.fn() }))
|
|
vi.mock('@/modules/downloads', () => ({ createPlatformExportTask: vi.fn() }))
|
|
vi.mock('@/shared/components/exportTaskCreatedDialog', () => ({ showExportTaskCreatedDialog: vi.fn() }))
|
|
vi.mock('../api/finance', () => ({ getReceivableStatistics: vi.fn() }))
|
|
|
|
const page = readFileSync(resolve(process.cwd(), 'src/modules/finance/pages/FinanceReceivableStatisticsView.vue'), 'utf8')
|
|
const statistics: ReceivableStatisticsResult = {
|
|
statisticsMonth: '2026-10', currency: 'CNY', totalReceivable: '2600', totalReceived: '2550', totalOutstanding: '50',
|
|
totalCustomers: 2, page: 1, pageSize: 20,
|
|
records: [
|
|
{ customerId: '10001', customerName: '客户A', currency: 'CNY', totalReceivable: '2400', totalReceived: '2400', totalOutstanding: '0' },
|
|
{ customerId: '10002', customerName: '客户 10002', currency: 'CNY', totalReceivable: '200', totalReceived: '150', totalOutstanding: '50' },
|
|
],
|
|
}
|
|
|
|
async function mountPage() {
|
|
const router = createRouter({ history: createMemoryHistory(), routes: [
|
|
{ path: '/finance/receivable-statistics', name: 'finance-receivable-statistics', component: FinanceReceivableStatisticsView },
|
|
{ path: '/other', name: 'other-page', component: { template: '<div>其他页面</div>' } },
|
|
] })
|
|
await router.push('/finance/receivable-statistics')
|
|
await router.isReady()
|
|
const wrapper = mount(FinanceReceivableStatisticsView, { attachTo: document.body, global: { plugins: [ElementPlus, router] } })
|
|
await flushPromises()
|
|
return { wrapper, router }
|
|
}
|
|
|
|
enableAutoUnmount(afterEach)
|
|
beforeEach(() => {
|
|
can.mockReturnValue(true)
|
|
vi.stubGlobal('ResizeObserver', class { observe() {} unobserve() {} disconnect() {} })
|
|
vi.mocked(listPlatformTenants).mockResolvedValue({ records: [{ id: '10002', tenantName: '客户B', status: 'ACTIVE' } as never], page: 1, size: 200, total: 1, pages: 1 })
|
|
vi.mocked(getReceivableStatistics).mockResolvedValue(statistics)
|
|
})
|
|
afterEach(() => { vi.restoreAllMocks(); vi.unstubAllGlobals(); document.body.innerHTML = '' })
|
|
|
|
describe('receivable statistics page', () => {
|
|
it('renders only the approved CNY derived metrics and current-filter actions', () => {
|
|
for (const label of ['统计月份', '应收单位', '应收总额', '已收合计', '余额未收', '打印', '导出Excel']) expect(page).toContain(label)
|
|
expect(page).toContain("exportType: 'FINANCE_RECEIVABLE_STATISTICS'")
|
|
expect(page).toContain('window.print()')
|
|
expect(page).toContain('aria-label="统计月份"')
|
|
expect(page).toContain('aria-label="应收单位"')
|
|
for (const removed of ['<span>统计月份</span>', '<span>应收单位</span>', '#before-results', '应收款明细', '仅统计CNY正式应收结算单']) expect(page).not.toContain(removed)
|
|
expect(page).toContain('displayCustomerName(row)')
|
|
expect(page).toContain('/^客户\\s*\\d+$/.test(snapshot)')
|
|
expect(page).toContain("return masterName || '—'")
|
|
for (const excluded of ['FBA直发', 'FBA专线', '零头减免', 'USD', '>编辑<']) expect(page).not.toContain(excluded)
|
|
})
|
|
|
|
it('keeps query reset, loading, empty, error and permission states explicit', () => {
|
|
expect(page).toContain('function reset()')
|
|
expect(page).toContain('无权访问应收款统计表')
|
|
expect(page).toContain('<LoadErrorState')
|
|
expect(page).toContain('当前月份暂无应收数据')
|
|
expect(page).toContain(':loading="loading"')
|
|
})
|
|
|
|
it('prints an isolated report with all five columns, the loaded month and server totals', async () => {
|
|
const print = vi.spyOn(window, 'print').mockImplementation(() => {})
|
|
const { wrapper } = await mountPage()
|
|
const report = document.body.querySelector(':scope > .receivable-statistics-print')!
|
|
expect(report).not.toBeNull()
|
|
expect(report.querySelector('h1')?.textContent).toBe('应收款统计表')
|
|
expect(report.textContent).toContain('统计月份:2026-10')
|
|
expect([...report.querySelectorAll('thead th')].map(cell => cell.textContent)).toEqual(['应收单位', '币种', '应收总额(CNY)', '已收合计(CNY)', '余额未收(CNY)'])
|
|
expect([...report.querySelectorAll('tbody tr')].map(row => [...row.querySelectorAll('td')].map(cell => cell.textContent))).toEqual([
|
|
['客户A', 'CNY', '2,400.00', '2,400.00', '0.00'],
|
|
['客户B', 'CNY', '200.00', '150.00', '50.00'],
|
|
])
|
|
expect([...report.querySelectorAll('tfoot td')].map(cell => cell.textContent)).toEqual(['2,600.00', '2,550.00', '50.00'])
|
|
expect(report.querySelector('button, input, .finance-metric-grid, .data-table__pagination')).toBeNull()
|
|
expect(page).toContain(':global(body:has(> .receivable-statistics-print) > :not(.receivable-statistics-print)) { display: none !important; }')
|
|
expect(page).toContain('width: 100%; border-collapse: collapse; table-layout: fixed;')
|
|
await wrapper.findAll('button').find(button => button.text() === '打印')!.trigger('click')
|
|
expect(print).toHaveBeenCalledOnce()
|
|
})
|
|
|
|
it('removes the print report when a cached statistics page is no longer the active route', async () => {
|
|
const { router } = await mountPage()
|
|
expect(document.querySelector('.receivable-statistics-print')).not.toBeNull()
|
|
await router.push('/other')
|
|
await flushPromises()
|
|
expect(document.querySelector('.receivable-statistics-print')).toBeNull()
|
|
await router.push('/finance/receivable-statistics')
|
|
await flushPromises()
|
|
expect(document.querySelector('.receivable-statistics-print')).not.toBeNull()
|
|
})
|
|
|
|
it.each(['loading', 'error', 'no-permission'])('does not print unavailable statistics: %s', async state => {
|
|
if (state === 'loading') vi.mocked(getReceivableStatistics).mockReturnValueOnce(new Promise(() => {}))
|
|
if (state === 'error') vi.mocked(getReceivableStatistics).mockRejectedValueOnce(new Error('不可用'))
|
|
if (state === 'no-permission') can.mockReturnValue(false)
|
|
const print = vi.spyOn(window, 'print').mockImplementation(() => {})
|
|
const { wrapper } = await mountPage()
|
|
const vm = wrapper.vm as unknown as { printCurrent(): void }
|
|
expect(document.querySelector('.receivable-statistics-print')).toBeNull()
|
|
vm.printCurrent()
|
|
expect(print).not.toHaveBeenCalled()
|
|
})
|
|
})
|