@@ -481,6 +481,128 @@ test('preview iframe keeps one base and one user style node across rerenders', a
481481 . toContain ( 'rgb(70, 80, 90)' )
482482} )
483483
484+ test ( 'config patch keeps preview style order stable around app head styles' , async ( {
485+ page,
486+ } ) => {
487+ await waitForInitialRender ( page )
488+
489+ await setWorkspaceTabSource ( page , {
490+ fileName : 'app.css' ,
491+ kind : 'styles' ,
492+ source : [ '.counter-button { color: rgb(80, 90, 100); }' ] . join ( '\n' ) ,
493+ } )
494+
495+ await setComponentEditorSource (
496+ page ,
497+ [
498+ "import '../styles/app.css'" ,
499+ '' ,
500+ "const injected = document.getElementById('app-head-style')" ,
501+ 'if (!(injected instanceof HTMLStyleElement)) {' ,
502+ " const style = document.createElement('style')" ,
503+ " style.id = 'app-head-style'" ,
504+ " style.textContent = '.counter-button { border-radius: 0px; }'" ,
505+ ' document.head.append(style)' ,
506+ '}' ,
507+ '' ,
508+ 'const App = () => <button class="counter-button">order check</button>' ,
509+ '' ,
510+ ] . join ( '\n' ) ,
511+ )
512+
513+ await expect ( page . getByRole ( 'status' , { name : 'App status' } ) ) . toHaveText ( 'Rendered' )
514+
515+ await expect
516+ . poll ( async ( ) => {
517+ return getPreviewFrame ( page )
518+ . locator ( 'html' )
519+ . evaluate ( ( ) => {
520+ const baseStyleElement = document . getElementById ( 'knighted-preview-base-styles' )
521+ const userStyleElement = document . getElementById ( 'knighted-preview-user-styles' )
522+ const appHeadStyleElement = document . getElementById ( 'app-head-style' )
523+ const styleElements = Array . from ( document . head . querySelectorAll ( 'style' ) )
524+
525+ if (
526+ ! ( baseStyleElement instanceof HTMLStyleElement ) ||
527+ ! ( userStyleElement instanceof HTMLStyleElement ) ||
528+ ! ( appHeadStyleElement instanceof HTMLStyleElement )
529+ ) {
530+ return null
531+ }
532+
533+ return {
534+ baseIndex : styleElements . indexOf ( baseStyleElement ) ,
535+ userIndex : styleElements . indexOf ( userStyleElement ) ,
536+ appIndex : styleElements . indexOf ( appHeadStyleElement ) ,
537+ }
538+ } )
539+ } )
540+ . not . toBeNull ( )
541+
542+ const resolvedOrderBeforePatch = await getPreviewFrame ( page )
543+ . locator ( 'html' )
544+ . evaluate ( ( ) => {
545+ const baseStyleElement = document . getElementById ( 'knighted-preview-base-styles' )
546+ const userStyleElement = document . getElementById ( 'knighted-preview-user-styles' )
547+ const appHeadStyleElement = document . getElementById ( 'app-head-style' )
548+ const styleElements = Array . from ( document . head . querySelectorAll ( 'style' ) )
549+
550+ if (
551+ ! ( baseStyleElement instanceof HTMLStyleElement ) ||
552+ ! ( userStyleElement instanceof HTMLStyleElement ) ||
553+ ! ( appHeadStyleElement instanceof HTMLStyleElement )
554+ ) {
555+ return null
556+ }
557+
558+ return {
559+ baseIndex : styleElements . indexOf ( baseStyleElement ) ,
560+ userIndex : styleElements . indexOf ( userStyleElement ) ,
561+ appIndex : styleElements . indexOf ( appHeadStyleElement ) ,
562+ }
563+ } )
564+
565+ if ( ! resolvedOrderBeforePatch ) {
566+ throw new Error ( 'Expected app-injected head style to exist before config patch.' )
567+ }
568+
569+ expect ( resolvedOrderBeforePatch . baseIndex ) . toBeLessThan (
570+ resolvedOrderBeforePatch . userIndex ,
571+ )
572+ expect ( resolvedOrderBeforePatch . userIndex ) . toBeLessThan (
573+ resolvedOrderBeforePatch . appIndex ,
574+ )
575+
576+ await page . getByLabel ( 'Background' ) . fill ( '#456789' )
577+
578+ await expect
579+ . poll ( async ( ) => {
580+ return getPreviewFrame ( page )
581+ . locator ( 'html' )
582+ . evaluate ( ( ) => {
583+ const baseStyleElement = document . getElementById ( 'knighted-preview-base-styles' )
584+ const userStyleElement = document . getElementById ( 'knighted-preview-user-styles' )
585+ const appHeadStyleElement = document . getElementById ( 'app-head-style' )
586+ const styleElements = Array . from ( document . head . querySelectorAll ( 'style' ) )
587+
588+ if (
589+ ! ( baseStyleElement instanceof HTMLStyleElement ) ||
590+ ! ( userStyleElement instanceof HTMLStyleElement ) ||
591+ ! ( appHeadStyleElement instanceof HTMLStyleElement )
592+ ) {
593+ return null
594+ }
595+
596+ return {
597+ baseIndex : styleElements . indexOf ( baseStyleElement ) ,
598+ userIndex : styleElements . indexOf ( userStyleElement ) ,
599+ appIndex : styleElements . indexOf ( appHeadStyleElement ) ,
600+ }
601+ } )
602+ } )
603+ . toEqual ( resolvedOrderBeforePatch )
604+ } )
605+
484606test ( 'nested module imports can bring styles into preview graph' , async ( { page } ) => {
485607 await waitForInitialRender ( page )
486608
0 commit comments