Cypress previewReady() flakes on opacity assertion against .editorFrame after #3574994
>>> [!note] Migrated issue <!-- Drupal.org comment --> <!-- Migrated from issue #3586806. --> Reported by: [penyaskito](https://www.drupal.org/user/959536) Related to !984 >>> <h3 id="overview">Overview</h3> <p>Cypress E2E specs that call <code>cy.previewReady()</code> intermittently fail with:</p> <p><code>expected &lt;div._editorFrame_&hellip;&gt; to have CSS property opacity with the value '1', but the value was '0'</code></p> <p>Example failure: <a href="https://git.drupalcode.org/project/canvas/-/jobs/9512425">job 9512425</a>, where all 30 tests in <code>multivalue-form-design-number-integer.cy.js</code> failed on this assertion. 16 specs use <code>previewReady</code>, so the flake surfaces unevenly across runs.</p> <p>The flake was introduced by <span class="drupalorg-gitlab-issue-link drupalorg-gitlab-link-wrapper"><a href="https://git.drupalcode.org/project/canvas/-/work_items/3574994" class="drupalorg-gitlab-link">https://git.drupalcode.org/project/canvas/-/work_items/3574994</a></span> (specifically MR !638), which changed the assertion target in <code>ui/tests/support/commands.js</code>:</p> <ul> <li>The previous selector <code>.canvasEditorFrameScalingContainer</code> has no <code>opacity</code> rule in the editor frame stylesheet, so its computed opacity is always <code>1</code> &mdash; the assertion was effectively a no-op presence check. </li> <li>The new selector <code>[data-testid="canvas-editor-frame"]</code> targets the parent <code>.editorFrame</code>, which starts at <code>opacity: 0</code> and transitions to <code>1</code> over <code>0.3s</code> only when the local <code>isVisible</code> state flips. <code>isVisible</code> depends on the Redux <code>firstLoadComplete</code> flag, which depends in turn on the preview iframe load completing. </li> </ul> <p>With Cypress's default 4s <code>defaultCommandTimeout</code>, that chain can exceed the budget on loaded CI runners, and a strict <code>'1'</code> string match can also miss mid-transition reads of values like <code>0.97</code>.</p> <h3 id="steps-to-reproduce">Steps to reproduce</h3> <ol> <li>Run any spec that calls <code>cy.previewReady()</code> on a CI runner under load (e.g. <code>multivalue-form-design-number-integer.cy.js</code>). </li> <li>Observe intermittent failures of the form <code>expected &lt;div._editorFrame_&gt; to have CSS property opacity with the value '1', but the value was '0'</code>. </li> </ol> <h3 id="proposed-resolution">Proposed resolution</h3> <p>Drop the editor-frame opacity assertion from <code>previewReady</code> entirely. The iframe selector that ran on the next line &mdash; <code>[data-test-canvas-content-initialized="true"][data-canvas-swap-active="true"]</code> with a 10s timeout &mdash; is the real "preview is ready" contract. That attribute is set in <code>Viewport.tsx</code> after <code>IframeSwapper</code>'s load-event-driven swap completes, so it already encodes "the iframe finished loading and is the active one." Any wrapper-level state (including the editor-frame opacity transition) is downstream of this signal and strictly racier.</p> <p>Harden the helper while we're there:</p> <ul> <li>Assert <code>contentDocument.readyState === 'complete'</code> independent of the data-attribute bookkeeping, so the test stays correct if the Viewport-side bookkeeping is ever refactored. </li> <li>Assert the iframe body has at least one child element, so we catch the "iframe loaded but document is empty" failure mode. </li> </ul> <p>No production-side changes are needed; this is a test-only fix in <code>ui/tests/support/commands.js</code>.</p> <h3 id="remaining-tasks">Remaining tasks</h3> <ul> <li>Review and merge the MR.</li> <li>Watch CI on subsequent runs to confirm the flake is gone.</li> </ul>
issue