browser_browsingContext-01.js (5432B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 const URL = "about:blank"; 7 8 async function getBrowsingContextId(browser, id) { 9 return SpecialPowers.spawn(browser, [id], async function (id) { 10 let contextId = content.window.docShell.browsingContext.id; 11 12 let frames = [content.window]; 13 while (frames.length) { 14 let frame = frames.pop(); 15 let target = frame.document.getElementById(id); 16 if (target) { 17 contextId = target.docShell.browsingContext.id; 18 break; 19 } 20 21 frames = frames.concat(Array.from(frame.frames)); 22 } 23 24 return contextId; 25 }); 26 } 27 28 async function addFrame(browser, id, parentId) { 29 return SpecialPowers.spawn( 30 browser, 31 [{ parentId, id }], 32 async function ({ parentId, id }) { 33 let parent = null; 34 if (parentId) { 35 let frames = [content.window]; 36 while (frames.length) { 37 let frame = frames.pop(); 38 let target = frame.document.getElementById(parentId); 39 if (target) { 40 parent = target.contentWindow.document.body; 41 break; 42 } 43 frames = frames.concat(Array.from(frame.frames)); 44 } 45 } else { 46 parent = content.document.body; 47 } 48 49 let frame = await new Promise(resolve => { 50 let frame = content.document.createElement("iframe"); 51 frame.id = id || ""; 52 frame.url = "about:blank"; 53 frame.onload = () => resolve(frame); 54 parent.appendChild(frame); 55 }); 56 57 return frame.contentWindow.docShell.browsingContext.id; 58 } 59 ); 60 } 61 62 async function removeFrame(browser, id) { 63 return SpecialPowers.spawn(browser, [id], async function (id) { 64 let frames = [content.window]; 65 while (frames.length) { 66 let frame = frames.pop(); 67 let target = frame.document.getElementById(id); 68 if (target) { 69 target.remove(); 70 break; 71 } 72 73 frames = frames.concat(Array.from(frame.frames)); 74 } 75 }); 76 } 77 78 function getBrowsingContextById(id) { 79 return BrowsingContext.get(id); 80 } 81 82 add_task(async function () { 83 await BrowserTestUtils.withNewTab( 84 { gBrowser, url: URL }, 85 async function (browser) { 86 let topId = await getBrowsingContextId(browser, ""); 87 let topContext = getBrowsingContextById(topId); 88 isnot(topContext, null); 89 is(topContext.parent, null); 90 is( 91 topId, 92 browser.browsingContext.id, 93 "<browser> has the correct browsingContext" 94 ); 95 is( 96 browser.browserId, 97 topContext.browserId, 98 "browsing context should have a correct <browser> id" 99 ); 100 101 let id0 = await addFrame(browser, "frame0"); 102 let browsingContext0 = getBrowsingContextById(id0); 103 isnot(browsingContext0, null); 104 is(browsingContext0.parent, topContext); 105 106 await removeFrame(browser, "frame0"); 107 108 is(topContext.children.indexOf(browsingContext0), -1); 109 110 // TODO(farre): Handle browsingContext removal [see Bug 1486719]. 111 todo_isnot(browsingContext0.parent, topContext); 112 } 113 ); 114 }); 115 116 add_task(async function () { 117 // If Fission is disabled, the pref is no-op. 118 await SpecialPowers.pushPrefEnv({ set: [["fission.bfcacheInParent", true]] }); 119 120 await BrowserTestUtils.withNewTab( 121 { 122 gBrowser, 123 url: 124 getRootDirectory(gTestPath).replace( 125 "chrome://mochitests/content", 126 // eslint-disable-next-line @microsoft/sdl/no-insecure-url 127 "http://example.com" 128 ) + "dummy_page.html", 129 }, 130 async function (browser) { 131 let path = getRootDirectory(gTestPath).replace( 132 "chrome://mochitests/content", 133 // eslint-disable-next-line @microsoft/sdl/no-insecure-url 134 "http://example.com" 135 ); 136 await SpecialPowers.spawn(browser, [path], async function (path) { 137 var bc = new content.BroadcastChannel("browser_browsingContext"); 138 function waitForMessage(command) { 139 let p = new Promise(resolve => { 140 bc.addEventListener("message", e => resolve(e), { once: true }); 141 }); 142 command(); 143 return p; 144 } 145 146 // Open a new window and wait for the message. 147 let e1 = await waitForMessage(_ => 148 content.window.open(path + "onpageshow_message.html", "", "noopener") 149 ); 150 151 is(e1.data, "pageshow", "Got page show"); 152 153 let e2 = await waitForMessage(_ => bc.postMessage("createiframe")); 154 is(e2.data.framesLength, 1, "Here we should have an iframe"); 155 156 let e3 = await waitForMessage(_ => bc.postMessage("nextpage")); 157 158 is(e3.data.event, "load"); 159 is(e3.data.framesLength, 0, "Here there shouldn't be an iframe"); 160 161 // Return to the previous document. N.B. we expect to trigger 162 // BFCache here, hence we wait for pageshow. 163 let e4 = await waitForMessage(_ => bc.postMessage("back")); 164 165 is(e4.data, "pageshow"); 166 167 let e5 = await waitForMessage(_ => bc.postMessage("queryframes")); 168 is(e5.data.framesLength, 1, "And again there should be an iframe"); 169 170 is(e5.outerWindowId, e2.outerWindowId, "BF cache cached outer window"); 171 is(e5.browsingContextId, e2.browsingContextId, "BF cache cached BC"); 172 173 let e6 = await waitForMessage(_ => bc.postMessage("close")); 174 is(e6.data, "closed"); 175 176 bc.close(); 177 }); 178 } 179 ); 180 });