diff options
Diffstat (limited to 'dom/events/test')
12 files changed, 407 insertions, 37 deletions
diff --git a/dom/events/test/clipboard/browser_navigator_clipboard_contextmenu_suppression.js b/dom/events/test/clipboard/browser_navigator_clipboard_contextmenu_suppression.js index f504e499c9..97066cd2eb 100644 --- a/dom/events/test/clipboard/browser_navigator_clipboard_contextmenu_suppression.js +++ b/dom/events/test/clipboard/browser_navigator_clipboard_contextmenu_suppression.js @@ -238,16 +238,10 @@ add_task(async function test_context_menu_suppression_image() { await pasteButtonIsShown; info("Test read from same-origin frame before paste contextmenu is closed"); - const clipboarCacheEnabled = SpecialPowers.getBoolPref( - "widget.clipboard.use-cached-data.enabled", - false - ); // If the cached data is used, it uses type order in cached transferable. SimpleTest.isDeeply( await readTypes(browser.browsingContext.children[0]), - clipboarCacheEnabled - ? ["text/plain", "text/html", "image/png"] - : ["text/html", "text/plain", "image/png"], + ["text/html", "text/plain", "image/png"], "read from same-origin should just be resolved without showing paste contextmenu shown" ); @@ -262,3 +256,158 @@ add_task(async function test_context_menu_suppression_image() { ); }); }); + +function testPasteContextMenuSuppressionPasteEvent( + aTriggerPasteFun, + aSuppress, + aMsg +) { + add_task(async function test_context_menu_suppression_paste_event() { + await BrowserTestUtils.withNewTab( + kContentFileUrl, + async function (browser) { + info(`Write data by in cross-origin frame`); + const clipboardText = "X" + Math.random(); + await SpecialPowers.spawn( + browser.browsingContext.children[1], + [clipboardText], + async text => { + content.document.notifyUserGestureActivation(); + return content.eval(`navigator.clipboard.writeText("${text}");`); + } + ); + + info("Test read should show contextmenu"); + let pasteButtonIsShown = waitForPasteContextMenu(); + let readTextRequest = readText(browser); + await pasteButtonIsShown; + + info("Click paste button, request should be resolved"); + await promiseClickPasteButton(); + is(await readTextRequest, clipboardText, "Request should be resolved"); + + info("Test read in paste event handler"); + readTextRequest = SpecialPowers.spawn(browser, [], async () => { + content.document.notifyUserGestureActivation(); + return content.eval(` + (() => { + return new Promise(resolve => { + document.addEventListener("paste", function(e) { + e.preventDefault(); + resolve(navigator.clipboard.readText()); + }, { once: true }); + }); + })(); + `); + }); + + if (aSuppress) { + let listener = function (e) { + if (e.target.getAttribute("id") == kPasteMenuPopupId) { + ok(!aSuppress, "paste contextmenu should not be shown"); + } + }; + document.addEventListener("popupshown", listener); + info(`Trigger paste event by ${aMsg}`); + // trigger paste event + await aTriggerPasteFun(browser); + is( + await readTextRequest, + clipboardText, + "Request should be resolved" + ); + document.removeEventListener("popupshown", listener); + } else { + let pasteButtonIsShown = waitForPasteContextMenu(); + info( + `Trigger paste event by ${aMsg}, read should still show contextmenu` + ); + // trigger paste event + await aTriggerPasteFun(browser); + await pasteButtonIsShown; + + info("Click paste button, request should be resolved"); + await promiseClickPasteButton(); + is( + await readTextRequest, + clipboardText, + "Request should be resolved" + ); + } + + info("Test read should still show contextmenu"); + pasteButtonIsShown = waitForPasteContextMenu(); + readTextRequest = readText(browser); + await pasteButtonIsShown; + + info("Click paste button, request should be resolved"); + await promiseClickPasteButton(); + is(await readTextRequest, clipboardText, "Request should be resolved"); + } + ); + }); +} + +// If platform supports selection clipboard, the middle click paste the content +// from selection clipboard instead, in such case, we don't suppress the +// contextmenu when access global clipboard via async clipboard API. +if ( + !Services.clipboard.isClipboardTypeSupported( + Services.clipboard.kSelectionClipboard + ) +) { + testPasteContextMenuSuppressionPasteEvent( + async browser => { + await SpecialPowers.pushPrefEnv({ + set: [["middlemouse.paste", true]], + }); + + await SpecialPowers.spawn(browser, [], async () => { + EventUtils.synthesizeMouse( + content.document.documentElement, + 1, + 1, + { button: 1 }, + content.window + ); + }); + }, + true, + "middle click" + ); +} + +testPasteContextMenuSuppressionPasteEvent( + async browser => { + await EventUtils.synthesizeAndWaitKey( + "v", + kIsMac ? { accelKey: true } : { ctrlKey: true } + ); + }, + true, + "keyboard shortcut" +); + +testPasteContextMenuSuppressionPasteEvent( + async browser => { + await SpecialPowers.spawn(browser, [], async () => { + return SpecialPowers.doCommand(content.window, "cmd_paste"); + }); + }, + true, + "paste command" +); + +testPasteContextMenuSuppressionPasteEvent( + async browser => { + await SpecialPowers.spawn(browser, [], async () => { + let div = content.document.createElement("div"); + div.setAttribute("contenteditable", "true"); + content.document.documentElement.appendChild(div); + div.focus(); + return SpecialPowers.doCommand(content.window, "cmd_pasteNoFormatting"); + }); + }, + false, + "pasteNoFormatting command" +); diff --git a/dom/events/test/mochitest.toml b/dom/events/test/mochitest.toml index b6b9e58368..53675a8f49 100644 --- a/dom/events/test/mochitest.toml +++ b/dom/events/test/mochitest.toml @@ -472,6 +472,9 @@ skip-if = [ "http2", ] +["test_mouse_events_after_touchend.html"] +skip-if = ["os == 'mac'"] # Bug 1881864 + ["test_mouse_over_at_removing_down_target.html"] ["test_moving_and_expanding_selection_per_page.html"] diff --git a/dom/events/test/pointerevents/mochitest_support_external.js b/dom/events/test/pointerevents/mochitest_support_external.js index 7f22166fdd..7a758a8c5f 100644 --- a/dom/events/test/pointerevents/mochitest_support_external.js +++ b/dom/events/test/pointerevents/mochitest_support_external.js @@ -2,6 +2,8 @@ // to tests on auto MochiTest system with minimum changes. // Author: Maksim Lebedev <alessarik@gmail.com> +/* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */ + // Function allows to prepare our tests after load document addEventListener( "load", diff --git a/dom/events/test/pointerevents/test_bug1315862.html b/dom/events/test/pointerevents/test_bug1315862.html index 92d61a518f..657947c156 100644 --- a/dom/events/test/pointerevents/test_bug1315862.html +++ b/dom/events/test/pointerevents/test_bug1315862.html @@ -36,10 +36,10 @@ function runTests() { let target = iframe.contentDocument.body.firstChild;
allPointerEvents.forEach((event, idx, arr) => {
- SpecialPowers.addSystemEventListener(target, event, () => {
+ SpecialPowers.wrap(target).addEventListener(event, () => {
ok(false, "Shouldn't dispatch " + event + " in the system group");
receivePointerEvents = true;
- });
+ }, { mozSystemGroup: true });
});
target.addEventListener("pointerdown", (e) => {
target.setPointerCapture(e.pointerId);
diff --git a/dom/events/test/test_accesskey.html b/dom/events/test/test_accesskey.html index cdfff54a28..4d382f2270 100644 --- a/dom/events/test/test_accesskey.html +++ b/dom/events/test/test_accesskey.html @@ -143,7 +143,7 @@ add_task(async function modifyAccessKey() { add_task(async function file_picker() { const file = document.getElementById("file"); const MockFilePicker = SpecialPowers.MockFilePicker; - MockFilePicker.init(window); + MockFilePicker.init(SpecialPowers.wrap(window).browsingContext); MockFilePicker.returnValue = MockFilePicker.returnCancel; let clicked = false; diff --git a/dom/events/test/test_bug226361.xhtml b/dom/events/test/test_bug226361.xhtml index 143a485757..c2c19ee2a7 100644 --- a/dom/events/test/test_bug226361.xhtml +++ b/dom/events/test/test_bug226361.xhtml @@ -20,7 +20,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=226361 </p> <div id="content" style="display: none"> - + </div> <pre id="test"> <script type="application/javascript"> @@ -43,8 +43,11 @@ function tab_to(id) { } function tab_iframe() { - doc = document; - tab_to('iframe'); + let canTabMoveFocusToRootElement = !SpecialPowers.getBoolPref("dom.disable_tab_focus_to_root_element"); + if (canTabMoveFocusToRootElement) { + doc = document; + tab_to('iframe'); + } // inside iframe doc = document.getElementById('iframe').contentDocument diff --git a/dom/events/test/test_bug238987.html b/dom/events/test/test_bug238987.html index b2712a25d0..34f870eeac 100644 --- a/dom/events/test/test_bug238987.html +++ b/dom/events/test/test_bug238987.html @@ -22,7 +22,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=238987 var shouldStop = false; var activateShift = false; - var expectedResult = "i1,i2,i3,i4,i5,i6,i7,i8,number,i9,i10,i11,i12"; + var expectedResult = "i1,i2,i3,i4,i5,i7,i8,number,i9,i10,i11,i12"; var forwardFocusArray = expectedResult.split(","); var backwardFocusArray = expectedResult.split(","); var forwardBlurArray = expectedResult.split(","); diff --git a/dom/events/test/test_bug336682.js b/dom/events/test/test_bug336682.js index e673f1eb99..11bd7d46bb 100644 --- a/dom/events/test/test_bug336682.js +++ b/dom/events/test/test_bug336682.js @@ -4,6 +4,8 @@ * Any copyright is dedicated to the Public Domain. * http://creativecommons.org/licenses/publicdomain/ */ +/* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */ + var gState = 0; /** * After all the on/offline handlers run, diff --git a/dom/events/test/test_bug448602.html b/dom/events/test/test_bug448602.html index 18b4cb2d2f..452a361a52 100644 --- a/dom/events/test/test_bug448602.html +++ b/dom/events/test/test_bug448602.html @@ -174,28 +174,7 @@ function runTests() { is(SpecialPowers.unwrap(infos[0].listenerObject), l, "Should have the right listener object (4)"); - // Event target chain tests l3 = document.getElementById("testlevel3"); - var textnode = l3.firstChild; - var chain = els.getEventTargetChainFor(textnode, true); - ok(chain.length > 3, "Too short event target chain."); - ok(SpecialPowers.compare(chain[0], textnode), "Wrong chain item (1)"); - ok(SpecialPowers.compare(chain[1], l3), "Wrong chain item (2)"); - ok(SpecialPowers.compare(chain[2], l2), "Wrong chain item (3)"); - ok(SpecialPowers.compare(chain[3], root), "Wrong chain item (4)"); - - var hasDocumentInChain = false; - var hasWindowInChain = false; - for (var i = 0; i < chain.length; ++i) { - if (SpecialPowers.compare(chain[i], document)) { - hasDocumentInChain = true; - } else if (SpecialPowers.compare(chain[i], window)) { - hasWindowInChain = true; - } - } - - ok(hasDocumentInChain, "Should have document in event target chain!"); - ok(hasWindowInChain, "Should have window in event target chain!"); try { els.getListenerInfoFor(null); diff --git a/dom/events/test/test_mouse_events_after_touchend.html b/dom/events/test/test_mouse_events_after_touchend.html new file mode 100644 index 0000000000..146c37e489 --- /dev/null +++ b/dom/events/test/test_mouse_events_after_touchend.html @@ -0,0 +1,232 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"> +<meta name="viewport" content="width=device-width, initial-scale=1.0"> +<title>Tests for mouse events after touchend</title> +<script src="/tests/SimpleTest/SimpleTest.js"></script> +<script src="/tests/SimpleTest/EventUtils.js"></script> +<script src="/tests/SimpleTest/paint_listener.js"></script> +<script src="/tests/gfx/layers/apz/test/mochitest/apz_test_utils.js"></script> +<script src="/tests/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js"></script> +<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +<style> +#parent, #child { + width: 300px; + height: 64px; + padding: 16px; +} +#parent { + background-color: black; +} +#child { + background-color: gray; +} +</style> +<script> +"use strict"; + +SimpleTest.waitForExplicitFinish(); +SimpleTest.requestFlakyTimeout("Required for waiting to prevent double tap at second tap"); +SimpleTest.waitForFocus(async () => { + function stringifyEvent(event) { + return `{ type: ${event.type}, target: ${ + event.target.id || event.target.nodeName + }${ + event.detail !== undefined ? `, detail: ${event.detail}` : "" + }${ + event.button !== undefined ? `, button: ${event.button}` : "" + }${ + event.buttons !== undefined ? `, buttons: ${event.buttons}` : "" + } }`; + } + function stringifyEvents(arrayOfEvents) { + if (!arrayOfEvents.length) { + return "[]"; + } + let ret = ""; + for (const event of arrayOfEvents) { + if (ret === "") { + ret = "[ "; + } else { + ret += ", "; + } + ret += stringifyEvent(event); + } + return ret + " ]"; + } + + let events = []; + for (const type of ["mousemove", + "mousedown", + "mouseup", + "click", + "dblclick", + "contextmenu", + "touchend"]) { + if (type == "touchend") { + addEventListener(type, event => { + info(`Received: ${stringifyEvent(event)}`); + events.push({type, target: event.target}); + }, {capture: true}); + } else { + addEventListener(type, event => { + info(`Received: ${stringifyEvent(event)}`); + events.push({ + type: event.type, + target: event.target, + detail: event.detail, + button: event.button, + buttons: event.buttons, + }); + }, {capture: true}); + } + } + + function shiftEventsBefore(arrayOfEvents, aType) { + const index = arrayOfEvents.findIndex(event => event.type == aType); + if (index <= 0) { + return []; + } + let ret = []; + for (let i = 0; i < index; i++) { + ret.push(arrayOfEvents.shift()); + } + return ret; + } + + const parent = document.getElementById("parent"); + const child = document.getElementById("child"); + + function promiseEvent(aType) { + return new Promise(resolve => + addEventListener(aType, resolve, {once: true}) + ); + } + + async function promiseFlushingAPZGestureState() { + await promiseApzFlushedRepaints(); + // Wait for a while to avoid that the next tap will be treated as 2nd tap of + // a double tap. + return new Promise( + resolve => setTimeout( + resolve, + // NOTE: x1.0 is not enough to avoid intermittent failures. + SpecialPowers.getIntPref("apz.max_tap_time") * 1.2 + ) + ); + } + + await waitUntilApzStable(); + for (const prefValue of [true, false]) { + await SpecialPowers.pushPrefEnv({ + set: [ + ["test.events.async.enabled", prefValue], + ["ui.click_hold_context_menus.delay", 15000], // disable long tap + ] + }); + const desc = `(test.events.async.enabled=${prefValue})`; + + await (async function test_single_tap() { + await promiseFlushingAPZGestureState(); + info("test_single_tap: testing..."); + events = []; + const waitForClick = promiseEvent("click"); + synthesizeTouch(child, 5, 5); + await waitForClick; + is( + stringifyEvents(events), + stringifyEvents([ + { type: "touchend", target: child }, + { type: "mousemove", target: child, detail: 0, button: 0, buttons: 0 }, + { type: "mousedown", target: child, detail: 1, button: 0, buttons: 1 }, + { type: "mouseup", target: child, detail: 1, button: 0, buttons: 0 }, + { type: "click", target: child, detail: 1, button: 0, buttons: 0 }, + ]), + `Single tap should cause a click ${desc}` + ); + })(); + + await (async function test_single_tap_with_consuming_touchstart() { + await promiseFlushingAPZGestureState(); + info("test_single_tap_with_consuming_touchstart: testing..."); + events = []; + const waitForTouchEnd = promiseEvent("touchend"); + child.addEventListener("touchstart", event => { + event.preventDefault(); + }, {once: true}); + synthesizeTouch(child, 5, 5); + await waitForTouchEnd; + const result = stringifyEvents(events); + const expected = stringifyEvents([{ type: "touchend", target: child }]); + // If testing this with APZ, the result is really unstable. Let's allow to + // fail for now. + (prefValue && result != expected ? todo_is : is)( + result, + expected, + `Single tap should not cause mouse events if touchstart is consumed ${desc}` + ); + })(); + + + await (async function test_single_tap_with_consuming_touchend() { + await promiseFlushingAPZGestureState(); + info("test_single_tap_with_consuming_touchend: testing..."); + events = []; + const waitForTouchEnd = promiseEvent("touchend"); + child.addEventListener("touchend", event => { + event.preventDefault(); + }, {once: true}); + synthesizeTouch(child, 5, 5); + await waitForTouchEnd; + is( + stringifyEvents(shiftEventsBefore(events)), + stringifyEvents([]), + `test_single_tap_with_consuming_touchstart() shouldn't cause mouse events after touchend` + ) + is( + stringifyEvents(events), + stringifyEvents([ + { type: "touchend", target: child }, + ]), + `Single tap should not cause mouse events if touchend is consumed ${desc}` + ); + })(); + + await (async function test_multi_touch() { + await promiseFlushingAPZGestureState(); + events = []; + info("test_multi_touch: testing..."); + const waitForTouchEnd = new Promise(resolve => { + let count = 0; + function onTouchEnd(event) { + if (++count == 2) { + removeEventListener("touchend", onTouchEnd, {capture: true}); + requestAnimationFrame(() => requestAnimationFrame(resolve)); + } + } + addEventListener("touchend", onTouchEnd, {capture: true}); + }); + synthesizeTouch(child, [5, 25], 5); + await waitForTouchEnd; + is( + stringifyEvents(shiftEventsBefore(events)), + stringifyEvents([]), + `test_single_tap_with_consuming_touchend() shouldn't cause mouse events after touchend` + ) + is( + stringifyEvents(events), + stringifyEvents([ + { type: "touchend", target: child }, + { type: "touchend", target: child }, + ]), + `Multiple touch should not cause mouse events ${desc}` + ); + })(); + } + SimpleTest.finish(); +}); +</script> +</head> +<body><div id="parent"><div id="child"></div></div></body> +</html> diff --git a/dom/events/test/test_use_split_keypress_event_model_on_old_Confluence.html b/dom/events/test/test_use_split_keypress_event_model_on_old_Confluence.html index 3898584b0a..43d8081606 100644 --- a/dom/events/test/test_use_split_keypress_event_model_on_old_Confluence.html +++ b/dom/events/test/test_use_split_keypress_event_model_on_old_Confluence.html @@ -39,7 +39,7 @@ SimpleTest.waitForExplicitFinish(); SimpleTest.waitForFocus(async function doTests() { let iframe = document.getElementById("iframe"); let waitForCheckKeyPressEventModelEvent = new Promise(resolve => { - SpecialPowers.addSystemEventListener(iframe.contentDocument, "CheckKeyPressEventModel", resolve, {once: true}); + SpecialPowers.wrap(iframe.contentDocument).addEventListener("CheckKeyPressEventModel", resolve, {mozSystemGroup: true, once: true}); }); iframe.contentDocument.body.setAttribute("contenteditable", "true"); await waitForCheckKeyPressEventModelEvent; diff --git a/dom/events/test/test_use_split_keypress_event_model_on_old_Office_Online_Server.html b/dom/events/test/test_use_split_keypress_event_model_on_old_Office_Online_Server.html index 68f52be41d..02047fef90 100644 --- a/dom/events/test/test_use_split_keypress_event_model_on_old_Office_Online_Server.html +++ b/dom/events/test/test_use_split_keypress_event_model_on_old_Office_Online_Server.html @@ -23,7 +23,7 @@ function srcdocLoaded() { waitForCheckKeyPressEventModelEvent = new Promise(resolve => { dump(document.querySelector("iframe").contentDocument.location + "\n"); var doc = document.querySelector("iframe").contentDocument; - SpecialPowers.addSystemEventListener(doc, "CheckKeyPressEventModel", resolve, {once: true}); + SpecialPowers.wrap(doc).addEventListener("CheckKeyPressEventModel", resolve, {mozSystemGroup: true, once: true}); doc.getElementById("WACViewPanel_EditingElement").contentEditable = "true"; }); } |