@@ -145,4 +145,90 @@ describe('PiPContext', () => {
145145 expect ( pipDocument . body . querySelector ( '#leftover' ) ) . toBeNull ( )
146146 } )
147147 } )
148+
149+ describe ( 'styleSheet propagation' , ( ) => {
150+ type FakeCssRule = { readonly cssText : string }
151+ type FakeStyleSheet = {
152+ readonly cssRules ?: ArrayLike < FakeCssRule >
153+ readonly href ?: string | null
154+ readonly type ?: string
155+ readonly media ?: { toString : ( ) => string }
156+ readonly ownerNode ?: Element | null
157+ }
158+
159+ function makeCssRules ( ...cssTexts : Array < string > ) : ArrayLike < FakeCssRule > {
160+ return cssTexts . map ( ( cssText ) => ( { cssText } ) )
161+ }
162+
163+ function stubParentStyleSheet ( sheet : FakeStyleSheet ) {
164+ return vi
165+ . spyOn ( document , 'styleSheets' , 'get' )
166+ . mockReturnValue ( [ sheet ] as unknown as StyleSheetList )
167+ }
168+
169+ it ( 'should copy parent stylesheets as "<style>" with the same id into the PiP document head' , ( ) => {
170+ const sourceStyle = document . createElement ( 'style' )
171+ sourceStyle . id = 'tsqd-source'
172+ const sheetSpy = stubParentStyleSheet ( {
173+ cssRules : makeCssRules ( '.tsqd { color: red; }' ) ,
174+ ownerNode : sourceStyle ,
175+ } )
176+ const { pipDocument } = stubPipWindow ( )
177+
178+ try {
179+ renderAndAct ( ( pip ) => pip ( ) . requestPipWindow ( 640 , 480 ) )
180+
181+ const copied = pipDocument . head . querySelector ( 'style#tsqd-source' )
182+ expect ( copied ) . not . toBeNull ( )
183+ expect ( copied ?. textContent ) . toBe ( '.tsqd { color: red; }' )
184+ } finally {
185+ sheetSpy . mockRestore ( )
186+ }
187+ } )
188+
189+ it ( 'should fall back to a "<link>" for cross-origin stylesheets whose "cssRules" throw' , ( ) => {
190+ const sheetSpy = stubParentStyleSheet ( {
191+ get cssRules ( ) : CSSRuleList {
192+ throw new DOMException ( 'blocked' , 'SecurityError' )
193+ } ,
194+ href : 'https://example.com/external.css' ,
195+ type : 'text/css' ,
196+ media : { toString : ( ) => 'all' } ,
197+ } )
198+ const { pipDocument } = stubPipWindow ( )
199+
200+ try {
201+ renderAndAct ( ( pip ) => pip ( ) . requestPipWindow ( 640 , 480 ) )
202+
203+ const link = pipDocument . head . querySelector < HTMLLinkElement > (
204+ 'link[href="https://example.com/external.css"]' ,
205+ )
206+ expect ( link ) . not . toBeNull ( )
207+ expect ( link ?. rel ) . toBe ( 'stylesheet' )
208+ } finally {
209+ sheetSpy . mockRestore ( )
210+ }
211+ } )
212+
213+ it ( 'should skip the "<link>" fallback when the cross-origin stylesheet has no "href"' , ( ) => {
214+ const sheetSpy = stubParentStyleSheet ( {
215+ get cssRules ( ) : CSSRuleList {
216+ throw new DOMException ( 'blocked' , 'SecurityError' )
217+ } ,
218+ href : null ,
219+ type : 'text/css' ,
220+ media : { toString : ( ) => 'all' } ,
221+ } )
222+ const { pipDocument } = stubPipWindow ( )
223+
224+ try {
225+ renderAndAct ( ( pip ) => pip ( ) . requestPipWindow ( 640 , 480 ) )
226+
227+ expect ( pipDocument . head . querySelector ( 'link' ) ) . toBeNull ( )
228+ expect ( pipDocument . head . querySelector ( 'style' ) ) . toBeNull ( )
229+ } finally {
230+ sheetSpy . mockRestore ( )
231+ }
232+ } )
233+ } )
148234} )
0 commit comments