import { test as authTest, expect, type APIRequestContext } from './auth.fixture' import { buildStatusPayload, buildProgressPayload, buildCompletedPayload, buildDubbedPayload, buildFailedPayload, randomWorkId, randomEventId, API_BASE, } from '../utils/webhook-helper' /** * 乐读派集成测试专用 Fixture * 封装 Webhook 发送、乐读派 Token API 调用等 */ type LeaiFixtures = { /** 发送 Webhook 请求到后端 */ sendWebhook: ( payload: Record, options?: { eventType?: string validSignature?: boolean timestamp?: string }, ) => Promise<{ status: number; body: Record }> /** 乐读派 Token API(需登录) */ leaiTokenApi: APIRequestContext /** Webhook API(无需登录) */ webhookApi: APIRequestContext } export const test = authTest.extend({ sendWebhook: async ({ request }, use) => { const sendWebhook = async ( payload: Record, options: { eventType?: string validSignature?: boolean timestamp?: string } = {}, ) => { const eventId = options.eventType === 'duplicate' ? 'evt_duplicate_test' : randomEventId() // 这里简化签名验证:直接构造请求 // 实际签名需要与 LeaiApiClient.verifyWebhookSignature 对齐 const crypto = await import('crypto') const body = JSON.stringify(payload) const timestamp = options.timestamp || Date.now().toString() const appSecret = 'leai_mnoi9q1a_mtcawrn8y' const signData = `${eventId}.${timestamp}.${body}` const signature = 'HMAC-SHA256=' + crypto.createHmac('sha256', appSecret).update(signData).digest('hex') const resp = await request.post(`${API_BASE}/webhook/leai`, { headers: { 'X-Webhook-Id': eventId, 'X-Webhook-Event': options.eventType || 'work.status_changed', 'X-Webhook-Timestamp': timestamp, 'X-Webhook-Signature': options.validSignature === false ? 'HMAC-SHA256=invalid_signature' : signature, 'Content-Type': 'application/json', }, data: payload, }) return { status: resp.status(), body: await resp.json().catch(() => ({})), } } await use(sendWebhook) }, leaiTokenApi: async ({ authedApi }, use) => { await use(authedApi) }, webhookApi: async ({ request }, use) => { await use(request) }, }) export { expect } export { buildStatusPayload, buildProgressPayload, buildCompletedPayload, buildDubbedPayload, buildFailedPayload, randomWorkId, randomEventId, }