This commit is contained in:
2026-10-08 17:08:03 +08:00
parent cc37a42298
commit 7b0df1db37
44 changed files with 574 additions and 405 deletions
@@ -0,0 +1,67 @@
import { effectScope } from 'vue'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { getConfirmedLoadingList, getPreloadPlan } from './api/platformLoadingLists'
import { useLoadingListDetail } from './useLoadingListDetail'
vi.mock('./api/platformLoadingLists', () => ({ getConfirmedLoadingList: vi.fn(), getPreloadPlan: vi.fn() }))
const scopes: ReturnType<typeof effectScope>[] = []
function createLoader() {
const scope = effectScope()
scopes.push(scope)
return scope.run(useLoadingListDetail)!
}
const result = (status = 'COMPLETED') => ({ summary: { planId: '1', status }, items: [], histories: [] })
beforeEach(() => vi.resetAllMocks())
afterEach(() => { scopes.splice(0).forEach(scope => scope.stop()) })
describe('shared loading list data', () => {
it('uses the same confirmed data once per plan and warehouse', async () => {
vi.mocked(getConfirmedLoadingList).mockResolvedValue(result() as never)
const state = createLoader()
await state.load('confirmed', '1', '11')
await state.load('confirmed', '1', '11')
expect(getConfirmedLoadingList).toHaveBeenCalledExactlyOnceWith('1', '11')
expect(state.detail.value).toEqual(result())
expect(state.loading.value).toBe(false)
})
it('switches APIs when a preload becomes confirmed and rejects an uncompleted manifest', async () => {
vi.mocked(getPreloadPlan).mockResolvedValue(result('LOADING') as never)
vi.mocked(getConfirmedLoadingList).mockResolvedValue(result('LOADING') as never)
const state = createLoader()
await state.load('preload', '1', '11')
expect(getPreloadPlan).toHaveBeenCalledExactlyOnceWith('1', '11')
await state.load('confirmed', '1', '11')
expect(state.detail.value).toBeNull()
expect(state.error.value?.code).toBe('MODE_STATUS_MISMATCH')
})
it('does not request detail without warehouse context', async () => {
const state = createLoader()
await state.load('confirmed', '1', '')
expect(state.error.value?.code).toBe('MISSING_WAREHOUSE_CONTEXT')
expect(getConfirmedLoadingList).not.toHaveBeenCalled()
})
it('supports retry after failure and reload after reset', async () => {
vi.mocked(getConfirmedLoadingList).mockRejectedValueOnce(new Error('failure')).mockResolvedValue(result() as never)
const state = createLoader()
await state.load('confirmed', '1', '11')
expect(state.error.value).not.toBeNull()
await state.load('confirmed', '1', '11')
expect(state.error.value).toBeNull()
expect(state.detail.value).toEqual(result())
state.reset()
await state.load('confirmed', '1', '11')
expect(getConfirmedLoadingList).toHaveBeenCalledTimes(3)
})
it('does not reuse an old plan when its request finishes after switching', async () => {
let resolveFirst!: (value: never) => void
vi.mocked(getConfirmedLoadingList).mockImplementationOnce(() => new Promise(resolve => { resolveFirst = resolve }))
.mockResolvedValueOnce({ ...result(), summary: { planId: '2', status: 'COMPLETED' } } as never)
const state = createLoader()
const first = state.load('confirmed', '1', '11')
await state.load('confirmed', '2', '22')
resolveFirst(result() as never)
await first
expect(state.detail.value?.summary.planId).toBe('2')
})
})