diff --git a/playwright.samples.config.ts b/playwright.samples.config.ts index 0582a44..ad21143 100644 --- a/playwright.samples.config.ts +++ b/playwright.samples.config.ts @@ -1,6 +1,6 @@ import { defineConfig, devices } from "@playwright/test"; -const baseURL = process.env.GEO_SAMPLE_BASE_URL ?? "http://127.0.0.1:3000"; +const baseURL = process.env.GEO_SAMPLE_BASE_URL ?? "http://localhost:3000"; const timeout = Number(process.env.GEO_SAMPLE_TIMEOUT_MS ?? "600000") + 60_000; export default defineConfig({ diff --git a/scripts/run-geo-sample-e2e.mjs b/scripts/run-geo-sample-e2e.mjs index 27209e9..a36ae2b 100644 --- a/scripts/run-geo-sample-e2e.mjs +++ b/scripts/run-geo-sample-e2e.mjs @@ -46,7 +46,7 @@ export async function main(rawArgs = process.argv.slice(2)) { mkdirSync(reportDir, { recursive: true }); const port = args.port ? Number(args.port) : await findAvailablePort(3000); - const baseURL = args.baseURL || `http://127.0.0.1:${port}`; + const baseURL = args.baseURL || baseURLForPort(port); const appDataDir = join(reportDir, "app-data"); mkdirSync(appDataDir, { recursive: true }); @@ -70,7 +70,7 @@ export async function main(rawArgs = process.argv.slice(2)) { stdio: ["ignore", "pipe", "pipe"], }); captureServerLogs(serverProcess, reportDir, runEnv); - await waitForServer(baseURL, 120000); + await waitForServer(baseURL, 120000, serverProcess); } status = await runPlaywright(runEnv, Boolean(args.headed)); @@ -108,6 +108,10 @@ export function parseArgs(rawArgs) { return parsed; } +export function baseURLForPort(port) { + return `http://localhost:${port}`; +} + export function parseEnvFile(content) { const values = {}; for (const line of content.split(/\r?\n/)) { @@ -177,9 +181,14 @@ export function redact(text, secrets) { return next; } -async function waitForServer(baseURL, timeoutMs) { +export async function waitForServer(baseURL, timeoutMs, serverProcess = null) { const started = Date.now(); while (Date.now() - started < timeoutMs) { + if (serverProcess?.exitCode !== null) { + throw new Error( + `dev server exited before ${baseURL} became ready; see server.log in the report directory`, + ); + } try { const response = await fetch(baseURL, { method: "HEAD" }); if (response.ok) return; diff --git a/tests/sample-flow/runner.test.ts b/tests/sample-flow/runner.test.ts index 4947943..1b7a0a1 100644 --- a/tests/sample-flow/runner.test.ts +++ b/tests/sample-flow/runner.test.ts @@ -1,9 +1,11 @@ import { describe, expect, it } from "vitest"; import { + baseURLForPort, parseEnvFile, preflight, redact, + waitForServer, } from "../../scripts/run-geo-sample-e2e.mjs"; describe("run-geo-sample-e2e helpers", () => { @@ -34,6 +36,10 @@ EMPTY= ).toThrow("DEEPSEEK_API_KEY is required for live sample E2E"); }); + it("uses localhost for Next dev URLs", () => { + expect(baseURLForPort(3000)).toBe("http://localhost:3000"); + }); + it("redacts configured secrets from logs", () => { expect( redact("x-api-key: local-dev-key provider secret", [ @@ -42,4 +48,12 @@ EMPTY= ]), ).toBe("x-api-key: [REDACTED] [REDACTED]"); }); + + it("fails fast when the dev server process exits before readiness", async () => { + await expect( + waitForServer("http://127.0.0.1:9", 1000, { + exitCode: 1, + }), + ).rejects.toThrow("dev server exited before http://127.0.0.1:9 became ready"); + }); });