54 lines
4.6 KiB
TypeScript
54 lines
4.6 KiB
TypeScript
import { flushPromises, mount } from '@vue/test-utils'
|
|
import ElementPlus from 'element-plus'
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import AppointmentCancellationDialog from './AppointmentCancellationDialog.vue'
|
|
import AppointmentCancellationHistory from './AppointmentCancellationHistory.vue'
|
|
import AppointmentCancellationRecords from './AppointmentCancellationRecords.vue'
|
|
import { deleteAppointment, listAppointmentCancellations, listAppointmentCancellationRecords } from './api'
|
|
const access = vi.hoisted(() => ({ canCancel: true }))
|
|
vi.mock('@/core/access/accessPreview', () => ({useAccessPreviewStore: () => ({can: () => access.canCancel})}))
|
|
vi.mock('vue-router', () => ({onBeforeRouteLeave: vi.fn(), onBeforeRouteUpdate: vi.fn()}))
|
|
vi.mock('./api', () => ({deleteAppointment: vi.fn(),listAppointmentCancellations: vi.fn(),listAppointmentCancellationRecords: vi.fn()}))
|
|
const record = {appointmentNo:'AP-CANCEL',version:1,cancelReason:null,cancelledAt:'2026-10-11T01:00:00',snapshot:{fbaWarehouseCode:'ABE3',appointmentStatus:'CANCELLED',appointmentRemark:'原备注保留',plannedDate:null,plannedAt:null,plannedEndAt:null,confirmationNo:'EXT-1',appointmentAt:'2026-10-15T09:00:00',appointmentEndAt:null,timezone:'America/New_York',selectedCount:1}}
|
|
function dialog() {
|
|
return mount(AppointmentCancellationDialog,{props:{appointmentNo:'AP-CANCEL',version:0,selectedCount:1},global:{plugins:[ElementPlus],stubs:{AppDialog:{name:'AppDialog',props:['beforeClose','showConfirm'],template:'<section><slot/><button v-if="showConfirm" data-save @click="$emit(\'confirm\')">取消</button></section>'}}}})
|
|
}
|
|
describe('appointment cancellation',()=>{
|
|
beforeEach(()=>{vi.resetAllMocks();access.canCancel=true})
|
|
it('requires a reason and retries the same reason and version after an unknown result',async()=>{
|
|
vi.mocked(deleteAppointment).mockRejectedValueOnce(new Error('lost')).mockResolvedValueOnce(undefined)
|
|
const wrapper=dialog();await flushPromises()
|
|
await wrapper.get('[data-save]').trigger('click');expect(deleteAppointment).not.toHaveBeenCalled()
|
|
await wrapper.get('textarea').setValue(' 仓库取消时段 ')
|
|
await wrapper.get('[data-save]').trigger('click');await flushPromises()
|
|
expect(deleteAppointment).toHaveBeenCalledWith('AP-CANCEL',0,'仓库取消时段')
|
|
const done=vi.fn();wrapper.getComponent({name:'AppDialog'}).props('beforeClose')(done);expect(done).not.toHaveBeenCalled()
|
|
expect(wrapper.get('textarea').attributes('disabled')).toBeDefined()
|
|
await wrapper.get('[data-save]').trigger('click');await flushPromises()
|
|
expect(deleteAppointment).toHaveBeenNthCalledWith(2,'AP-CANCEL',0,'仓库取消时段')
|
|
expect(wrapper.emitted('cancelled')).toHaveLength(1);wrapper.unmount()
|
|
})
|
|
it('does not expose or invoke cancellation without its independent permission',async()=>{
|
|
access.canCancel=false;const wrapper=dialog();await flushPromises()
|
|
expect(wrapper.find('[data-save]').exists()).toBe(false)
|
|
wrapper.getComponent({name:'AppDialog'}).vm.$emit('confirm');await flushPromises()
|
|
expect(deleteAppointment).not.toHaveBeenCalled();wrapper.unmount()
|
|
})
|
|
it('reads history once per page and keeps missing historical reason explicit',async()=>{
|
|
vi.mocked(listAppointmentCancellations).mockResolvedValue({records:[record],total:11})
|
|
const wrapper=mount(AppointmentCancellationHistory,{props:{appointmentNo:'AP-CANCEL'},global:{plugins:[ElementPlus]}});await flushPromises()
|
|
expect(listAppointmentCancellations).toHaveBeenCalledExactlyOnceWith('AP-CANCEL',1,10)
|
|
expect(wrapper.text()).toContain('历史原因未记录');expect(wrapper.text()).toContain('原备注保留')
|
|
wrapper.getComponent({name:'DataTable'}).vm.$emit('update:page',2);await flushPromises()
|
|
expect(listAppointmentCancellations).toHaveBeenLastCalledWith('AP-CANCEL',2,10);wrapper.unmount()
|
|
})
|
|
it('discovers persisted cancellations with one server page and opens by business number',async()=>{
|
|
vi.mocked(listAppointmentCancellationRecords).mockResolvedValue({records:[{appointmentNo:'AP-CANCEL',version:1,cancelReason:'实际原因',cancelledAt:record.cancelledAt,fbaWarehouseCode:'ABE3',selectedCount:1}],total:1})
|
|
const wrapper=mount(AppointmentCancellationRecords,{global:{plugins:[ElementPlus]}});await flushPromises()
|
|
expect(listAppointmentCancellationRecords).toHaveBeenCalledExactlyOnceWith(1,10)
|
|
expect(listAppointmentCancellations).not.toHaveBeenCalled()
|
|
await wrapper.get('.el-table__body-wrapper .el-table__row').findAll('button').find(b=>b.text()==='查看')!.trigger('click')
|
|
expect(wrapper.emitted('view')).toEqual([['AP-CANCEL']]);wrapper.unmount()
|
|
})
|
|
})
|