import { expect, type BrowserContext, type Page } from "@playwright/test"; export const e2eEmailCredentials = { email: "chanwillian0@gmail.com", password: "12345678", }; export async function clearBrowserState( context: BrowserContext, page: Page, baseURL?: string, ) { await context.clearCookies(); const client = await context.newCDPSession(page); const origins = new Set([ new URL(baseURL ?? "http://127.0.0.1:3000").origin, "http://127.0.0.1:3000", "http://localhost:3000", ]); for (const origin of origins) { await client .send("Storage.clearDataForOrigin", { origin, storageTypes: "all", }) .catch(() => {}); } } export async function enterChatFromSplash( page: Page, options: { expectedUrl?: RegExp; timeout?: number; waitUntil?: "commit" | "domcontentloaded" | "load" | "networkidle"; } = {}, ) { const { expectedUrl = /\/chat$/, timeout = 10_000, waitUntil, } = options; await page.goto("/splash", { waitUntil }); const skipButton = page.getByRole("button", { name: "Skip" }); await expect(skipButton).toBeVisible({ timeout }); await expect(skipButton).toBeEnabled(); for (let attempt = 0; attempt < 3; attempt += 1) { await skipButton.click(); try { await expect(page).toHaveURL(expectedUrl, { timeout: 3_000 }); return; } catch { await page.waitForTimeout(500); } } await expect(page).toHaveURL(expectedUrl, { timeout }); } export async function dismissChatInterruptions(page: Page) { for (const buttonName of ["Later", "Cancel", "OK"]) { const button = page.getByRole("button", { name: buttonName }).first(); if (await button.isVisible().catch(() => false)) { await button.click(); } } } export async function switchToEmailSignIn(page: Page) { const otherOptionsButton = page.getByRole("button", { name: /Other Sign In Options/i, }); const otherOptionsDialog = page.getByRole("dialog", { name: /Other sign-in options/i, }); await expect(otherOptionsButton).toBeVisible({ timeout: 10_000 }); await expect(otherOptionsButton).toBeEnabled(); for (let attempt = 0; attempt < 3; attempt += 1) { await otherOptionsButton.click(); try { await expect(otherOptionsDialog).toBeVisible({ timeout: 2_000 }); break; } catch (error) { if (attempt === 2) throw error; await otherOptionsButton.evaluate((button) => (button as HTMLButtonElement).click(), ); if (await otherOptionsDialog.isVisible().catch(() => false)) { break; } await page.waitForTimeout(500); } } await page.getByRole("button", { name: "Email Sign In" }).click(); await expect(page.getByPlaceholder("Email")).toHaveValue( e2eEmailCredentials.email, ); await expect(page.getByPlaceholder("Password")).toHaveValue( e2eEmailCredentials.password, ); } export async function submitEmailLogin( page: Page, options: { expectedUrl?: RegExp; waitForRequest?: boolean; urlTimeout?: number; } = {}, ) { const { expectedUrl, waitForRequest = true, urlTimeout = 10_000, } = options; const loginButton = page.getByRole("button", { name: "Login" }); if (!waitForRequest) { await Promise.all([ expectedUrl ? page.waitForURL(expectedUrl, { timeout: urlTimeout }) : Promise.resolve(), loginButton.click(), ]); return null; } const loginRequestPromise = page.waitForRequest("**/api/auth/login"); await loginButton.click(); const loginRequest = await loginRequestPromise; expect(loginRequest.postDataJSON()).toMatchObject({ email: e2eEmailCredentials.email, password: e2eEmailCredentials.password, isTestAccount: true, }); if (expectedUrl) { await expect(page).toHaveURL(expectedUrl, { timeout: urlTimeout }); } return loginRequest; } export async function signInWithEmailAndOpenChat(page: Page) { await page.goto("/auth"); await switchToEmailSignIn(page); const historyResponsePromise = page .waitForResponse("**/api/chat/history**", { timeout: 10_000 }) .catch(() => null); await submitEmailLogin(page, { expectedUrl: /\/chat$/ }); await historyResponsePromise; await dismissChatInterruptions(page); } export async function completeVipPayment(page: Page) { const createOrderRequestPromise = page.waitForRequest( "**/api/payment/create-order", ); const orderStatusRequestPromise = page.waitForRequest( "**/api/payment/order-status**", ); await page.getByRole("button", { name: /Pay and Activ/i }).click(); const createOrderRequest = await createOrderRequestPromise; expect(createOrderRequest.postDataJSON()).toMatchObject({ planId: "vip_monthly", payChannel: "stripe", }); await orderStatusRequestPromise; const paymentSuccessDialog = page.getByRole("alertdialog", { name: "Payment successful", }); await expect(paymentSuccessDialog).toBeVisible(); await paymentSuccessDialog.getByRole("button", { name: "OK" }).click(); } export async function expectInsufficientCreditsDialog(page: Page) { const insufficientCreditsDialog = page.getByRole("dialog", { name: "Not enough credits", }); await expect(insufficientCreditsDialog).toBeVisible(); await expect(insufficientCreditsDialog.getByText("Balance")).toBeVisible(); await expect(insufficientCreditsDialog.getByText("Required")).toBeVisible(); await expect( insufficientCreditsDialog.getByText("Still needed"), ).toBeVisible(); return insufficientCreditsDialog; } export async function expectVipChatSubscriptionUrl(page: Page) { await expect(page).toHaveURL(/\/subscription\?/); const url = new URL(page.url()); expect(url.pathname).toBe("/subscription"); expect(url.searchParams.get("type")).toBe("vip"); expect(url.searchParams.get("returnTo")).toBe("chat"); } export function expectAuthRedirectToVipChatSubscription(page: Page) { const redirect = new URL(page.url()).searchParams.get("redirect"); expect(redirect).not.toBeNull(); const redirectUrl = new URL(redirect ?? "", "http://e2e.local"); expect(redirectUrl.pathname).toBe("/subscription"); expect(redirectUrl.searchParams.get("type")).toBe("vip"); expect(redirectUrl.searchParams.get("returnTo")).toBe("chat"); }