summaryrefslogtreecommitdiffstats
path: root/browser/base/content/test/general/browser_contentSearchUI.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/base/content/test/general/browser_contentSearchUI.js')
-rw-r--r--browser/base/content/test/general/browser_contentSearchUI.js771
1 files changed, 771 insertions, 0 deletions
diff --git a/browser/base/content/test/general/browser_contentSearchUI.js b/browser/base/content/test/general/browser_contentSearchUI.js
new file mode 100644
index 000000000..003f80aff
--- /dev/null
+++ b/browser/base/content/test/general/browser_contentSearchUI.js
@@ -0,0 +1,771 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const TEST_PAGE_BASENAME = "contentSearchUI.html";
+const TEST_CONTENT_SCRIPT_BASENAME = "contentSearchUI.js";
+const TEST_ENGINE_PREFIX = "browser_searchSuggestionEngine";
+const TEST_ENGINE_BASENAME = "searchSuggestionEngine.xml";
+const TEST_ENGINE_2_BASENAME = "searchSuggestionEngine2.xml";
+
+const TEST_MSG = "ContentSearchUIControllerTest";
+
+requestLongerTimeout(2);
+
+add_task(function* emptyInput() {
+ yield setUp();
+
+ let state = yield msg("key", { key: "x", waitForSuggestions: true });
+ checkState(state, "x", ["xfoo", "xbar"], -1);
+
+ state = yield msg("key", "VK_BACK_SPACE");
+ checkState(state, "", [], -1);
+
+ yield msg("reset");
+});
+
+add_task(function* blur() {
+ yield setUp();
+
+ let state = yield msg("key", { key: "x", waitForSuggestions: true });
+ checkState(state, "x", ["xfoo", "xbar"], -1);
+
+ state = yield msg("blur");
+ checkState(state, "x", [], -1);
+
+ yield msg("reset");
+});
+
+add_task(function* upDownKeys() {
+ yield setUp();
+
+ let state = yield msg("key", { key: "x", waitForSuggestions: true });
+ checkState(state, "x", ["xfoo", "xbar"], -1);
+
+ // Cycle down the suggestions starting from no selection.
+ state = yield msg("key", "VK_DOWN");
+ checkState(state, "xfoo", ["xfoo", "xbar"], 0);
+
+ state = yield msg("key", "VK_DOWN");
+ checkState(state, "xbar", ["xfoo", "xbar"], 1);
+
+ state = yield msg("key", "VK_DOWN");
+ checkState(state, "x", ["xfoo", "xbar"], 2);
+
+ state = yield msg("key", "VK_DOWN");
+ checkState(state, "x", ["xfoo", "xbar"], 3);
+
+ state = yield msg("key", "VK_DOWN");
+ checkState(state, "x", ["xfoo", "xbar"], -1);
+
+ // Cycle up starting from no selection.
+ state = yield msg("key", "VK_UP");
+ checkState(state, "x", ["xfoo", "xbar"], 3);
+
+ state = yield msg("key", "VK_UP");
+ checkState(state, "x", ["xfoo", "xbar"], 2);
+
+ state = yield msg("key", "VK_UP");
+ checkState(state, "xbar", ["xfoo", "xbar"], 1);
+
+ state = yield msg("key", "VK_UP");
+ checkState(state, "xfoo", ["xfoo", "xbar"], 0);
+
+ state = yield msg("key", "VK_UP");
+ checkState(state, "x", ["xfoo", "xbar"], -1);
+
+ yield msg("reset");
+});
+
+add_task(function* rightLeftKeys() {
+ yield setUp();
+
+ let state = yield msg("key", { key: "x", waitForSuggestions: true });
+ checkState(state, "x", ["xfoo", "xbar"], -1);
+
+ state = yield msg("key", "VK_LEFT");
+ checkState(state, "x", ["xfoo", "xbar"], -1);
+
+ state = yield msg("key", "VK_LEFT");
+ checkState(state, "x", ["xfoo", "xbar"], -1);
+
+ state = yield msg("key", "VK_RIGHT");
+ checkState(state, "x", ["xfoo", "xbar"], -1);
+
+ state = yield msg("key", "VK_RIGHT");
+ checkState(state, "x", [], -1);
+
+ state = yield msg("key", { key: "VK_DOWN", waitForSuggestions: true });
+ checkState(state, "x", ["xfoo", "xbar"], -1);
+
+ state = yield msg("key", "VK_DOWN");
+ checkState(state, "xfoo", ["xfoo", "xbar"], 0);
+
+ // This should make the xfoo suggestion sticky. To make sure it sticks,
+ // trigger suggestions again and cycle through them by pressing Down until
+ // nothing is selected again.
+ state = yield msg("key", "VK_RIGHT");
+ checkState(state, "xfoo", [], -1);
+
+ state = yield msg("key", { key: "VK_DOWN", waitForSuggestions: true });
+ checkState(state, "xfoo", ["xfoofoo", "xfoobar"], -1);
+
+ state = yield msg("key", "VK_DOWN");
+ checkState(state, "xfoofoo", ["xfoofoo", "xfoobar"], 0);
+
+ state = yield msg("key", "VK_DOWN");
+ checkState(state, "xfoobar", ["xfoofoo", "xfoobar"], 1);
+
+ state = yield msg("key", "VK_DOWN");
+ checkState(state, "xfoo", ["xfoofoo", "xfoobar"], 2);
+
+ state = yield msg("key", "VK_DOWN");
+ checkState(state, "xfoo", ["xfoofoo", "xfoobar"], 3);
+
+ state = yield msg("key", "VK_DOWN");
+ checkState(state, "xfoo", ["xfoofoo", "xfoobar"], -1);
+
+ yield msg("reset");
+});
+
+add_task(function* tabKey() {
+ yield setUp();
+ yield msg("key", { key: "x", waitForSuggestions: true });
+
+ let state = yield msg("key", "VK_TAB");
+ checkState(state, "x", ["xfoo", "xbar"], 2);
+
+ state = yield msg("key", "VK_TAB");
+ checkState(state, "x", ["xfoo", "xbar"], 3);
+
+ state = yield msg("key", { key: "VK_TAB", modifiers: { shiftKey: true }});
+ checkState(state, "x", ["xfoo", "xbar"], 2);
+
+ state = yield msg("key", { key: "VK_TAB", modifiers: { shiftKey: true }});
+ checkState(state, "x", [], -1);
+
+ yield setUp();
+
+ yield msg("key", { key: "VK_DOWN", waitForSuggestions: true });
+
+ for (let i = 0; i < 3; ++i) {
+ state = yield msg("key", "VK_TAB");
+ }
+ checkState(state, "x", [], -1);
+
+ yield setUp();
+
+ yield msg("key", { key: "VK_DOWN", waitForSuggestions: true });
+ state = yield msg("key", "VK_DOWN");
+ checkState(state, "xfoo", ["xfoo", "xbar"], 0);
+
+ state = yield msg("key", "VK_TAB");
+ checkState(state, "xfoo", ["xfoo", "xbar"], 0, 0);
+
+ state = yield msg("key", "VK_TAB");
+ checkState(state, "xfoo", ["xfoo", "xbar"], 0, 1);
+
+ state = yield msg("key", "VK_DOWN");
+ checkState(state, "xbar", ["xfoo", "xbar"], 1, 1);
+
+ state = yield msg("key", "VK_DOWN");
+ checkState(state, "x", ["xfoo", "xbar"], 2);
+
+ state = yield msg("key", "VK_UP");
+ checkState(state, "xbar", ["xfoo", "xbar"], 1);
+
+ state = yield msg("key", "VK_TAB");
+ checkState(state, "xbar", ["xfoo", "xbar"], 1, 0);
+
+ state = yield msg("key", "VK_TAB");
+ checkState(state, "xbar", ["xfoo", "xbar"], 1, 1);
+
+ state = yield msg("key", "VK_TAB");
+ checkState(state, "xbar", [], -1);
+
+ yield msg("reset");
+});
+
+add_task(function* cycleSuggestions() {
+ yield setUp();
+ yield msg("key", { key: "x", waitForSuggestions: true });
+
+ let cycle = Task.async(function* (aSelectedButtonIndex) {
+ let modifiers = {
+ shiftKey: true,
+ accelKey: true,
+ };
+
+ let state = yield msg("key", { key: "VK_DOWN", modifiers: modifiers });
+ checkState(state, "xfoo", ["xfoo", "xbar"], 0, aSelectedButtonIndex);
+
+ state = yield msg("key", { key: "VK_DOWN", modifiers: modifiers });
+ checkState(state, "xbar", ["xfoo", "xbar"], 1, aSelectedButtonIndex);
+
+ state = yield msg("key", { key: "VK_DOWN", modifiers: modifiers });
+ checkState(state, "x", ["xfoo", "xbar"], -1, aSelectedButtonIndex);
+
+ state = yield msg("key", { key: "VK_DOWN", modifiers: modifiers });
+ checkState(state, "xfoo", ["xfoo", "xbar"], 0, aSelectedButtonIndex);
+
+ state = yield msg("key", { key: "VK_UP", modifiers: modifiers });
+ checkState(state, "x", ["xfoo", "xbar"], -1, aSelectedButtonIndex);
+
+ state = yield msg("key", { key: "VK_UP", modifiers: modifiers });
+ checkState(state, "xbar", ["xfoo", "xbar"], 1, aSelectedButtonIndex);
+
+ state = yield msg("key", { key: "VK_UP", modifiers: modifiers });
+ checkState(state, "xfoo", ["xfoo", "xbar"], 0, aSelectedButtonIndex);
+
+ state = yield msg("key", { key: "VK_UP", modifiers: modifiers });
+ checkState(state, "x", ["xfoo", "xbar"], -1, aSelectedButtonIndex);
+ });
+
+ yield cycle();
+
+ // Repeat with a one-off selected.
+ let state = yield msg("key", "VK_TAB");
+ checkState(state, "x", ["xfoo", "xbar"], 2);
+ yield cycle(0);
+
+ // Repeat with the settings button selected.
+ state = yield msg("key", "VK_TAB");
+ checkState(state, "x", ["xfoo", "xbar"], 3);
+ yield cycle(1);
+
+ yield msg("reset");
+});
+
+add_task(function* cycleOneOffs() {
+ yield setUp();
+ yield msg("key", { key: "x", waitForSuggestions: true });
+
+ yield msg("addDuplicateOneOff");
+
+ let state = yield msg("key", "VK_DOWN");
+ state = yield msg("key", "VK_DOWN");
+ checkState(state, "xbar", ["xfoo", "xbar"], 1);
+
+ let modifiers = {
+ altKey: true,
+ };
+
+ state = yield msg("key", { key: "VK_DOWN", modifiers: modifiers });
+ checkState(state, "xbar", ["xfoo", "xbar"], 1, 0);
+
+ state = yield msg("key", { key: "VK_DOWN", modifiers: modifiers });
+ checkState(state, "xbar", ["xfoo", "xbar"], 1, 1);
+
+ state = yield msg("key", { key: "VK_DOWN", modifiers: modifiers });
+ checkState(state, "xbar", ["xfoo", "xbar"], 1);
+
+ state = yield msg("key", { key: "VK_UP", modifiers: modifiers });
+ checkState(state, "xbar", ["xfoo", "xbar"], 1, 1);
+
+ state = yield msg("key", { key: "VK_UP", modifiers: modifiers });
+ checkState(state, "xbar", ["xfoo", "xbar"], 1, 0);
+
+ state = yield msg("key", { key: "VK_UP", modifiers: modifiers });
+ checkState(state, "xbar", ["xfoo", "xbar"], 1);
+
+ // If the settings button is selected, pressing alt+up/down should select the
+ // last/first one-off respectively (and deselect the settings button).
+ yield msg("key", "VK_TAB");
+ yield msg("key", "VK_TAB");
+ state = yield msg("key", "VK_TAB"); // Settings button selected.
+ checkState(state, "xbar", ["xfoo", "xbar"], 1, 2);
+
+ state = yield msg("key", { key: "VK_UP", modifiers: modifiers });
+ checkState(state, "xbar", ["xfoo", "xbar"], 1, 1);
+
+ state = yield msg("key", "VK_TAB");
+ checkState(state, "xbar", ["xfoo", "xbar"], 1, 2);
+
+ state = yield msg("key", { key: "VK_DOWN", modifiers: modifiers });
+ checkState(state, "xbar", ["xfoo", "xbar"], 1, 0);
+
+ yield msg("removeLastOneOff");
+ yield msg("reset");
+});
+
+add_task(function* mouse() {
+ yield setUp();
+
+ let state = yield msg("key", { key: "x", waitForSuggestions: true });
+ checkState(state, "x", ["xfoo", "xbar"], -1);
+
+ state = yield msg("mousemove", 0);
+ checkState(state, "x", ["xfoo", "xbar"], 0);
+
+ state = yield msg("mousemove", 1);
+ checkState(state, "x", ["xfoo", "xbar"], 1);
+
+ state = yield msg("mousemove", 2);
+ checkState(state, "x", ["xfoo", "xbar"], 1, 0);
+
+ state = yield msg("mousemove", 3);
+ checkState(state, "x", ["xfoo", "xbar"], 1, 1);
+
+ state = yield msg("mousemove", -1);
+ checkState(state, "x", ["xfoo", "xbar"], 1);
+
+ yield msg("reset");
+ yield setUp();
+
+ state = yield msg("key", { key: "x", waitForSuggestions: true });
+ checkState(state, "x", ["xfoo", "xbar"], -1);
+
+ state = yield msg("mousemove", 0);
+ checkState(state, "x", ["xfoo", "xbar"], 0);
+
+ state = yield msg("mousemove", 2);
+ checkState(state, "x", ["xfoo", "xbar"], 0, 0);
+
+ state = yield msg("mousemove", -1);
+ checkState(state, "x", ["xfoo", "xbar"], 0);
+
+ yield msg("reset");
+});
+
+add_task(function* formHistory() {
+ yield setUp();
+
+ // Type an X and add it to form history.
+ let state = yield msg("key", { key: "x", waitForSuggestions: true });
+ checkState(state, "x", ["xfoo", "xbar"], -1);
+ // Wait for Satchel to say it's been added to form history.
+ let deferred = Promise.defer();
+ Services.obs.addObserver(function onAdd(subj, topic, data) {
+ if (data == "formhistory-add") {
+ Services.obs.removeObserver(onAdd, "satchel-storage-changed");
+ executeSoon(() => deferred.resolve());
+ }
+ }, "satchel-storage-changed", false);
+ yield Promise.all([msg("addInputValueToFormHistory"), deferred.promise]);
+
+ // Reset the input.
+ state = yield msg("reset");
+ checkState(state, "", [], -1);
+
+ // Type an X again. The form history entry should appear.
+ state = yield msg("key", { key: "x", waitForSuggestions: true });
+ checkState(state, "x", [{ str: "x", type: "formHistory" }, "xfoo", "xbar"],
+ -1);
+
+ // Select the form history entry and delete it.
+ state = yield msg("key", "VK_DOWN");
+ checkState(state, "x", [{ str: "x", type: "formHistory" }, "xfoo", "xbar"],
+ 0);
+
+ // Wait for Satchel.
+ deferred = Promise.defer();
+ Services.obs.addObserver(function onRemove(subj, topic, data) {
+ if (data == "formhistory-remove") {
+ Services.obs.removeObserver(onRemove, "satchel-storage-changed");
+ executeSoon(() => deferred.resolve());
+ }
+ }, "satchel-storage-changed", false);
+
+ state = yield msg("key", "VK_DELETE");
+ checkState(state, "x", ["xfoo", "xbar"], -1);
+
+ yield deferred.promise;
+
+ // Reset the input.
+ state = yield msg("reset");
+ checkState(state, "", [], -1);
+
+ // Type an X again. The form history entry should still be gone.
+ state = yield msg("key", { key: "x", waitForSuggestions: true });
+ checkState(state, "x", ["xfoo", "xbar"], -1);
+
+ yield msg("reset");
+});
+
+add_task(function* cycleEngines() {
+ yield setUp();
+ yield msg("key", { key: "VK_DOWN", waitForSuggestions: true });
+
+ let promiseEngineChange = function(newEngineName) {
+ let deferred = Promise.defer();
+ Services.obs.addObserver(function resolver(subj, topic, data) {
+ if (data != "engine-current") {
+ return;
+ }
+ SimpleTest.is(subj.name, newEngineName, "Engine cycled correctly");
+ Services.obs.removeObserver(resolver, "browser-search-engine-modified");
+ deferred.resolve();
+ }, "browser-search-engine-modified", false);
+ return deferred.promise;
+ }
+
+ let p = promiseEngineChange(TEST_ENGINE_PREFIX + " " + TEST_ENGINE_2_BASENAME);
+ yield msg("key", { key: "VK_DOWN", modifiers: { accelKey: true }});
+ yield p;
+
+ p = promiseEngineChange(TEST_ENGINE_PREFIX + " " + TEST_ENGINE_BASENAME);
+ yield msg("key", { key: "VK_UP", modifiers: { accelKey: true }});
+ yield p;
+
+ yield msg("reset");
+});
+
+add_task(function* search() {
+ yield setUp();
+
+ let modifiers = {};
+ ["altKey", "ctrlKey", "metaKey", "shiftKey"].forEach(k => modifiers[k] = true);
+
+ // Test typing a query and pressing enter.
+ let p = msg("waitForSearch");
+ yield msg("key", { key: "x", waitForSuggestions: true });
+ yield msg("key", { key: "VK_RETURN", modifiers: modifiers });
+ let mesg = yield p;
+ let eventData = {
+ engineName: TEST_ENGINE_PREFIX + " " + TEST_ENGINE_BASENAME,
+ searchString: "x",
+ healthReportKey: "test",
+ searchPurpose: "test",
+ originalEvent: modifiers,
+ };
+ SimpleTest.isDeeply(eventData, mesg, "Search event data");
+
+ yield promiseTab();
+ yield setUp();
+
+ // Test typing a query, then selecting a suggestion and pressing enter.
+ p = msg("waitForSearch");
+ yield msg("key", { key: "x", waitForSuggestions: true });
+ yield msg("key", "VK_DOWN");
+ yield msg("key", "VK_DOWN");
+ yield msg("key", { key: "VK_RETURN", modifiers: modifiers });
+ mesg = yield p;
+ eventData.searchString = "xfoo";
+ eventData.engineName = TEST_ENGINE_PREFIX + " " + TEST_ENGINE_BASENAME;
+ eventData.selection = {
+ index: 1,
+ kind: "key",
+ }
+ SimpleTest.isDeeply(eventData, mesg, "Search event data");
+
+ yield promiseTab();
+ yield setUp();
+
+ // Test typing a query, then selecting a one-off button and pressing enter.
+ p = msg("waitForSearch");
+ yield msg("key", { key: "x", waitForSuggestions: true });
+ yield msg("key", "VK_UP");
+ yield msg("key", "VK_UP");
+ yield msg("key", { key: "VK_RETURN", modifiers: modifiers });
+ mesg = yield p;
+ delete eventData.selection;
+ eventData.searchString = "x";
+ eventData.engineName = TEST_ENGINE_PREFIX + " " + TEST_ENGINE_2_BASENAME;
+ SimpleTest.isDeeply(eventData, mesg, "Search event data");
+
+ yield promiseTab();
+ yield setUp();
+
+ // Test typing a query and clicking the search engine header.
+ p = msg("waitForSearch");
+ modifiers.button = 0;
+ yield msg("key", { key: "x", waitForSuggestions: true });
+ yield msg("mousemove", -1);
+ yield msg("click", { eltIdx: -1, modifiers: modifiers });
+ mesg = yield p;
+ eventData.originalEvent = modifiers;
+ eventData.engineName = TEST_ENGINE_PREFIX + " " + TEST_ENGINE_BASENAME;
+ SimpleTest.isDeeply(eventData, mesg, "Search event data");
+
+ yield promiseTab();
+ yield setUp();
+
+ // Test typing a query and then clicking a suggestion.
+ yield msg("key", { key: "x", waitForSuggestions: true });
+ p = msg("waitForSearch");
+ yield msg("mousemove", 1);
+ yield msg("click", { eltIdx: 1, modifiers: modifiers });
+ mesg = yield p;
+ eventData.searchString = "xfoo";
+ eventData.selection = {
+ index: 1,
+ kind: "mouse",
+ };
+ SimpleTest.isDeeply(eventData, mesg, "Search event data");
+
+ yield promiseTab();
+ yield setUp();
+
+ // Test typing a query and then clicking a one-off button.
+ yield msg("key", { key: "x", waitForSuggestions: true });
+ p = msg("waitForSearch");
+ yield msg("mousemove", 3);
+ yield msg("click", { eltIdx: 3, modifiers: modifiers });
+ mesg = yield p;
+ eventData.searchString = "x";
+ eventData.engineName = TEST_ENGINE_PREFIX + " " + TEST_ENGINE_2_BASENAME;
+ delete eventData.selection;
+ SimpleTest.isDeeply(eventData, mesg, "Search event data");
+
+ yield promiseTab();
+ yield setUp();
+
+ // Test selecting a suggestion, then clicking a one-off without deselecting the
+ // suggestion.
+ yield msg("key", { key: "x", waitForSuggestions: true });
+ p = msg("waitForSearch");
+ yield msg("mousemove", 1);
+ yield msg("mousemove", 3);
+ yield msg("click", { eltIdx: 3, modifiers: modifiers });
+ mesg = yield p;
+ eventData.searchString = "xfoo"
+ eventData.selection = {
+ index: 1,
+ kind: "mouse",
+ };
+ SimpleTest.isDeeply(eventData, mesg, "Search event data");
+
+ yield promiseTab();
+ yield setUp();
+
+ // Same as above, but with the keyboard.
+ delete modifiers.button;
+ yield msg("key", { key: "x", waitForSuggestions: true });
+ p = msg("waitForSearch");
+ yield msg("key", "VK_DOWN");
+ yield msg("key", "VK_DOWN");
+ yield msg("key", "VK_TAB");
+ yield msg("key", { key: "VK_RETURN", modifiers: modifiers });
+ mesg = yield p;
+ eventData.selection = {
+ index: 1,
+ kind: "key",
+ };
+ SimpleTest.isDeeply(eventData, mesg, "Search event data");
+
+ yield promiseTab();
+ yield setUp();
+
+ // Test searching when using IME composition.
+ let state = yield msg("startComposition", { data: "" });
+ checkState(state, "", [], -1);
+ state = yield msg("changeComposition", { data: "x", waitForSuggestions: true });
+ checkState(state, "x", [{ str: "x", type: "formHistory" },
+ { str: "xfoo", type: "formHistory" }, "xbar"], -1);
+ yield msg("commitComposition");
+ delete modifiers.button;
+ p = msg("waitForSearch");
+ yield msg("key", { key: "VK_RETURN", modifiers: modifiers });
+ mesg = yield p;
+ eventData.searchString = "x"
+ eventData.originalEvent = modifiers;
+ eventData.engineName = TEST_ENGINE_PREFIX + " " + TEST_ENGINE_BASENAME;
+ delete eventData.selection;
+ SimpleTest.isDeeply(eventData, mesg, "Search event data");
+
+ yield promiseTab();
+ yield setUp();
+
+ state = yield msg("startComposition", { data: "" });
+ checkState(state, "", [], -1);
+ state = yield msg("changeComposition", { data: "x", waitForSuggestions: true });
+ checkState(state, "x", [{ str: "x", type: "formHistory" },
+ { str: "xfoo", type: "formHistory" }, "xbar"], -1);
+
+ // Mouse over the first suggestion.
+ state = yield msg("mousemove", 0);
+ checkState(state, "x", [{ str: "x", type: "formHistory" },
+ { str: "xfoo", type: "formHistory" }, "xbar"], 0);
+
+ // Mouse over the second suggestion.
+ state = yield msg("mousemove", 1);
+ checkState(state, "x", [{ str: "x", type: "formHistory" },
+ { str: "xfoo", type: "formHistory" }, "xbar"], 1);
+
+ modifiers.button = 0;
+ p = msg("waitForSearch");
+ yield msg("click", { eltIdx: 1, modifiers: modifiers });
+ mesg = yield p;
+ eventData.searchString = "xfoo";
+ eventData.originalEvent = modifiers;
+ eventData.selection = {
+ index: 1,
+ kind: "mouse",
+ };
+ SimpleTest.isDeeply(eventData, mesg, "Search event data");
+
+ yield promiseTab();
+ yield setUp();
+
+ // Remove form history entries.
+ // Wait for Satchel.
+ let deferred = Promise.defer();
+ let historyCount = 2;
+ Services.obs.addObserver(function onRemove(subj, topic, data) {
+ if (data == "formhistory-remove") {
+ if (--historyCount) {
+ return;
+ }
+ Services.obs.removeObserver(onRemove, "satchel-storage-changed");
+ executeSoon(() => deferred.resolve());
+ }
+ }, "satchel-storage-changed", false);
+
+ yield msg("key", { key: "x", waitForSuggestions: true });
+ yield msg("key", "VK_DOWN");
+ yield msg("key", "VK_DOWN");
+ yield msg("key", "VK_DELETE");
+ yield msg("key", "VK_DOWN");
+ yield msg("key", "VK_DELETE");
+ yield deferred.promise;
+
+ yield msg("reset");
+ state = yield msg("key", { key: "x", waitForSuggestions: true });
+ checkState(state, "x", ["xfoo", "xbar"], -1);
+
+ yield promiseTab();
+ yield setUp();
+ yield msg("reset");
+});
+
+add_task(function* settings() {
+ yield setUp();
+ yield msg("key", { key: "VK_DOWN", waitForSuggestions: true });
+ yield msg("key", "VK_UP");
+ let p = msg("waitForSearchSettings");
+ yield msg("key", "VK_RETURN");
+ yield p;
+
+ yield msg("reset");
+});
+
+var gDidInitialSetUp = false;
+
+function setUp(aNoEngine) {
+ return Task.spawn(function* () {
+ if (!gDidInitialSetUp) {
+ Cu.import("resource:///modules/ContentSearch.jsm");
+ let originalOnMessageSearch = ContentSearch._onMessageSearch;
+ let originalOnMessageManageEngines = ContentSearch._onMessageManageEngines;
+ ContentSearch._onMessageSearch = () => {};
+ ContentSearch._onMessageManageEngines = () => {};
+ registerCleanupFunction(() => {
+ ContentSearch._onMessageSearch = originalOnMessageSearch;
+ ContentSearch._onMessageManageEngines = originalOnMessageManageEngines;
+ });
+ yield setUpEngines();
+ yield promiseTab();
+ gDidInitialSetUp = true;
+ }
+ yield msg("focus");
+ });
+}
+
+function msg(type, data=null) {
+ gMsgMan.sendAsyncMessage(TEST_MSG, {
+ type: type,
+ data: data,
+ });
+ let deferred = Promise.defer();
+ gMsgMan.addMessageListener(TEST_MSG, function onMsg(msgObj) {
+ if (msgObj.data.type != type) {
+ return;
+ }
+ gMsgMan.removeMessageListener(TEST_MSG, onMsg);
+ deferred.resolve(msgObj.data.data);
+ });
+ return deferred.promise;
+}
+
+function checkState(actualState, expectedInputVal, expectedSuggestions,
+ expectedSelectedIdx, expectedSelectedButtonIdx) {
+ expectedSuggestions = expectedSuggestions.map(sugg => {
+ return typeof(sugg) == "object" ? sugg : {
+ str: sugg,
+ type: "remote",
+ };
+ });
+
+ if (expectedSelectedIdx == -1 && expectedSelectedButtonIdx != undefined) {
+ expectedSelectedIdx = expectedSuggestions.length + expectedSelectedButtonIdx;
+ }
+
+ let expectedState = {
+ selectedIndex: expectedSelectedIdx,
+ numSuggestions: expectedSuggestions.length,
+ suggestionAtIndex: expectedSuggestions.map(s => s.str),
+ isFormHistorySuggestionAtIndex:
+ expectedSuggestions.map(s => s.type == "formHistory"),
+
+ tableHidden: expectedSuggestions.length == 0,
+
+ inputValue: expectedInputVal,
+ ariaExpanded: expectedSuggestions.length == 0 ? "false" : "true",
+ };
+ if (expectedSelectedButtonIdx != undefined) {
+ expectedState.selectedButtonIndex = expectedSelectedButtonIdx;
+ }
+ else if (expectedSelectedIdx < expectedSuggestions.length) {
+ expectedState.selectedButtonIndex = -1;
+ }
+ else {
+ expectedState.selectedButtonIndex = expectedSelectedIdx - expectedSuggestions.length;
+ }
+
+ SimpleTest.isDeeply(actualState, expectedState, "State");
+}
+
+var gMsgMan;
+
+function* promiseTab() {
+ let deferred = Promise.defer();
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser);
+ registerCleanupFunction(() => BrowserTestUtils.removeTab(tab));
+ let pageURL = getRootDirectory(gTestPath) + TEST_PAGE_BASENAME;
+ tab.linkedBrowser.addEventListener("load", function onLoad(event) {
+ tab.linkedBrowser.removeEventListener("load", onLoad, true);
+ gMsgMan = tab.linkedBrowser.messageManager;
+ gMsgMan.sendAsyncMessage("ContentSearch", {
+ type: "AddToWhitelist",
+ data: [pageURL],
+ });
+ promiseMsg("ContentSearch", "AddToWhitelistAck", gMsgMan).then(() => {
+ let jsURL = getRootDirectory(gTestPath) + TEST_CONTENT_SCRIPT_BASENAME;
+ gMsgMan.loadFrameScript(jsURL, false);
+ deferred.resolve(msg("init"));
+ });
+ }, true, true);
+ openUILinkIn(pageURL, "current");
+ return deferred.promise;
+}
+
+function promiseMsg(name, type, msgMan) {
+ let deferred = Promise.defer();
+ info("Waiting for " + name + " message " + type + "...");
+ msgMan.addMessageListener(name, function onMsg(msgObj) {
+ info("Received " + name + " message " + msgObj.data.type + "\n");
+ if (msgObj.data.type == type) {
+ msgMan.removeMessageListener(name, onMsg);
+ deferred.resolve(msgObj);
+ }
+ });
+ return deferred.promise;
+}
+
+function setUpEngines() {
+ return Task.spawn(function* () {
+ info("Removing default search engines");
+ let currentEngineName = Services.search.currentEngine.name;
+ let currentEngines = Services.search.getVisibleEngines();
+ info("Adding test search engines");
+ let engine1 = yield promiseNewSearchEngine(TEST_ENGINE_BASENAME);
+ yield promiseNewSearchEngine(TEST_ENGINE_2_BASENAME);
+ Services.search.currentEngine = engine1;
+ for (let engine of currentEngines) {
+ Services.search.removeEngine(engine);
+ }
+ registerCleanupFunction(() => {
+ Services.search.restoreDefaultEngines();
+ Services.search.currentEngine = Services.search.getEngineByName(currentEngineName);
+ });
+ });
+}