Testing is a part of life. Sadly, that means we have to write tests for things that involve the clipboard. The clipboard is complicated enough with all of this flavor and transferable stuff we have going on. Throw in the fact that the clipboard can be asynchronous (thanks Linux), and it gets worse. We’ve had a number of tests that fail due to expectations that the clipboard be synchronous. Most of those tests have been changed to use a “polling” strategy - essentially waiting for the clipboard to have the expected value. If it doesn’t have the right value after a few seconds, then the test fails. I know of at least 3 tests that use this strategy now, and they all ended up having similar code, perhaps even copy-pasted directly from another test.

Gavin made me use polling for the test in a bug I fixed recently. Then the following week there was a password manager bug that I saw doing clipboard stuff (without polling) so I passed along the “polling is good” requirement.

Instead of making everybody rewrite the wheel, I decided to write SimpleTest.waitForClipboard to take care of this polling stuff for us. It only works with the global clipboard, and only with text/unicode strings (text/plain should work too since it’s available on the clipboard in the unicode flavor). It works by setting the clipboard to a known value (different than your expected value), then polling for that value. After the known value is found, your setup function is called, and we poll again. When we find the value, we add a PASS & then your success function is called. If at any point we timeout waiting for the expected value, we add a FAIL & then your failure function is called.

Following are the arguments and then a simple example test. Hopefully it’s clear how to make use of waitForClipboard in tests you write in the future. I’ve already converted a few tests to use this method. If there are any existing [orange]s that you think could benefit from this, please convert them!

/*
* Polls the clipboard waiting for the expected value. A known value different than
* the expected value is put on the clipboard first (and also polled for) so we
* can be sure the value we get isn't just the expected value because it was already
* on the clipboard. This only uses the global clipboard and only for text/unicode
* values.
*
* @param aExpectedVal
* The string value that is expected to be on the clipboard
* @param aSetupFn
* A function responsible for setting the clipboard to the expected value,
* called after the known value setting succeeds.
* @param aSuccessFn
* A function called when the expected value is found on the clipboard.
* @param aFailureFn
* A function called if the expected value isn't found on the clipboard
* within 5s. It can also be called if the known value can't be found.
*/
SimpleTest.waitForClipboard = function(aExpectedVal, aSetupFn, aSuccessFn, aFailureFn) {
function test() {
waitForExplicitFinish();
// the value we expect to be on the clipboard
const EXPECTED_VAL = "foo";
// function that will set up the clipboard
function setup() {
Cc["@mozilla.org/widget/clipboardhelper;1"].
getService(Ci.nsIClipboardHelper).
copyString(EXPECTED_VAL);
}
// function that will be run after the clipboard has EXPECTED_VAL
function nextTest() {
// do some other testing here if you want
finish();
}
waitForClipboard(EXPECTED_VAL, setup, nextTest, finish);
}