Files
computer-playbook/roles/web-app-dashboard/files/playwright/test-header-navbar-logos.js
kevinveenbirkenbachandClaude Opus 5 73e633a96d fix(dashboard/e2e): gate the logo spec on asset and wait for the decode
Without web-svc-asset the platform logo URL falls back to clearnet, which an
onion deploy's Tor-proxied browser cannot fetch — naturalWidth stayed 0 while
the URL assertion above it passed. The spec gated on cdn only, so it ran in a
scenario where it cannot hold. The added poll also separates 'never loaded'
from 'measured too early', since toBeVisible says nothing about the bytes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 13:04:56 +02:00

72 lines
3.2 KiB
JavaScript

const { test, expect } = require("./fixtures/onion-test");
const { resolveTimeout } = require("./timeouts");
const { decodeDotenvQuotedValue, gotoOnion } = require("./personas");
const platformLogoUrl = decodeDotenvQuotedValue(process.env.PLATFORM_LOGO_URL);
const platformFaviconUrl = decodeDotenvQuotedValue(process.env.PLATFORM_FAVICON_URL);
async function getCurrentImageSource(locator) {
return locator.evaluate((img) => img.currentSrc || img.src || "");
}
async function expectImageLoaded(locator, label, expectedUrl) {
await expect(locator).toBeVisible({ timeout: resolveTimeout(60_000) });
await expect
.poll(() => locator.evaluate((img) => img.complete && img.naturalWidth > 0), {
timeout: resolveTimeout(60_000),
message: `${label} never finished decoding`,
})
.toBe(true);
const loaded = await locator.evaluate((img) => ({
source: img.currentSrc || img.src || "",
naturalWidth: img.naturalWidth,
}));
// port-ui >= 2.0.0's probe-first resolver embeds reachable image URLs
// directly, so the rendered src is the asset URL Ansible computed and
// passed via PLATFORM_LOGO_URL — assert the exact value rather than a
// shape regex so a regression in the resolver is loud.
expect(loaded.source, `${label} should render the resolved platform logo URL`).toBe(expectedUrl);
expect(loaded.naturalWidth, `${label} should resolve to a non-empty dashboard image asset`).toBeGreaterThan(0);
}
exports.register = function (shared) {
test("dashboard loads role-core JavaScript modules and renders header/navbar logos", async ({ page }) => {
shared.skipUnlessServiceEnabled("cdn");
shared.skipUnlessServiceEnabled("asset");
const diagnostics = shared.attachDiagnostics(page);
const documentResponse = await gotoOnion(page,"/");
expect(documentResponse.status()).toBeLessThan(400);
const documentHtml = await documentResponse.text();
await shared.waitForDashboardReady(page);
await shared.waitForResourceResponse(diagnostics.responses, `${shared.env.dashboardJsBaseUrl}/iframe.js`, "dashboard iframe sync script");
expect(documentHtml).toContain("loadScriptSequential");
expect(documentHtml).toContain(shared.env.dashboardJsBaseUrl);
expect(documentHtml).toContain('"iframe.js"');
if (shared.isServiceEnabled("sso")) {
await shared.waitForResourceResponse(diagnostics.responses, `${shared.env.dashboardJsBaseUrl}/oidc.js`, "dashboard oidc script");
expect(documentHtml).toContain('"oidc.js"');
}
const headerLogo = page.locator("header.header img[alt='logo']").first();
const navbarLogo = page.locator("#navbar_logo img").first();
await expectImageLoaded(headerLogo, "Header logo", platformLogoUrl);
await expectImageLoaded(navbarLogo, "Navbar logo", platformLogoUrl);
expect(await getCurrentImageSource(headerLogo)).toBe(await getCurrentImageSource(navbarLogo));
// Favicon — a <link rel="icon"> is not "visible" in Playwright's sense,
// so just assert that its href is the resolved PLATFORM_FAVICON_URL.
const faviconHref = await page.locator('link[rel="icon"]').first().getAttribute("href");
expect(faviconHref, "favicon link should render the resolved platform favicon URL").toBe(
platformFaviconUrl
);
});
};