Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions docs/qa/platform-checklist/areas/platform-core.json
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@
"title": "Every showcase nav surface renders without page errors, and failures surface the error boundary — never a blank page",
"since": "v15",
"status": "active",
"revision": 5,
"revision": 6,
"priority": "P0",
"surface": "browser",
"personas": ["seeded admin (admin@objectos.ai / admin123)"],
Expand All @@ -271,7 +271,7 @@
],
"acceptance": [
{
"clause": "no surface throws a pageerror, renders an empty <main>, stays on the console's boot splash ('Initializing application…'), or leaks a 'no actions configured' placeholder; chart surfaces draw a real SVG whose box is measured by POLLING until non-null within a bounded budget — never by a fixed wall-clock wait followed by a single boundingBox read, which measures the layout window rather than the product",
"clause": "no surface throws a pageerror, renders an empty <main>, stays on the console's boot splash (its data-boot-splash marker is in the page, or <main> reads its English line 'Initializing application…' or 'Opening your console…'), or leaks a 'no actions configured' placeholder; chart surfaces draw a real SVG whose box is measured by POLLING until non-null within a bounded budget — never by a fixed wall-clock wait followed by a single boundingBox read, which measures the layout window rather than the product",
"oracle": "test",
"verify": "pnpm -C examples/app-showcase test:smoke (SURFACES array in e2e/showcase-smoke.spec.ts) — green; the main-content wait treats the boot splash as not-yet-rendered and the assertion refuses a surface still on it; the chart assertion polls boundingBox against a bounded deadline and keeps the last non-null sample, so a null-box failure and a collapsed-panel failure report as different assertions (#7569)",
"evidence": "test run output + the failing assertion's message for any chart red"
Expand All @@ -297,7 +297,7 @@
],
"negative": [
"a surface that renders a blank <main> is a FAIL even with no console error — transitional emptiness must be ruled out by the screenshot-first protocol, then the persistent blank is the finding",
"the boot splash is NOT rendered content: 'Initializing application…' is text inside <main>, so a non-empty check passes on a surface that never rendered. QA run #21056 read it as the FIRST <main> text on 22 of 49 surfaces, and the suite's own non-chart check passed on it until revision 5. A hand walk waits past the splash before judging, exactly as the suite now does",
"the boot splash is NOT rendered content: it is text inside <main>, so a non-empty check passes on a surface that never rendered. QA run #21056 read it as the FIRST <main> text on 22 of 49 surfaces, and the suite's own non-chart check passed on it until revision 5. Recognise it by its language-independent data-boot-splash marker (objectui 54159d3 on), or by either English line: 'Initializing application…' before that commit, 'Opening your console…' from it. From that commit on the line follows the browser's language and is absent until that language's catalogue lands, so neither English line matches a non-English splash or an empty-line one, which shows only the product name; on a console pinned before that commit there is no marker. A hand walk waits past the splash before judging, exactly as the suite now does",
"a bad route producing a white page (shell gone) is a FAIL of the error-boundary clause",
"a chart red obtained from a SINGLE boundingBox read at a fixed instant is NOT a product finding and must not be filed as one — it measures the ResponsiveContainer layout window, and it cost a triage cycle every run until #7569 replaced that read with a bounded poll. Re-introducing any fixed sleep-then-read-once in this suite re-opens it. The converse holds both ways: a box that stays null through the WHOLE bounded poll, or a laid-out width ≤ 200 (the #2616 D collapsed-panel case), IS a FAIL"
],
Expand All @@ -319,6 +319,12 @@
"date": "2026-10-01",
"change": "the pin caught up with QA run #21056's three findings: SURFACES covered 31 of 49 served destinations, and the 18 the run hand-walked are now in it (Revenue Pulse and the Hours by Status chart report as chart surfaces); the non-chart check passed on the boot splash, and the wait and assertion now treat the splash as not rendered; the config hard-coded port 3000 and offered no browser override, and now reads SMOKE_API_URL for the server it boots and OS_TEST_CHROMIUM_EXECUTABLE_PATH for the browser. Measured on this branch: 49 passed on a free port with the container's chromium, and an instrumented run saw 29 of the 49 surfaces on the splash first",
"ref": "#21060"
},
{
"revision": 6,
"date": "2026-10-12",
"change": "the boot-splash clause and negative named only the old English line 'Initializing application…'. objectui 54159d3 changed that line to 'Opening your console…', in the browser's language and absent until its catalogue lands, and put a language-independent data-boot-splash marker on the splash root. Both now name the two English lines and the marker, matching the suite: a surface is still on the splash when the marker is in the page or <main> reads either line. The line half is the one that holds on a pin older than 54159d3, which has no marker",
"ref": "#22992"
}
]
},
Expand Down
42 changes: 33 additions & 9 deletions examples/app-showcase/e2e/showcase-smoke.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,30 @@ const SURFACES: { name: string; path: string; chart?: boolean }[] = [

/**
* The console's boot splash — objectui app-shell's `LoadingScreen`, which the
* shell also renders as a `Suspense` fallback INSIDE its `<main>` — reads
* "Initializing application…" under the default locale. Its text is not empty,
* so a check of "main has text" passed on a surface that had not rendered at
* all: QA run #21056 read the splash as the FIRST `<main>` text on 22 of 49
* surfaces. The wait below treats the splash as not-yet-rendered, and the
* assertions refuse a surface that is still on it at the deadline.
* shell also renders as a `Suspense` fallback INSIDE its `<main>`. Its text is
* not empty, so a check of "main has text" passed on a surface that had not
* rendered at all: QA run #21056 read the splash as the FIRST `<main>` text on
* 22 of 49 surfaces. The wait below treats the splash as not-yet-rendered, and
* the assertions refuse a surface that is still on it at the deadline.
*
* A surface is on the splash when EITHER of these holds, and both stay:
*
* - `BOOT_SPLASH_MARKER` is in the page. From objectui `54159d3` on, the
* splash root carries `data-boot-splash` in every state (loading, `message`,
* error). It is the only language-independent sign: the splash's line
* follows the user's language from that commit on, and it is absent until
* that language's catalogue lands, leaving only the product name. Neither
* English line below matches either case.
* - `<main>`'s text matches `BOOT_SPLASH_LINE`, the splash's English line in
* both spellings: "Initializing application…" before objectui `54159d3`,
* "Opening your console…" from it. A console pinned before that commit has
* no marker, so the line is the only half that sees its splash.
* ⛔ Never key on the marker alone while `.objectui-sha` is older than
* `54159d3`: the marker then matches nothing, and the wait passes on the
* splash.
*/
const BOOT_SPLASH = /Initializing application/i;
const BOOT_SPLASH_MARKER = '[data-boot-splash]';
const BOOT_SPLASH_LINE = /Initializing application|Opening your console/i;

/**
* The budget every wait in this file spends, measured from the start of the
Expand Down Expand Up @@ -149,10 +165,14 @@ for (const surface of SURFACES) {
// [#21060] Rendered means past the boot splash, not merely non-empty: the
// splash is text too. The last sample is kept whatever it was, so a surface
// stuck on the splash fails as exactly that rather than as "no content".
// The marker is read BEFORE the text: a splash that leaves between the two
// reads then errs toward "not yet", never toward "rendered".
let mainText = '';
let splashMarkers = 0;
await pollUntil(async () => {
splashMarkers = await page.locator(BOOT_SPLASH_MARKER).count();
mainText = ((await main.innerText().catch(() => '')) || '').trim();
return mainText.length > 0 && !BOOT_SPLASH.test(mainText);
return mainText.length > 0 && splashMarkers === 0 && !BOOT_SPLASH_LINE.test(mainText);
}, deadline);

let chartBox: { width: number; height: number } | null = null;
Expand Down Expand Up @@ -181,7 +201,11 @@ for (const surface of SURFACES) {
`leaked placeholder on ${surface.name}`,
).toHaveCount(0);
expect(mainText.length, `${surface.name} rendered no main content`).toBeGreaterThan(0);
expect(mainText, `${surface.name} never got past the boot splash`).not.toMatch(BOOT_SPLASH);
expect(
splashMarkers,
`${surface.name} never got past the boot splash (${BOOT_SPLASH_MARKER} still in the page)`,
).toBe(0);
expect(mainText, `${surface.name} never got past the boot splash`).not.toMatch(BOOT_SPLASH_LINE);

if (surface.chart) {
expect(
Expand Down
Loading