import { test, expect } from '@playwright/test'; import path from 'path'; import fs from 'fs'; import { SITE_URLS } from '@d3ro/core/web-urls'; const SCREENSHOT_DIR = path.resolve('C:/Users/encep/.gemini/antigravity/brain/bbff18a3-721d-4c43-989f-1d6964e15be7/screenshots'); test.describe.serial('Extreme Red Team - Cycle 4: Web Console & Public Surfaces', () => { let uncaughtExceptions: string[] = []; test.beforeAll(() => { if (!fs.existsSync(SCREENSHOT_DIR)) { fs.mkdirSync(SCREENSHOT_DIR, { recursive: true }); } }); test.beforeEach(({ page }) => { uncaughtExceptions = []; page.on('pageerror', (err) => { console.error('[WEB PAGEERROR]:', err.message); uncaughtExceptions.push(err.message); }); }); test('RT-14: Web Public Hub - /login and the /download redirect to the landing site', async ({ page }) => { // 1. Test /login await page.goto('/app/login'); await page.waitForLoadState('domcontentloaded'); await expect(page.getByText(/D3RO[- ]VOICE/i)).toBeVisible({ timeout: 10000 }); await expect(page.getByRole('button', { name: /Google/i })).toBeVisible(); await expect(page.getByRole('button', { name: /GitHub/i })).toBeVisible(); // Screenshot login await page.screenshot({ path: path.join(SCREENSHOT_DIR, 'rt14_01_web_login.png'), }); // 2. /download lives only on the landing site; the web app just redirects there. const downloadRes = await page.request.get('/app/download', { maxRedirects: 0 }); expect([307, 308]).toContain(downloadRes.status()); expect(downloadRes.headers()['location']).toBe(SITE_URLS.download); expect(uncaughtExceptions).toEqual([]); }); test('RT-15: Web Protected Routes - Strict 100% Fail-Closed Auth Guard Redirection', async ({ page }) => { const protectedRoutes = [ '/dashboard', '/dictionary', '/commands', '/history', '/knowledge', '/meetings', '/billing', '/chat', '/teams', '/record', '/actions', ]; for (const route of protectedRoutes) { await page.goto(`/app${route}`); await page.waitForURL(/\/login/, { timeout: 10000 }); expect(page.url()).toContain('/login'); } expect(uncaughtExceptions).toEqual([]); }); });