136 lines
4.4 KiB
TypeScript
136 lines
4.4 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
import { DebugEmlUploadError, uploadDebugEmlSuperAgentRun } from '@/services/debugEmlService'
|
|
import { setUnauthorizedHandler } from '@/services/httpClient'
|
|
|
|
const jsonHeaders = {
|
|
headers: {
|
|
get: (name: string) => (name.toLowerCase() === 'content-type' ? 'application/json' : null),
|
|
},
|
|
}
|
|
|
|
function mockJsonResponse(payload: unknown, status = 201): Response {
|
|
return {
|
|
ok: status >= 200 && status < 300,
|
|
status,
|
|
json: async () => payload,
|
|
text: async () => JSON.stringify(payload),
|
|
...jsonHeaders,
|
|
} as Response
|
|
}
|
|
|
|
describe('debugEmlService', () => {
|
|
beforeEach(() => {
|
|
vi.restoreAllMocks()
|
|
setUnauthorizedHandler(null)
|
|
})
|
|
|
|
it('uploads an eml file with FormData and debug key header', async () => {
|
|
const fetchMock = vi.spyOn(globalThis, 'fetch').mockResolvedValue(
|
|
mockJsonResponse({
|
|
debug_run_id: '90001',
|
|
source_message_id: '30001',
|
|
source_provider: 'DEBUG_EML_UPLOAD',
|
|
external_message_id: 'debug-eml-run-90001-abcdef123456',
|
|
external_conversation_id: 'debug-thread-90001',
|
|
original_eml_oss_url: 'https://oss.example/raw.eml',
|
|
original_eml_sha256: 'sha256',
|
|
uploaded_media: [],
|
|
html_body_with_oss_urls: '<strong>raw</strong>',
|
|
html_body_sanitized: '<strong>safe</strong>',
|
|
html_sanitize_required: true,
|
|
html_render_mode: 'SANITIZED_HTML',
|
|
agentbus_like_payload: { schema_version: 'debug-eml-upload-v1' },
|
|
superagent_session_id: 'session-1',
|
|
superagent_run_id: 'run-1',
|
|
superagent_raw_answer: '{"ok":true}',
|
|
superagent_parsed_json: { ok: true },
|
|
warnings: [],
|
|
status: 'SUPERAGENT_SUCCEEDED',
|
|
}),
|
|
)
|
|
const file = new File(['From: guest@example.test'], 'booking.eml', { type: 'message/rfc822' })
|
|
|
|
const result = await uploadDebugEmlSuperAgentRun({
|
|
hotelId: 'HOTEL-TEST',
|
|
debugUploadKey: ' manual-debug-key ',
|
|
runLabel: 'frontend-smoke',
|
|
file,
|
|
})
|
|
|
|
expect(fetchMock).toHaveBeenCalledTimes(1)
|
|
const [url, init] = fetchMock.mock.calls[0]!
|
|
expect(url).toBe('/api/system/debug/eml-superagent-runs')
|
|
expect(init).toMatchObject({
|
|
method: 'POST',
|
|
headers: {
|
|
Accept: 'application/json',
|
|
'X-TH-Hotel-Debug-Upload-Key': 'manual-debug-key',
|
|
},
|
|
})
|
|
expect(init?.headers).not.toHaveProperty('Content-Type')
|
|
expect(init?.body).toBeInstanceOf(FormData)
|
|
const formData = init?.body as FormData
|
|
expect(formData.get('hotel_id')).toBe('HOTEL-TEST')
|
|
expect(formData.get('run_label')).toBe('frontend-smoke')
|
|
expect(formData.get('file')).toBe(file)
|
|
expect(result.debug_run_id).toBe('90001')
|
|
})
|
|
|
|
it('throws a typed safe error for backend error_code responses', async () => {
|
|
const unauthorizedHandler = vi.fn()
|
|
setUnauthorizedHandler(unauthorizedHandler)
|
|
vi.spyOn(globalThis, 'fetch').mockResolvedValue(
|
|
mockJsonResponse(
|
|
{
|
|
error_code: 'DEBUG_UPLOAD_KEY_INVALID',
|
|
message: 'Debug 上传访问口令缺失或错误。',
|
|
},
|
|
401,
|
|
),
|
|
)
|
|
const file = new File(['From: guest@example.test'], 'booking.eml', { type: 'message/rfc822' })
|
|
|
|
await expect(
|
|
uploadDebugEmlSuperAgentRun({
|
|
hotelId: 'HOTEL-TEST',
|
|
debugUploadKey: 'wrong-key',
|
|
file,
|
|
}),
|
|
).rejects.toMatchObject({
|
|
status: 401,
|
|
errorCode: 'DEBUG_UPLOAD_KEY_INVALID',
|
|
message: 'Debug 上传访问口令缺失或错误。',
|
|
} satisfies Partial<DebugEmlUploadError>)
|
|
expect(unauthorizedHandler).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('runs the shared unauthorized handler for auth session errors', async () => {
|
|
const unauthorizedHandler = vi.fn()
|
|
setUnauthorizedHandler(unauthorizedHandler)
|
|
vi.spyOn(globalThis, 'fetch').mockResolvedValue(
|
|
mockJsonResponse(
|
|
{
|
|
error_code: 'AUTH_SESSION_INVALID',
|
|
message: '登录已失效。',
|
|
},
|
|
401,
|
|
),
|
|
)
|
|
const file = new File(['From: guest@example.test'], 'booking.eml', { type: 'message/rfc822' })
|
|
|
|
await expect(
|
|
uploadDebugEmlSuperAgentRun({
|
|
hotelId: 'HOTEL-TEST',
|
|
debugUploadKey: 'manual-debug-key',
|
|
file,
|
|
}),
|
|
).rejects.toMatchObject({
|
|
status: 401,
|
|
errorCode: 'AUTH_SESSION_INVALID',
|
|
} satisfies Partial<DebugEmlUploadError>)
|
|
|
|
expect(unauthorizedHandler).toHaveBeenCalledOnce()
|
|
})
|
|
})
|