diff options
Diffstat (limited to 'toolkit/components/satchel/test/satchel_common.js')
-rw-r--r-- | toolkit/components/satchel/test/satchel_common.js | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/toolkit/components/satchel/test/satchel_common.js b/toolkit/components/satchel/test/satchel_common.js new file mode 100644 index 000000000..c047f40af --- /dev/null +++ b/toolkit/components/satchel/test/satchel_common.js @@ -0,0 +1,274 @@ +/* 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/. */ + +var gPopupShownExpected = false; +var gPopupShownListener; +var gLastAutoCompleteResults; +var gChromeScript; + +/* + * Returns the element with the specified |name| attribute. + */ +function $_(formNum, name) { + var form = document.getElementById("form" + formNum); + if (!form) { + ok(false, "$_ couldn't find requested form " + formNum); + return null; + } + + var element = form.elements.namedItem(name); + if (!element) { + ok(false, "$_ couldn't find requested element " + name); + return null; + } + + // Note that namedItem is a bit stupid, and will prefer an + // |id| attribute over a |name| attribute when looking for + // the element. + + if (element.hasAttribute("name") && element.getAttribute("name") != name) { + ok(false, "$_ got confused."); + return null; + } + + return element; +} + +// Mochitest gives us a sendKey(), but it's targeted to a specific element. +// This basically sends an untargeted key event, to whatever's focused. +function doKey(aKey, modifier) { + var keyName = "DOM_VK_" + aKey.toUpperCase(); + var key = SpecialPowers.Ci.nsIDOMKeyEvent[keyName]; + + // undefined --> null + if (!modifier) + modifier = null; + + // Window utils for sending fake key events. + var wutils = SpecialPowers.getDOMWindowUtils(window); + + if (wutils.sendKeyEvent("keydown", key, 0, modifier)) { + wutils.sendKeyEvent("keypress", key, 0, modifier); + } + wutils.sendKeyEvent("keyup", key, 0, modifier); +} + +function registerPopupShownListener(listener) { + if (gPopupShownListener) { + ok(false, "got too many popupshownlisteners"); + return; + } + gPopupShownListener = listener; +} + +function getMenuEntries() { + if (!gLastAutoCompleteResults) { + throw new Error("no autocomplete results"); + } + + var results = gLastAutoCompleteResults; + gLastAutoCompleteResults = null; + return results; +} + +function checkArrayValues(actualValues, expectedValues, msg) { + is(actualValues.length, expectedValues.length, "Checking array values: " + msg); + for (var i = 0; i < expectedValues.length; i++) + is(actualValues[i], expectedValues[i], msg + " Checking array entry #" + i); +} + +var checkObserver = { + verifyStack: [], + callback: null, + + init() { + gChromeScript.sendAsyncMessage("addObserver"); + gChromeScript.addMessageListener("satchel-storage-changed", this.observe.bind(this)); + }, + + uninit() { + gChromeScript.sendAsyncMessage("removeObserver"); + }, + + waitForChecks: function(callback) { + if (this.verifyStack.length == 0) + callback(); + else + this.callback = callback; + }, + + observe: function({ subject, topic, data }) { + if (data != "formhistory-add" && data != "formhistory-update") + return; + ok(this.verifyStack.length > 0, "checking if saved form data was expected"); + + // Make sure that every piece of data we expect to be saved is saved, and no + // more. Here it is assumed that for every entry satchel saves or modifies, a + // message is sent. + // + // We don't actually check the content of the message, but just that the right + // quantity of messages is received. + // - if there are too few messages, test will time out + // - if there are too many messages, test will error out here + // + var expected = this.verifyStack.shift(); + + countEntries(expected.name, expected.value, + function(num) { + ok(num > 0, expected.message); + if (checkObserver.verifyStack.length == 0) { + var callback = checkObserver.callback; + checkObserver.callback = null; + callback(); + } + }); + } +}; + +function checkForSave(name, value, message) { + checkObserver.verifyStack.push({ name : name, value: value, message: message }); +} + +function getFormSubmitButton(formNum) { + var form = $("form" + formNum); // by id, not name + ok(form != null, "getting form " + formNum); + + // we can't just call form.submit(), because that doesn't seem to + // invoke the form onsubmit handler. + var button = form.firstChild; + while (button && button.type != "submit") { button = button.nextSibling; } + ok(button != null, "getting form submit button"); + + return button; +} + +// Count the number of entries with the given name and value, and call then(number) +// when done. If name or value is null, then the value of that field does not matter. +function countEntries(name, value, then = null) { + return new Promise(resolve => { + gChromeScript.sendAsyncMessage("countEntries", { name, value }); + gChromeScript.addMessageListener("entriesCounted", function counted(data) { + gChromeScript.removeMessageListener("entriesCounted", counted); + if (!data.ok) { + ok(false, "Error occurred counting form history"); + SimpleTest.finish(); + return; + } + + if (then) { + then(data.count); + } + resolve(data.count); + }); + }); +} + +// Wrapper around FormHistory.update which handles errors. Calls then() when done. +function updateFormHistory(changes, then = null) { + return new Promise(resolve => { + gChromeScript.sendAsyncMessage("updateFormHistory", { changes }); + gChromeScript.addMessageListener("formHistoryUpdated", function updated({ ok }) { + gChromeScript.removeMessageListener("formHistoryUpdated", updated); + if (!ok) { + ok(false, "Error occurred updating form history"); + SimpleTest.finish(); + return; + } + + if (then) { + then(); + } + resolve(); + }); + }); +} + +function notifyMenuChanged(expectedCount, expectedFirstValue, then = null) { + return new Promise(resolve => { + gChromeScript.sendAsyncMessage("waitForMenuChange", + { expectedCount, + expectedFirstValue }); + gChromeScript.addMessageListener("gotMenuChange", function changed({ results }) { + gChromeScript.removeMessageListener("gotMenuChange", changed); + gLastAutoCompleteResults = results; + if (then) { + then(results); + } + resolve(results); + }); + }); +} + +function notifySelectedIndex(expectedIndex, then = null) { + return new Promise(resolve => { + gChromeScript.sendAsyncMessage("waitForSelectedIndex", { expectedIndex }); + gChromeScript.addMessageListener("gotSelectedIndex", function changed() { + gChromeScript.removeMessageListener("gotSelectedIndex", changed); + if (then) { + then(); + } + resolve(); + }); + }); +} + +function getPopupState(then = null) { + return new Promise(resolve => { + gChromeScript.sendAsyncMessage("getPopupState"); + gChromeScript.addMessageListener("gotPopupState", function listener(state) { + gChromeScript.removeMessageListener("gotPopupState", listener); + if (then) { + then(state); + } + resolve(state); + }); + }); +} + +function listenForUnexpectedPopupShown() { + gPopupShownListener = function onPopupShown() { + if (!gPopupShownExpected) { + ok(false, "Unexpected autocomplete popupshown event"); + } + }; +} + +function* promiseNoUnexpectedPopupShown() { + gPopupShownExpected = false; + listenForUnexpectedPopupShown(); + SimpleTest.requestFlakyTimeout("Giving a chance for an unexpected popupshown to occur"); + yield new Promise(resolve => setTimeout(resolve, 1000)); +} + +/** + * Resolve at the next popupshown event for the autocomplete popup + * @return {Promise} with the results + */ +function promiseACShown() { + gPopupShownExpected = true; + return new Promise(resolve => { + gPopupShownListener = ({ results }) => { + gPopupShownExpected = false; + resolve(results); + }; + }); +} + +function satchelCommonSetup() { + var chromeURL = SimpleTest.getTestFileURL("parent_utils.js"); + gChromeScript = SpecialPowers.loadChromeScript(chromeURL); + gChromeScript.addMessageListener("onpopupshown", ({ results }) => { + gLastAutoCompleteResults = results; + if (gPopupShownListener) + gPopupShownListener({results}); + }); + + SimpleTest.registerCleanupFunction(() => { + gChromeScript.sendAsyncMessage("cleanup"); + gChromeScript.destroy(); + }); +} + + +satchelCommonSetup(); |