browser_resources_stylesheets_navigation.js (8474B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 // Test the ResourceCommand API around STYLESHEET and navigation (reloading, creation of new browsing context, …) 7 8 const ORG_DOC_BUILDER = "https://example.org/document-builder.sjs"; 9 const COM_DOC_BUILDER = "https://example.com/document-builder.sjs"; 10 11 // Since the order of resources is not guaranteed, we put a number in the title attribute 12 // of the <style> elements so we can sort them in a way that makes it easier for us to assert. 13 let currentStyleTitle = 0; 14 15 const TEST_URI = 16 `${ORG_DOC_BUILDER}?html=1<h1>top-level example.org</h1>` + 17 `<style title="${currentStyleTitle++}">.top-level-org{}</style>` + 18 `<iframe id="same-origin-1" src="${ORG_DOC_BUILDER}?html=<h2>example.org 1</h2><style title=${currentStyleTitle++}>.frame-org-1{}</style>"></iframe>` + 19 `<iframe id="same-origin-2" src="${ORG_DOC_BUILDER}?html=<h2>example.org 2</h2><style title=${currentStyleTitle++}>.frame-org-2{}</style>"></iframe>` + 20 `<iframe id="remote-origin-1" src="${COM_DOC_BUILDER}?html=<h2>example.com 1</h2><style title=${currentStyleTitle++}>.frame-com-1{}</style>"></iframe>` + 21 `<iframe id="remote-origin-2" src="${COM_DOC_BUILDER}?html=<h2>example.com 2</h2><style title=${currentStyleTitle++}>.frame-com-2{}</style>"></iframe>`; 22 23 const COOP_HEADERS = "Cross-Origin-Opener-Policy:same-origin"; 24 const TEST_URI_NEW_BROWSING_CONTEXT = 25 `${ORG_DOC_BUILDER}?headers=${COOP_HEADERS}` + 26 `&html=<h1>top-level example.org</div>` + 27 `<style>.top-level-org-new-bc{}</style>`; 28 29 add_task(async function () { 30 info( 31 "Open a new tab and check that styleSheetChangeEventsEnabled is false by default" 32 ); 33 const tab = await addTab(TEST_URI); 34 35 is( 36 await getDocumentStyleSheetChangeEventsEnabled(tab.linkedBrowser), 37 false, 38 `styleSheetChangeEventsEnabled is false at the beginning` 39 ); 40 41 const { client, resourceCommand, targetCommand } = 42 await initResourceCommand(tab); 43 44 let availableResources = []; 45 await resourceCommand.watchResources([resourceCommand.TYPES.STYLESHEET], { 46 onAvailable: resources => { 47 availableResources.push(...resources); 48 }, 49 }); 50 51 info("Wait for all the stylesheets resources of main document and iframes"); 52 await waitFor(() => availableResources.length === 5); 53 is(availableResources.length, 5, "Retrieved the expected stylesheets"); 54 55 // the order of the resources is not guaranteed. 56 sortResourcesByExpectedOrder(availableResources); 57 await assertResource(availableResources[0], { 58 styleText: `.top-level-org{}`, 59 }); 60 await assertResource(availableResources[1], { 61 styleText: `.frame-org-1{}`, 62 }); 63 await assertResource(availableResources[2], { 64 styleText: `.frame-org-2{}`, 65 }); 66 await assertResource(availableResources[3], { 67 styleText: `.frame-com-1{}`, 68 }); 69 await assertResource(availableResources[4], { 70 styleText: `.frame-com-2{}`, 71 }); 72 73 // clear availableResources so it's easier to test 74 availableResources = []; 75 76 is( 77 await getDocumentStyleSheetChangeEventsEnabled(tab.linkedBrowser), 78 true, 79 `styleSheetChangeEventsEnabled is true after watching stylesheets` 80 ); 81 82 info("Navigate a remote frame to a different page"); 83 const iframeNewUrl = 84 `https://example.com/document-builder.sjs?` + 85 `html=<h2>example.com new bc</h2><style title=6>.frame-com-new-bc{}</style>`; 86 await SpecialPowers.spawn(tab.linkedBrowser, [iframeNewUrl], url => { 87 const { browsingContext } = 88 content.document.querySelector("#remote-origin-2"); 89 return SpecialPowers.spawn(browsingContext, [url], innerUrl => { 90 content.document.location = innerUrl; 91 }); 92 }); 93 await waitFor(() => availableResources.length == 1); 94 ok(true, "We're notified about the iframe new document stylesheet"); 95 await assertResource(availableResources[0], { 96 styleText: `.frame-com-new-bc{}`, 97 }); 98 const iframeNewBrowsingContext = await SpecialPowers.spawn( 99 tab.linkedBrowser, 100 [], 101 () => content.document.querySelector("#remote-origin-2").browsingContext 102 ); 103 104 is( 105 await getDocumentStyleSheetChangeEventsEnabled(iframeNewBrowsingContext), 106 true, 107 `styleSheetChangeEventsEnabled is still true after navigating the iframe` 108 ); 109 110 // clear availableResources so it's easier to test 111 availableResources = []; 112 113 info("Check that styleSheetChangeEventsEnabled persist after reloading"); 114 await reloadBrowser(); 115 116 const expectedStylesheetResources = 5; 117 info( 118 "Wait until we're notified about all the stylesheets (top-level document + iframe)" 119 ); 120 await waitFor( 121 () => availableResources.length === expectedStylesheetResources 122 ); 123 is( 124 availableResources.length, 125 expectedStylesheetResources, 126 "Retrieved the expected stylesheets after the page was reloaded" 127 ); 128 129 // the order of the resources is not guaranteed. 130 sortResourcesByExpectedOrder(availableResources); 131 await assertResource(availableResources[0], { 132 styleText: `.top-level-org{}`, 133 }); 134 await assertResource(availableResources[1], { 135 styleText: `.frame-org-1{}`, 136 }); 137 await assertResource(availableResources[2], { 138 styleText: `.frame-org-2{}`, 139 }); 140 await assertResource(availableResources[3], { 141 styleText: `.frame-com-1{}`, 142 }); 143 await assertResource(availableResources[4], { 144 styleText: `.frame-com-new-bc{}`, 145 }); 146 147 is( 148 await getDocumentStyleSheetChangeEventsEnabled(tab.linkedBrowser), 149 true, 150 `styleSheetChangeEventsEnabled is still true on the top level document after reloading` 151 ); 152 153 const bc = await SpecialPowers.spawn( 154 tab.linkedBrowser, 155 [], 156 () => content.document.querySelector("#same-origin-1").browsingContext 157 ); 158 is( 159 await getDocumentStyleSheetChangeEventsEnabled(bc), 160 true, 161 `styleSheetChangeEventsEnabled is still true on the iframe after reloading` 162 ); 163 164 // clear availableResources so it's easier to test 165 availableResources = []; 166 167 info( 168 "Check that styleSheetChangeEventsEnabled persist when navigating to a page that creates a new browsing context" 169 ); 170 const previousBrowsingContextId = tab.linkedBrowser.browsingContext.id; 171 const onLoaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser); 172 BrowserTestUtils.startLoadingURIString( 173 tab.linkedBrowser, 174 TEST_URI_NEW_BROWSING_CONTEXT 175 ); 176 await onLoaded; 177 178 isnot( 179 tab.linkedBrowser.browsingContext.id, 180 previousBrowsingContextId, 181 "A new browsing context was created" 182 ); 183 184 info("Wait to get the stylesheet for the new document"); 185 await waitFor(() => availableResources.length === 1); 186 ok(true, "We received the stylesheet for the new document"); 187 await assertResource(availableResources[0], { 188 styleText: `.top-level-org-new-bc{}`, 189 }); 190 is( 191 await getDocumentStyleSheetChangeEventsEnabled(tab.linkedBrowser), 192 true, 193 `styleSheetChangeEventsEnabled is still true after navigating to a new browsing context` 194 ); 195 196 targetCommand.destroy(); 197 await client.close(); 198 }); 199 200 /** 201 * Returns the value of the browser/browsingContext document `styleSheetChangeEventsEnabled` 202 * property. 203 * 204 * @param {Browser|BrowsingContext} browserOrBrowsingContext: The browser element or a 205 * browsing context. 206 * @returns {Promise<boolean>} 207 */ 208 function getDocumentStyleSheetChangeEventsEnabled(browserOrBrowsingContext) { 209 return SpecialPowers.spawn(browserOrBrowsingContext, [], () => { 210 return content.document.styleSheetChangeEventsEnabled; 211 }); 212 } 213 214 /** 215 * Sort the passed array of stylesheet resources. 216 * 217 * Since the order of resources are not guaranteed, the <style> elements we use in this test 218 * have a "title" attribute that represent their expected order so we can sort them in 219 * a way that makes it easier for us to assert. 220 * 221 * @param {Array<object>} resources: Array of stylesheet resources 222 */ 223 function sortResourcesByExpectedOrder(resources) { 224 resources.sort((a, b) => { 225 return Number(a.title) > Number(b.title); 226 }); 227 } 228 229 /** 230 * Check that the resources have the expected text 231 * 232 * @param {Array<object>} resources: Array of stylesheet resources 233 * @param {Array<object>} expected: Array of object of the following shape: 234 * @param {object} expected[] 235 * @param {object} expected[].styleText: Expected text content of the stylesheet 236 */ 237 async function assertResource(resource, expected) { 238 const styleText = (await getStyleSheetResourceText(resource)).trim(); 239 is(styleText, expected.styleText, "Style text is correct"); 240 }