- Public QR menu: BFF proxy endpoints (no auth), PosDataService public methods - Revenue analytics + staff performance: Dapper queries, validators, BFF proxy - Playwright E2E tests: 8 spec files covering auth, admin, 5 POS verticals, reports - Observability: Grafana dashboard (HTTP metrics, infra, business), Prometheus alert rules - Fixes: validator frozen-date bug (Must vs LessThanOrEqualTo), PublicMenuController logging + CancellationToken Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
79 lines
2.8 KiB
TypeScript
79 lines
2.8 KiB
TypeScript
import { type Page, expect } from '@playwright/test';
|
|
import { ADMIN_USER, MERCHANT_USER, ROUTES, BLAZOR_LOAD_TIMEOUT } from './test-data';
|
|
|
|
/**
|
|
* EN: Wait for Blazor WASM to finish loading (spinner disappears, interactive DOM ready).
|
|
* VI: Doi Blazor WASM tai xong (spinner bien mat, DOM tuong tac san sang).
|
|
*/
|
|
export async function waitForBlazor(page: Page): Promise<void> {
|
|
// Blazor WASM renders a loading placeholder; wait until the app root has content.
|
|
// MudBlazor injects a .mud- prefixed element once the framework boots.
|
|
await page.waitForLoadState('networkidle', { timeout: BLAZOR_LOAD_TIMEOUT });
|
|
|
|
// Wait for any MudBlazor rendered element, indicating the Blazor runtime is active.
|
|
await page.waitForSelector('.mud-layout, .mud-main-content, [class*="mud-"]', {
|
|
timeout: BLAZOR_LOAD_TIMEOUT,
|
|
state: 'attached',
|
|
});
|
|
}
|
|
|
|
/**
|
|
* EN: Log in as admin (owner/merchant) and wait for redirect to admin dashboard.
|
|
* VI: Dang nhap voi vai tro admin (owner/merchant) va doi redirect ve admin dashboard.
|
|
*/
|
|
export async function loginAsAdmin(
|
|
page: Page,
|
|
email = ADMIN_USER.email,
|
|
password = ADMIN_USER.password,
|
|
): Promise<void> {
|
|
await page.goto(ROUTES.LOGIN_ADMIN);
|
|
await waitForBlazor(page);
|
|
|
|
// Fill email
|
|
await page.locator('input[type="email"], input[autocomplete="email"]').first().fill(email);
|
|
// Fill password
|
|
await page.locator('input[type="password"]').first().fill(password);
|
|
// Submit
|
|
await page.locator('button[type="submit"]').first().click();
|
|
|
|
// Wait for navigation to admin area
|
|
await page.waitForURL('**/admin**', { timeout: 15_000 });
|
|
await waitForBlazor(page);
|
|
}
|
|
|
|
/**
|
|
* EN: Log in as merchant and wait for redirect to admin dashboard.
|
|
* VI: Dang nhap voi vai tro merchant va doi redirect ve admin dashboard.
|
|
*/
|
|
export async function loginAsMerchant(
|
|
page: Page,
|
|
email = MERCHANT_USER.email,
|
|
password = MERCHANT_USER.password,
|
|
): Promise<void> {
|
|
await loginAsAdmin(page, email, password);
|
|
}
|
|
|
|
/**
|
|
* EN: Verify the user is logged in by checking for user-profile or avatar elements.
|
|
* VI: Xac nhan nguoi dung da dang nhap bang cach kiem tra phan tu user-profile hoac avatar.
|
|
*/
|
|
export async function expectLoggedIn(page: Page): Promise<void> {
|
|
// The admin layout should render a sidebar or user menu once authenticated.
|
|
await expect(
|
|
page.locator('.mud-navmenu, .mud-drawer, [class*="sidebar"], [class*="user-menu"]').first(),
|
|
).toBeVisible({ timeout: 10_000 });
|
|
}
|
|
|
|
/**
|
|
* EN: Log out by navigating to profile and clicking logout, or clearing localStorage token.
|
|
* VI: Dang xuat bang cach vao profile va nhan logout, hoac xoa token trong localStorage.
|
|
*/
|
|
export async function logout(page: Page): Promise<void> {
|
|
// Clear the JWT token from localStorage (key: aPOS_token)
|
|
await page.evaluate(() => {
|
|
localStorage.removeItem('aPOS_token');
|
|
});
|
|
await page.goto(ROUTES.LOGIN);
|
|
await waitForBlazor(page);
|
|
}
|