library-picturebook-activity/frontend/e2e/fixtures/leai.fixture.ts
En 922f650365 feat: 添加乐读派(leai)集成模块及E2E测试基础设施
后端:
- 新增 leai 模块:认证、Webhook、数据同步、定时对账
- 新增 LeaiConfig/RestTemplateConfig/SchedulingConfig 配置
- 新增 FlywayRepairConfig 处理迁移修复
- 新增 V5__leai_integration.sql 迁移脚本
- 扩展所有实体类添加 tenantId 等字段
- 更新 SecurityConfig 放行 leai 公开接口
- 添加 application-test.yml 测试环境配置

前端:
- 添加乐读派认证 API (public.ts)
- 优化 Generating.vue 生成页
- 添加 Playwright E2E 测试配置及依赖
- 添加测试 fixtures、utils、mock-h5.html
- 添加 leai 模块完整 E2E 测试套件

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 21:52:32 +08:00

99 lines
2.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<string, unknown>,
options?: {
eventType?: string
validSignature?: boolean
timestamp?: string
},
) => Promise<{ status: number; body: Record<string, unknown> }>
/** 乐读派 Token API需登录 */
leaiTokenApi: APIRequestContext
/** Webhook API无需登录 */
webhookApi: APIRequestContext
}
export const test = authTest.extend<LeaiFixtures>({
sendWebhook: async ({ request }, use) => {
const sendWebhook = async (
payload: Record<string, unknown>,
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,
}