Source code
Revision control
Copy as Markdown
Other Tools
Test Info: Warnings
- This test gets skipped with pattern: headless
- Manifest: dom/events/test/clipboard/browser.toml
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
"use strict";
requestLongerTimeout(2);
const kContentFileUrl = kBaseUrlForContent + "simple_page_ext.html";
const kIsMac = navigator.platform.indexOf("Mac") > -1;
// Custom key config.
const kCustomKey = "j";
const kCustomKeyDisabled = "y";
const kCustomKeyModifier = { accelKey: true, shiftKey: true, altKey: true };
const kKeyEventTests = [
{
description: "Paste",
key: "v",
modifiers: { accelKey: true },
shouldSuppressContextMenu: true,
},
{
description: "Paste without formatting",
key: "v",
modifiers: { accelKey: true, shiftKey: true },
shouldSuppressContextMenu: true,
},
{
description: "Paste without formatting (Mac only)",
key: "v",
modifiers: { accelKey: true, shiftKey: true, altKey: true },
shouldSuppressContextMenu: kIsMac,
},
{
description: "Custom XUL command",
key: kCustomKey,
modifiers: kCustomKeyModifier,
// XUL key command should always not suppress context menu
shouldSuppressContextMenu: false,
},
{
description: "Custom disabled XUL command",
key: kCustomKeyDisabled,
modifiers: kCustomKeyModifier,
// XUL key command should anot suppress context menu
shouldSuppressContextMenu: false,
},
];
async function promiseExecCommandFromKeyboardEvent(aBrowser, aKeyboardEvent) {
const promiseEvent = SpecialPowers.spawn(
aBrowser,
[aKeyboardEvent],
aKeyboardEvent => {
return new Promise(resolve => {
content.document.addEventListener(
aKeyboardEvent,
e => {
info(`Received ${e.type} event`);
e.preventDefault();
resolve(Cu.waiveXrays(content.document).execCommand("paste"));
},
{ once: true }
);
});
}
);
// Ensure the event listener is registered on remote target.
await SpecialPowers.spawn(aBrowser, [], async () => {
await new Promise(resolve => {
SpecialPowers.executeSoon(resolve);
});
});
return promiseEvent;
}
async function runKeyEventTest(
aKey,
aModifiers,
aKeyboardEventType,
aShouldSuppressContextMenu
) {
let listener = function (e) {
if (e.target.getAttribute("id") == kPasteMenuPopupId) {
ok(
!aShouldSuppressContextMenu,
`paste contextmenu should ${aShouldSuppressContextMenu ? "not " : ""}be shown`
);
SpecialPowers.executeSoon(async () => {
await promiseDismissPasteButton();
// XXX not sure why first promiseDismissPasteButton doesn't work on Windows opt build.
await promiseDismissPasteButton();
});
}
};
document.addEventListener("popupshown", listener);
info(`Write random text to clipboard`);
await promiseWritingRandomTextToClipboard();
await BrowserTestUtils.withNewTab(kContentFileUrl, async browser => {
const resultPromise = promiseExecCommandFromKeyboardEvent(
browser,
aKeyboardEventType
);
info(`synthesizeAndWaitKey`);
await EventUtils.synthesizeAndWaitKey(aKey, aModifiers);
let result = await resultPromise;
is(result, aShouldSuppressContextMenu, `Check execCommand("paste") result`);
});
document.removeEventListener("popupshown", listener);
}
function getModifierString(aModifiers) {
let modifiers = [];
for (const [key, value] of Object.entries(aModifiers)) {
if (value) {
modifiers.push(key.substring(0, key.indexOf("Key")));
}
}
return modifiers.join(",");
}
function createKeyElementWithPasteCommand(
aKeySetId,
aId,
aKey,
aModifiers,
aDisabled = false
) {
let keyset = document.getElementById(aKeySetId);
let key = document.createXULElement("key");
key.setAttribute("id", aId);
key.setAttribute("key", aKey);
key.setAttribute("modifiers", getModifierString(aModifiers));
key.setAttribute("command", "cmd_paste");
if (aDisabled) {
key.setAttribute("disabled", "true");
}
keyset.prepend(key);
return key;
}
add_setup(async function () {
await SpecialPowers.pushPrefEnv({
set: [
["test.events.async.enabled", true],
// Disable the paste contextmenu delay to make the test run faster.
["security.dialog_enable_delay", 0],
],
});
// Setup custom XUL key command.
let key = createKeyElementWithPasteCommand(
"mainKeyset",
"key_custom",
kCustomKey,
kCustomKeyModifier
);
let keyDisabled = createKeyElementWithPasteCommand(
"mainKeyset",
"key_custom_disabled",
kCustomKeyDisabled,
kCustomKeyModifier,
true
);
registerCleanupFunction(async function () {
key.remove();
keyDisabled.remove();
});
});
kKeyEventTests.forEach(keyEventTest => {
describe(`Test ${keyEventTest.description}`, () => {
it("keydown", async () => {
await runKeyEventTest(
keyEventTest.key,
keyEventTest.modifiers,
"keydown",
keyEventTest.shouldSuppressContextMenu
);
});
it("keyup", async () => {
await runKeyEventTest(
keyEventTest.key,
keyEventTest.modifiers,
"keyup",
false /* keyup event should not suppress contextmenu */
);
});
});
});