diff options
Diffstat (limited to '')
-rw-r--r-- | devtools/shared/commands/resource/tests/browser_resources_stylesheets_navigation.js | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/devtools/shared/commands/resource/tests/browser_resources_stylesheets_navigation.js b/devtools/shared/commands/resource/tests/browser_resources_stylesheets_navigation.js new file mode 100644 index 0000000000..cfe4076ac4 --- /dev/null +++ b/devtools/shared/commands/resource/tests/browser_resources_stylesheets_navigation.js @@ -0,0 +1,257 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test the ResourceCommand API around STYLESHEET and navigation (reloading, creation of new browsing context, …) + +const ORG_DOC_BUILDER = "https://example.org/document-builder.sjs"; +const COM_DOC_BUILDER = "https://example.com/document-builder.sjs"; + +// Since the order of resources is not guaranteed, we put a number in the title attribute +// of the <style> elements so we can sort them in a way that makes it easier for us to assert. +let currentStyleTitle = 0; + +const TEST_URI = + `${ORG_DOC_BUILDER}?html=1<h1>top-level example.org</h1>` + + `<style title="${currentStyleTitle++}">.top-level-org{}</style>` + + `<iframe id="same-origin-1" src="${ORG_DOC_BUILDER}?html=<h2>example.org 1</h2><style title=${currentStyleTitle++}>.frame-org-1{}</style>"></iframe>` + + `<iframe id="same-origin-2" src="${ORG_DOC_BUILDER}?html=<h2>example.org 2</h2><style title=${currentStyleTitle++}>.frame-org-2{}</style>"></iframe>` + + `<iframe id="remote-origin-1" src="${COM_DOC_BUILDER}?html=<h2>example.com 1</h2><style title=${currentStyleTitle++}>.frame-com-1{}</style>"></iframe>` + + `<iframe id="remote-origin-2" src="${COM_DOC_BUILDER}?html=<h2>example.com 2</h2><style title=${currentStyleTitle++}>.frame-com-2{}</style>"></iframe>`; + +const COOP_HEADERS = "Cross-Origin-Opener-Policy:same-origin"; +const TEST_URI_NEW_BROWSING_CONTEXT = + `${ORG_DOC_BUILDER}?headers=${COOP_HEADERS}` + + `&html=<h1>top-level example.org</div>` + + `<style>.top-level-org-new-bc{}</style>`; + +add_task(async function () { + info( + "Open a new tab and check that styleSheetChangeEventsEnabled is false by default" + ); + const tab = await addTab(TEST_URI); + + is( + await getDocumentStyleSheetChangeEventsEnabled(tab.linkedBrowser), + false, + `styleSheetChangeEventsEnabled is false at the beginning` + ); + + const { client, resourceCommand, targetCommand } = await initResourceCommand( + tab + ); + + let availableResources = []; + await resourceCommand.watchResources([resourceCommand.TYPES.STYLESHEET], { + onAvailable: resources => { + availableResources.push(...resources); + }, + }); + + info("Wait for all the stylesheets resources of main document and iframes"); + await waitFor(() => availableResources.length === 5); + is(availableResources.length, 5, "Retrieved the expected stylesheets"); + + // the order of the resources is not guaranteed. + sortResourcesByExpectedOrder(availableResources); + await assertResource(availableResources[0], { + styleText: `.top-level-org{}`, + }); + await assertResource(availableResources[1], { + styleText: `.frame-org-1{}`, + }); + await assertResource(availableResources[2], { + styleText: `.frame-org-2{}`, + }); + await assertResource(availableResources[3], { + styleText: `.frame-com-1{}`, + }); + await assertResource(availableResources[4], { + styleText: `.frame-com-2{}`, + }); + + // clear availableResources so it's easier to test + availableResources = []; + + is( + await getDocumentStyleSheetChangeEventsEnabled(tab.linkedBrowser), + true, + `styleSheetChangeEventsEnabled is true after watching stylesheets` + ); + + info("Navigate a remote frame to a different page"); + const iframeNewUrl = + `https://example.com/document-builder.sjs?` + + `html=<h2>example.com new bc</h2><style title=6>.frame-com-new-bc{}</style>`; + await SpecialPowers.spawn(tab.linkedBrowser, [iframeNewUrl], url => { + const { browsingContext } = + content.document.querySelector("#remote-origin-2"); + return SpecialPowers.spawn(browsingContext, [url], innerUrl => { + content.document.location = innerUrl; + }); + }); + await waitFor(() => availableResources.length == 1); + ok(true, "We're notified about the iframe new document stylesheet"); + await assertResource(availableResources[0], { + styleText: `.frame-com-new-bc{}`, + }); + const iframeNewBrowsingContext = await SpecialPowers.spawn( + tab.linkedBrowser, + [], + () => content.document.querySelector("#remote-origin-2").browsingContext + ); + + is( + await getDocumentStyleSheetChangeEventsEnabled(iframeNewBrowsingContext), + true, + `styleSheetChangeEventsEnabled is still true after navigating the iframe` + ); + + // clear availableResources so it's easier to test + availableResources = []; + + info("Check that styleSheetChangeEventsEnabled persist after reloading"); + await reloadBrowser(); + + // ⚠️ When EFT is disabled, we're only getting the stylesheets for the top-level document + // and the remote frames; the same-origin iframes stylesheets are missing. + const expectedStylesheetResources = isEveryFrameTargetEnabled() ? 5 : 3; + info( + "Wait until we're notified about all the stylesheets (top-level document + iframe)" + ); + await waitFor( + () => availableResources.length === expectedStylesheetResources + ); + is( + availableResources.length, + expectedStylesheetResources, + "Retrieved the expected stylesheets after the page was reloaded" + ); + + // the order of the resources is not guaranteed. + sortResourcesByExpectedOrder(availableResources); + await assertResource(availableResources[0], { + styleText: `.top-level-org{}`, + }); + if (isEveryFrameTargetEnabled()) { + await assertResource(availableResources[1], { + styleText: `.frame-org-1{}`, + }); + await assertResource(availableResources[2], { + styleText: `.frame-org-2{}`, + }); + await assertResource(availableResources[3], { + styleText: `.frame-com-1{}`, + }); + await assertResource(availableResources[4], { + styleText: `.frame-com-new-bc{}`, + }); + } else { + await assertResource(availableResources[1], { + styleText: `.frame-com-1{}`, + }); + await assertResource(availableResources[2], { + styleText: `.frame-com-new-bc{}`, + }); + } + + is( + await getDocumentStyleSheetChangeEventsEnabled(tab.linkedBrowser), + true, + `styleSheetChangeEventsEnabled is still true on the top level document after reloading` + ); + + if (isEveryFrameTargetEnabled()) { + const bc = await SpecialPowers.spawn( + tab.linkedBrowser, + [], + () => content.document.querySelector("#same-origin-1").browsingContext + ); + is( + await getDocumentStyleSheetChangeEventsEnabled(bc), + true, + `styleSheetChangeEventsEnabled is still true on the iframe after reloading` + ); + } + + // clear availableResources so it's easier to test + availableResources = []; + + info( + "Check that styleSheetChangeEventsEnabled persist when navigating to a page that creates a new browsing context" + ); + const previousBrowsingContextId = tab.linkedBrowser.browsingContext.id; + const onLoaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser); + await BrowserTestUtils.loadURIString( + tab.linkedBrowser, + TEST_URI_NEW_BROWSING_CONTEXT + ); + await onLoaded; + + isnot( + tab.linkedBrowser.browsingContext.id, + previousBrowsingContextId, + "A new browsing context was created" + ); + + info("Wait to get the stylesheet for the new document"); + await waitFor(() => availableResources.length === 1); + ok(true, "We received the stylesheet for the new document"); + await assertResource(availableResources[0], { + styleText: `.top-level-org-new-bc{}`, + }); + is( + await getDocumentStyleSheetChangeEventsEnabled(tab.linkedBrowser), + true, + `styleSheetChangeEventsEnabled is still true after navigating to a new browsing context` + ); + + targetCommand.destroy(); + await client.close(); +}); + +/** + * Returns the value of the browser/browsingContext document `styleSheetChangeEventsEnabled` + * property. + * + * @param {Browser|BrowsingContext} browserOrBrowsingContext: The browser element or a + * browsing context. + * @returns {Promise<Boolean>} + */ +function getDocumentStyleSheetChangeEventsEnabled(browserOrBrowsingContext) { + return SpecialPowers.spawn(browserOrBrowsingContext, [], () => { + return content.document.styleSheetChangeEventsEnabled; + }); +} + +/** + * Sort the passed array of stylesheet resources. + * + * Since the order of resources are not guaranteed, the <style> elements we use in this test + * have a "title" attribute that represent their expected order so we can sort them in + * a way that makes it easier for us to assert. + * + * @param {Array<Object>} resources: Array of stylesheet resources + */ +function sortResourcesByExpectedOrder(resources) { + resources.sort((a, b) => { + return Number(a.title) > Number(b.title); + }); +} + +/** + * Check that the resources have the expected text + * + * @param {Array<Object>} resources: Array of stylesheet resources + * @param {Array<Object>} expected: Array of object of the following shape: + * @param {Object} expected[] + * @param {Object} expected[].styleText: Expected text content of the stylesheet + */ +async function assertResource(resource, expected) { + const styleSheetsFront = await resource.targetFront.getFront("stylesheets"); + const styleText = ( + await styleSheetsFront.getText(resource.resourceId) + ).str.trim(); + is(styleText, expected.styleText, "Style text is correct"); +} |