browser_navigator_clipboard_contextmenu_suppression_ext.js (4498B)
1 /* -*- Mode: JavaScript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 "use strict"; 8 requestLongerTimeout(2); 9 10 const kContentFileUrl = kBaseUrlForContent + "file_toplevel.html"; 11 const kIsMac = navigator.platform.indexOf("Mac") > -1; 12 13 async function waitForPasteContextMenu() { 14 await waitForPasteMenuPopupEvent("shown"); 15 let pasteButton = document.getElementById(kPasteMenuItemId); 16 info("Wait for paste button enabled"); 17 await BrowserTestUtils.waitForMutationCondition( 18 pasteButton, 19 { attributeFilter: ["disabled"] }, 20 () => !pasteButton.disabled, 21 "Wait for paste button enabled" 22 ); 23 } 24 25 async function readText(aBrowser) { 26 return SpecialPowers.spawn(aBrowser, [], async () => { 27 content.document.notifyUserGestureActivation(); 28 return content.eval(`navigator.clipboard.readText();`); 29 }); 30 } 31 32 async function testPasteContextMenu( 33 aBrowser, 34 aClipboardText, 35 aShouldShow = true 36 ) { 37 let pasteButtonIsShown; 38 if (aShouldShow) { 39 pasteButtonIsShown = waitForPasteContextMenu(); 40 } 41 let readTextRequest = readText(aBrowser); 42 if (aShouldShow) { 43 await pasteButtonIsShown; 44 } 45 46 info("Click paste button, request should be resolved"); 47 if (aShouldShow) { 48 await promiseClickPasteButton(); 49 } 50 is(await readTextRequest, aClipboardText, "Request should be resolved"); 51 } 52 53 async function installAndStartExtension(aContentScript) { 54 let extension = ExtensionTestUtils.loadExtension({ 55 manifest: { 56 content_scripts: [ 57 { 58 js: ["content_script.js"], 59 matches: ["https://example.com/*/file_toplevel.html"], 60 }, 61 ], 62 }, 63 files: { 64 "content_script.js": aContentScript, 65 }, 66 }); 67 68 await extension.startup(); 69 70 return extension; 71 } 72 73 function testExtensionContentScript(aContentScript, aMessage) { 74 add_task(async function test_context_menu_suppression_ext() { 75 info(`${aMessage}`); 76 const extension = await installAndStartExtension(aContentScript); 77 await BrowserTestUtils.withNewTab( 78 kContentFileUrl, 79 async function (browser) { 80 const clipboardText = "X" + Math.random(); 81 await SpecialPowers.spawn(browser, [clipboardText], async text => { 82 info(`Set clipboard text to ${text}`); 83 let div = content.document.createElement("div"); 84 div.id = "container"; 85 div.innerText = text; 86 content.document.documentElement.appendChild(div); 87 }); 88 89 let writePromise = extension.awaitMessage("write-data-ready"); 90 // trigger keyboard shortcut to copy. 91 await EventUtils.synthesizeAndWaitKey( 92 "c", 93 kIsMac ? { accelKey: true } : { ctrlKey: true } 94 ); 95 // Wait a bit for clipboard write. 96 await writePromise; 97 98 info("Test read from same frame"); 99 await testPasteContextMenu(browser, clipboardText, false); 100 101 info("Test read from same-origin subframe"); 102 await testPasteContextMenu( 103 browser.browsingContext.children[0], 104 clipboardText, 105 false 106 ); 107 108 info("Test read from cross-origin subframe"); 109 await testPasteContextMenu( 110 browser.browsingContext.children[1], 111 clipboardText, 112 true 113 ); 114 } 115 ); 116 117 await extension.unload(); 118 }); 119 } 120 121 add_setup(async function () { 122 await SpecialPowers.pushPrefEnv({ 123 set: [ 124 ["test.events.async.enabled", true], 125 // Avoid paste button delay enabling making test too long. 126 ["security.dialog_enable_delay", 0], 127 ], 128 }); 129 }); 130 131 testExtensionContentScript(() => { 132 document.addEventListener("copy", function (e) { 133 e.preventDefault(); 134 let div = document.getElementById("container"); 135 let text = div.innerText; 136 e.clipboardData.setData("text/plain", text); 137 browser.test.sendMessage("write-data-ready"); 138 }); 139 }, "Write data by DataTransfer API in extension"); 140 141 testExtensionContentScript(() => { 142 document.addEventListener("copy", async function (e) { 143 e.preventDefault(); 144 let div = document.getElementById("container"); 145 let text = div.innerText; 146 await navigator.clipboard.writeText(text); 147 browser.test.sendMessage("write-data-ready"); 148 }); 149 }, "Write data by Async Clipboard API in extension");