browser_inspector_fission_frame_navigation.js (5516B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 "use strict"; 4 5 const EXAMPLE_COM_URI = 6 "https://example.com/document-builder.sjs?html=<div id=com>com"; 7 const EXAMPLE_NET_URI = 8 "https://example.net/document-builder.sjs?html=<div id=net>net"; 9 10 const ORG_URL_ROOT = URL_ROOT.replace("example.com", "example.org"); 11 const TEST_ORG_URI = 12 ORG_URL_ROOT + "doc_inspector_fission_frame_navigation.html"; 13 14 add_task(async function () { 15 const { inspector } = await openInspectorForURL(TEST_ORG_URI); 16 const tree = ` 17 id="root" 18 iframe 19 #document 20 html 21 head 22 body 23 id="org"`; 24 // Note: the assertMarkupViewAsTree uses very high level APIs and is similar 25 // to what should happen when a user interacts with the markup view. 26 // It is important to avoid explicitly fetching walkers or node fronts during 27 // the test, as it might cause reparenting of remote frames and make the test 28 // succeed without actually testing that the feature works correctly. 29 await assertMarkupViewAsTree(tree, "#root", inspector); 30 31 await navigateIframeTo(inspector, EXAMPLE_COM_URI); 32 const treeAfterLoadingCom = ` 33 id="root" 34 iframe 35 #document 36 html 37 head 38 body 39 id="com"`; 40 await assertMarkupViewAsTree(treeAfterLoadingCom, "#root", inspector); 41 42 await navigateIframeTo(inspector, EXAMPLE_NET_URI); 43 const treeAfterLoadingNet = ` 44 id="root" 45 iframe 46 #document 47 html 48 head 49 body 50 id="net"`; 51 await assertMarkupViewAsTree(treeAfterLoadingNet, "#root", inspector); 52 }); 53 54 /** 55 * This test will check the behavior when navigating a frame which is not 56 * visible in the markup view, because its parentNode has not been expanded yet. 57 * 58 * We expect a root-node resource to be emitted, but ideally we should not 59 * initialize the walker and inspector actors for the target of this root-node 60 * resource. 61 */ 62 add_task(async function navigateFrameNotExpandedInMarkupView() { 63 const { inspector } = await openInspectorForURL(TEST_ORG_URI); 64 const { resourceCommand } = inspector.commands; 65 66 // At this stage the expected layout of the markup view is 67 // v html (expanded) 68 // v body (expanded) 69 // > p (collapsed) 70 // > div (collapsed) 71 // 72 // The iframe we are about to navigate is therefore hidden and we are not 73 // watching it - ie, it is not in the list of known NodeFronts/Actors. 74 const resource = await navigateIframeTo(inspector, EXAMPLE_COM_URI); 75 76 is( 77 resource.resourceType, 78 resourceCommand.TYPES.ROOT_NODE, 79 "A resource with resourceType ROOT_NODE was received when navigating" 80 ); 81 82 // This highlights what doesn't work with the current approach. 83 // Since the root-node resource is a NodeFront watched via the WalkerFront, 84 // watching it for a new remote frame target implies initializing the 85 // inspector & walker fronts. 86 // 87 // If the resource was not a front (eg ContentDOMreference?) and was emitted 88 // by the target actor instead of the walker actor, the client can decide if 89 // the inspector and walker fronts should be initialized or not. 90 // 91 // In this test scenario, the children of the iframe were not known by the 92 // inspector before this navigation. Per the explanation above, the new target 93 // should not have an already instantiated inspector front. 94 // 95 // This should be fixed when implementing the RootNode resource on the server 96 // in https://bugzilla.mozilla.org/show_bug.cgi?id=1644190 97 todo( 98 !resource.targetFront.getCachedFront("inspector"), 99 "The inspector front for the new target should not be initialized" 100 ); 101 }); 102 103 async function navigateIframeTo(inspector, url) { 104 info("Navigate the test iframe to " + url); 105 106 const { commands } = inspector; 107 const { resourceCommand } = inspector.commands; 108 const onTargetProcessed = waitForTargetProcessed(commands, url); 109 110 const { onResource: onNewRoot } = await resourceCommand.waitForNextResource( 111 resourceCommand.TYPES.ROOT_NODE, 112 { 113 ignoreExistingResources: true, 114 predicate: resource => resource.targetFront.url === encodeURI(url), 115 } 116 ); 117 118 info("Update the src attribute of the iframe tag"); 119 await SpecialPowers.spawn(gBrowser.selectedBrowser, [url], function (_url) { 120 content.document.querySelector("iframe").setAttribute("src", _url); 121 }); 122 123 info("Wait for frameLoad/newRoot to resolve"); 124 const newRootResult = await onNewRoot; 125 126 info("Wait for pending children updates"); 127 await inspector.markup._waitForChildren(); 128 129 info("Wait until the new target has been processed by TargetCommand"); 130 await onTargetProcessed; 131 132 // Note: the newRootResult changes when the test runs with or without fission. 133 return newRootResult; 134 } 135 136 /** 137 * Returns a promise that waits until the provided commands's TargetCommand has fully 138 * processed a target with the provided URL. 139 * This will avoid navigating again before the new resource command have fully 140 * attached to the new target. 141 */ 142 function waitForTargetProcessed(commands, url) { 143 return new Promise(resolve => { 144 const onTargetProcessed = targetFront => { 145 if (targetFront.url !== encodeURI(url)) { 146 return; 147 } 148 commands.targetCommand.off( 149 "processed-available-target", 150 onTargetProcessed 151 ); 152 resolve(); 153 }; 154 commands.targetCommand.on("processed-available-target", onTargetProcessed); 155 }); 156 }