102 lines
5.7 KiB
TypeScript
102 lines
5.7 KiB
TypeScript
import { readFileSync } from 'node:fs'
|
|
import { resolve } from 'node:path'
|
|
import { describe, expect, it } from 'vitest'
|
|
|
|
const source = readFileSync(resolve(process.cwd(), 'src/modules/finance/pages/FinanceManualPage.vue'), 'utf8')
|
|
|
|
describe('FinanceManualPage delivery contract', () => {
|
|
it('keeps every business table operation column first and fixed left', () => {
|
|
const declarations = [...source.matchAll(/return \[([^\n]+)\]/g)].map((match) => match[1] || '').filter((value) => value.includes("key: 'actions'"))
|
|
expect(declarations).toHaveLength(3)
|
|
for (const declaration of declarations) {
|
|
expect(declaration.trim().startsWith("{ key: 'actions'")).toBe(true)
|
|
expect(declaration).toContain("fixed: 'left'")
|
|
}
|
|
})
|
|
|
|
it('exposes supported bill operations with permission checks and traceable errors', () => {
|
|
expect(source).toContain("platform:finance:bill:update")
|
|
expect(source).toContain("platform:finance:bill:adjust")
|
|
expect(source).toContain("platform:finance:bill:void")
|
|
expect(source).toContain("openBill(row, 'detail')")
|
|
expect(source).toContain("openBill(row, 'edit')")
|
|
expect(source).toContain("openBill(row, 'adjust')")
|
|
expect(source).toContain('<ApiErrorMeta :details="actionError"')
|
|
expect(source).toContain('<ApiErrorMeta :details="drawerError"')
|
|
})
|
|
|
|
it('uses real voucher uploads and declares narrow-screen layouts', () => {
|
|
expect(source).toContain('uploadFinanceVoucher(form.customerId, file.value)')
|
|
expect(source).toContain('voucherFileIds = uploadedVoucher.value ? [uploadedVoucher.value.fileId] : []')
|
|
expect(source).toContain("form.costType === 'CONTAINER_SHARED' ? form.referenceNo : undefined")
|
|
expect(source).toContain('由后端从 Firstleg 获取真实柜内订单体积快照并完成分摊')
|
|
expect(source).not.toContain('containerOrders')
|
|
expect(source).not.toContain('体积(CBM)')
|
|
expect(source).toContain('type="file" accept="image/*" :disabled="saving"')
|
|
expect(source).toContain('@media (max-width: 720px)')
|
|
expect(source).toContain('@media (max-width: 480px)')
|
|
expect(source).toContain('grid-template-columns: 1fr')
|
|
})
|
|
|
|
it('loads and displays real revision history without fabricated data', () => {
|
|
expect(source).toContain('listFinanceBillRevisions(detail.id, detail.customerId)')
|
|
expect(source).toContain('v-for="revision in billRevisions"')
|
|
expect(source).toContain('<ApiErrorMeta :details="revisionError"')
|
|
expect(source).toContain('暂无历史修订记录')
|
|
expect(source).not.toContain('mockRevision')
|
|
})
|
|
|
|
it('renders list and detail statuses through the finance translation contract', () => {
|
|
expect(source).toContain('financeBillStatusOptions')
|
|
expect(source).toContain('financeStatusLabel(selectedBill.status)')
|
|
expect(source).toContain('financeStatusLabel(revision.status)')
|
|
expect(source).toContain('financeStatusLabel(selectedLedgerRow.status)')
|
|
expect(source).not.toContain('{{ selectedBill.status }}')
|
|
})
|
|
|
|
it('uses business selectors instead of asking operators for internal ids', () => {
|
|
expect(source).toContain("type: 'select', label: '客户名称'")
|
|
expect(source).toContain("placeholder: '全部客户'")
|
|
expect(source).toContain('clearable: true')
|
|
expect(source).toContain("const customerId = String(filters.value.customerId || '').trim() || undefined")
|
|
expect(source).not.toContain('if (!customerId) { allRows.value = []; total.value = 0; return }')
|
|
expect(source).toContain('placeholder="选择订单 / 入库单"')
|
|
expect(source).toContain('placeholder="选择费用来源"')
|
|
expect(source).toContain("listPlatformUnifiedOrderFeeDetails(form.customerId, inboundId)")
|
|
expect(source).toContain('placeholder="请选择未结清账单"')
|
|
expect(source).toContain('placeholder="请选择客户订单"')
|
|
expect(source).toContain('placeholder="请选择客户订单关联的柜次"')
|
|
expect(source).toContain('const records = await listFinanceStatements(customerId)')
|
|
expect(source).not.toContain('listFinanceBills')
|
|
expect(source).toContain('listContainers({ page: 1, size: 100 })')
|
|
expect(source).not.toContain('placeholder="请输入客户ID"')
|
|
expect(source).not.toContain('placeholder="费用来源ID"')
|
|
expect(source).not.toContain('placeholder="账单ID"')
|
|
expect(source).not.toContain("'请输入订单ID'")
|
|
expect(source).not.toContain("'请输入柜次ID'")
|
|
expect(source).not.toContain('label="客户ID"')
|
|
expect(source).toContain('customerNameById(selectedLedgerRow.customerId)')
|
|
expect(source).toContain('options: activeCustomers.value.map')
|
|
expect(source).toContain('v-for="customer in selectableFormCustomers"')
|
|
expect(source).not.toContain("disabled: customer.status !== 'ACTIVE'")
|
|
expect(source).not.toContain(':disabled="customer.status !== \'ACTIVE\'"')
|
|
})
|
|
|
|
it('keeps customer selection separate from business keyword matching', () => {
|
|
expect(source).toContain("placeholder: '单号/费用项目/供应商'")
|
|
expect(source).toContain('searchableRowValues(row)')
|
|
expect(source).not.toContain('Object.values(row).some')
|
|
})
|
|
|
|
it('exposes loading, empty and retry states for dependent business options', () => {
|
|
expect(source).toContain('该客户暂无未结清账单')
|
|
expect(source).toContain('该客户暂无可选订单')
|
|
expect(source).toContain('该客户订单暂无关联柜次')
|
|
expect(source).toContain('重新加载未结清账单')
|
|
expect(source).toContain('重新加载业务对象')
|
|
expect(source).toContain('重新加载客户订单')
|
|
expect(source).toContain('由账单分配金额自动汇总')
|
|
expect(source).toContain('账单分配金额不能超过该账单的未收金额')
|
|
})
|
|
})
|