browser_targetTopLevelLinkClicksToBlank.js (8933B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 /** 7 * This test exercises the behaviour where user-initiated link clicks on 8 * the top-level document result in pageloads in a _blank target in a new 9 * browser window. 10 */ 11 12 const TEST_PAGE = "https://example.com/browser/"; 13 const TEST_PAGE_2 = "https://example.com/browser/components/"; 14 const TEST_IFRAME_PAGE = 15 getRootDirectory(gTestPath).replace( 16 "chrome://mochitests/content", 17 "https://example.com" 18 ) + "dummy_iframe_page.html"; 19 20 // There is an <a> element with this href=".." in the TEST_PAGE 21 // that we will click, which should take us up a level. 22 const LINK_URL = "https://example.com/"; 23 24 /** 25 * Test that a user-initiated link click results in targeting to a new 26 * <browser> element, and that this properly sets the referrer on the newly 27 * loaded document. 28 */ 29 add_task(async function target_to_new_blank_browser() { 30 let win = await BrowserTestUtils.openNewBrowserWindow(); 31 let originalTab = win.gBrowser.selectedTab; 32 let originalBrowser = originalTab.linkedBrowser; 33 BrowserTestUtils.startLoadingURIString(originalBrowser, TEST_PAGE); 34 await BrowserTestUtils.browserLoaded(originalBrowser, false, TEST_PAGE); 35 36 // Now set the targetTopLevelLinkClicksToBlank property to true, since it 37 // defaults to false. 38 originalBrowser.browsingContext.targetTopLevelLinkClicksToBlank = true; 39 40 let newTabPromise = BrowserTestUtils.waitForNewTab(win.gBrowser, LINK_URL); 41 await SpecialPowers.spawn(originalBrowser, [], async () => { 42 let anchor = content.document.querySelector(`a[href=".."]`); 43 let userInput = content.windowUtils.setHandlingUserInput(true); 44 try { 45 anchor.click(); 46 } finally { 47 userInput.destruct(); 48 } 49 }); 50 let newTab = await newTabPromise; 51 let newBrowser = newTab.linkedBrowser; 52 53 Assert.notStrictEqual( 54 originalBrowser, 55 newBrowser, 56 "A new browser should have been created." 57 ); 58 await SpecialPowers.spawn(newBrowser, [TEST_PAGE], async referrer => { 59 Assert.equal( 60 content.document.referrer, 61 referrer, 62 "Should have gotten the right referrer set" 63 ); 64 }); 65 await BrowserTestUtils.switchTab(win.gBrowser, originalTab); 66 BrowserTestUtils.removeTab(newTab); 67 68 // Now do the same thing with a subframe targeting "_top". This should also 69 // get redirected to "_blank". 70 BrowserTestUtils.startLoadingURIString(originalBrowser, TEST_IFRAME_PAGE); 71 await BrowserTestUtils.browserLoaded( 72 originalBrowser, 73 false, 74 TEST_IFRAME_PAGE 75 ); 76 77 newTabPromise = BrowserTestUtils.waitForNewTab(win.gBrowser, LINK_URL); 78 let frameBC1 = originalBrowser.browsingContext.children[0]; 79 Assert.ok(frameBC1, "Should have found a subframe BrowsingContext"); 80 81 await SpecialPowers.spawn(frameBC1, [LINK_URL], async linkUrl => { 82 let anchor = content.document.createElement("a"); 83 anchor.setAttribute("href", linkUrl); 84 anchor.setAttribute("target", "_top"); 85 content.document.body.appendChild(anchor); 86 let userInput = content.windowUtils.setHandlingUserInput(true); 87 try { 88 anchor.click(); 89 } finally { 90 userInput.destruct(); 91 } 92 }); 93 newTab = await newTabPromise; 94 newBrowser = newTab.linkedBrowser; 95 96 Assert.notStrictEqual( 97 originalBrowser, 98 newBrowser, 99 "A new browser should have been created." 100 ); 101 await SpecialPowers.spawn( 102 newBrowser, 103 [frameBC1.currentURI.spec], 104 async referrer => { 105 Assert.equal( 106 content.document.referrer, 107 referrer, 108 "Should have gotten the right referrer set" 109 ); 110 } 111 ); 112 await BrowserTestUtils.switchTab(win.gBrowser, originalTab); 113 BrowserTestUtils.removeTab(newTab); 114 115 await BrowserTestUtils.closeWindow(win); 116 }); 117 118 /** 119 * Test that we don't target to _blank loads caused by: 120 * 1. POST requests 121 * 2. Any load that isn't "normal" (in the nsIDocShell.LOAD_CMD_NORMAL sense) 122 * 3. Any loads that are caused by location.replace 123 * 4. Any loads that were caused by setting location.href 124 * 5. Link clicks fired without user interaction. 125 */ 126 add_task(async function skip_blank_target_for_some_loads() { 127 let win = await BrowserTestUtils.openNewBrowserWindow(); 128 let currentBrowser = win.gBrowser.selectedBrowser; 129 BrowserTestUtils.startLoadingURIString(currentBrowser, TEST_PAGE); 130 await BrowserTestUtils.browserLoaded(currentBrowser, false, TEST_PAGE); 131 132 // Now set the targetTopLevelLinkClicksToBlank property to true, since it 133 // defaults to false. 134 currentBrowser.browsingContext.targetTopLevelLinkClicksToBlank = true; 135 136 let ensureSingleBrowser = () => { 137 Assert.equal( 138 win.gBrowser.browsers.length, 139 1, 140 "There should only be 1 browser." 141 ); 142 143 Assert.ok( 144 currentBrowser.browsingContext.targetTopLevelLinkClicksToBlank, 145 "Should still be targeting top-level clicks to _blank" 146 ); 147 }; 148 149 // First we'll test a POST request 150 let sameBrowserLoad = BrowserTestUtils.browserLoaded( 151 currentBrowser, 152 false, 153 TEST_PAGE 154 ); 155 await SpecialPowers.spawn(currentBrowser, [], async () => { 156 let doc = content.document; 157 let form = doc.createElement("form"); 158 form.setAttribute("method", "post"); 159 doc.body.appendChild(form); 160 let userInput = content.windowUtils.setHandlingUserInput(true); 161 try { 162 form.submit(); 163 } finally { 164 userInput.destruct(); 165 } 166 }); 167 await sameBrowserLoad; 168 ensureSingleBrowser(); 169 170 // Next, we'll try a non-normal load - specifically, we'll try a reload. 171 // Since we've got a page loaded via a POST request, an attempt to reload 172 // will cause the "repost" dialog to appear, so we temporarily allow the 173 // repost to go through with the always_accept testing pref. 174 await SpecialPowers.pushPrefEnv({ 175 set: [["dom.confirm_repost.testing.always_accept", true]], 176 }); 177 sameBrowserLoad = BrowserTestUtils.browserLoaded( 178 currentBrowser, 179 false, 180 TEST_PAGE 181 ); 182 await SpecialPowers.spawn(currentBrowser, [], async () => { 183 let userInput = content.windowUtils.setHandlingUserInput(true); 184 try { 185 content.location.reload(); 186 } finally { 187 userInput.destruct(); 188 } 189 }); 190 await sameBrowserLoad; 191 ensureSingleBrowser(); 192 await SpecialPowers.popPrefEnv(); 193 194 // Next, we'll try a location.replace 195 sameBrowserLoad = BrowserTestUtils.browserLoaded( 196 currentBrowser, 197 false, 198 TEST_PAGE_2 199 ); 200 await SpecialPowers.spawn(currentBrowser, [TEST_PAGE_2], async page2 => { 201 let userInput = content.windowUtils.setHandlingUserInput(true); 202 try { 203 content.location.replace(page2); 204 } finally { 205 userInput.destruct(); 206 } 207 }); 208 await sameBrowserLoad; 209 ensureSingleBrowser(); 210 211 // Finally we'll try setting location.href 212 sameBrowserLoad = BrowserTestUtils.browserLoaded( 213 currentBrowser, 214 false, 215 TEST_PAGE 216 ); 217 await SpecialPowers.spawn(currentBrowser, [TEST_PAGE], async page1 => { 218 let userInput = content.windowUtils.setHandlingUserInput(true); 219 try { 220 content.location.href = page1; 221 } finally { 222 userInput.destruct(); 223 } 224 }); 225 await sameBrowserLoad; 226 ensureSingleBrowser(); 227 228 // Now that we're back at TEST_PAGE, let's try a scripted link click. This 229 // shouldn't target to _blank. 230 sameBrowserLoad = BrowserTestUtils.browserLoaded( 231 currentBrowser, 232 false, 233 LINK_URL 234 ); 235 await SpecialPowers.spawn(currentBrowser, [], async () => { 236 let anchor = content.document.querySelector(`a[href=".."]`); 237 anchor.click(); 238 }); 239 await sameBrowserLoad; 240 ensureSingleBrowser(); 241 242 // A javascript:void(0); link should also not target to _blank. 243 sameBrowserLoad = BrowserTestUtils.browserLoaded( 244 currentBrowser, 245 false, 246 TEST_PAGE 247 ); 248 await SpecialPowers.spawn(currentBrowser, [TEST_PAGE], async newPageURL => { 249 let anchor = content.document.querySelector(`a[href=".."]`); 250 anchor.href = "javascript:void(0);"; 251 anchor.addEventListener("click", () => { 252 content.location.href = newPageURL; 253 }); 254 let userInput = content.windowUtils.setHandlingUserInput(true); 255 try { 256 anchor.click(); 257 } finally { 258 userInput.destruct(); 259 } 260 }); 261 await sameBrowserLoad; 262 ensureSingleBrowser(); 263 264 // Let's also try a non-void javascript: location. 265 sameBrowserLoad = BrowserTestUtils.browserLoaded( 266 currentBrowser, 267 false, 268 TEST_PAGE 269 ); 270 await SpecialPowers.spawn(currentBrowser, [TEST_PAGE], async newPageURL => { 271 let anchor = content.document.querySelector(`a[href=".."]`); 272 anchor.href = `javascript:"string-to-navigate-to"`; 273 anchor.addEventListener("click", () => { 274 content.location.href = newPageURL; 275 }); 276 let userInput = content.windowUtils.setHandlingUserInput(true); 277 try { 278 anchor.click(); 279 } finally { 280 userInput.destruct(); 281 } 282 }); 283 await sameBrowserLoad; 284 ensureSingleBrowser(); 285 286 await BrowserTestUtils.closeWindow(win); 287 });