test_blockParsing.html (5437B)
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <title>Test for document.blockParsing</title> 5 <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> 6 <link rel="stylesheet" href="chrome://mochikit/content/tests/SimpleTest/test.css"> 7 </head> 8 <body> 9 <script> 10 const {TestUtils} = ChromeUtils.importESModule( 11 "resource://testing-common/TestUtils.sys.mjs" 12 ); 13 14 async function runTest(url, initialHTML, finalHTML) { 15 let iframe = document.createElement("iframe"); 16 iframe.src = url; 17 18 let blockerPromise; 19 let promise = TestUtils.topicObserved("document-element-inserted", document => { 20 if (document !== iframe.contentDocument) { 21 return false; 22 } 23 24 blockerPromise = new Promise(resolve => { 25 setTimeout(resolve, 0); 26 }).then(() => { 27 return new Promise(resolve => setTimeout(resolve, 0)); 28 }).then(() => { 29 return new Promise(resolve => setTimeout(resolve, 0)); 30 }); 31 32 is(document.documentElement.outerHTML, initialHTML, 33 "Should have initial HTML during document-element-inserted"); 34 is(document.defaultView.wrappedJSObject.scriptRan, undefined, 35 "Script node should not have run"); 36 37 document.blockParsing(blockerPromise); 38 39 return true; 40 }).then(([document]) => { 41 return document; 42 }); 43 44 document.body.appendChild(iframe); 45 46 // Wait for document-element-inserted to fire. 47 let doc = await promise; 48 let win = doc.defaultView.wrappedJSObject; 49 let root = doc.documentElement; 50 51 // At this point, if the parser was successfully blocked, we should still 52 // have the initial skeleton HTML for the page. 53 is(root.outerHTML, initialHTML, "Should have initial HTML after document-element-inserted returns"); 54 is(win.scriptRan, undefined, "Script node should still not have run"); 55 56 await blockerPromise; 57 58 // Just after the promise that's blocking the parser fires, we shouldn't have 59 // returned to the main event loop, so we should still have the initial HTML. 60 is(root.outerHTML, initialHTML, "Should still have initial HTML"); 61 is(win.scriptRan, undefined, "Script node should still not have run"); 62 63 await new Promise(resolve => win.addEventListener("DOMContentLoaded", resolve, {once: true})); 64 65 // Parsing should have resumed, and we should have finished loading the document. 66 is(root.outerHTML, finalHTML, "Should have final HTML"); 67 is(win.scriptRan, true, "Script node should have run"); 68 69 iframe.remove(); 70 } 71 72 add_task(async function() { 73 await runTest("http://mochi.test:8888/chrome/dom/base/test/file_inline_script.html", 74 '<html lang="en"></html>', 75 '<html lang="en"><head>\n <script>window.scriptRan = true;<\/script>\n <meta charset="utf-8">\n <title></title>\n</head>\n<body>\n <p>Hello Mochitest</p>\n\n\n</body></html>'); 76 77 await runTest("http://mochi.test:8888/chrome/dom/base/test/file_inline_script.xhtml", 78 '<html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml"></html>', 79 '<html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">\n<head>\n <script>window.scriptRan = true;<\/script>\n <title></title>\n</head>\n<body>\n <p>Hello Mochitest</p>\n</body>\n</html>'); 80 81 await runTest("http://mochi.test:8888/chrome/dom/base/test/file_external_script.html", 82 '<html lang="en"></html>', 83 '<html lang="en"><head>\n <script src="file_script.js"><\/script>\n <meta charset="utf-8">\n <title></title>\n</head>\n<body>\n <p>Hello Mochitest</p>\n\n\n</body></html>'); 84 85 await runTest("http://mochi.test:8888/chrome/dom/base/test/file_external_script.xhtml", 86 '<html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml"></html>', 87 '<html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">\n<head>\n <script src="file_script.js"><\/script>\n <title></title>\n</head>\n<body>\n <p>Hello Mochitest</p>\n</body>\n</html>'); 88 }); 89 90 add_task(async function test_cleanup() { 91 const TOPIC = "blocking-promise-destroyed"; 92 93 const finalizationWitness = Cc["@mozilla.org/toolkit/finalizationwitness;1"] 94 .getService(Ci.nsIFinalizationWitnessService); 95 96 for (let url of ["http://mochi.test:8888/chrome/dom/base/test/file_inline_script.html", 97 "http://mochi.test:8888/chrome/dom/base/test/file_inline_script.xhtml"]) { 98 let iframe = document.createElement("iframe"); 99 iframe.src = url; 100 101 // Create a promise that never resolves. 102 let blockerPromise = new Promise(() => {}); 103 104 // Create a finalization witness so we can be sure that the promises 105 // have been collected before the end of the test. 106 let destroyedPromise = TestUtils.topicObserved(TOPIC); 107 let witness = finalizationWitness.make(TOPIC, url); 108 blockerPromise.witness = witness; 109 110 let insertedPromise = TestUtils.topicObserved("document-element-inserted", document => { 111 document.blockParsing(blockerPromise).witness = witness; 112 113 return true; 114 }); 115 116 document.body.appendChild(iframe); 117 await insertedPromise; 118 119 // Clear the promise reference, destroy the document, and force GC/CC. This should 120 // trigger any potential leaks or cleanup issues. 121 blockerPromise = null; 122 witness = null; 123 iframe.remove(); 124 125 Cu.forceGC(); 126 Cu.forceCC(); 127 Cu.forceGC(); 128 129 // Make sure the blocker promise has been collected. 130 let [, data] = await destroyedPromise; 131 is(data, url, "Should have correct finalizer URL"); 132 } 133 }); 134 </script> 135 </body> 136 </html>