Harden demo public browser smoke readiness

This commit is contained in:
rcourtman 2026-04-12 17:07:50 +01:00
parent 12294b587e
commit 18f4580e03
4 changed files with 41 additions and 5 deletions

View file

@ -226,7 +226,10 @@ sufficient; after those checks pass, the governed helpers
`scripts/run_demo_public_browser_smoke.sh` and
`scripts/demo_public_browser_smoke.cjs` must exercise the public demo in a real
Chromium session and prove the login shell actually renders instead of failing
open on API-only reachability.
open on API-only reachability. That proof must treat the visible login controls
as the readiness signal and must not block on Playwright `networkidle`, because
the public demo shell can keep background activity alive after the page is
already usable.
Those same governed release workflows also own the operator-facing wording for
that promotion metadata. Human-visible workflow inputs, summaries, and error
messages must describe the path as a prerelease or preview flow rather than

View file

@ -21,15 +21,18 @@ async function main() {
try {
const page = await browser.newPage({ viewport: { width: 1280, height: 900 } });
const response = await page.goto(siteUrl, {
waitUntil: 'networkidle',
// Public demo shells can keep background activity alive long after the
// page is usable, so wait for the first document and then assert the
// actual login UI instead of blocking on network quiescence.
waitUntil: 'domcontentloaded',
timeout: 120000,
});
assert(response, `No response received for ${siteUrl}`);
assert(response.ok(), `Unexpected status ${response.status()} loading ${siteUrl}`);
await page.getByLabel('Username').waitFor();
await page.getByLabel('Password').waitFor();
await page.getByRole('button', { name: 'Sign in to Pulse' }).waitFor();
await page.getByLabel('Username').waitFor({ state: 'visible', timeout: 120000 });
await page.getByLabel('Password').waitFor({ state: 'visible', timeout: 120000 });
await page.getByRole('button', { name: 'Sign in to Pulse' }).waitFor({ state: 'visible', timeout: 120000 });
const title = normalizeText(await page.title());
assert(title === 'Pulse', `Unexpected page title: ${title}`);

View file

@ -171,6 +171,30 @@ func TestUpdateDemoWorkflowUsesGovernedNetworkPath(t *testing.T) {
}
}
func TestDemoPublicBrowserSmokeWaitsForVisibleLoginUI(t *testing.T) {
scriptBytes, err := os.ReadFile(repoFile("scripts", "demo_public_browser_smoke.cjs"))
if err != nil {
t.Fatalf("read demo public browser smoke script: %v", err)
}
script := string(scriptBytes)
required := []string{
`waitUntil: 'domcontentloaded'`,
`getByLabel('Username').waitFor({ state: 'visible', timeout: 120000 })`,
`getByLabel('Password').waitFor({ state: 'visible', timeout: 120000 })`,
`getByRole('button', { name: 'Sign in to Pulse' }).waitFor({ state: 'visible', timeout: 120000 })`,
}
for _, needle := range required {
if !strings.Contains(script, needle) {
t.Fatalf("demo public browser smoke missing visible-login readiness proof: %s", needle)
}
}
if strings.Contains(script, `waitUntil: 'networkidle'`) {
t.Fatal("demo public browser smoke still depends on networkidle instead of visible login readiness")
}
}
func TestDockerfileStagesShippedDocsForEmbeddedFrontendBuild(t *testing.T) {
dockerfileBytes, err := os.ReadFile(repoFile("Dockerfile"))
if err != nil {

View file

@ -242,6 +242,7 @@ class ReleasePromotionPolicyTest(unittest.TestCase):
helm_pages = read(".github/workflows/helm-pages.yml")
chart = read("deploy/helm/pulse/Chart.yaml")
chart_sync = read("scripts/sync_chart_release_metadata.py")
demo_smoke = read("scripts/demo_public_browser_smoke.cjs")
runbook = read("docs/releases/V6_PRERELEASE_RUNBOOK.md")
self.assertIn("control_plane.py --branch-for-version", publish)
self.assertIn("control_plane.py --branch-for-version", promote)
@ -297,6 +298,11 @@ class ReleasePromotionPolicyTest(unittest.TestCase):
self.assertIn("separate v6 preview demo environment", runbook)
self.assertIn("preview-v6", runbook)
self.assertIn(promotion_metadata_envelope(), normalize_ws(runbook))
self.assertIn("waitUntil: 'domcontentloaded'", demo_smoke)
self.assertIn("getByLabel('Username').waitFor({ state: 'visible', timeout: 120000 })", demo_smoke)
self.assertIn("getByLabel('Password').waitFor({ state: 'visible', timeout: 120000 })", demo_smoke)
self.assertIn("getByRole('button', { name: 'Sign in to Pulse' }).waitFor({ state: 'visible', timeout: 120000 })", demo_smoke)
self.assertNotIn("waitUntil: 'networkidle'", demo_smoke)
def test_blocked_record_tracks_current_target_and_candidate_version(self) -> None:
blocked_record_surface = {