接入前端P0页面真实接口
This commit is contained in:
1 parent
5c5b8e33b0
commit
66a613d6cd
45 files changed
+8719
No files matched your search
@@ -0,0 +1,183 @@
|
||||
import { flushPromises, mount, type VueWrapper } from '@vue/test-utils'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { createI18n } from 'vue-i18n'
|
||||
import { createMemoryHistory, createRouter } from 'vue-router'
|
||||
|
||||
import zhCN from '@/i18n/locales/zh-CN'
|
||||
import ReservationTaskDetailPanel from '@/components/reservation/ReservationTaskDetailPanel.vue'
|
||||
import type {
|
||||
ReservationTaskAuditLogResult,
|
||||
ReservationTaskDetailResult,
|
||||
ReservationTaskPayloadMutationResult,
|
||||
} from '@/types/reservation'
|
||||
|
||||
vi.mock('@/services/reservationService', async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import('@/services/reservationService')>()
|
||||
return {
|
||||
...actual,
|
||||
fetchReservationTaskDetail: vi.fn(),
|
||||
fetchReservationTaskAudits: vi.fn(),
|
||||
saveReservationTaskDraft: vi.fn(),
|
||||
confirmReservationTask: vi.fn(),
|
||||
}
|
||||
})
|
||||
|
||||
const service = await import('@/services/reservationService')
|
||||
|
||||
function createTaskDetail(): ReservationTaskDetailResult {
|
||||
return {
|
||||
task_id: '10001',
|
||||
order_id: '20001',
|
||||
source_message_id: '30001',
|
||||
source_subject: 'Booking Request',
|
||||
source_sender_summary: 'guest@example.test',
|
||||
source_received_at: '2026-07-08T03:00:00Z',
|
||||
external_conversation_id: 'thread-30001',
|
||||
conversation_message_count: 2,
|
||||
system_task_type: 'NEW_BOOKING',
|
||||
task_card_type: 'NEW_BOOKING',
|
||||
task_status: 'PENDING_CONFIRM',
|
||||
field_contract_version: '20260708-3.0',
|
||||
draft_payload: null,
|
||||
confirmed_payload: null,
|
||||
availability: {
|
||||
blocked: false,
|
||||
read_only: false,
|
||||
editable: true,
|
||||
confirmable: true,
|
||||
executable: false,
|
||||
blocked_by_task_id: null,
|
||||
blocked_reason: null,
|
||||
},
|
||||
fields: [],
|
||||
opera_operations: [],
|
||||
}
|
||||
}
|
||||
|
||||
function createMutationResult(taskStatus = 'PENDING_CONFIRM'): ReservationTaskPayloadMutationResult {
|
||||
return {
|
||||
task_id: '10001',
|
||||
order_id: '20001',
|
||||
task_status: taskStatus,
|
||||
draft_payload: {},
|
||||
confirmed_payload: taskStatus === 'READY' ? {} : null,
|
||||
opera_operations: [],
|
||||
}
|
||||
}
|
||||
|
||||
function createAudit(auditId: string, action: string): ReservationTaskAuditLogResult {
|
||||
return {
|
||||
audit_id: auditId,
|
||||
order_id: '20001',
|
||||
task_id: '10001',
|
||||
operation_id: null,
|
||||
actor_type: 'USER',
|
||||
actor_id: 'andy',
|
||||
action,
|
||||
reason: null,
|
||||
before_snapshot: null,
|
||||
after_snapshot: null,
|
||||
occurred_at: '2026-07-08T03:00:00Z',
|
||||
}
|
||||
}
|
||||
|
||||
async function mountPanel() {
|
||||
const i18n = createI18n({
|
||||
legacy: false,
|
||||
locale: 'zh-CN',
|
||||
messages: {
|
||||
'zh-CN': zhCN,
|
||||
},
|
||||
})
|
||||
const router = createRouter({
|
||||
history: createMemoryHistory(),
|
||||
routes: [
|
||||
{ path: '/reservation/tasks/:taskId', component: { template: '<div />' } },
|
||||
{ path: '/reservation/orders/:orderId', component: { template: '<div />' } },
|
||||
{ path: '/reservation/source-messages/:sourceMessageId/conversation', component: { template: '<div />' } },
|
||||
],
|
||||
})
|
||||
await router.push('/reservation/tasks/10001')
|
||||
await router.isReady()
|
||||
|
||||
const wrapper = mount(ReservationTaskDetailPanel, {
|
||||
props: {
|
||||
taskId: '10001',
|
||||
},
|
||||
global: {
|
||||
plugins: [i18n, router],
|
||||
stubs: {
|
||||
RouterLink: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
await flushPromises()
|
||||
return wrapper
|
||||
}
|
||||
|
||||
function findButton(wrapper: VueWrapper, label: string) {
|
||||
const button = wrapper.findAll('button').find((item) => item.text().includes(label))
|
||||
if (!button) {
|
||||
throw new Error(`Button ${label} was not found.`)
|
||||
}
|
||||
return button
|
||||
}
|
||||
|
||||
describe('ReservationTaskDetailPanel', () => {
|
||||
beforeEach(() => {
|
||||
vi.mocked(service.fetchReservationTaskDetail).mockReset()
|
||||
vi.mocked(service.fetchReservationTaskAudits).mockReset()
|
||||
vi.mocked(service.saveReservationTaskDraft).mockReset()
|
||||
vi.mocked(service.confirmReservationTask).mockReset()
|
||||
vi.mocked(service.fetchReservationTaskDetail).mockResolvedValue(createTaskDetail())
|
||||
vi.mocked(service.fetchReservationTaskAudits).mockResolvedValue({
|
||||
task_id: '10001',
|
||||
items: [],
|
||||
})
|
||||
})
|
||||
|
||||
it('shows draft save errors instead of leaving an unhandled rejection', async () => {
|
||||
vi.mocked(service.saveReservationTaskDraft).mockRejectedValue(new Error('Draft save failed'))
|
||||
|
||||
const wrapper = await mountPanel()
|
||||
await findButton(wrapper, '保存草稿').trigger('click')
|
||||
await flushPromises()
|
||||
|
||||
expect(wrapper.text()).toContain('Draft save failed')
|
||||
expect(findButton(wrapper, '保存草稿').attributes('disabled')).toBeUndefined()
|
||||
})
|
||||
|
||||
it('shows confirm errors instead of leaving an unhandled rejection', async () => {
|
||||
vi.mocked(service.confirmReservationTask).mockRejectedValue(new Error('Confirm failed'))
|
||||
|
||||
const wrapper = await mountPanel()
|
||||
await findButton(wrapper, '确认').trigger('click')
|
||||
await flushPromises()
|
||||
|
||||
expect(wrapper.text()).toContain('Confirm failed')
|
||||
expect(findButton(wrapper, '确认').attributes('disabled')).toBeUndefined()
|
||||
})
|
||||
|
||||
it('refreshes audit records after saving a draft', async () => {
|
||||
vi.mocked(service.fetchReservationTaskAudits)
|
||||
.mockResolvedValueOnce({
|
||||
task_id: '10001',
|
||||
items: [createAudit('audit-1', 'TASK_LOADED')],
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
task_id: '10001',
|
||||
items: [createAudit('audit-2', 'DRAFT_SAVED')],
|
||||
})
|
||||
vi.mocked(service.saveReservationTaskDraft).mockResolvedValue(createMutationResult())
|
||||
|
||||
const wrapper = await mountPanel()
|
||||
expect(wrapper.text()).toContain('TASK_LOADED')
|
||||
|
||||
await findButton(wrapper, '保存草稿').trigger('click')
|
||||
await flushPromises()
|
||||
|
||||
expect(service.fetchReservationTaskAudits).toHaveBeenCalledTimes(2)
|
||||
expect(wrapper.text()).toContain('DRAFT_SAVED')
|
||||
expect(wrapper.text()).not.toContain('TASK_LOADED')
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user