72 lines
3.8 KiB
TypeScript
72 lines
3.8 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import { http } from '@/shared/api/http'
|
|
import { projectContainerSchedule } from './schedule'
|
|
import { getCalendarSources, getWarehouseArrivals } from './scheduleApi'
|
|
|
|
vi.mock('@/shared/api/http', async original => ({
|
|
...await original<typeof import('@/shared/api/http')>(),
|
|
http: { get: vi.fn(), post: vi.fn() },
|
|
}))
|
|
|
|
const range = { from: '2026-09-28', to: '2026-11-02' }
|
|
const bookingId = '9007199254740993'
|
|
// 使用真实接口的结构:Long 数量序列化为字符串,空时间字段不输出。
|
|
const wire = {
|
|
sourceContainerBookingId: bookingId, containerNo: 'CALENDAR-CONT',
|
|
warehouseName: '接仓仓库', warehouseCode: 'US-W', version: 0, planCount: '0', canEdit: true,
|
|
}
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
vi.mocked(http.get).mockResolvedValue({ code: '200', message: 'OK', data: {
|
|
containers: [{ containerBookingId: bookingId, cabinetNo: 'D-CALENDAR', containerNo: 'CALENDAR-CONT',
|
|
vesselName: null, voyageNo: null, destinationPortName: null, destinationWarehouseCode: null,
|
|
arrivalAt: '2026-10-20T23:00:00', arrivalType: 'ESTIMATED' }],
|
|
emptyReturns: [], emptyReturnsReadable: true,
|
|
} })
|
|
})
|
|
|
|
async function readSchedule(overrides: Record<string, unknown> = {}) {
|
|
vi.mocked(http.post).mockResolvedValue({ code: '200', message: 'OK', data: [{ ...wire, ...overrides }] })
|
|
const sources = await getCalendarSources(range)
|
|
const warehouses = await getWarehouseArrivals(range, [bookingId])
|
|
return { warehouses, event: projectContainerSchedule(sources, warehouses, range, true).find(row => row.type === 'warehouse') }
|
|
}
|
|
|
|
describe('warehouse calendar response to schedule', () => {
|
|
it.each(['0', 0])('uses zero plan count %j to show arrival plus two days without inventing a time', async planCount => {
|
|
const { warehouses, event } = await readSchedule({ planCount, plannedDate: '2026-10-22', isDefault: true })
|
|
expect(warehouses[0]).toMatchObject({ sourceContainerBookingId: bookingId, planCount: 0, plannedAt: null, actualAt: null })
|
|
expect(event).toMatchObject({ date: '2026-10-22', time: '', canEdit: true, subtitle: '到港日期+2个自然日(默认)' })
|
|
expect(event?.fields).toContainEqual({ label: '计划到仓', value: '2026-10-22' })
|
|
expect(event?.fields).toContainEqual({ label: '实际到仓', value: '—' })
|
|
})
|
|
|
|
it('keeps the authoritative frozen plan instead of recalculating from arrival', async () => {
|
|
const { warehouses, event } = await readSchedule({ planCount: '2', plannedAt: '2026-10-25T09:30:00', canEdit: false })
|
|
expect(warehouses[0]?.planCount).toBe(2)
|
|
expect(event).toMatchObject({ date: '2026-10-25', time: '09:30', canEdit: false, subtitle: '已有入库计划,日期已冻结' })
|
|
})
|
|
|
|
it('keeps a manually maintained time when there is no inbound plan', async () => {
|
|
const { event } = await readSchedule({ version: 1, plannedAt: '2026-10-24T08:00:00' })
|
|
expect(event).toMatchObject({ date: '2026-10-24', time: '08:00', subtitle: '人工维护' })
|
|
})
|
|
|
|
it('does not calculate a default when existing plans have no unified time', async () => {
|
|
const { event } = await readSchedule({ planCount: '2', canEdit: false })
|
|
expect(event?.date).toBeNull()
|
|
})
|
|
|
|
it('keeps conflicting authoritative versions unresolved even with zero plans', async () => {
|
|
const { event } = await readSchedule({ version: -1, canEdit: false })
|
|
expect(event).toMatchObject({ date: null, canEdit: false, subtitle: '柜内计划时间不一致,待核实' })
|
|
})
|
|
|
|
it.each([undefined, null, '', 'invalid', '-1', '1.5', '9007199254740992', -1, Infinity])(
|
|
'rejects invalid or unsafe plan count %j rather than treating it as no plans', async planCount => {
|
|
await expect(readSchedule({ planCount })).rejects.toThrow('入库计划数量无效')
|
|
},
|
|
)
|
|
})
|