import { test, expect } from '@playwright/test' // Smoke tests for AZ-456 e2e infrastructure (AC-1, AC-2, AC-5, AC-8). // Every other test file under e2e/tests/ is owned by AZ-457..AZ-482; those // tasks add the production-shaped assertions per group. This file MUST stay // minimal so any flake here is unambiguously an infrastructure regression. const EXTERNAL_HOSTS = [ /api\.openweathermap\.org/, /unpkg\.com/, /\.tile\.openstreetmap\.org$/, /^tile\.openstreetmap\.org$/, ] test.describe('AZ-456 e2e infrastructure', () => { test.beforeEach(async ({ context }, testInfo) => { // AC-8: external-host firewall. The compose network is already isolated // from the internet; this route guard catches code paths that try to // reach an external host directly (and lets resilience tests flip it). const externalHits: string[] = [] await context.route(/.*/, async (route) => { const url = route.request().url() if (EXTERNAL_HOSTS.some((re) => re.test(new URL(url).hostname))) { externalHits.push(url) await route.abort() return } await route.continue() }) testInfo.attachments.push({ name: 'externalHits', contentType: 'application/json', body: Buffer.from('[]') }) ;(testInfo as unknown as { __externalHits: string[] }).__externalHits = externalHits }) test.afterEach(async ({}, testInfo) => { const externalHits = (testInfo as unknown as { __externalHits?: string[] }).__externalHits ?? [] expect(externalHits, 'leaked external requests detected').toEqual([]) }) test('AC-1: SPA HTML is served from azaion-ui', async ({ page }) => { const response = await page.goto('/') expect(response?.ok()).toBeTruthy() const html = await page.content() expect(html).toMatch(/]/i) }) test('AC-2: owm-stub returns the canned wind shape', async ({ request }) => { const res = await request.get('http://owm-stub:8081/data/2.5/weather?lat=0&lon=0&appid=test') expect(res.status()).toBe(200) const body = await res.json() expect(body.wind).toEqual({ speed: 5.0, deg: 270 }) }) test('AC-2: tile-stub returns a 256x256 PNG', async ({ request }) => { const res = await request.get('http://tile-stub:8082/1/0/0.png') expect(res.status()).toBe(200) expect(res.headers()['content-type']).toBe('image/png') const body = await res.body() expect(body.subarray(0, 8)).toEqual(Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a])) }) test('AC-5: Playwright runs under the configured browser project', async ({ browserName }) => { expect(['chromium', 'firefox']).toContain(browserName) }) test('AC-8: external host is blocked by the route guard', async ({ page }) => { const externalHits = (test.info() as unknown as { __externalHits?: string[] }).__externalHits ?? [] const beforeCount = externalHits.length await page.goto('/') await page.evaluate(() => fetch('https://api.openweathermap.org/data/2.5/weather?appid=leak').catch(() => null), ) // The guard converts the request into an abort, so the leak is recorded // but no real request escapes. The afterEach assertion will fire next. expect(externalHits.length).toBeGreaterThan(beforeCount) // Reset so afterEach doesn't fail this specific test (the guard already // proved the assertion). externalHits.length = 0 }) })