import { expect, test, type Page } from '@playwright/test'; type SigninCase = { path: '/ko/signin' | '/en/signin'; theme: 'light' | 'dark'; }; const signinCases: SigninCase[] = [ { path: '/ko/signin', theme: 'light' }, { path: '/ko/signin', theme: 'dark' }, { path: '/en/signin', theme: 'light' }, { path: '/en/signin', theme: 'dark' }, ]; async function mockPublicApis(page: Page): Promise { await page.route('**/api/v1/**', async (route) => { const requestUrl = new URL(route.request().url()); if (requestUrl.pathname.endsWith('/api/v1/user/me')) { await route.fulfill({ status: 401, contentType: 'application/json', body: JSON.stringify({ error: 'unauthorized' }), }); return; } if (requestUrl.pathname.endsWith('/api/v1/auth/tenant-info')) { await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({}), }); return; } await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ ok: true }), }); }); } async function expectFlutterCanvasRendered(page: Page): Promise { const canvas = page.locator('canvas').first(); await expect(canvas).toBeVisible({ timeout: 30_000 }); const box = await canvas.boundingBox(); expect(box?.width ?? 0).toBeGreaterThan(100); expect(box?.height ?? 0).toBeGreaterThan(100); } async function seedAuthTheme(page: Page, theme: SigninCase['theme']): Promise { await page.addInitScript((themeValue) => { window.localStorage.setItem('userfront_auth_theme', themeValue); window.localStorage.setItem('flutter.userfront_auth_theme', themeValue); }, theme); } test.describe('UserFront signin runtime matrix', () => { test.beforeEach(async ({ page }) => { await mockPublicApis(page); }); for (const entry of signinCases) { test(`${entry.path} renders in ${entry.theme} theme`, async ({ page }) => { await seedAuthTheme(page, entry.theme); await page.goto(entry.path); await expect(page).toHaveURL(new RegExp(`${entry.path}(?:\\?.*)?$`)); await expectFlutterCanvasRendered(page); }); } test('signin uses configured BACKEND_URL for public API requests', async ({ page, }) => { const expectedBackendOrigin = process.env.EXPECTED_BACKEND_ORIGIN; test.skip(!expectedBackendOrigin, 'set EXPECTED_BACKEND_ORIGIN'); const requestedApiOrigins = new Set(); page.on('request', (request) => { const requestUrl = new URL(request.url()); if (requestUrl.pathname.startsWith('/api/v1/')) { requestedApiOrigins.add(requestUrl.origin); } }); for (const entry of signinCases) { await seedAuthTheme(page, entry.theme); await page.goto(entry.path); await expectFlutterCanvasRendered(page); await expect .poll(() => [...requestedApiOrigins], { timeout: 30_000 }) .toContain(expectedBackendOrigin); expect(requestedApiOrigins).not.toContain('https://sso.example.test'); } }); });