import { expect, type APIRequestContext, type Page } from '@playwright/test'; import { Wait, waitForDashboardReady, waitForAppReady } from './wait'; export type InquiryListItem = { id: number; name: string; phone: string; message: string; }; export async function getAdminToken( request: APIRequestContext, baseUrl: string, username: string, password: string, ) { const response = await request.post(`${baseUrl}/api/auth/login`, { data: { username, password }, }); expect(response.status(), 'login API should accept the configured admin credentials').toBe(200); const body = await response.json(); expect(body?.token, 'login API should return a token').toBeTruthy(); return body.token as string; } export async function installAdminToken(page: Page, token: string) { await page.addInitScript(value => { localStorage.setItem('accessToken', value); localStorage.setItem('refreshToken', 'ci-test-refresh-token'); // Calculate C# Ticks for 1 hour from now: (JS_ms * 10000) + 621355968000000000 const expiryMs = Date.now() + 3600 * 1000; const ticks = (expiryMs * 10000) + 621355968000000000; localStorage.setItem('tokenExpiry', ticks.toString()); }, token); } export async function loginThroughAdminUi( page: Page, baseUrl: string, username: string, password: string, ) { const token = await getAdminToken(page.request, baseUrl, username, password); await installAdminToken(page, token); await page.goto(`${baseUrl}/admin/dashboard`); await waitForDashboardReady(page); } export async function navigateInBlazor(page: Page, targetUrl: string) { await page.goto(targetUrl, { waitUntil: 'domcontentloaded' }); await waitForAppReady(page).catch(() => {}); await page.waitForLoadState('networkidle').catch(() => {}); const spinner = page.locator('.mud-progress-circular, .mud-progress-linear-bar'); try { if (await spinner.count() > 0) { await spinner.first().waitFor({ state: 'hidden', timeout: Wait.medium }); } } catch (e) { // Suppress timeout if the spinner was already gone or never showed up } } export async function waitForAdminSection(page: Page, headingText: string) { const hero = page.locator('.admin-page-hero'); await expect(page.locator('body')).toContainText(headingText, { timeout: Wait.page }); await expect(hero).toBeVisible({ timeout: Wait.page }); await expect(hero).toContainText(headingText, { timeout: Wait.page }); await expect(page.getByRole('heading', { name: headingText, exact: true })).toBeVisible({ timeout: Wait.page }); } export async function findInquiryByName( request: APIRequestContext, baseUrl: string, token: string, name: string, ) { const response = await request.get(`${baseUrl}/api/inquiry?page=1&pageSize=100`, { headers: { Authorization: `Bearer ${token}` }, }); expect(response.status(), 'admin inquiry list API should be accessible with the token').toBe(200); const body = await response.json(); const items = (body?.data ?? []) as InquiryListItem[]; const inquiry = items.find(item => item.name === name); expect(inquiry, `created inquiry ${name} should appear in the admin inquiry API`).toBeTruthy(); return inquiry!; }