fix(appointments): ignore stale impact history responses

This commit is contained in:
2026-10-11 21:09:30 +08:00
parent 43611ecc55
commit 20b4d1425b
2 changed files with 53 additions and 6 deletions
@@ -11,6 +11,51 @@ const detail: ImpactDetail = { impact: { containerBookingId: '1', impactNo: 'AI-
const render = (canWrite = true) => mount(AppointmentImpactDialog, { props: { containerId: '1', canWrite }, global: { provide: { 'appointment-register-leave-guard': guards.register }, plugins: [ElementPlus], stubs: { AppDialog: { name: 'AppDialog', props: ['beforeClose'], template: '<section><slot /><button data-close @click="$emit(\'update:model-value\',false)">关闭</button></section>' } } } })
describe('appointment impact handling', () => {
beforeEach(() => { vi.resetAllMocks(); guards.register.mockReturnValue(guards.unregister); vi.mocked(getImpact).mockResolvedValue(detail) })
function deferred() {
let resolve!: (value: ImpactDetail) => void, reject!: (reason: Error) => void
const promise=new Promise<ImpactDetail>((yes,no)=>{resolve=yes;reject=no})
return {promise,resolve,reject}
}
const pageDetail=(label:string):ImpactDetail=>({...detail,history:{total:60,records:[{version:1,action:'RECORD',operatorName:null,result:label,nextAction:null,followupDate:null,createdAt:'2026-10-11T00:00:00'}]}})
it('keeps the latest history page when responses finish in reverse order',async()=>{
vi.mocked(getImpact).mockResolvedValueOnce(pageDetail('第一页'))
const wrapper=render();await flushPromises()
const second=deferred(),third=deferred()
vi.mocked(getImpact).mockReturnValueOnce(second.promise).mockReturnValueOnce(third.promise)
const pager=wrapper.findComponent({name:'ElPagination'})
pager.vm.$emit('update:current-page',2);pager.vm.$emit('current-change',2)
pager.vm.$emit('update:current-page',3);pager.vm.$emit('current-change',3)
await flushPromises()
third.resolve(pageDetail('第三页最新'));await flushPromises()
second.resolve(pageDetail('第二页过期'));await flushPromises()
expect(wrapper.text()).toContain('第三页最新');expect(wrapper.text()).not.toContain('第二页过期')
wrapper.unmount()
})
it('ignores an obsolete failure and keeps loading until the current request finishes',async()=>{
vi.mocked(getImpact).mockResolvedValueOnce(pageDetail('第一页'))
const wrapper=render();await flushPromises()
const second=deferred(),third=deferred()
vi.mocked(getImpact).mockReturnValueOnce(second.promise).mockReturnValueOnce(third.promise)
const pager=wrapper.findComponent({name:'ElPagination'})
pager.vm.$emit('update:current-page',2);pager.vm.$emit('current-change',2)
pager.vm.$emit('update:current-page',3);pager.vm.$emit('current-change',3)
second.reject(new Error('obsolete page failure'));await flushPromises()
expect(wrapper.text()).not.toContain('obsolete page failure')
expect(pager.props('disabled')).toBe(true)
expect(wrapper.findAll('button').find(b=>b.text()==='认领跟进')!.attributes('disabled')).toBeDefined()
wrapper.findAllComponents({name:'ElButton'}).find(b=>b.text()==='认领跟进')!.vm.$emit('click')
await flushPromises();expect(handleImpact).not.toHaveBeenCalled()
third.resolve(pageDetail('第三页最新'));await flushPromises()
expect(pager.props('disabled')).toBe(false);wrapper.unmount()
})
it('does not let a closed dialog response replace a newly opened impact',async()=>{
const old=deferred();vi.mocked(getImpact).mockReturnValueOnce(old.promise)
const first=render();await flushPromises();first.unmount()
vi.mocked(getImpact).mockResolvedValueOnce({...pageDetail('新影响历史'),impact:{...detail.impact,impactNo:'AI-NEW'}})
const next=render();await flushPromises()
old.resolve(pageDetail('已关闭历史'));await flushPromises()
expect(next.text()).toContain('AI-NEW');expect(next.text()).not.toContain('已关闭历史');next.unmount()
})
it('shows separate forecasts, unchanged confirmed appointment and omitted transport permission', async () => {
const wrapper = render(false); await flushPromises()
expect(wrapper.text()).toContain('2026-10-15T09:00:00')