/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; const EXAMPLE_COM_URI = "https://example.com/document-builder.sjs?html=
com"; const EXAMPLE_NET_URI = "https://example.net/document-builder.sjs?html=
net"; const ORG_URL_ROOT = URL_ROOT.replace("example.com", "example.org"); const TEST_ORG_URI = ORG_URL_ROOT + "doc_inspector_fission_frame_navigation.html"; add_task(async function () { const { inspector } = await openInspectorForURL(TEST_ORG_URI); const tree = ` id="root" iframe #document html head body id="org"`; // Note: the assertMarkupViewAsTree uses very high level APIs and is similar // to what should happen when a user interacts with the markup view. // It is important to avoid explicitly fetching walkers or node fronts during // the test, as it might cause reparenting of remote frames and make the test // succeed without actually testing that the feature works correctly. await assertMarkupViewAsTree(tree, "#root", inspector); await navigateIframeTo(inspector, EXAMPLE_COM_URI); const treeAfterLoadingCom = ` id="root" iframe #document html head body id="com"`; await assertMarkupViewAsTree(treeAfterLoadingCom, "#root", inspector); await navigateIframeTo(inspector, EXAMPLE_NET_URI); const treeAfterLoadingNet = ` id="root" iframe #document html head body id="net"`; await assertMarkupViewAsTree(treeAfterLoadingNet, "#root", inspector); }); /** * This test will check the behavior when navigating a frame which is not * visible in the markup view, because its parentNode has not been expanded yet. * * We expect a root-node resource to be emitted, but ideally we should not * initialize the walker and inspector actors for the target of this root-node * resource. */ add_task(async function navigateFrameNotExpandedInMarkupView() { if (!isFissionEnabled()) { // This test only makes sense with Fission and remote frames, otherwise the // root-node resource will not be emitted for a frame navigation. return; } const { inspector } = await openInspectorForURL(TEST_ORG_URI); const resourceCommand = inspector.toolbox.resourceCommand; // At this stage the expected layout of the markup view is // v html (expanded) // v body (expanded) // > p (collapsed) // > div (collapsed) // // The iframe we are about to navigate is therefore hidden and we are not // watching it - ie, it is not in the list of known NodeFronts/Actors. const resource = await navigateIframeTo(inspector, EXAMPLE_COM_URI); is( resource.resourceType, resourceCommand.TYPES.ROOT_NODE, "A resource with resourceType ROOT_NODE was received when navigating" ); // This highlights what doesn't work with the current approach. // Since the root-node resource is a NodeFront watched via the WalkerFront, // watching it for a new remote frame target implies initializing the // inspector & walker fronts. // // If the resource was not a front (eg ContentDOMreference?) and was emitted // by the target actor instead of the walker actor, the client can decide if // the inspector and walker fronts should be initialized or not. // // In this test scenario, the children of the iframe were not known by the // inspector before this navigation. Per the explanation above, the new target // should not have an already instantiated inspector front. // // This should be fixed when implementing the RootNode resource on the server // in https://bugzilla.mozilla.org/show_bug.cgi?id=1644190 todo( !resource.targetFront.getCachedFront("inspector"), "The inspector front for the new target should not be initialized" ); }); async function navigateIframeTo(inspector, url) { info("Navigate the test iframe to " + url); const { commands } = inspector; const { resourceCommand } = inspector.toolbox; const onTargetProcessed = waitForTargetProcessed(commands, url); const { onResource: onNewRoot } = await resourceCommand.waitForNextResource( resourceCommand.TYPES.ROOT_NODE, { ignoreExistingResources: true, } ); info("Update the src attribute of the iframe tag"); await SpecialPowers.spawn(gBrowser.selectedBrowser, [url], function (_url) { content.document.querySelector("iframe").setAttribute("src", _url); }); info("Wait for frameLoad/newRoot to resolve"); const newRootResult = await onNewRoot; info("Wait for pending children updates"); await inspector.markup._waitForChildren(); if (isFissionEnabled()) { info("Wait until the new target has been processed by TargetCommand"); await onTargetProcessed; } // Note: the newRootResult changes when the test runs with or without fission. return newRootResult; } /** * Returns a promise that waits until the provided commands's TargetCommand has fully * processed a target with the provided URL. * This will avoid navigating again before the new resource command have fully * attached to the new target. */ function waitForTargetProcessed(commands, url) { return new Promise(resolve => { const onTargetProcessed = targetFront => { if (targetFront.url !== encodeURI(url)) { return; } commands.targetCommand.off( "processed-available-target", onTargetProcessed ); resolve(); }; commands.targetCommand.on("processed-available-target", onTargetProcessed); }); }