diff options
Diffstat (limited to '')
-rw-r--r-- | browser/actors/test/browser/browser.ini | 4 | ||||
-rw-r--r-- | browser/actors/test/browser/browser_nested_link_clicks.js | 45 | ||||
-rw-r--r-- | browser/actors/test/browser/browser_untrusted_click_event.js | 107 | ||||
-rw-r--r-- | browser/actors/test/browser/click.html | 76 |
4 files changed, 232 insertions, 0 deletions
diff --git a/browser/actors/test/browser/browser.ini b/browser/actors/test/browser/browser.ini new file mode 100644 index 0000000000..586e4962e8 --- /dev/null +++ b/browser/actors/test/browser/browser.ini @@ -0,0 +1,4 @@ +[browser_nested_link_clicks.js] +[browser_untrusted_click_event.js] +support-files = + click.html diff --git a/browser/actors/test/browser/browser_nested_link_clicks.js b/browser/actors/test/browser/browser_nested_link_clicks.js new file mode 100644 index 0000000000..32ac6a4685 --- /dev/null +++ b/browser/actors/test/browser/browser_nested_link_clicks.js @@ -0,0 +1,45 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Nested links should only open a single tab when ctrl-clicked. + */ +add_task(async function nested_link_click_opens_single_tab() { + await BrowserTestUtils.withNewTab( + "https://example.com/empty", + async browser => { + await SpecialPowers.spawn(browser, [], () => { + let doc = content.document; + let outerLink = doc.createElement("a"); + outerLink.href = "https://mozilla.org/"; + let link = doc.createElement("a"); + link.href = "https://example.org/linked"; + link.textContent = "Click me"; + link.id = "mylink"; + outerLink.append(link); + doc.body.append(outerLink); + }); + + let startingNumberOfTabs = gBrowser.tabs.length; + let newTabPromise = BrowserTestUtils.waitForNewTab( + gBrowser, + "https://example.org/linked", + true + ); + await BrowserTestUtils.synthesizeMouseAtCenter( + "#mylink", + { accelKey: true }, + browser + ); + let tab = await newTabPromise; + is( + gBrowser.tabs.length, + startingNumberOfTabs + 1, + "Should only have opened 1 tab." + ); + BrowserTestUtils.removeTab(tab); + } + ); +}); diff --git a/browser/actors/test/browser/browser_untrusted_click_event.js b/browser/actors/test/browser/browser_untrusted_click_event.js new file mode 100644 index 0000000000..7bb579223d --- /dev/null +++ b/browser/actors/test/browser/browser_untrusted_click_event.js @@ -0,0 +1,107 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const TEST_PATH = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "https://example.com" +); + +/** + * Ensure that click handlers that prevent the default action but fire + * a different click event that does open a tab are allowed to work. + */ +add_task(async function test_untrusted_click_opens_tab() { + await BrowserTestUtils.withNewTab(TEST_PATH + "click.html", async browser => { + let newTabOpened = BrowserTestUtils.waitForNewTab( + gBrowser, + "https://example.org/", + true + ); + info("clicking link with modifier pressed."); + let eventObj = {}; + eventObj[AppConstants.platform == "macosx" ? "metaKey" : "ctrlKey"] = true; + await BrowserTestUtils.synthesizeMouseAtCenter("#test", eventObj, browser); + info( + "Waiting for new tab to open from frontend; if we timeout the test is broken." + ); + let newTab = await newTabOpened; + ok(newTab, "New tab should be opened."); + BrowserTestUtils.removeTab(newTab); + }); +}); + +/** + * Ensure that click handlers that redirect a modifier-less click into + * an untrusted event without modifiers don't run afoul of the popup + * blocker by having their transient user gesture bit consumed in the + * child by the handling code for modified clicks. + */ +add_task(async function test_unused_click_doesnt_consume_activation() { + // Enable the popup blocker. + await SpecialPowers.pushPrefEnv({ + set: [ + ["dom.disable_open_during_load", true], + ["dom.block_multiple_popups", true], + ], + }); + await BrowserTestUtils.withNewTab(TEST_PATH + "click.html", async browser => { + let newTabOpened = BrowserTestUtils.waitForNewTab( + gBrowser, + "https://example.com/", + true + ); + info("clicking button that generates link press."); + await BrowserTestUtils.synthesizeMouseAtCenter( + "#fire-untrusted", + {}, + browser + ); + info( + "Waiting for new tab to open through gecko; if we timeout the test is broken." + ); + let newTab = await newTabOpened; + ok(newTab, "New tab should be opened."); + BrowserTestUtils.removeTab(newTab); + }); +}); + +/** + * Ensure that click handlers redirecting to elements without href don't + * trigger user gesture consumption either. + */ +add_task(async function test_click_without_href_doesnt_consume_activation() { + // Enable the popup blocker. + await SpecialPowers.pushPrefEnv({ + set: [ + ["dom.disable_open_during_load", true], + ["dom.block_multiple_popups", true], + ], + }); + await BrowserTestUtils.withNewTab(TEST_PATH + "click.html", async browser => { + let newTabOpened = BrowserTestUtils.waitForNewTab(gBrowser, "about:blank"); + info("clicking link that generates link click on target-less link."); + await BrowserTestUtils.synthesizeMouseAtCenter( + "#fire-targetless-link", + {}, + browser + ); + info( + "Waiting for new tab to open after targetless link; if we timeout the test is broken." + ); + let newTab = await newTabOpened; + ok(newTab, "New tab should be opened."); + BrowserTestUtils.removeTab(newTab); + + newTabOpened = BrowserTestUtils.waitForNewTab(gBrowser, "about:blank"); + info("clicking link that generates button click."); + await BrowserTestUtils.synthesizeMouseAtCenter("#fire-button", {}, browser); + info( + "Waiting for new tab to open after button redirect; if we timeout the test is broken." + ); + newTab = await newTabOpened; + ok(newTab, "New tab should be opened."); + BrowserTestUtils.removeTab(newTab); + }); +}); diff --git a/browser/actors/test/browser/click.html b/browser/actors/test/browser/click.html new file mode 100644 index 0000000000..42afdf8050 --- /dev/null +++ b/browser/actors/test/browser/click.html @@ -0,0 +1,76 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <title>Click a link whose event we intercept</title> +</head> +<body> + +<a id="test" href="https://example.com/">click me</a><br><br> + +<a id="untrusted-only" href="https://example.com/" target="_blank">This is a link, works only with untrusted events</a><br> +<input id="fire-untrusted" type=button value="Click me to trigger an untrusted event"><br><br> + +<a id="fire-targetless-link" href="unused">Click me (dispatch untrusted event to link without href)</a><br> +<a id="fire-button" href="unused">Click me (dispatch untrusted event to button)</a> + +<script> + + document.getElementById("test").addEventListener("click", originalClick => { + const newLink = document.createElement("a"); + newLink.setAttribute("rel", "noreferrer"); + newLink.setAttribute("target", "_blank"); + newLink.setAttribute("href", "https://example.org/"); + + + document.body.appendChild(newLink); + + const evt = document.createEvent('MouseEvent'); + evt.initMouseEvent( + "click", true, true, window, 0, + originalClick.screenX, originalClick.screenY, originalClick.clientX, originalClick.clientY, + originalClick.ctrlKey, originalClick.altKey, originalClick.shiftKey, originalClick.metaKey, + originalClick.button, originalClick.relatedTarget + ); + newLink.dispatchEvent(evt); + + + originalClick.preventDefault(); + originalClick.stopPropagation(); + }); + + document.getElementById("untrusted-only").addEventListener("click", ev => { + if (ev.isTrusted) { + ev.preventDefault(); + } + }); + + document.getElementById("fire-untrusted").addEventListener("click", () => { + document.getElementById("untrusted-only").dispatchEvent(new MouseEvent("click")); + }); + + function handleTargetless(e) { + e.preventDefault(); + e.stopPropagation(); + + const buttonOrLink = e.target.id.includes("button") ? "button" : "a"; + const newElement = document.createElement(buttonOrLink); + document.body.appendChild(newElement); + + const evt = document.createEvent("MouseEvent"); + evt.initMouseEvent("click", true, true, window, 0, e.screenX, e.screenY, + e.clientX, e.clientY, e.ctrlKey, e.altKey, e.shiftKey, + e.metaKey, e.button, e.relatedTarget); + newElement.dispatchEvent(evt); + newElement.remove(); + + setTimeout(() => { + window.open(); + }, 0); + } + document.getElementById("fire-targetless-link").addEventListener("click", handleTargetless); + document.getElementById("fire-button").addEventListener("click", handleTargetless); + +</script> +</body> +</html> |