Source code

Revision control

Other Tools

Test Info: Warnings

  • This test gets skipped with pattern: (!e10s || (os == 'android')) || (toolkit == 'android' || tsan)
  • This test was skipped 90 times in the preceding 7 days.
  • This test ran 116 times in the preceding 7 days with an average run time of 3.50 secs.
<!DOCTYPE HTML>
<html>
<head>
<title>Async Clipboard permissions tests</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
<script src="head.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head>
<body>
<script>
"use strict";
// Bug 1479956 - On android-debug verify this test times out
SimpleTest.requestLongerTimeout(2);
/* globals clipboardWriteText, clipboardWrite, clipboardReadText, clipboardRead */
function shared() {
this.clipboardWriteText = function(txt) {
return navigator.clipboard.writeText(txt);
};
this.clipboardWrite = function(dt) {
return navigator.clipboard.write(dt);
};
this.clipboardReadText = function() {
return navigator.clipboard.readText();
};
this.clipboardRead = function() {
return navigator.clipboard.read();
};
}
/**
* Clear the clipboard.
*
* This is needed because Services.clipboard.emptyClipboard() does not clear the actual system clipboard.
*/
function clearClipboard() {
if (AppConstants.platform == "android") {
// On android, this clears the actual system clipboard
SpecialPowers.Services.clipboard.emptyClipboard(SpecialPowers.Services.clipboard.kGlobalClipboard);
return;
}
// Need to do this hack on other platforms to clear the actual system clipboard
let transf = SpecialPowers.Cc["@mozilla.org/widget/transferable;1"]
.createInstance(SpecialPowers.Ci.nsITransferable);
transf.init(null);
// Empty transferables may cause crashes, so just add an unknown type.
const TYPE = "text/x-moz-place-empty";
transf.addDataFlavor(TYPE);
transf.setTransferData(TYPE, {}, 0);
SpecialPowers.Services.clipboard.setData(transf, null, SpecialPowers.Services.clipboard.kGlobalClipboard);
}
add_task(async function setup() {
await SpecialPowers.pushPrefEnv({"set": [
["dom.events.asyncClipboard", true],
["dom.events.asyncClipboard.dataTransfer", true],
]});
});
// Test that without enough permissions, we are NOT allowed to use writeText, write, read or readText in background script
add_task(async function test_background_async_clipboard_no_permissions() {
function backgroundScript() {
let dt = new DataTransfer();
dt.items.add("Howdy", "text/plain");
browser.test.assertRejects(clipboardRead(), undefined, "Read should be denied without permission");
browser.test.assertRejects(clipboardWrite(dt), undefined, "Write should be denied without permission");
browser.test.assertRejects(clipboardWriteText("blabla"), undefined, "WriteText should be denied without permission");
browser.test.assertRejects(clipboardReadText(), undefined, "ReadText should be denied without permission");
browser.test.sendMessage("ready");
}
let extensionData = {
background: [shared, backgroundScript],
};
let extension = ExtensionTestUtils.loadExtension(extensionData);
await extension.startup();
await extension.awaitMessage("ready");
await extension.unload();
});
// Test that without enough permissions, we are NOT allowed to use writeText, write, read or readText in content script
add_task(async function test_contentscript_async_clipboard_no_permission() {
function contentScript() {
let dt = new DataTransfer();
dt.items.add("Howdy", "text/plain");
browser.test.assertRejects(clipboardRead(), undefined, "Read should be denied without permission");
browser.test.assertRejects(clipboardWrite(dt), undefined, "Write should be denied without permission");
browser.test.assertRejects(clipboardWriteText("blabla"), undefined, "WriteText should be denied without permission");
browser.test.assertRejects(clipboardReadText(), undefined, "ReadText should be denied without permission");
browser.test.sendMessage("ready");
}
let extensionData = {
manifest: {
content_scripts: [{
js: ["shared.js", "contentscript.js"],
}],
},
files: {
"shared.js": shared,
"contentscript.js": contentScript,
},
};
let extension = ExtensionTestUtils.loadExtension(extensionData);
await extension.startup();
await extension.awaitMessage("ready");
win.close();
await extension.unload();
});
// Test that with enough permissions, we are allowed to use writeText in content script
add_task(async function test_contentscript_clipboard_permission_writetext() {
function contentScript() {
let str = "HI";
clipboardWriteText(str).then(function() {
// nothing here
browser.test.sendMessage("ready");
}, function(err) {
browser.test.fail("WriteText promise rejected");
browser.test.sendMessage("ready");
}); // clipboardWriteText
}
let extensionData = {
manifest: {
content_scripts: [{
js: ["shared.js", "contentscript.js"],
}],
permissions: [
"clipboardWrite",
"clipboardRead",
],
},
files: {
"shared.js": shared,
"contentscript.js": contentScript,
},
};
let extension = ExtensionTestUtils.loadExtension(extensionData);
await extension.startup();
await extension.awaitMessage("ready");
const actual = SpecialPowers.getClipboardData("text/unicode");
is(actual, "HI", "right string copied by write");
win.close();
await extension.unload();
});
// Test that with enough permissions, we are allowed to use readText in content script
add_task(async function test_contentscript_clipboard_permission_readtext() {
function contentScript() {
let str = "HI";
clipboardReadText().then(function(strData) {
if (strData == str) {
browser.test.succeed("Successfully read from clipboard");
} else {
browser.test.fail("ReadText read the wrong thing from clipboard:" + strData);
}
browser.test.sendMessage("ready");
}, function(err) {
browser.test.fail("ReadText promise rejected");
browser.test.sendMessage("ready");
}); // clipboardReadText
}
let extensionData = {
manifest: {
content_scripts: [{
js: ["shared.js", "contentscript.js"],
}],
permissions: [
"clipboardWrite",
"clipboardRead",
],
},
files: {
"shared.js": shared,
"contentscript.js": contentScript,
},
};
await SimpleTest.promiseClipboardChange("HI", () => {
SpecialPowers.clipboardCopyString("HI");
}, "text/unicode");
let extension = ExtensionTestUtils.loadExtension(extensionData);
await extension.startup();
await extension.awaitMessage("ready");
win.close();
await extension.unload();
});
// Test that with enough permissions, we are allowed to use write in content script
add_task(async function test_contentscript_clipboard_permission_write() {
function contentScript() {
let str = "HI";
let dt = new DataTransfer();
dt.items.add(str, "text/plain");
clipboardWrite(dt).then(function() {
// nothing here
browser.test.sendMessage("ready");
}, function(err) { // clipboardWrite promise error function
browser.test.fail("Write promise rejected");
browser.test.sendMessage("ready");
}); // clipboard write
}
let extensionData = {
manifest: {
content_scripts: [{
js: ["shared.js", "contentscript.js"],
}],
permissions: [
"clipboardWrite",
"clipboardRead",
],
},
files: {
"shared.js": shared,
"contentscript.js": contentScript,
},
};
let extension = ExtensionTestUtils.loadExtension(extensionData);
await extension.startup();
await extension.awaitMessage("ready");
const actual = SpecialPowers.getClipboardData("text/unicode");
is(actual, "HI", "right string copied by write");
win.close();
await extension.unload();
});
// Test that with enough permissions, we are allowed to use read in content script
add_task(async function test_contentscript_clipboard_permission_read() {
function contentScript() {
clipboardRead().then(function(dt) {
let s = dt.getData("text/plain");
if (s == "HELLO") {
browser.test.succeed("Read promise successfully read the right thing");
} else {
browser.test.fail("Read read the wrong string from clipboard:" + s);
}
browser.test.sendMessage("ready");
}, function(err) { // clipboardRead promise error function
browser.test.fail("Read promise rejected");
browser.test.sendMessage("ready");
}); // clipboard read
}
let extensionData = {
manifest: {
content_scripts: [{
js: ["shared.js", "contentscript.js"],
}],
permissions: [
"clipboardWrite",
"clipboardRead",
],
},
files: {
"shared.js": shared,
"contentscript.js": contentScript,
},
};
await SimpleTest.promiseClipboardChange("HELLO", () => {
SpecialPowers.clipboardCopyString("HELLO");
}, "text/unicode");
let extension = ExtensionTestUtils.loadExtension(extensionData);
await extension.startup();
await extension.awaitMessage("ready");
win.close();
await extension.unload();
});
// Test that performing readText(...) when the clipboard is empty returns an empty string
add_task(async function test_contentscript_clipboard_nocontents_readtext() {
function contentScript() {
clipboardReadText().then(function(strData) {
if (strData == "") {
browser.test.succeed("ReadText successfully read correct thing from an empty clipboard");
} else {
browser.test.fail("ReadText should have read an empty string, but read:" + strData);
}
browser.test.sendMessage("ready");
}, function(err) {
browser.test.fail("ReadText promise rejected: " + err);
browser.test.sendMessage("ready");
});
}
let extensionData = {
manifest: {
content_scripts: [{
js: ["shared.js", "contentscript.js"],
}],
permissions: [
"clipboardRead",
],
},
files: {
"shared.js": shared,
"contentscript.js": contentScript,
},
};
await SimpleTest.promiseClipboardChange("", () => {
clearClipboard();
}, "text/x-moz-place-empty");
let extension = ExtensionTestUtils.loadExtension(extensionData);
await extension.startup();
await extension.awaitMessage("ready");
win.close();
await extension.unload();
});
// Test that performing read(...) when the clipboard is empty returns an empty data transfer
add_task(async function test_contentscript_clipboard_nocontents_read() {
function contentScript() {
clipboardRead().then(function(dataT) {
// On macOS if we clear the clipboard and read from it, there will be
// no items in the data transfer object.
// On linux with e10s enabled clearing of the clipboard does not happen in
// the same way as it does on other platforms. So when we clear the clipboard
// and read from it, the data transfer object contains an item of type
// text/plain and kind string, but we can't call getAsString on it to verify
// that at least it is an empty string because the callback never gets invoked.
if (!dataT.items.length ||
(dataT.items.length == 1 && dataT.items[0].type == "text/plain" &&
dataT.items[0].kind == "string")) {
browser.test.succeed("Read promise successfully resolved");
} else {
browser.test.fail("Read read the wrong thing from clipboard, " +
"data transfer has this many items:" + dataT.items.length);
}
browser.test.sendMessage("ready");
}, function(err) {
browser.test.fail("Read promise rejected: " + err);
browser.test.sendMessage("ready");
});
}
let extensionData = {
manifest: {
content_scripts: [{
js: ["shared.js", "contentscript.js"],
}],
permissions: [
"clipboardRead",
],
},
files: {
"shared.js": shared,
"contentscript.js": contentScript,
},
};
await SimpleTest.promiseClipboardChange("", () => {
clearClipboard();
}, "text/x-moz-place-empty");
let extension = ExtensionTestUtils.loadExtension(extensionData);
await extension.startup();
await extension.awaitMessage("ready");
win.close();
await extension.unload();
});
</script>
</body>
</html>