import type { Page } from "@playwright/test"; import { apiEnvelope } from "../data/common"; import { chatSendResponse, createChatSendResponse, createPaidImageHistoryResponse, createWeeklyLimitChatSendResponse, emptyChatHistoryResponse, insufficientCreditsUnlockImageResponse, insufficientCreditsUnlockVoiceResponse, paidImageChatSendResponse, paidImageUnlockHistoryResponse, paidVoiceHistoryResponse } from "../data/chat"; export interface ChatMockOptions { chatLimitTriggerAt?: number; chatSendTokenRefreshFlow: boolean; paidImageFlow: boolean; paidImageInsufficientCreditsFlow: boolean; paidVoiceInsufficientCreditsFlow: boolean; } export interface ChatMockState { hasExpiredChatSend: boolean; paidImageRequested: boolean; paidImageUnlocked: boolean; } export async function registerChatMocks(page: Page, options: ChatMockOptions, state: ChatMockState) { let sendCount = 0; await page.route("**/api/chat/history**", async (route) => { const response = options.paidVoiceInsufficientCreditsFlow ? paidVoiceHistoryResponse : options.paidImageInsufficientCreditsFlow ? createPaidImageHistoryResponse(false) : options.paidImageFlow && state.paidImageRequested ? createPaidImageHistoryResponse(state.paidImageUnlocked) : emptyChatHistoryResponse; await route.fulfill({ json: apiEnvelope(response) }); }); await page.route("**/api/chat/send", async (route) => { sendCount += 1; const requestBody = route.request().postDataJSON() as { message?: unknown } | undefined; const message = typeof requestBody?.message === "string" ? requestBody.message : ""; if (options.chatSendTokenRefreshFlow && !state.hasExpiredChatSend) { state.hasExpiredChatSend = true; await route.fulfill({ status: 401, json: { message: "expired" } }); return; } const response = options.paidImageFlow && message.includes("给我发图片") ? paidImageChatSendResponse : options.chatLimitTriggerAt != null && sendCount >= options.chatLimitTriggerAt ? createWeeklyLimitChatSendResponse(sendCount, options.chatLimitTriggerAt) : options.chatLimitTriggerAt != null ? createChatSendResponse(sendCount) : chatSendResponse; if (options.paidImageFlow && message.includes("给我发图片")) { state.paidImageRequested = true; state.paidImageUnlocked = false; } await route.fulfill({ json: apiEnvelope(response) }); }); await page.route("**/api/chat/unlock-history", async (route) => { if (options.paidImageFlow && state.paidImageRequested) state.paidImageUnlocked = true; const response = options.paidImageFlow && state.paidImageRequested ? paidImageUnlockHistoryResponse : { unlocked: true, reason: "no_locked_messages", totalLocked: 0, unlockedCount: 0, privateCount: 0, imageCount: 0, voiceCount: 0, requiredCredits: 0, currentCredits: 0, remainingCredits: 0, shortfallCredits: 0, costsByMessage: {}, messageIds: [] }; await route.fulfill({ json: apiEnvelope(response) }); }); await page.route("**/api/chat/unlock-private", async (route) => { const response = options.paidVoiceInsufficientCreditsFlow ? insufficientCreditsUnlockVoiceResponse : options.paidImageInsufficientCreditsFlow || options.paidImageFlow && state.paidImageRequested && !state.paidImageUnlocked ? insufficientCreditsUnlockImageResponse : { unlocked: true, content: "Unlocked message", reason: "ok", creditBalance: 100, creditsCharged: 0, requiredCredits: 0, shortfallCredits: 0, lockDetail: { locked: false, showContent: true, showUpgrade: false, reason: null, hint: null, detail: null } }; await route.fulfill({ json: apiEnvelope(response) }); }); }