library-picturebook-activity/frontend/e2e/utils/webhook-helper.ts

174 lines
4.0 KiB
TypeScript
Raw Normal View History

import crypto from 'crypto'
/**
* Webhook
* Playwright API Webhook
*/
/** 测试配置(与 application-dev.yml 对齐) */
export const LEAI_TEST_CONFIG = {
orgId: 'gdlib',
appSecret: 'leai_mnoi9q1a_mtcawrn8y',
apiUrl: 'http://192.168.1.72:8080',
h5Url: 'http://192.168.1.72:3001',
testPhone: '13800001111',
}
/** 后端 API 地址(前端 vite proxy 转发) */
export const API_BASE = process.env.API_BASE_URL || 'http://localhost:8580/api'
/** HMAC-SHA256 签名 */
function hmacSha256(data: string, secret: string): string {
return crypto.createHmac('sha256', secret).update(data).digest('hex')
}
/** 生成随机事件 ID */
export function randomEventId(): string {
return `evt_test_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`
}
/** 生成随机作品 ID */
export function randomWorkId(): string {
return `wk_test_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`
}
/**
* Webhook
* headers + body
*/
export function buildWebhookRequest(
payload: Record<string, unknown>,
options: {
eventId?: string
eventType?: string
timestamp?: string
appSecret?: string
validSignature?: boolean
} = {},
) {
const {
eventId = randomEventId(),
eventType = 'work.status_changed',
timestamp = Date.now().toString(),
appSecret = LEAI_TEST_CONFIG.appSecret,
validSignature = true,
} = options
const body = JSON.stringify(payload)
let signature: string
if (validSignature) {
const signData = `${eventId}.${timestamp}.${body}`
signature = `HMAC-SHA256=${hmacSha256(signData, appSecret)}`
} else {
signature = 'HMAC-SHA256=invalid_signature'
}
return {
url: `${API_BASE}/webhook/leai`,
headers: {
'X-Webhook-Id': eventId,
'X-Webhook-Event': eventType,
'X-Webhook-Timestamp': timestamp,
'X-Webhook-Signature': signature,
'Content-Type': 'application/json',
},
body,
eventId,
}
}
/**
* Webhook payload
*/
export function buildWebhookPayload(
remoteWorkId: string,
data: Record<string, unknown>,
event = 'work.status_changed',
) {
return {
event,
data: {
work_id: remoteWorkId,
...data,
},
}
}
/**
* payload
*/
export function buildStatusPayload(
remoteWorkId: string,
status: number,
extra: Record<string, unknown> = {},
) {
return buildWebhookPayload(remoteWorkId, { status, ...extra })
}
/**
* payload
*/
export function buildProgressPayload(
remoteWorkId: string,
progress: number,
progressMessage: string,
) {
return buildWebhookPayload(
remoteWorkId,
{ status: 2, progress, progressMessage },
'work.progress',
)
}
/**
* payload
*/
export function buildCompletedPayload(
remoteWorkId: string,
pageCount = 6,
) {
const pageList = Array.from({ length: pageCount }, (_, i) => ({
imageUrl: `https://cdn.example.com/pages/${remoteWorkId}/page_${i + 1}.png`,
text: `${i + 1}页的文字内容`,
}))
return buildStatusPayload(remoteWorkId, 3, {
title: `测试绘本_${remoteWorkId.slice(-6)}`,
phone: LEAI_TEST_CONFIG.testPhone,
style: 'cartoon',
pageList,
})
}
/**
* payload audioUrl
*/
export function buildDubbedPayload(
remoteWorkId: string,
pageCount = 6,
) {
const pageList = Array.from({ length: pageCount }, (_, i) => ({
imageUrl: `https://cdn.example.com/pages/${remoteWorkId}/page_${i + 1}.png`,
text: `${i + 1}页的文字内容`,
audioUrl: `https://cdn.example.com/audio/${remoteWorkId}/page_${i + 1}.mp3`,
}))
return buildStatusPayload(remoteWorkId, 5, {
title: `测试绘本_${remoteWorkId.slice(-6)}`,
author: '测试作者',
phone: LEAI_TEST_CONFIG.testPhone,
pageList,
})
}
/**
* payload
*/
export function buildFailedPayload(
remoteWorkId: string,
failReason = 'AI 处理超时',
) {
return buildStatusPayload(remoteWorkId, -1, { failReason })
}