browser_inspector_inspect_loading_document.js (5564B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 // Fix blank inspector bug when opening DevTools on a webpage with a document 7 // where document.write is called without ever calling document.close. 8 // Such a document remains forever in the "loading" readyState. See Bug 1765760. 9 10 const TEST_URL = 11 `data:text/html;charset=utf-8,` + 12 encodeURIComponent(` 13 <!DOCTYPE html> 14 <html lang="en"> 15 <body> 16 <div id=outsideframe></div> 17 <script type="text/javascript"> 18 const iframe = document.createElement("iframe"); 19 iframe.src = "about:blank"; 20 iframe.addEventListener('load', () => { 21 iframe.contentDocument.write('<div id=inframe>inframe</div>'); 22 }, true); 23 document.body.appendChild(iframe); 24 </script> 25 </body> 26 </html> 27 `); 28 29 add_task(async function testSlowLoadingFrame() { 30 const loadingTab = BrowserTestUtils.addTab(gBrowser, TEST_URL); 31 gBrowser.selectedTab = loadingTab; 32 33 // Note: we cannot use `await addTab` here because the iframe never finishes 34 // loading. But we still want to wait for the frame to reach the loading state 35 // and to display a test element so that we can reproduce the initial issue 36 // fixed by Bug 1765760. 37 info("Wait for the loading iframe to be ready to test"); 38 await TestUtils.waitForCondition(async () => { 39 try { 40 return await ContentTask.spawn(gBrowser.selectedBrowser, {}, () => { 41 const iframe = content.document.querySelector("iframe"); 42 return ( 43 iframe?.contentDocument.readyState === "loading" && 44 iframe.contentDocument.getElementById("inframe") 45 ); 46 }); 47 } catch (e) { 48 return false; 49 } 50 }); 51 52 const { inspector } = await openInspector(); 53 54 info("Check the markup view displays the loading iframe successfully"); 55 await assertMarkupViewAsTree( 56 ` 57 body 58 div id="outsideframe" 59 script!ignore-children 60 iframe 61 #document 62 html 63 head 64 body 65 div id="inframe"`, 66 "body", 67 inspector 68 ); 69 }); 70 71 add_task(async function testSlowLoadingDocument() { 72 info("Create a test server serving a slow document"); 73 const httpServer = createTestHTTPServer(); 74 httpServer.registerContentType("html", "text/html"); 75 76 // This promise allows to block serving the complete document from the test. 77 let unblockRequest; 78 const onRequestUnblocked = new Promise(r => (unblockRequest = r)); 79 80 httpServer.registerPathHandler(`/`, async function (request, response) { 81 response.processAsync(); 82 response.setStatusLine(request.httpVersion, 200, "OK"); 83 84 // Split the page content in 2 parts: 85 // - opening body tag and the "#start" div will be returned immediately 86 // - "#end" div and closing body tag are blocked on a promise. 87 const page_start = "<body><div id='start'>start</div>"; 88 const page_end = "<div id='end'>end</div></body>"; 89 const page = page_start + page_end; 90 91 response.setHeader("Content-Type", "text/html; charset=utf-8", false); 92 response.setHeader("Content-Length", page.length + "", false); 93 response.write(page_start); 94 95 await onRequestUnblocked; 96 97 response.write(page_end); 98 response.finish(); 99 }); 100 101 const port = httpServer.identity.primaryPort; 102 const TEST_URL_2 = `http://localhost:${port}/`; 103 104 // Same as in the other task, we cannot wait for the full load. 105 info("Open a new tab on TEST_URL_2 and select it"); 106 const loadingTab = BrowserTestUtils.addTab(gBrowser, TEST_URL_2); 107 gBrowser.selectedTab = loadingTab; 108 109 info("Wait for the #start div to be available in the document"); 110 await TestUtils.waitForCondition(async () => { 111 try { 112 return await ContentTask.spawn(gBrowser.selectedBrowser, {}, () => 113 content.document.getElementById("start") 114 ); 115 } catch (e) { 116 return false; 117 } 118 }); 119 120 const { inspector } = await openInspector(); 121 122 info("Check that the inspector is not blank and only shows the #start div"); 123 await assertMarkupViewAsTree( 124 ` 125 body 126 div id="start"`, 127 "body", 128 inspector 129 ); 130 131 // Navigate to about:blank to clean the state. 132 await navigateTo("about:blank"); 133 134 const markuploaded = inspector.once("markuploaded"); 135 const onNewRoot = inspector.once("new-root"); 136 const onUpdated = inspector.once("inspector-updated"); 137 138 await navigateTo(TEST_URL_2, { waitForLoad: false }); 139 info("Wait for the #start div to be available as a markupview container"); 140 await TestUtils.waitForCondition(async () => { 141 const nodeFront = await getNodeFront("#start", inspector); 142 return nodeFront && getContainerForNodeFront(nodeFront, inspector); 143 }); 144 145 info("Check that the inspector is not blank and only shows the #start div"); 146 await assertMarkupViewAsTree( 147 ` 148 body 149 div id="start"`, 150 "body", 151 inspector 152 ); 153 154 info("Unblock the document request"); 155 unblockRequest(); 156 157 info("Wait for the #end div to be available as a markupview container"); 158 await TestUtils.waitForCondition(async () => { 159 const nodeFront = await getNodeFront("#end", inspector); 160 return nodeFront && getContainerForNodeFront(nodeFront, inspector); 161 }); 162 163 info("Check that the inspector will ultimately show the #end div"); 164 await assertMarkupViewAsTree( 165 ` 166 body 167 div id="start" 168 div id="end"`, 169 "body", 170 inspector 171 ); 172 173 info( 174 "Waiting for inspector to update after having released the document load" 175 ); 176 await markuploaded; 177 await onNewRoot; 178 await onUpdated; 179 });