73 lines
6.3 KiB
TypeScript
73 lines
6.3 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import { http } from '@/shared/api/http'
|
|
import { createTruckAppointment, deleteTruckAppointmentAttachment, getTruckAppointment, listTruckAppointmentAttachments, listTruckAppointmentHistory, listTruckAppointments, performTruckAppointmentAction, referenceTruckAppointmentAttachment, rescheduleTruckAppointment, uploadTruckAppointmentAttachment } from './platformTrucking'
|
|
|
|
vi.mock('@/shared/api/http', () => ({ http: { get: vi.fn(), post: vi.fn(), put: vi.fn(), patch: vi.fn(), delete: vi.fn() }, unwrapApiResponse: (response: { data: unknown }) => response.data }))
|
|
|
|
describe('truck appointment API', () => {
|
|
beforeEach(() => { vi.clearAllMocks() })
|
|
|
|
it('normalizes page values and maps filters', async () => {
|
|
vi.mocked(http.get).mockResolvedValue({ data: { records: [{ id: 1, oceanBookingId: 2, containerBookingId: 3, warehouseId: 4, shippingCompanyId: 5, bookingAgentId: 6, oceanBookingNo: 'OB-1', cabinetNo: 'CAB-1', containerNo: 'MSCU-1', warehouseName: '义乌仓', shippingCompanyName: '船公司', bookingAgentName: '订舱代理', attachmentCount: '2' }], page: '2', size: '20', total: '21', pages: '2' } })
|
|
await expect(listTruckAppointments({ page: 2, size: 20, keyword: ' BY ', status: 'DISPATCHED', containerBookingId: '77' })).resolves.toMatchObject({ page: 2, total: 21, pages: 2, records: [{ id: '1', oceanBookingId: '2', containerBookingId: '3', warehouseId: '4', shippingCompanyId: '5', bookingAgentId: '6', oceanBookingNo: 'OB-1', cabinetNo: 'CAB-1', containerNo: 'MSCU-1', attachmentCount: 2 }] })
|
|
expect(http.get).toHaveBeenCalledWith('/platform/v1/truck-appointments', { params: { page: 2, size: 20, keyword: 'BY', status: 'DISPATCHED', containerBookingId: '77' } })
|
|
})
|
|
|
|
it('uses detail, create, and status contracts', async () => {
|
|
vi.mocked(http.get).mockResolvedValue({ data: { id: '9001', status: 'DRAFT' } })
|
|
vi.mocked(http.post).mockResolvedValue({ data: '9001' })
|
|
vi.mocked(http.post).mockResolvedValue({ data: { id: '9001', status: 'DISPATCHED' } })
|
|
await expect(getTruckAppointment('9001')).resolves.toMatchObject({ id: '9001' })
|
|
await expect(createTruckAppointment({ carrierId: '200', oceanBookingId: '300', containerBookingId: '400', loadingPlanId: null, plannedLoadingAt: '2026-08-10T10:00:00', expectedVersion: 0 })).resolves.toMatchObject({ id: '9001' })
|
|
expect(http.post).toHaveBeenNthCalledWith(1, '/platform/v1/truck-appointments', { carrierId: '200', oceanBookingId: '300', containerBookingId: '400', loadingPlanId: null, plannedLoadingAt: '2026-08-10T10:00:00', currency: 'RMB', expectedVersion: 0 })
|
|
await expect(performTruckAppointmentAction('9001', 'DISPATCH', 2)).resolves.toMatchObject({ status: 'DISPATCHED' })
|
|
expect(http.post).toHaveBeenCalledWith('/platform/v1/truck-appointments/9001/dispatch', { expectedVersion: 2, reason: null }, { headers: { 'Idempotency-Key': expect.stringContaining('truck-appointment-dispatch-9001-') } })
|
|
})
|
|
|
|
it('drops legacy customer fields instead of forwarding hidden compatibility data', async () => {
|
|
vi.mocked(http.post).mockResolvedValueOnce({ data: { id: '9001', status: 'DRAFT', attachmentCount: 0 } })
|
|
const payload = { carrierId: '200', oceanBookingId: '300', containerBookingId: '400', plannedLoadingAt: '2026-08-10T10:00:00', expectedVersion: 0, currency: 'EUR', receivableAmount: '999.00', customerId: 'legacy-customer', customerName: '旧客户快照' }
|
|
await createTruckAppointment(payload as never)
|
|
expect(http.post).toHaveBeenCalledWith('/platform/v1/truck-appointments', {
|
|
carrierId: '200', oceanBookingId: '300', containerBookingId: '400', plannedLoadingAt: '2026-08-10T10:00:00', currency: 'RMB', expectedVersion: 0,
|
|
})
|
|
})
|
|
|
|
it('sends the required idempotency header for rescheduling', async () => {
|
|
vi.mocked(http.post).mockResolvedValue({ data: { id: '9001', status: 'RESCHEDULED' } })
|
|
await expect(rescheduleTruckAppointment('9001', '2026-08-20T10:00:00', 2, '调整时间')).resolves.toMatchObject({ status: 'RESCHEDULED' })
|
|
expect(http.post).toHaveBeenCalledWith('/platform/v1/truck-appointments/9001/reschedule', { expectedVersion: 2, reason: '调整时间' }, {
|
|
params: { plannedLoadingAt: '2026-08-20T10:00:00' },
|
|
headers: { 'Idempotency-Key': expect.stringContaining('truck-appointment-reschedule-9001-') },
|
|
})
|
|
})
|
|
|
|
it('uses scoped attachment and immutable history contracts', async () => {
|
|
vi.mocked(http.get)
|
|
.mockResolvedValueOnce({ data: [{ id: 1, fileId: 9007199254740993, fileName: '派车单.pdf' }] })
|
|
.mockResolvedValueOnce({ data: [{ id: 2, action: 'DISPATCH', fromStatus: 'PENDING_DISPATCH', toStatus: 'DISPATCHED', operatorId: 3 }] })
|
|
vi.mocked(http.post).mockResolvedValue({ data: { id: '1', fileId: '9007199254740993', fileName: '派车单.pdf' } })
|
|
vi.mocked(http.delete).mockResolvedValue({ data: null })
|
|
|
|
await expect(listTruckAppointmentAttachments('77')).resolves.toMatchObject([{ id: '1', fileName: '派车单.pdf' }])
|
|
await expect(listTruckAppointmentHistory('77')).resolves.toMatchObject([{ id: '2', operatorId: '3', action: 'DISPATCH' }])
|
|
await referenceTruckAppointmentAttachment('77', { fileId: '9007199254740993', fileName: '派车单.pdf' })
|
|
await deleteTruckAppointmentAttachment('77', '1')
|
|
|
|
expect(http.get).toHaveBeenNthCalledWith(1, '/platform/v1/truck-appointments/77/attachments')
|
|
expect(http.get).toHaveBeenNthCalledWith(2, '/platform/v1/truck-appointments/77/history')
|
|
expect(http.post).toHaveBeenCalledWith('/platform/v1/truck-appointments/77/attachments', { fileId: '9007199254740993', fileName: '派车单.pdf' })
|
|
expect(http.delete).toHaveBeenCalledWith('/platform/v1/truck-appointments/77/attachments/1')
|
|
})
|
|
|
|
it('uploads an attachment through the frozen multipart endpoint', async () => {
|
|
vi.mocked(http.post).mockResolvedValue({ data: { id: '1', fileId: '2', fileName: '派车单.pdf' } })
|
|
const file = new File(['dispatch'], '派车单.pdf', { type: 'application/pdf' })
|
|
await uploadTruckAppointmentAttachment('77', file, 'DISPATCH_ORDER')
|
|
expect(http.post).toHaveBeenCalledWith('/platform/v1/truck-appointments/77/attachments/upload', expect.any(FormData), { headers: { 'Content-Type': 'multipart/form-data' } })
|
|
const form = vi.mocked(http.post).mock.calls[0]?.[1] as FormData
|
|
expect(form.get('file')).toBe(file)
|
|
expect(form.get('attachmentType')).toBe('DISPATCH_ORDER')
|
|
})
|
|
})
|