优化
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
import ElementPlus from 'element-plus'
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { enableAutoUnmount, flushPromises, mount } from '@vue/test-utils'
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { useAccessPreviewStore } from '@/core/access/accessPreview'
|
||||
import { useAuthStore } from '@/core/auth/auth'
|
||||
import { ApiResponseError } from '@/shared/api/http'
|
||||
import {
|
||||
adjustInboundFeeDetail, createInboundFeeDetail, deleteInboundFeeDetail,
|
||||
listInboundFeeDetails, listInboundFeeItemOptions, listInboundFeePartnerOptions,
|
||||
reviewInboundFeeDetail, updateInboundFeeDetail, voidInboundFeeDetail,
|
||||
} from '@/modules/unified-orders/api/inboundFeeDetails'
|
||||
import InboundFeeDetailManager from './InboundFeeDetailManager.vue'
|
||||
import type { InboundFeeDetail } from '@/modules/unified-orders/api/inboundFeeDetails'
|
||||
|
||||
vi.mock('@/modules/unified-orders/api/inboundFeeDetails', () => ({
|
||||
listInboundFeeDetails: vi.fn(), listInboundFeeItemOptions: vi.fn(), listInboundFeePartnerOptions: vi.fn(),
|
||||
createInboundFeeDetail: vi.fn(), updateInboundFeeDetail: vi.fn(), deleteInboundFeeDetail: vi.fn(),
|
||||
reviewInboundFeeDetail: vi.fn(), adjustInboundFeeDetail: vi.fn(), voidInboundFeeDetail: vi.fn(),
|
||||
}))
|
||||
|
||||
const pending: InboundFeeDetail = {
|
||||
id: '11', inboundId: '88', feeItemId: '31', sourceType: 'MANUAL', sourceFeeVersion: 1,
|
||||
inboundCode: 'RK-88', direction: 'RECEIVABLE', partnerId: null, partnerName: null,
|
||||
businessDate: '2026-08-12', customerName: '测试客户', feeTypeNameSnapshot: '操作费',
|
||||
unitPrice: 10, currency: 'CNY', amount: 100, remark: 'marker', reviewStatus: 'PENDING',
|
||||
reviewReason: null, reviewerName: null, reviewedAt: null, publicationStatus: 'DRAFT', settlementIncluded: true,
|
||||
}
|
||||
const approved: InboundFeeDetail = { ...pending, id: '12', sourceFeeVersion: 3, reviewStatus: 'APPROVED', publicationStatus: 'PUBLISHED' }
|
||||
|
||||
enableAutoUnmount(afterEach)
|
||||
|
||||
function mountManager(permissions: string[]) {
|
||||
const pinia = createPinia(); setActivePinia(pinia)
|
||||
const auth = useAuthStore(); auth.token = 'token'; auth.permissions = permissions
|
||||
useAccessPreviewStore().initializeAfterLogin()
|
||||
return mount(InboundFeeDetailManager, { attachTo: document.body, props: { accountId: '100', inboundId: '88' }, global: { plugins: [pinia, ElementPlus] } })
|
||||
}
|
||||
|
||||
describe('InboundFeeDetailManager', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks(); document.body.innerHTML = ''
|
||||
vi.mocked(listInboundFeeDetails).mockResolvedValue([pending, approved])
|
||||
vi.mocked(listInboundFeeItemOptions).mockResolvedValue([{ id: '31', feeTypeName: '操作费', warehouseReceivable: true, warehousePayable: true }])
|
||||
vi.mocked(listInboundFeePartnerOptions).mockResolvedValue([{ id: '41', partnerName: '测试往来单位' }])
|
||||
vi.mocked(createInboundFeeDetail).mockResolvedValue(pending)
|
||||
vi.mocked(updateInboundFeeDetail).mockResolvedValue(pending)
|
||||
vi.mocked(adjustInboundFeeDetail).mockResolvedValue({ ...approved, reviewStatus: 'PENDING' })
|
||||
vi.mocked(reviewInboundFeeDetail).mockResolvedValue(null)
|
||||
vi.mocked(deleteInboundFeeDetail).mockResolvedValue(null)
|
||||
vi.mocked(voidInboundFeeDetail).mockResolvedValue(null)
|
||||
})
|
||||
|
||||
it('renders actions from backend status and exact permissions', async () => {
|
||||
const wrapper = mountManager(['firstleg:inbound:fee-detail:view', 'firstleg:inbound:fee-detail:edit', 'firstleg:inbound:fee-detail:delete', 'firstleg:inbound:fee-detail:review'])
|
||||
await flushPromises()
|
||||
expect(listInboundFeeDetails).toHaveBeenCalledWith('100', '88')
|
||||
const first = wrapper.findAll('.el-table__row')[0]!.text()
|
||||
const second = wrapper.findAll('.el-table__row')[1]!.text()
|
||||
const secondButtons = wrapper.findAll('.el-table__row')[1]!.findAll('button').map((button) => button.text())
|
||||
expect(first).toContain('编辑'); expect(first).toContain('审核'); expect(first).toContain('驳回')
|
||||
expect(second).toContain('调整'); expect(second).toContain('作废'); expect(secondButtons).not.toContain('审核')
|
||||
expect(wrapper.find('th').text()).toContain('操作')
|
||||
})
|
||||
|
||||
it('does not request or expose fee rows without view permission', async () => {
|
||||
mountManager([]); await flushPromises()
|
||||
expect(listInboundFeeDetails).not.toHaveBeenCalled()
|
||||
expect(document.body.textContent).toContain('没有查看费用明细的权限')
|
||||
})
|
||||
|
||||
it('approves a pending fee then refreshes rows and emits changed', async () => {
|
||||
const wrapper = mountManager(['firstleg:inbound:fee-detail:view', 'firstleg:inbound:fee-detail:review'])
|
||||
await flushPromises()
|
||||
wrapper.findAll('button').find((button) => button.text().includes('审核'))?.trigger('click')
|
||||
await flushPromises()
|
||||
expect(reviewInboundFeeDetail).toHaveBeenCalledWith('100', '88', '11', 'approve')
|
||||
expect(listInboundFeeDetails).toHaveBeenCalledTimes(2)
|
||||
expect(wrapper.emitted('changed')).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('preserves request and trace IDs when a write fails', async () => {
|
||||
vi.mocked(reviewInboundFeeDetail).mockRejectedValue(new ApiResponseError('状态冲突', 'A0409', 409, null, 'request-fee', 'trace-fee'))
|
||||
const wrapper = mountManager(['firstleg:inbound:fee-detail:view', 'firstleg:inbound:fee-detail:review'])
|
||||
await flushPromises()
|
||||
wrapper.findAll('button').find((button) => button.text().includes('审核'))?.trigger('click')
|
||||
await flushPromises()
|
||||
expect(document.body.textContent).toContain('request-fee')
|
||||
expect(document.body.textContent).toContain('trace-fee')
|
||||
})
|
||||
|
||||
it('keeps currency fixed to CNY in the form and write payload', async () => {
|
||||
const wrapper = mountManager(['firstleg:inbound:fee-detail:view', 'firstleg:inbound:fee-detail:edit'])
|
||||
await flushPromises()
|
||||
await wrapper.findAll('button').find((button) => button.text().includes('新增费用'))?.trigger('click')
|
||||
await flushPromises()
|
||||
const currency = document.querySelector<HTMLInputElement>('input[aria-label="货币 CNY"]')
|
||||
expect(currency?.readOnly).toBe(true)
|
||||
expect(currency?.value).toBe('CNY')
|
||||
})
|
||||
|
||||
it('uses only the Element Plus table scroller without an outer horizontal scrollbar', async () => {
|
||||
const wrapper = mountManager(['firstleg:inbound:fee-detail:view'])
|
||||
await flushPromises()
|
||||
expect(wrapper.find('.fee-table-shell').exists()).toBe(true)
|
||||
expect(wrapper.find('.detail-table-wrap').exists()).toBe(false)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user