fix: align audit and dispatch workflows and release failed requests

This commit is contained in:
2026-10-22 23:10:09 +08:00
parent 9cdcb9c077
commit 4a3456756f
124 changed files with 1296 additions and 2120 deletions
@@ -141,23 +141,24 @@ it('receives the native original carton whole into a verified target without inv
expect(getOverseasLocation).toHaveBeenCalledWith('92', '40')
wrapper.unmount()
})
it('retains the exact command after unknown failure even if the visible form is changed', async () => {
it('allows editing after unknown failure and submits a new command', async () => {
vi.mocked(commandException).mockRejectedValueOnce(new Error('network lost')).mockResolvedValueOnce({ exceptionNo: 'EX-1', version: 2, status: 'PROCESSING', restoredPackages: 2, replayed: true })
const wrapper = open(); await flushPromises(); await fill(wrapper)
await wrapper.get('[data-test="complete"]').trigger('click'); await flushPromises()
const payload = JSON.parse(JSON.stringify(vi.mocked(commandException).mock.calls[0]![3]))
expect(wrapper.text()).toContain('已保留原请求')
expect(wrapper.get('[data-test="notes"]').attributes('disabled')).toBeUndefined()
await wrapper.get('[data-test="notes"]').setValue('changed')
await wrapper.get('[data-test="complete"]').trigger('click'); await flushPromises()
expect(vi.mocked(commandException).mock.calls[1]![3]).toEqual(payload)
expect(vi.mocked(commandException).mock.calls[1]![3].idempotencyKey).not.toBe(payload.idempotencyKey); expect(vi.mocked(commandException).mock.calls[1]![3]).toEqual(expect.objectContaining({ handlingResult: 'changed' }))
wrapper.unmount()
})
it('refreshes a definite stale version and requires a reviewed new submission', async () => {
it('keeps a conflict visible and lets the operator refresh voluntarily', async () => {
vi.mocked(getExceptionDetail).mockResolvedValueOnce(snapshot()).mockResolvedValueOnce(snapshot('EX-1', 7, 2))
vi.mocked(commandException).mockRejectedValueOnce(new ApiResponseError('版本变化', 'A0409', 409))
const wrapper = open(); await flushPromises(); await fill(wrapper)
await wrapper.get('[data-test="complete"]').trigger('click'); await flushPromises()
expect(wrapper.text()).toContain('已重新读取当前版本'); expect(commandException).toHaveBeenCalledTimes(1)
expect(wrapper.text()).toContain('版本变化'); expect(commandException).toHaveBeenCalledTimes(1); expect(getExceptionDetail).toHaveBeenCalledTimes(1)
await wrapper.findAll('button').find(button => button.text() === '重新读取详情')!.trigger('click'); await flushPromises()
await fill(wrapper); await wrapper.get('[data-test="complete"]').trigger('click'); await flushPromises()
expect(vi.mocked(commandException).mock.calls[1]![3].expectedVersion).toBe(7)
expect(vi.mocked(commandException).mock.calls[1]![3].idempotencyKey).not.toBe(vi.mocked(commandException).mock.calls[0]![3].idempotencyKey)
@@ -246,7 +247,7 @@ it('allows cancellation and ordinary completion with standard audit text and sti
wrapper.unmount()
})
it('closing and reopening cannot replay an in-flight command or lose a later unknown batch', async () => {
it('closing and reopening blocks only the active request and failures release each subsequent command', async () => {
let rejectFirst!: (reason: Error) => void
vi.mocked(commandException).mockImplementationOnce(() => new Promise((_resolve, reject) => { rejectFirst = reject }))
const wrapper = open(); await flushPromises(); await fill(wrapper)
@@ -258,15 +259,15 @@ it('closing and reopening cannot replay an in-flight command or lose a later unk
rejectFirst(new Error('R1 outcome unknown')); await flushPromises()
vi.mocked(getExceptionDetail).mockResolvedValue(snapshot('EX-1', 2, 2))
vi.mocked(commandException).mockResolvedValueOnce({ exceptionNo: 'EX-1', version: 2, status: 'PROCESSING', restoredPackages: 2, replayed: true })
await wrapper.get('[data-test="complete"]').trigger('click'); await flushPromises()
expect(vi.mocked(commandException).mock.calls[1]![3].idempotencyKey).toBe(originalKey)
await fill(wrapper); await wrapper.get('[data-test="complete"]').trigger('click'); await flushPromises()
expect(vi.mocked(commandException).mock.calls[1]![3].idempotencyKey).not.toBe(originalKey)
await fill(wrapper)
vi.mocked(commandException).mockRejectedValueOnce(new Error('next batch unknown')).mockRejectedValueOnce(new Error('still unknown'))
await wrapper.get('[data-test="complete"]').trigger('click'); await flushPromises()
const newKey = vi.mocked(commandException).mock.calls[2]![3].idempotencyKey
expect(newKey).not.toBe(originalKey)
await wrapper.get('[data-test="complete"]').trigger('click'); await flushPromises()
expect(vi.mocked(commandException).mock.calls[3]![3].idempotencyKey).toBe(newKey)
expect(vi.mocked(commandException).mock.calls[3]![3].idempotencyKey).not.toBe(newKey)
wrapper.unmount()
})