Files
admin 9deb320cf6 feat(profile)!: replace sidebar and add avatar navigation
Rename the global Sidebar route, UI, assets, analytics, and payment return context to Profile. Add accessible message-avatar navigation and preserve the source character across auth and logout flows.

BREAKING CHANGE: /sidebar has been removed; use /profile instead.
2026-07-21 18:08:12 +08:00

76 lines
3.3 KiB
TypeScript

import { expect, type Page } from "@playwright/test";
import { e2eEmailUser } from "../data/auth";
export const e2eEmailCredentials = {
email: "chanwillian0@gmail.com",
password: "12345678",
};
export const splashStartChatButtonName = "Start Chatting";
export const defaultCharacterSlug = "elio";
export const defaultCharacterSplashPath = `/characters/${defaultCharacterSlug}/splash`;
export const defaultCharacterChatPath = `/characters/${defaultCharacterSlug}/chat`;
export const defaultCharacterProfilePath = `/profile?returnTo=%2Fcharacters%2F${defaultCharacterSlug}%2Fchat`;
export const defaultCharacterChatUrl = new RegExp(
`/characters/${defaultCharacterSlug}/chat(?:\\?.*)?$`,
);
export function getSplashStartChatButton(page: Page) {
return page.getByRole("button", { name: splashStartChatButtonName });
}
export async function setEmailSessionStorage(page: Page) {
await page.evaluate((user) => {
localStorage.setItem("cozsweet:login_token", "e2e-email-token");
localStorage.setItem("cozsweet:refresh_token", "e2e-email-refresh-token");
localStorage.setItem("cozsweet:login_provider", "email");
localStorage.setItem("cozsweet:user_id", user.id);
localStorage.setItem("cozsweet:user", JSON.stringify(user));
}, e2eEmailUser);
}
export async function seedEmailSession(page: Page) {
await page.goto(defaultCharacterSplashPath);
await setEmailSessionStorage(page);
await page.reload();
// Let the root auth provider hydrate the seeded session before navigation.
await page.waitForTimeout(750);
}
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());
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;
}