From a4af5a20082c129f38b4daeb9fe4082eac4340b0 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 30 Sep 2026 20:52:28 +0300 Subject: [PATCH] test(backdrop): probe editor backgrounds after the mode transition (#715) The 6b probes entered each mode with a private _setMode call and read the stage and paper colours 220 ms later. The mode transition interpolates exactly those colours (inline stage background, --hp-mode-paper under .stage.mode-transition) for its 220 ms plus a measurement frame, and it is driven by animation frames, so under load the probe caught an intermediate colour and plan_editor_stage_white_with_backdrop / plan_editor_paper_white_with_backdrop went red. Slowing frames to 60 ms reproduces both every time; three parallel copies of the smoke fail 16 of 18 runs. Each probe now enters its mode through __hpTest.setMode and waits until the transition has ended by the card's own markers: the stage carries mode- and no longer mode-transition, and neither the stage nor the paper has a running animation. The same wait precedes the View probe. The colour assertions are unchanged; a plan stage forced to a non-white background still fails the check. Issue: #715 User-Visible: no Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd --- demo/smoke_backdrop.mjs | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/demo/smoke_backdrop.mjs b/demo/smoke_backdrop.mjs index 99967685..d353b770 100644 --- a/demo/smoke_backdrop.mjs +++ b/demo/smoke_backdrop.mjs @@ -283,13 +283,31 @@ check('picture_is_below_the_walls', layers.iImage < layers.iRoom, true); // ---------- 6b) editors keep a WHITE sheet under the grid with a backdrop -- const editorWhite = await page.evaluate(async () => { const c = window.__card; + const hp = window.__hpTest; const sr = () => c.shadowRoot || c.renderRoot; - const upd = async () => { c.requestUpdate(); await c.updateComplete; }; - const navSettled = () => new Promise((resolve) => setTimeout(resolve, 220)); + // A mode switch paints the stage and the paper with interpolated colours + // for 220 ms plus a measurement frame, driven by animation frames: under + // load that outlasts any fixed pause (#715). A probe belongs to the settled + // mode: the stage carries `mode-` and no longer `mode-transition`, + // and neither the stage nor the paper runs an animation of its own. + const enter = async (mode) => { + await hp.setMode(mode); + const deadline = performance.now() + 5000; + for (;;) { + const stage = sr().querySelector('.stage'); + const paper = sr().querySelector('.stage svg .hp-paper'); + const running = [stage, paper].flatMap((node) => node?.getAnimations() ?? []) + .filter((animation) => animation.playState === 'running'); + if (stage?.classList.contains(`mode-${mode}`) && !stage.classList.contains('mode-transition') + && !running.length) return; + if (performance.now() > deadline) { + throw new Error(`smoke_backdrop: переход в ${mode} не завершился (.stage: ${stage?.className})`); + } + await hp.settled(); + } + }; const probe = async (mode) => { - c._setMode(mode); - await upd(); - await navSettled(); + await enter(mode); const stage = sr().querySelector('.stage'); const paper = sr().querySelector('.stage svg .hp-paper'); return { @@ -303,9 +321,7 @@ const editorWhite = await page.evaluate(async () => { const plan = await probe('plan'); const devices = await probe('devices'); const decor = await probe('decor'); - c._setMode('view'); - await upd(); - await navSettled(); + await enter('view'); const viewStage = sr().querySelector('.stage'); // View with a backdrop must NOT force white — theme/card colour stays const viewForcedWhite = getComputedStyle(viewStage).backgroundColor === 'rgb(255, 255, 255)'