commit 3e8fc8711ca6686c64c15690e6b18bd98bf907fa
parent 6e9b70a60f870dc766dd7ec5be8101e06542435a
Author: Edgar Chen <echen@mozilla.com>
Date: Thu, 27 Nov 2025 19:37:05 +0000
Bug 2002020 - Rewrite tests for queryCommandEnabled() and queryCommandSupported(); r=smaug
Rewrites test_bug1170911.html as a browser test and adds more coverage, e.g.,
for web extensions and paste command.
Differential Revision: https://phabricator.services.mozilla.com/D273900
Diffstat:
6 files changed, 956 insertions(+), 92 deletions(-)
diff --git a/dom/events/test/clipboard/browser.toml b/dom/events/test/clipboard/browser.toml
@@ -5,6 +5,12 @@ support-files = [
"!/gfx/layers/apz/test/mochitest/apz_test_utils.js",
]
+["browser_document_command_copy.js"]
+
+["browser_document_command_cut.js"]
+
+["browser_document_command_paste.js"]
+
["browser_navigator_clipboard_clickjacking.js"]
support-files = ["simple_navigator_clipboard_keydown.html"]
run-if = [
diff --git a/dom/events/test/clipboard/browser_document_command_copy.js b/dom/events/test/clipboard/browser_document_command_copy.js
@@ -0,0 +1,319 @@
+/* -*- Mode: JavaScript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const kContentFileUrl = kBaseUrlForContent + "simple_page_ext.html";
+
+// https://bugzilla.mozilla.org/show_bug.cgi?id=1170911
+[true, false].forEach(aPrefValue => {
+ describe(`dom.allow_cut_copy=${aPrefValue}`, () => {
+ it("set preference", async () => {
+ await SpecialPowers.pushPrefEnv({
+ set: [["dom.allow_cut_copy", aPrefValue]],
+ });
+ });
+
+ it(`called from system principal`, () => {
+ document.clearUserGestureActivation();
+
+ // Test without editing.
+ ok(
+ document.queryCommandSupported("copy"),
+ "Check if the 'copy' command is supported"
+ );
+ ok(
+ document.queryCommandEnabled("copy"),
+ "Check if the 'copy' command is enabled"
+ );
+ ok(
+ document.execCommand("copy"),
+ "Check if the 'copy' command is succeed"
+ );
+
+ // Test with editing.
+ const textArea = document.createElement("textarea");
+ document.body.appendChild(textArea);
+ textArea.textContent = "textarea text";
+ textArea.setSelectionRange(0, textArea.value.length);
+ textArea.focus();
+ ok(
+ document.queryCommandEnabled("copy"),
+ "Check if the 'copy' command is enabled when editing"
+ );
+ ok(
+ document.execCommand("copy"),
+ "Check if the 'copy' command is succeed when editing"
+ );
+ textArea.remove();
+ });
+
+ it(`called from web content`, async () => {
+ await BrowserTestUtils.withNewTab(kContentFileUrl, async browser => {
+ await SpecialPowers.spawn(browser, [aPrefValue], async aPrefValue => {
+ const doc = Cu.waiveXrays(content.document);
+ is(
+ doc.queryCommandSupported("copy"),
+ aPrefValue,
+ `Check if the 'copy' command is supported`
+ );
+
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=1012662
+ // Test no user activation.
+ content.document.clearUserGestureActivation();
+ ok(
+ !doc.queryCommandEnabled("copy"),
+ "Check if the 'copy' command is enabled without user activation"
+ );
+ ok(
+ !doc.execCommand("copy"),
+ "Check if the 'copy' command is succeed without user activation"
+ );
+
+ // Test with user activation.
+ content.document.notifyUserGestureActivation();
+ is(
+ doc.queryCommandEnabled("copy"),
+ aPrefValue,
+ "Check if the 'copy' command is enabled with user activation"
+ );
+ is(
+ doc.execCommand("copy"),
+ aPrefValue,
+ "Check if the 'copy' command is succeed with user activation"
+ );
+
+ // Test with editing.
+ const textArea = content.document.createElement("textarea");
+ content.document.body.appendChild(textArea);
+ textArea.textContent = "textarea text";
+ textArea.setSelectionRange(0, textArea.value.length);
+ textArea.focus();
+
+ // Test no user activation.
+ content.document.clearUserGestureActivation();
+ ok(
+ !doc.queryCommandEnabled("copy"),
+ "Check if the 'copy' command is enabled without user activation when editing"
+ );
+ ok(
+ !doc.execCommand("copy"),
+ "Check if the 'copy' command is succeed without user activation when editing"
+ );
+
+ // Test with user activation.
+ content.document.notifyUserGestureActivation();
+ is(
+ doc.queryCommandEnabled("copy"),
+ aPrefValue,
+ "Check if the 'copy' command is enabled with user activation when editing"
+ );
+ is(
+ doc.execCommand("copy"),
+ aPrefValue,
+ "Check if the 'copy' command is succeed with user activation when editing"
+ );
+ });
+ });
+ });
+
+ [true, false].forEach(aPermission => {
+ describe(`extension ${aPermission ? "with" : "without"} clipboardWrite permission`, () => {
+ const sharedScript = function () {
+ this.testCopyCommand = function () {
+ return [
+ document.queryCommandSupported("copy"),
+ document.queryCommandEnabled("copy"),
+ document.execCommand("copy"),
+ ];
+ };
+ };
+
+ it("called from content script", async () => {
+ const contentScript = function () {
+ document
+ .querySelector("button")
+ .addEventListener("click", function (e) {
+ browser.test.sendMessage("result", testCopyCommand());
+ });
+ browser.test.sendMessage("ready", testCopyCommand());
+ };
+ const extensionData = {
+ manifest: {
+ content_scripts: [
+ {
+ js: ["sharedScript.js", "contentscript.js"],
+ matches: ["https://example.com/*"],
+ },
+ ],
+ },
+ files: {
+ "sharedScript.js": sharedScript,
+ "contentscript.js": contentScript,
+ },
+ };
+ if (aPermission) {
+ extensionData.manifest.permissions = ["clipboardWrite"];
+ }
+
+ // Load and start the extension.
+ const extension = ExtensionTestUtils.loadExtension(extensionData);
+ await extension.startup();
+ await BrowserTestUtils.withNewTab(kContentFileUrl, async browser => {
+ let [supported, enabled, succeed] =
+ await extension.awaitMessage("ready");
+ // XXX: should "copy" command be supported if extension has
+ // clipboardWrite permission?
+ is(
+ supported,
+ aPrefValue,
+ "Check if the 'copy' command is supported"
+ );
+ is(
+ enabled,
+ aPermission,
+ "Check if the 'copy' command is enabled without user activation"
+ );
+ is(
+ succeed,
+ aPermission,
+ "Check if the 'copy' command is succeed without user activation"
+ );
+
+ // Click on the content to trigger user activation.
+ promiseClickContentElement(browser, "btn");
+ [supported, enabled, succeed] =
+ await extension.awaitMessage("result");
+ is(
+ enabled,
+ aPrefValue || aPermission,
+ "Check if the 'copy' command is enabled with user activation"
+ );
+ is(
+ succeed,
+ aPrefValue || aPermission,
+ "Check if the 'copy' command is succeed with user activation"
+ );
+ });
+ await extension.unload();
+ });
+
+ it("called from content script when editing", async () => {
+ const contentScript = function () {
+ const textArea = document.createElement("textarea");
+ document.body.appendChild(textArea);
+ const testCopyCommandWhenEditing = function () {
+ // Start editing.
+ textArea.textContent = "textarea text";
+ textArea.setSelectionRange(0, textArea.value.length);
+ textArea.focus();
+ return testCopyCommand();
+ };
+ document
+ .querySelector("button")
+ .addEventListener("click", function (e) {
+ browser.test.sendMessage(
+ "result",
+ testCopyCommandWhenEditing()
+ );
+ });
+ browser.test.sendMessage("ready", testCopyCommandWhenEditing());
+ };
+ const extensionData = {
+ manifest: {
+ content_scripts: [
+ {
+ js: ["sharedScript.js", "contentscript.js"],
+ matches: ["https://example.com/*"],
+ },
+ ],
+ },
+ files: {
+ "sharedScript.js": sharedScript,
+ "contentscript.js": contentScript,
+ },
+ };
+ if (aPermission) {
+ extensionData.manifest.permissions = ["clipboardWrite"];
+ }
+
+ // Load and start the extension.
+ const extension = ExtensionTestUtils.loadExtension(extensionData);
+ await extension.startup();
+ await BrowserTestUtils.withNewTab(kContentFileUrl, async browser => {
+ let [supported, enabled, succeed] =
+ await extension.awaitMessage("ready");
+ // XXX: should "copy" command be supported if extension has
+ // clipboardWrite permission?
+ is(
+ supported,
+ aPrefValue,
+ "Check if the 'copy' command is supported"
+ );
+ is(
+ enabled,
+ aPermission,
+ "Check if the 'copy' command is enabled without user activation"
+ );
+ is(
+ succeed,
+ aPermission,
+ "Check if the 'copy' command is succeed without user activation"
+ );
+
+ // Click on the content to trigger user activation.
+ promiseClickContentElement(browser, "btn");
+ [supported, enabled, succeed] =
+ await extension.awaitMessage("result");
+ is(
+ enabled,
+ aPrefValue || aPermission,
+ "Check if the 'copy' command is enabled with user activation"
+ );
+ is(
+ succeed,
+ aPrefValue || aPermission,
+ "Check if the 'copy' command is succeed with user activation"
+ );
+ });
+ await extension.unload();
+ });
+
+ it("called from background script", async () => {
+ const backgroundScript = function () {
+ browser.test.sendMessage("ready", testCopyCommand());
+ };
+ const extensionData = {
+ background: [sharedScript, backgroundScript],
+ };
+ if (aPermission) {
+ extensionData.manifest = {
+ permissions: ["clipboardWrite"],
+ };
+ }
+
+ // Load and start the extension.
+ const extension = ExtensionTestUtils.loadExtension(extensionData);
+ await extension.startup();
+ await BrowserTestUtils.withNewTab(kContentFileUrl, async browser => {
+ let [supported, enabled, succeed] =
+ await extension.awaitMessage("ready");
+ // XXX: should "copy" command be supported if extension has
+ // clipboardWrite permission.
+ is(
+ supported,
+ aPrefValue,
+ "Check if the 'copy' command is supported"
+ );
+ is(enabled, aPermission, "Check if the 'copy' command is enabled");
+ is(succeed, aPermission, "Check if the 'copy' command is succeed");
+ });
+ await extension.unload();
+ });
+ });
+ });
+ });
+});
diff --git a/dom/events/test/clipboard/browser_document_command_cut.js b/dom/events/test/clipboard/browser_document_command_cut.js
@@ -0,0 +1,328 @@
+/* -*- Mode: JavaScript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const kContentFileUrl = kBaseUrlForContent + "simple_page_ext.html";
+
+// https://bugzilla.mozilla.org/show_bug.cgi?id=1170911
+[true, false].forEach(aPrefValue => {
+ describe(`dom.allow_cut_copy=${aPrefValue}`, () => {
+ it("set preference", async () => {
+ await SpecialPowers.pushPrefEnv({
+ set: [["dom.allow_cut_copy", aPrefValue]],
+ });
+ });
+
+ it(`called from system principal`, () => {
+ document.clearUserGestureActivation();
+
+ // Test without editing.
+ ok(
+ document.queryCommandSupported("cut"),
+ "Check if the 'cut' command is supported"
+ );
+ // XXX: should "cut" command be disabled without an editing target,
+ // even if it is called from system principal?
+ ok(
+ document.queryCommandEnabled("cut"),
+ "Check if the 'cut' command is enabled without editing"
+ );
+ // XXX: Should the "cut" command succeed even without an editable target
+ // when it’s called from the system principal?
+ ok(
+ document.execCommand("cut"),
+ "Check if the 'cut' command is succeed without editing"
+ );
+
+ // Test with editing.
+ const textArea = document.createElement("textarea");
+ document.body.appendChild(textArea);
+ textArea.textContent = "textarea text";
+ textArea.setSelectionRange(0, textArea.value.length);
+ textArea.focus();
+ ok(
+ document.queryCommandEnabled("cut"),
+ "Check if the 'cut' command is enabled when editing"
+ );
+ ok(
+ document.execCommand("cut"),
+ "Check if the 'cut' command is succeed when editing"
+ );
+ textArea.remove();
+ });
+
+ it(`called from web content`, async () => {
+ await BrowserTestUtils.withNewTab(kContentFileUrl, async browser => {
+ await SpecialPowers.spawn(browser, [aPrefValue], async aPrefValue => {
+ const doc = Cu.waiveXrays(content.document);
+ is(
+ doc.queryCommandSupported("cut"),
+ aPrefValue,
+ `Check if the 'cut' command is supported`
+ );
+
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=1012662
+ // Test no user activation.
+ content.document.clearUserGestureActivation();
+ ok(
+ !doc.queryCommandEnabled("cut"),
+ "Check if the 'cut' command is enabled without user activation"
+ );
+ ok(
+ !doc.execCommand("cut"),
+ "Check if the 'cut' command is succeed without user activation"
+ );
+
+ // Test with user activation.
+ // XXX: should "cut" command be disabled without an editing target?
+ content.document.notifyUserGestureActivation();
+ is(
+ doc.queryCommandEnabled("cut"),
+ aPrefValue,
+ "Check if the 'cut' command is enabled with user activation"
+ );
+ ok(
+ !doc.execCommand("cut"),
+ "Check if the 'cut' command is succeed with user activation"
+ );
+
+ // Test with editing.
+ const textArea = content.document.createElement("textarea");
+ content.document.body.appendChild(textArea);
+ textArea.textContent = "textarea text";
+ textArea.setSelectionRange(0, textArea.value.length);
+ textArea.focus();
+
+ // Test no user activation.
+ content.document.clearUserGestureActivation();
+ ok(
+ !doc.queryCommandEnabled("cut"),
+ "Check if the 'cut' command is enabled without user activation when editing"
+ );
+ ok(
+ !doc.execCommand("cut"),
+ "Check if the 'cut' command is succeed without user activation when editing"
+ );
+
+ // Test with user activation.
+ textArea.textContent = "textarea text";
+ textArea.setSelectionRange(0, textArea.value.length);
+ textArea.focus();
+ content.document.notifyUserGestureActivation();
+ is(
+ doc.queryCommandEnabled("cut"),
+ aPrefValue,
+ "Check if the 'cut' command is enabled with user activation when editing"
+ );
+ is(
+ doc.execCommand("cut"),
+ aPrefValue,
+ "Check if the 'cut' command is succeed with user activation when editing"
+ );
+ });
+ });
+ });
+
+ [true, false].forEach(aPermission => {
+ describe(`extension ${aPermission ? "with" : "without"} clipboardWrite permission`, () => {
+ const sharedScript = function () {
+ this.testCutCommand = function () {
+ return [
+ document.queryCommandSupported("cut"),
+ document.queryCommandEnabled("cut"),
+ document.execCommand("cut"),
+ ];
+ };
+ };
+
+ it("called from content script", async () => {
+ const contentScript = function () {
+ document
+ .querySelector("button")
+ .addEventListener("click", function (e) {
+ browser.test.sendMessage("result", testCutCommand());
+ });
+ browser.test.sendMessage("ready", testCutCommand());
+ };
+ const extensionData = {
+ manifest: {
+ content_scripts: [
+ {
+ js: ["sharedScript.js", "contentscript.js"],
+ matches: ["https://example.com/*"],
+ },
+ ],
+ },
+ files: {
+ "sharedScript.js": sharedScript,
+ "contentscript.js": contentScript,
+ },
+ };
+ if (aPermission) {
+ extensionData.manifest.permissions = ["clipboardWrite"];
+ }
+
+ // Load and start the extension.
+ const extension = ExtensionTestUtils.loadExtension(extensionData);
+ await extension.startup();
+ await BrowserTestUtils.withNewTab(kContentFileUrl, async browser => {
+ let [supported, enabled, succeed] =
+ await extension.awaitMessage("ready");
+ // XXX: should "cut" command be supported if extension has
+ // clipboardWrite permission?
+ is(
+ supported,
+ aPrefValue,
+ "Check if the 'cut' command is supported"
+ );
+
+ // Test with user activation.
+ // XXX: should "cut" command be disabled without an editing target?
+ is(
+ enabled,
+ aPermission,
+ "Check if the 'cut' command is enabled without user activation"
+ );
+ ok(
+ !succeed,
+ "Check if the 'cut' command is succeed without user activation"
+ );
+
+ // Click on the content to trigger user activation.
+ promiseClickContentElement(browser, "btn");
+ [supported, enabled, succeed] =
+ await extension.awaitMessage("result");
+ // XXX: should "cut" command be disabled without an editing target?
+ is(
+ enabled,
+ aPrefValue || aPermission,
+ "Check if the 'cut' command is enabled with user activation"
+ );
+ ok(
+ !succeed,
+ "Check if the 'cut' command is succeed with user activation"
+ );
+ });
+ await extension.unload();
+ });
+
+ it("called from content script when editing", async () => {
+ const contentScript = function () {
+ const textArea = document.createElement("textarea");
+ document.body.appendChild(textArea);
+ const testCutCommandWhenEditing = function () {
+ // Start editing.
+ textArea.textContent = "textarea text";
+ textArea.setSelectionRange(0, textArea.value.length);
+ textArea.focus();
+ return testCutCommand();
+ };
+ document
+ .querySelector("button")
+ .addEventListener("click", function (e) {
+ browser.test.sendMessage("result", testCutCommandWhenEditing());
+ });
+ browser.test.sendMessage("ready", testCutCommandWhenEditing());
+ };
+ const extensionData = {
+ manifest: {
+ content_scripts: [
+ {
+ js: ["sharedScript.js", "contentscript.js"],
+ matches: ["https://example.com/*"],
+ },
+ ],
+ },
+ files: {
+ "sharedScript.js": sharedScript,
+ "contentscript.js": contentScript,
+ },
+ };
+ if (aPermission) {
+ extensionData.manifest.permissions = ["clipboardWrite"];
+ }
+
+ // Load and start the extension.
+ const extension = ExtensionTestUtils.loadExtension(extensionData);
+ await extension.startup();
+ await BrowserTestUtils.withNewTab(kContentFileUrl, async browser => {
+ let [supported, enabled, succeed] =
+ await extension.awaitMessage("ready");
+ // XXX: should "cut" command be supported if extension has
+ // clipboardWrite permission?
+ is(
+ supported,
+ aPrefValue,
+ "Check if the 'cut' command is supported"
+ );
+
+ // Test with user activation.
+ is(
+ enabled,
+ aPermission,
+ "Check if the 'cut' command is enabled without user activation"
+ );
+ is(
+ succeed,
+ aPermission,
+ "Check if the 'cut' command is succeed without user activation"
+ );
+
+ // Click on the content to trigger user activation.
+ promiseClickContentElement(browser, "btn");
+ [supported, enabled, succeed] =
+ await extension.awaitMessage("result");
+ is(
+ enabled,
+ aPrefValue || aPermission,
+ "Check if the 'cut' command is enabled with user activation"
+ );
+ is(
+ succeed,
+ aPrefValue || aPermission,
+ "Check if the 'cut' command is succeed with user activation"
+ );
+ });
+ await extension.unload();
+ });
+
+ it("called from background script", async () => {
+ const backgroundScript = function () {
+ browser.test.sendMessage("ready", testCutCommand());
+ };
+ const extensionData = {
+ background: [sharedScript, backgroundScript],
+ };
+ if (aPermission) {
+ extensionData.manifest = {
+ permissions: ["clipboardWrite"],
+ };
+ }
+
+ // Load and start the extension.
+ const extension = ExtensionTestUtils.loadExtension(extensionData);
+ await extension.startup();
+ await BrowserTestUtils.withNewTab(kContentFileUrl, async browser => {
+ let [supported, enabled, succeed] =
+ await extension.awaitMessage("ready");
+ // XXX: should "cut" command be supported if extension has
+ // clipboardWrite permission.
+ is(
+ supported,
+ aPrefValue,
+ "Check if the 'cut' command is supported"
+ );
+ // XXX: should "cut" command be disabled without an editing target?
+ is(enabled, aPermission, "Check if the 'cut' command is enabled");
+ ok(!succeed, "Check if the 'cut' command is succeed");
+ });
+ await extension.unload();
+ });
+ });
+ });
+ });
+});
diff --git a/dom/events/test/clipboard/browser_document_command_paste.js b/dom/events/test/clipboard/browser_document_command_paste.js
@@ -0,0 +1,303 @@
+/* -*- Mode: JavaScript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const kContentFileUrl = kBaseUrlForContent + "simple_page_ext.html";
+
+beforeEach(async () => {
+ info("Write random text to clipboard");
+ await promiseWritingRandomTextToClipboard();
+});
+
+describe("test paste comment", () => {
+ it(`called from system principal`, async () => {
+ document.clearUserGestureActivation();
+ ok(
+ document.queryCommandSupported("paste"),
+ "Check if the 'paste' command is supported"
+ );
+
+ // Test without editing.
+ ok(
+ !document.queryCommandEnabled("paste"),
+ "Check if the 'paste' command is enabled without editing"
+ );
+ ok(
+ !document.execCommand("paste"),
+ "Check if the 'paste' command is succeed without editing"
+ );
+
+ // Test with editing.
+ const textArea = document.createElement("textarea");
+ document.body.appendChild(textArea);
+ textArea.textContent = "textarea text";
+ textArea.setSelectionRange(0, textArea.value.length);
+ textArea.focus();
+ ok(
+ document.queryCommandEnabled("paste"),
+ "Check if the 'paste' command is enabled when editing"
+ );
+ ok(
+ document.execCommand("paste"),
+ "Check if the 'paste' command is succeed when editing"
+ );
+ textArea.remove();
+ });
+
+ it(`called from web content`, async () => {
+ await BrowserTestUtils.withNewTab(kContentFileUrl, async browser => {
+ await SpecialPowers.spawn(browser, [], async () => {
+ const doc = Cu.waiveXrays(content.document);
+ ok(
+ !doc.queryCommandSupported("paste"),
+ `Check if the 'paste' command is supported`
+ );
+
+ // Test no user activation.
+ content.document.clearUserGestureActivation();
+ ok(
+ !doc.queryCommandEnabled("paste"),
+ "Check if the 'paste' command is enabled without user activation"
+ );
+ ok(
+ !doc.execCommand("paste"),
+ "Check if the 'paste' command is succeed without user activation"
+ );
+
+ // Test with user activation.
+ content.document.notifyUserGestureActivation();
+ ok(
+ !doc.queryCommandEnabled("paste"),
+ "Check if the 'paste' command is enabled with user activation"
+ );
+ ok(
+ !doc.execCommand("paste"),
+ "Check if the 'paste' command is succeed with user activation"
+ );
+
+ // Test with editing.
+ const textArea = content.document.createElement("textarea");
+ content.document.body.appendChild(textArea);
+ textArea.textContent = "textarea text";
+ textArea.setSelectionRange(0, textArea.value.length);
+ textArea.focus();
+
+ // Test no user activation.
+ content.document.clearUserGestureActivation();
+ ok(
+ !doc.queryCommandEnabled("paste"),
+ "Check if the 'paste' command is enabled without user activation when editing"
+ );
+ ok(
+ !doc.execCommand("paste"),
+ "Check if the 'paste' command is succeed without user activation when editing"
+ );
+
+ // Test with user activation.
+ textArea.textContent = "textarea text";
+ textArea.setSelectionRange(0, textArea.value.length);
+ textArea.focus();
+ content.document.notifyUserGestureActivation();
+ ok(
+ !doc.queryCommandEnabled("paste"),
+ "Check if the 'paste' command is enabled with user activation when editing"
+ );
+ ok(
+ !doc.execCommand("paste"),
+ "Check if the 'paste' command is succeed with user activation when editing"
+ );
+ });
+ });
+ });
+
+ [true, false].forEach(aPermission => {
+ describe(`extension ${aPermission ? "with" : "without"} clipboardRead permission`, () => {
+ const sharedScript = function () {
+ this.testPasteCommand = function () {
+ return [
+ document.queryCommandSupported("paste"),
+ document.queryCommandEnabled("paste"),
+ document.execCommand("paste"),
+ ];
+ };
+ };
+
+ it("called from content script", async () => {
+ const contentScript = function () {
+ document
+ .querySelector("button")
+ .addEventListener("click", function (e) {
+ browser.test.sendMessage("result", testPasteCommand());
+ });
+ browser.test.sendMessage("ready", testPasteCommand());
+ };
+ const extensionData = {
+ manifest: {
+ content_scripts: [
+ {
+ js: ["sharedScript.js", "contentscript.js"],
+ matches: ["https://example.com/*"],
+ },
+ ],
+ },
+ files: {
+ "sharedScript.js": sharedScript,
+ "contentscript.js": contentScript,
+ },
+ };
+ if (aPermission) {
+ extensionData.manifest.permissions = ["clipboardRead"];
+ }
+
+ // Load and start the extension.
+ const extension = ExtensionTestUtils.loadExtension(extensionData);
+ await extension.startup();
+ await BrowserTestUtils.withNewTab(kContentFileUrl, async browser => {
+ let [supported, enabled, succeed] =
+ await extension.awaitMessage("ready");
+ // XXX: should "paste" command be supported if extension has
+ // clipboardRead permission?
+ ok(!supported, "Check if the 'paste' command is supported");
+ // XXX: should "paste" command be enabled if extension has
+ // clipboardRead permission?
+ ok(
+ !enabled,
+ "Check if the 'paste' command is enabled without user activation"
+ );
+ is(
+ succeed,
+ aPermission,
+ "Check if the 'paste' command is succeed without user activation"
+ );
+
+ // Click on the content to trigger user activation.
+ promiseClickContentElement(browser, "btn");
+ [supported, enabled, succeed] =
+ await extension.awaitMessage("result");
+ // XXX: should "paste" command be enabled if extension has
+ // clipboardRead permission?
+ ok(
+ !enabled,
+ "Check if the 'paste' command is enabled with user activation"
+ );
+ is(
+ succeed,
+ aPermission,
+ "Check if the 'paste' command is succeed with user activation"
+ );
+ });
+ await extension.unload();
+ });
+
+ it("called from content script when editing", async () => {
+ const contentScript = function () {
+ const textArea = document.createElement("textarea");
+ document.body.appendChild(textArea);
+ const testPasteCommandWhenEditing = function () {
+ // Start editing.
+ textArea.textContent = "textarea text";
+ textArea.setSelectionRange(0, textArea.value.length);
+ textArea.focus();
+ return testPasteCommand();
+ };
+ document
+ .querySelector("button")
+ .addEventListener("click", function (e) {
+ browser.test.sendMessage("result", testPasteCommandWhenEditing());
+ });
+ browser.test.sendMessage("ready", testPasteCommandWhenEditing());
+ };
+ const extensionData = {
+ manifest: {
+ content_scripts: [
+ {
+ js: ["sharedScript.js", "contentscript.js"],
+ matches: ["https://example.com/*"],
+ },
+ ],
+ },
+ files: {
+ "sharedScript.js": sharedScript,
+ "contentscript.js": contentScript,
+ },
+ };
+ if (aPermission) {
+ extensionData.manifest.permissions = ["clipboardRead"];
+ }
+
+ // Load and start the extension.
+ const extension = ExtensionTestUtils.loadExtension(extensionData);
+ await extension.startup();
+ await BrowserTestUtils.withNewTab(kContentFileUrl, async browser => {
+ let [supported, enabled, succeed] =
+ await extension.awaitMessage("ready");
+ // XXX: should "paste" command be supported if extension has
+ // clipboardRead permission?
+ ok(!supported, "Check if the 'paste' command is supported");
+ // XXX: should "paste" command be enabled if extension has
+ // clipboardRead permission?
+ ok(
+ !enabled,
+ "Check if the 'paste' command is enabled without user activation"
+ );
+ is(
+ succeed,
+ aPermission,
+ "Check if the 'paste' command is succeed without user activation"
+ );
+
+ // Click on the content to trigger user activation.
+ promiseClickContentElement(browser, "btn");
+ [supported, enabled, succeed] =
+ await extension.awaitMessage("result");
+ // XXX: should "paste" command be enabled if extension has
+ // clipboardRead permission?
+ ok(
+ !enabled,
+ "Check if the 'paste' command is enabled with user activation"
+ );
+ is(
+ succeed,
+ aPermission,
+ "Check if the 'paste' command is succeed with user activation"
+ );
+ });
+ await extension.unload();
+ });
+
+ it("called from background script", async () => {
+ const backgroundScript = function () {
+ browser.test.sendMessage("ready", testPasteCommand());
+ };
+ const extensionData = {
+ background: [sharedScript, backgroundScript],
+ };
+ if (aPermission) {
+ extensionData.manifest = {
+ permissions: ["clipboardRead"],
+ };
+ }
+
+ // Load and start the extension.
+ const extension = ExtensionTestUtils.loadExtension(extensionData);
+ await extension.startup();
+ await BrowserTestUtils.withNewTab(kContentFileUrl, async browser => {
+ let [supported, enabled, succeed] =
+ await extension.awaitMessage("ready");
+ // XXX: should "paste" command be supported if extension has
+ // clipboardRead permission?
+ ok(!supported, "Check if the 'paste' command is supported");
+ // XXX: should "paste" command be enabled if extension has
+ // clipboardRead permission?
+ ok(!enabled, "Check if the 'paste' command is enabled");
+ is(succeed, aPermission, "Check if the 'paste' command is succeed");
+ });
+ await extension.unload();
+ });
+ });
+ });
+});
diff --git a/dom/tests/mochitest/general/mochitest.toml b/dom/tests/mochitest/general/mochitest.toml
@@ -89,8 +89,6 @@ support-files = [
["test_bug1161721.html"]
-["test_bug1170911.html"]
-
["test_bug1208217.html"]
["test_bug1313753.html"]
diff --git a/dom/tests/mochitest/general/test_bug1170911.html b/dom/tests/mochitest/general/test_bug1170911.html
@@ -1,90 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1012662
--->
-<head>
- <title>Test for Bug 1170911</title>
- <script src="/tests/SimpleTest/SimpleTest.js"></script>
- <script src="/tests/SimpleTest/EventUtils.js"></script>
- <script src="/tests/SimpleTest/WindowSnapshot.js"></script>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1170911">Mozilla Bug 1170911</a>
-<p id="display"></p>
-
-<div id="content">
- <textarea>textarea text</textarea>
-</div>
-
-<pre id="test">
-<script>
-const TEXTAREA = document.querySelector('textarea');
-const TEXTAREA_VALUE = TEXTAREA.value;
-
-function doTest() {
- is(document.queryCommandSupported("copy"), false,
- "Copy support should have been disabled");
- is(document.queryCommandSupported("cut"), false,
- "Cut support should have been disabled");
-
- document.addEventListener("keydown", tryCopy);
- sendString("Q");
-}
-
-function tryCopy(evt) {
- evt.preventDefault();
- document.removeEventListener("keydown", tryCopy);
- TEXTAREA.setSelectionRange(0, TEXTAREA_VALUE.length);
- TEXTAREA.focus();
-
- SimpleTest.waitForClipboard(null, function () {
- is(document.queryCommandEnabled("copy"), false,
- "Copy should not be allowed when dom.allow_cut_copy is off");
- is(document.execCommand("copy"), false,
- "Copy should not be executed when dom.allow_cut_copy is off");
- is(TEXTAREA.value, TEXTAREA_VALUE,
- "Content in the textarea shouldn't be changed");
- TEXTAREA.value = TEXTAREA_VALUE;
- },
- /* success fn */ SimpleTest.finish,
- /* failure fn */ function () {
- document.addEventListener("keydown", tryCut);
- sendString("Q");
- },
- /* flavor */ undefined,
- /* timeout */ undefined,
- /* expect failure */ true);
-}
-
-function tryCut(evt) {
- evt.preventDefault();
- document.removeEventListener("keydown", tryCut);
- TEXTAREA.setSelectionRange(0, TEXTAREA_VALUE.length);
- TEXTAREA.focus();
-
- SimpleTest.waitForClipboard(null, function () {
- is(document.queryCommandEnabled("cut"), false,
- "Cut should not be allowed when dom.allow_cut_copy is off");
- is(document.execCommand("cut"), false,
- "Cut should not be executed when dom.allow_cut_copy is off");
- is(TEXTAREA.value, TEXTAREA_VALUE,
- "Content in the textarea shouldn't be changed");
- },
- /* success fn */ SimpleTest.finish,
- /* failure fn */ SimpleTest.finish,
- /* flavor */ undefined,
- /* timeout */ undefined,
- /* expect failure */ true);
-}
-
-SimpleTest.waitForExplicitFinish();
-SimpleTest.waitForFocus(() => {
- SpecialPowers.pushPrefEnv({"set": [["dom.allow_cut_copy", false]]}, doTest);
-});
-
-</script>
-</pre>
-</body>
-</html>