@@ -114,4 +114,104 @@ describe("Root Layout Component", () => {
114114 expect ( jsContent . length ) . toBeGreaterThan ( 100 ) ;
115115 } ) ;
116116 } ) ;
117+
118+ describe ( "Browser CSS Order Tests" , ( ) => {
119+ let devServer : ViteDevServer ;
120+
121+ beforeAll ( async ( ) => {
122+ devServer = await createServer ( {
123+ root : FIXTURE_WITH_ROOT_DIR ,
124+ configFile : path . join ( FIXTURE_WITH_ROOT_DIR , "vite.config.ts" ) ,
125+ server : {
126+ port : 5177 ,
127+ } ,
128+ logLevel : "warn" ,
129+ } ) ;
130+ await devServer . listen ( ) ;
131+ } ) ;
132+
133+ afterAll ( async ( ) => {
134+ await devServer ?. close ( ) ;
135+ } ) ;
136+
137+ it ( "should inject root layout styles before widget styles in the browser" , async ( ) => {
138+ const { content : html } = await getWidgetHTML ( "WidgetA" , { devServer } ) ;
139+
140+ // Write the HTML to a temp file for serving
141+ const tempHtmlPath = path . join ( BUILD_WITH_ROOT_DIR , "test-css-order.html" ) ;
142+ // Replace absolute URLs to point to our dev server
143+ const localHtml = html . replace ( / h t t p s : \/ \/ e x a m p l e \. c o m \/ / g, "http://localhost:5177/" ) ;
144+ await fs . writeFile ( tempHtmlPath , localHtml ) ;
145+
146+ // Create a simple HTTP server to serve the HTML file
147+ const { createServer : createHttpServer } = await import ( "http" ) ;
148+ const { readFile : fsReadFile } = await import ( "fs/promises" ) ;
149+
150+ const server = createHttpServer ( ( req , res ) => {
151+ void ( async ( ) => {
152+ try {
153+ const content = await fsReadFile ( tempHtmlPath ) ;
154+ res . writeHead ( 200 , {
155+ "Content-Type" : "text/html" ,
156+ "Access-Control-Allow-Origin" : "*" ,
157+ } ) ;
158+ res . end ( content ) ;
159+ } catch {
160+ res . writeHead ( 404 ) ;
161+ res . end ( "Not found" ) ;
162+ }
163+ } ) ( ) ;
164+ } ) ;
165+
166+ const port = 5178 ;
167+ await new Promise < void > ( ( resolve ) => {
168+ server . listen ( port , resolve ) ;
169+ } ) ;
170+
171+ try {
172+ const { chromium } = await import ( "playwright" ) ;
173+ const browser = await chromium . launch ( ) ;
174+ const page = await browser . newPage ( ) ;
175+
176+ await page . goto ( `http://localhost:${ port } /` , { waitUntil : "networkidle" } ) ;
177+ // Wait for styles to be injected
178+ await page . waitForTimeout ( 2000 ) ;
179+
180+ const html = await page . content ( ) ;
181+ console . log ( html ) ;
182+ // Get all style tags from the document head, extracting their content
183+ const styleContents = await page . evaluate ( ( ) => {
184+ const styles = document . querySelectorAll ( "head style" ) ;
185+ return Array . from ( styles ) . map ( ( style ) => style . textContent || "" ) ;
186+ } ) ;
187+
188+ await browser . close ( ) ;
189+
190+ // Find which style tag contains root styles vs widget styles
191+ let rootStyleIndex = - 1 ;
192+ let widgetStyleIndex = - 1 ;
193+
194+ for ( let i = 0 ; i < styleContents . length ; i ++ ) {
195+ const content = styleContents [ i ] ;
196+ if ( content . includes ( ".root-layout" ) && rootStyleIndex === - 1 ) {
197+ rootStyleIndex = i ;
198+ }
199+ if ( content . includes ( ".widget-a" ) && widgetStyleIndex === - 1 ) {
200+ widgetStyleIndex = i ;
201+ }
202+ }
203+
204+ // Verify both styles were found
205+ expect ( rootStyleIndex ) . toBeGreaterThan ( - 1 ) ;
206+ expect ( widgetStyleIndex ) . toBeGreaterThan ( - 1 ) ;
207+
208+ // Root layout styles should be injected BEFORE widget styles
209+ // This ensures proper CSS cascade - widget styles can override root styles
210+ expect ( rootStyleIndex ) . toBeLessThan ( widgetStyleIndex ) ;
211+ } finally {
212+ server . close ( ) ;
213+ await fs . unlink ( tempHtmlPath ) . catch ( ( ) => { } ) ;
214+ }
215+ } ) ;
216+ } ) ;
117217} ) ;
0 commit comments