diff --git a/.github/workflows/screenshots-capture.yml b/.github/workflows/screenshots-capture.yml index b31f4e72..59161d71 100644 --- a/.github/workflows/screenshots-capture.yml +++ b/.github/workflows/screenshots-capture.yml @@ -45,6 +45,8 @@ jobs: - name: Build the frontend run: bun run build + env: + VITE_FEATURE_FLAG_COLLECTOR_PAGE: "true" - name: Create screenshots directory run: mkdir -p screenshots diff --git a/ecosystem-explorer/scripts/take-screenshots.mjs b/ecosystem-explorer/scripts/take-screenshots.mjs index 75e6138b..b09dbc56 100644 --- a/ecosystem-explorer/scripts/take-screenshots.mjs +++ b/ecosystem-explorer/scripts/take-screenshots.mjs @@ -24,9 +24,23 @@ const SCREENSHOTS_DIR = path.resolve("screenshots"); const PORT = 4173; const BASE_URL = `http://localhost:${PORT}`; -// Pick an instrumentation known to have telemetry and configuration data -const DETAIL_VERSION = "2.25.0"; +// Resolve latest versions at runtime from the generated data files. +// This prevents the script from going stale when new versions are released. +function resolveLatestVersion(indexPath) { + const index = JSON.parse(fs.readFileSync(indexPath, "utf-8")); + const latest = index.versions.find((v) => v.is_latest); + if (!latest) throw new Error(`No latest version found in ${indexPath}`); + return latest.version; +} + +const DETAIL_VERSION = resolveLatestVersion( + path.resolve("public/data/javaagent/versions-index.json") +); const DETAIL_NAME = "spring-webmvc-6.0"; +const COLLECTOR_VERSION = resolveLatestVersion( + path.resolve("public/data/collector/versions-index.json") +); +const COLLECTOR_DETAIL_ID = "core-receiver-otlpreceiver"; // Viewport sizes captured for each page. Edit here to add, remove, or resize. const VIEWPORTS = [ @@ -104,6 +118,16 @@ async function clickTab(page, name) { } } +async function assertNoError(page, url) { + const errorHeading = page.getByRole("heading", { name: /error/i }); + const notFound = page.getByRole("heading", { name: /not found/i }); + const hasError = await errorHeading.isVisible().catch(() => false); + const has404 = await notFound.isVisible().catch(() => false); + if (hasError || has404) { + throw new Error(`Screenshot aborted: error page detected at ${url}`); + } +} + async function takeScreenshots() { const server = await startServer(); let browser; @@ -150,6 +174,7 @@ async function takeScreenshots() { // 1. Home page await page.goto(BASE_URL, { waitUntil: "domcontentloaded", timeout: 10000 }); await page.waitForSelector("h1", { state: "visible", timeout: 5000 }); + await assertNoError(page, BASE_URL); await page.screenshot({ path: p("home") }); // 2. Java agent instrumentation list @@ -158,20 +183,24 @@ async function takeScreenshots() { timeout: 10000, }); await settle(page); + await assertNoError(page, `${BASE_URL}/java-agent/instrumentation`); await page.screenshot({ path: p("instrumentation-list") }); // 3. Java agent instrumentation detail - Details tab const detailUrl = `${BASE_URL}/java-agent/instrumentation/${DETAIL_VERSION}/${DETAIL_NAME}`; await page.goto(detailUrl, { waitUntil: "domcontentloaded", timeout: 10000 }); await settle(page); + await assertNoError(page, detailUrl); await page.screenshot({ path: p("detail-details"), fullPage: true }); // 4. Telemetry tab (skipped gracefully if tabs aren't present in this branch) await clickTab(page, "Telemetry"); + await assertNoError(page, detailUrl); await page.screenshot({ path: p("detail-telemetry"), fullPage: true }); // 5. Configuration tab (skipped gracefully if tabs aren't present in this branch) await clickTab(page, "Configuration"); + await assertNoError(page, detailUrl); await page.screenshot({ path: p("detail-configuration"), fullPage: true }); // 6. Collector list @@ -180,14 +209,17 @@ async function takeScreenshots() { timeout: 10000, }); await settle(page); + await assertNoError(page, `${BASE_URL}/collector/components`); await page.screenshot({ path: p("collector-list") }); // 7. Collector detail - await page.goto(`${BASE_URL}/collector/components/latest/receiver-otlp`, { + const collectorDetailUrl = `${BASE_URL}/collector/components/${COLLECTOR_VERSION}/${COLLECTOR_DETAIL_ID}`; + await page.goto(collectorDetailUrl, { waitUntil: "domcontentloaded", timeout: 10000, }); await settle(page); + await assertNoError(page, collectorDetailUrl); await page.screenshot({ path: p("collector-detail"), fullPage: true }); logTime(`${viewport.name} done`);