mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1171344 - Update in-content search UI tests. r=adw
This commit is contained in:
parent
a063f90543
commit
a3423dfcbc
@ -80,6 +80,7 @@ support-files =
|
||||
redirect_bug623155.sjs
|
||||
searchSuggestionEngine.sjs
|
||||
searchSuggestionEngine.xml
|
||||
searchSuggestionEngine2.xml
|
||||
subtst_contextmenu.html
|
||||
test-mixedcontent-securityerrors.html
|
||||
test_bug435035.html
|
||||
@ -369,10 +370,10 @@ skip-if = buildapp == 'mulet' || e10s # Bug 933103 - mochitest's EventUtils.synt
|
||||
skip-if = buildapp == 'mulet'
|
||||
[browser_save_video_frame.js]
|
||||
[browser_scope.js]
|
||||
[browser_searchSuggestionUI.js]
|
||||
[browser_contentSearchUI.js]
|
||||
support-files =
|
||||
searchSuggestionUI.html
|
||||
searchSuggestionUI.js
|
||||
contentSearchUI.html
|
||||
contentSearchUI.js
|
||||
[browser_selectpopup.js]
|
||||
run-if = e10s
|
||||
[browser_selectTabAtIndex.js]
|
||||
|
@ -101,28 +101,15 @@ let gTests = [
|
||||
// Make this actually work in healthreport by giving it an ID:
|
||||
engine.wrappedJSObject._identifier = 'org.mozilla.testsearchsuggestions';
|
||||
|
||||
let promise = promiseBrowserAttributes(gBrowser.selectedTab);
|
||||
let p = promiseContentSearchChange(engine.name);
|
||||
Services.search.currentEngine = engine;
|
||||
yield promise;
|
||||
yield p;
|
||||
|
||||
let numSearchesBefore = 0;
|
||||
let searchEventDeferred = Promise.defer();
|
||||
let doc = gBrowser.contentDocument;
|
||||
let engineName = doc.documentElement.getAttribute("searchEngineName");
|
||||
let engineName = gBrowser.contentWindow.wrappedJSObject.gContentSearchController.defaultEngine.name;
|
||||
is(engine.name, engineName, "Engine name in DOM should match engine we just added");
|
||||
let mm = gBrowser.selectedBrowser.messageManager;
|
||||
|
||||
mm.loadFrameScript(TEST_CONTENT_HELPER, false);
|
||||
|
||||
mm.addMessageListener("AboutHomeTest:CheckRecordedSearch", function (msg) {
|
||||
let data = JSON.parse(msg.data);
|
||||
is(data.engineName, engineName, "Detail is search engine name");
|
||||
|
||||
getNumberOfSearches(engineName).then(num => {
|
||||
is(num, numSearchesBefore + 1, "One more search recorded.");
|
||||
searchEventDeferred.resolve();
|
||||
});
|
||||
});
|
||||
|
||||
// Get the current number of recorded searches.
|
||||
let searchStr = "a search";
|
||||
@ -137,7 +124,12 @@ let gTests = [
|
||||
let expectedURL = Services.search.currentEngine.
|
||||
getSubmission(searchStr, null, "homepage").
|
||||
uri.spec;
|
||||
let loadPromise = waitForDocLoadAndStopIt(expectedURL);
|
||||
let loadPromise = waitForDocLoadAndStopIt(expectedURL).then(() => {
|
||||
getNumberOfSearches(engineName).then(num => {
|
||||
is(num, numSearchesBefore + 1, "One more search recorded.");
|
||||
searchEventDeferred.resolve();
|
||||
});
|
||||
});
|
||||
|
||||
try {
|
||||
yield Promise.all([searchEventDeferred.promise, loadPromise]);
|
||||
@ -236,11 +228,11 @@ let gTests = [
|
||||
{
|
||||
desc: "Check POST search engine support",
|
||||
setup: function() {},
|
||||
run: function()
|
||||
run: function* ()
|
||||
{
|
||||
let deferred = Promise.defer();
|
||||
let currEngine = Services.search.defaultEngine;
|
||||
let searchObserver = function search_observer(aSubject, aTopic, aData) {
|
||||
let searchObserver = Task.async(function* search_observer(aSubject, aTopic, aData) {
|
||||
let engine = aSubject.QueryInterface(Ci.nsISearchEngine);
|
||||
info("Observer: " + aData + " for " + engine.name);
|
||||
|
||||
@ -255,24 +247,15 @@ let gTests = [
|
||||
let document = gBrowser.selectedBrowser.contentDocument;
|
||||
let searchText = document.getElementById("searchText");
|
||||
|
||||
// We're about to change the search engine. Once the change has
|
||||
// propagated to the about:home content, we want to perform a search.
|
||||
let mutationObserver = new MutationObserver(function (mutations) {
|
||||
for (let mutation of mutations) {
|
||||
if (mutation.attributeName == "searchEngineName") {
|
||||
searchText.value = needle;
|
||||
searchText.focus();
|
||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
}
|
||||
}
|
||||
});
|
||||
mutationObserver.observe(document.documentElement, { attributes: true });
|
||||
|
||||
// Change the search engine, triggering the observer above.
|
||||
let p = promiseContentSearchChange(engine.name);
|
||||
Services.search.defaultEngine = engine;
|
||||
yield p;
|
||||
|
||||
searchText.value = needle;
|
||||
searchText.focus();
|
||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
mutationObserver.disconnect();
|
||||
Services.search.removeEngine(engine);
|
||||
Services.search.defaultEngine = currEngine;
|
||||
});
|
||||
@ -286,7 +269,7 @@ let gTests = [
|
||||
"Search text should arrive correctly");
|
||||
deferred.resolve();
|
||||
});
|
||||
};
|
||||
});
|
||||
Services.obs.addObserver(searchObserver, "browser-search-engine-modified", false);
|
||||
registerCleanupFunction(function () {
|
||||
Services.obs.removeObserver(searchObserver, "browser-search-engine-modified");
|
||||
@ -335,8 +318,7 @@ let gTests = [
|
||||
},
|
||||
|
||||
{
|
||||
// See browser_searchSuggestionUI.js for comprehensive content search
|
||||
// suggestion UI tests.
|
||||
// See browser_contentSearchUI.js for comprehensive content search UI tests.
|
||||
desc: "Search suggestion smoke test",
|
||||
setup: function() {},
|
||||
run: function()
|
||||
@ -344,12 +326,12 @@ let gTests = [
|
||||
return Task.spawn(function* () {
|
||||
// Add a test engine that provides suggestions and switch to it.
|
||||
let engine = yield promiseNewEngine("searchSuggestionEngine.xml");
|
||||
let promise = promiseBrowserAttributes(gBrowser.selectedTab);
|
||||
let p = promiseContentSearchChange(engine.name);
|
||||
Services.search.currentEngine = engine;
|
||||
yield promise;
|
||||
yield p;
|
||||
|
||||
// Avoid intermittent failures.
|
||||
gBrowser.contentWindow.wrappedJSObject.gSearchSuggestionController.remoteTimeout = 5000;
|
||||
gBrowser.contentWindow.wrappedJSObject.gContentSearchController.remoteTimeout = 5000;
|
||||
|
||||
// Type an X in the search input.
|
||||
let input = gBrowser.contentDocument.getElementById("searchText");
|
||||
@ -401,9 +383,11 @@ let gTests = [
|
||||
caret: { start: 1, length: 0 }
|
||||
}, gBrowser.contentWindow);
|
||||
|
||||
let searchController =
|
||||
gBrowser.contentWindow.wrappedJSObject.gContentSearchController;
|
||||
|
||||
// Wait for the search suggestions to become visible.
|
||||
let table =
|
||||
gBrowser.contentDocument.getElementById("searchSuggestionTable");
|
||||
let table = searchController._suggestionsList;
|
||||
let deferred = Promise.defer();
|
||||
let observer = new MutationObserver(() => {
|
||||
if (input.getAttribute("aria-expanded") == "true") {
|
||||
@ -424,9 +408,14 @@ let gTests = [
|
||||
uri.spec;
|
||||
let loadPromise = waitForDocLoadAndStopIt(expectedURL);
|
||||
let row = table.children[1];
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" }, row, gBrowser.contentWindow);
|
||||
// ContentSearchUIController looks at the current selectedIndex when
|
||||
// performing a search. Synthesizing the mouse event on the suggestion
|
||||
// doesn't actually mouseover the suggestion and trigger it to be flagged
|
||||
// as selected, so we manually select it first.
|
||||
searchController.selectedIndex = 1;
|
||||
EventUtils.synthesizeMouseAtCenter(row, {button: 0}, gBrowser.contentWindow);
|
||||
yield loadPromise;
|
||||
ok(input.value == "xbar", "Suggestion is selected");
|
||||
ok(input.value == "x", "Input value did not change");
|
||||
});
|
||||
}
|
||||
},
|
||||
@ -477,26 +466,6 @@ let gTests = [
|
||||
is(gBrowser.currentURI.spec, "about:accounts?entrypoint=abouthome",
|
||||
"Entry point should be `abouthome`.");
|
||||
})
|
||||
},
|
||||
{
|
||||
desc: "Clicking the icon should open the popup",
|
||||
setup: function () {},
|
||||
run: Task.async(function* () {
|
||||
let doc = gBrowser.selectedBrowser.contentDocument;
|
||||
let searchIcon = doc.getElementById("searchIcon");
|
||||
let panel = window.document.getElementById("abouthome-search-panel");
|
||||
|
||||
info("Waiting for popup to open");
|
||||
EventUtils.synthesizeMouseAtCenter(searchIcon, {}, gBrowser.selectedBrowser.contentWindow);
|
||||
yield promiseWaitForEvent(panel, "popupshown");
|
||||
info("Saw popup open");
|
||||
|
||||
let promise = promisePrefsOpen();
|
||||
let item = window.document.getElementById("abouthome-search-panel-manage");
|
||||
EventUtils.synthesizeMouseAtCenter(item, {});
|
||||
|
||||
yield promise;
|
||||
})
|
||||
}
|
||||
|
||||
];
|
||||
@ -576,38 +545,6 @@ function promiseSetupSnippetsMap(aTab, aSetupFn)
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for the attributes being set by browser.js.
|
||||
*
|
||||
* @param aTab
|
||||
* The tab containing about:home.
|
||||
* @return {Promise} resolved when the attributes are ready.
|
||||
*/
|
||||
function promiseBrowserAttributes(aTab)
|
||||
{
|
||||
let deferred = Promise.defer();
|
||||
|
||||
let docElt = aTab.linkedBrowser.contentDocument.documentElement;
|
||||
let observer = new MutationObserver(function (mutations) {
|
||||
for (let mutation of mutations) {
|
||||
info("Got attribute mutation: " + mutation.attributeName +
|
||||
" from " + mutation.oldValue);
|
||||
// Now we just have to wait for the last attribute.
|
||||
if (mutation.attributeName == "searchEngineName") {
|
||||
info("Remove attributes observer");
|
||||
observer.disconnect();
|
||||
// Must be sure to continue after the page mutation observer.
|
||||
executeSoon(function() deferred.resolve());
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
info("Add attributes observer");
|
||||
observer.observe(docElt, { attributes: true });
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the number of about:home searches recorded for the current day.
|
||||
*
|
||||
@ -711,6 +648,18 @@ let promisePrefsOpen = Task.async(function*() {
|
||||
}
|
||||
});
|
||||
|
||||
function promiseContentSearchChange(newEngineName) {
|
||||
return new Promise(resolve => {
|
||||
content.addEventListener("ContentSearchService", function listener(aEvent) {
|
||||
if (aEvent.detail.type == "CurrentState" &&
|
||||
gBrowser.contentWindow.wrappedJSObject.gContentSearchController.defaultEngine.name == newEngineName) {
|
||||
content.removeEventListener("ContentSearchService", listener);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function promiseNewEngine(basename) {
|
||||
info("Waiting for engine to be added: " + basename);
|
||||
let addDeferred = Promise.defer();
|
||||
|
529
browser/base/content/test/general/browser_contentSearchUI.js
Normal file
529
browser/base/content/test/general/browser_contentSearchUI.js
Normal file
@ -0,0 +1,529 @@
|
||||
/* 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";
|
||||
|
||||
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", [], 0);
|
||||
|
||||
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* mouse() {
|
||||
yield setUp();
|
||||
|
||||
let state = yield msg("key", { key: "x", waitForSuggestions: true });
|
||||
checkState(state, "x", ["xfoo", "xbar"], -1);
|
||||
|
||||
for (let i = 0; i < 4; ++i) {
|
||||
state = yield msg("mousemove", i);
|
||||
checkState(state, "x", ["xfoo", "xbar"], i);
|
||||
}
|
||||
|
||||
state = yield msg("mousemove", -1);
|
||||
checkState(state, "x", ["xfoo", "xbar"], -1);
|
||||
|
||||
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* 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 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.originalEvent = modifiers;
|
||||
eventData.engineName = TEST_ENGINE_PREFIX + " " + TEST_ENGINE_BASENAME;
|
||||
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;
|
||||
let currentTab = gBrowser.selectedTab;
|
||||
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");
|
||||
});
|
||||
|
||||
let 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(msg) {
|
||||
if (msg.data.type != type) {
|
||||
return;
|
||||
}
|
||||
gMsgMan.removeMessageListener(TEST_MSG, onMsg);
|
||||
deferred.resolve(msg.data.data);
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function checkState(actualState, expectedInputVal, expectedSuggestions,
|
||||
expectedSelectedIdx) {
|
||||
expectedSuggestions = expectedSuggestions.map(sugg => {
|
||||
return typeof(sugg) == "object" ? sugg : {
|
||||
str: sugg,
|
||||
type: "remote",
|
||||
};
|
||||
});
|
||||
|
||||
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",
|
||||
};
|
||||
|
||||
SimpleTest.isDeeply(actualState, expectedState, "State");
|
||||
}
|
||||
|
||||
var gMsgMan;
|
||||
|
||||
function promiseTab() {
|
||||
let deferred = Promise.defer();
|
||||
let tab = gBrowser.addTab();
|
||||
registerCleanupFunction(() => gBrowser.removeTab(tab));
|
||||
gBrowser.selectedTab = 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(msg) {
|
||||
info("Received " + name + " message " + msg.data.type + "\n");
|
||||
if (msg.data.type == type) {
|
||||
msgMan.removeMessageListener(name, onMsg);
|
||||
deferred.resolve(msg);
|
||||
}
|
||||
});
|
||||
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 promiseNewEngine(TEST_ENGINE_BASENAME);
|
||||
let engine2 = yield promiseNewEngine(TEST_ENGINE_2_BASENAME);
|
||||
Services.search.currentEngine = engine1;
|
||||
for (let engine of currentEngines) {
|
||||
Services.search.removeEngine(engine);
|
||||
}
|
||||
registerCleanupFunction(() => {
|
||||
Services.search.restoreDefaultEngines();
|
||||
Services.search.removeEngine(engine1);
|
||||
Services.search.removeEngine(engine2);
|
||||
Services.search.currentEngine = Services.search.getEngineByName(currentEngineName);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function promiseNewEngine(basename) {
|
||||
info("Waiting for engine to be added: " + basename);
|
||||
let addDeferred = Promise.defer();
|
||||
let url = getRootDirectory(gTestPath) + basename;
|
||||
Services.search.addEngine(url, Ci.nsISearchEngine.TYPE_MOZSEARCH, "", false, {
|
||||
onSuccess: function (engine) {
|
||||
info("Search engine added: " + basename);
|
||||
addDeferred.resolve(engine);
|
||||
},
|
||||
onError: function (errCode) {
|
||||
ok(false, "addEngine failed with error code " + errCode);
|
||||
addDeferred.reject();
|
||||
},
|
||||
});
|
||||
return addDeferred.promise;
|
||||
}
|
@ -1,345 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const TEST_PAGE_BASENAME = "searchSuggestionUI.html";
|
||||
const TEST_CONTENT_SCRIPT_BASENAME = "searchSuggestionUI.js";
|
||||
const TEST_ENGINE_BASENAME = "searchSuggestionEngine.xml";
|
||||
|
||||
const TEST_MSG = "SearchSuggestionUIControllerTest";
|
||||
|
||||
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* arrowKeys() {
|
||||
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"], -1);
|
||||
|
||||
// Cycle up starting from no selection.
|
||||
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");
|
||||
});
|
||||
|
||||
// The right arrow and return key function the same.
|
||||
function rightArrowOrReturn(keyName) {
|
||||
return function* rightArrowOrReturnTest() {
|
||||
yield setUp();
|
||||
|
||||
let state = yield msg("key", { key: "x", 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", keyName);
|
||||
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"], -1);
|
||||
|
||||
yield msg("reset");
|
||||
};
|
||||
}
|
||||
|
||||
add_task(rightArrowOrReturn("VK_RIGHT"));
|
||||
add_task(rightArrowOrReturn("VK_RETURN"));
|
||||
|
||||
add_task(function* mouse() {
|
||||
yield setUp();
|
||||
|
||||
let state = yield msg("key", { key: "x", waitForSuggestions: true });
|
||||
checkState(state, "x", ["xfoo", "xbar"], -1);
|
||||
|
||||
// Mouse over the first suggestion.
|
||||
state = yield msg("mousemove", 0);
|
||||
checkState(state, "x", ["xfoo", "xbar"], 0);
|
||||
|
||||
// Mouse over the second suggestion.
|
||||
state = yield msg("mousemove", 1);
|
||||
checkState(state, "x", ["xfoo", "xbar"], 1);
|
||||
|
||||
// Click the second suggestion. This should make it sticky. To make sure it
|
||||
// sticks, trigger suggestions again and cycle through them by pressing Down
|
||||
// until nothing is selected again.
|
||||
state = yield msg("mousedown", 1);
|
||||
checkState(state, "xbar", [], -1);
|
||||
|
||||
state = yield msg("key", { key: "VK_DOWN", waitForSuggestions: true });
|
||||
checkState(state, "xbar", ["xbarfoo", "xbarbar"], -1);
|
||||
|
||||
state = yield msg("key", "VK_DOWN");
|
||||
checkState(state, "xbarfoo", ["xbarfoo", "xbarbar"], 0);
|
||||
|
||||
state = yield msg("key", "VK_DOWN");
|
||||
checkState(state, "xbarbar", ["xbarfoo", "xbarbar"], 1);
|
||||
|
||||
state = yield msg("key", "VK_DOWN");
|
||||
checkState(state, "xbar", ["xbarfoo", "xbarbar"], -1);
|
||||
|
||||
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);
|
||||
yield msg("addInputValueToFormHistory");
|
||||
|
||||
// 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 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);
|
||||
|
||||
state = yield msg("key", "VK_DELETE");
|
||||
checkState(state, "x", ["xfoo", "xbar"], -1);
|
||||
|
||||
// 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);
|
||||
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* composition() {
|
||||
yield setUp();
|
||||
|
||||
let state = yield msg("startComposition", { data: "" });
|
||||
checkState(state, "", [], -1);
|
||||
state = yield msg("changeComposition", { data: "x", waitForSuggestions: true });
|
||||
checkState(state, "x", ["xfoo", "xbar"], -1);
|
||||
|
||||
// Mouse over the first suggestion.
|
||||
state = yield msg("mousemove", 0);
|
||||
checkState(state, "x", ["xfoo", "xbar"], 0);
|
||||
|
||||
// Mouse over the second suggestion.
|
||||
state = yield msg("mousemove", 1);
|
||||
checkState(state, "x", ["xfoo", "xbar"], 1);
|
||||
|
||||
// Click the second suggestion. This should make it sticky. To make sure it
|
||||
// sticks, trigger suggestions again and cycle through them by pressing Down
|
||||
// until nothing is selected again.
|
||||
state = yield msg("mousedown", 1);
|
||||
|
||||
checkState(state, "xbar", [], -1);
|
||||
|
||||
state = yield msg("key", { key: "VK_DOWN", waitForSuggestions: true });
|
||||
checkState(state, "xbar", ["xbarfoo", "xbarbar"], -1);
|
||||
|
||||
state = yield msg("key", "VK_DOWN");
|
||||
checkState(state, "xbarfoo", ["xbarfoo", "xbarbar"], 0);
|
||||
|
||||
state = yield msg("key", "VK_DOWN");
|
||||
checkState(state, "xbarbar", ["xbarfoo", "xbarbar"], 1);
|
||||
|
||||
state = yield msg("key", "VK_DOWN");
|
||||
checkState(state, "xbar", ["xbarfoo", "xbarbar"], -1);
|
||||
|
||||
yield msg("reset");
|
||||
});
|
||||
|
||||
|
||||
let gDidInitialSetUp = false;
|
||||
|
||||
function setUp() {
|
||||
return Task.spawn(function* () {
|
||||
if (!gDidInitialSetUp) {
|
||||
yield promiseNewEngine(TEST_ENGINE_BASENAME);
|
||||
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(msg) {
|
||||
gMsgMan.removeMessageListener(TEST_MSG, onMsg);
|
||||
deferred.resolve(msg.data);
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function checkState(actualState, expectedInputVal, expectedSuggestions,
|
||||
expectedSelectedIdx) {
|
||||
expectedSuggestions = expectedSuggestions.map(sugg => {
|
||||
return typeof(sugg) == "object" ? sugg : {
|
||||
str: sugg,
|
||||
type: "remote",
|
||||
};
|
||||
});
|
||||
|
||||
let expectedState = {
|
||||
selectedIndex: expectedSelectedIdx,
|
||||
numSuggestions: expectedSuggestions.length,
|
||||
suggestionAtIndex: expectedSuggestions.map(s => s.str),
|
||||
isFormHistorySuggestionAtIndex:
|
||||
expectedSuggestions.map(s => s.type == "formHistory"),
|
||||
|
||||
tableHidden: expectedSuggestions.length == 0,
|
||||
tableChildrenLength: expectedSuggestions.length,
|
||||
tableChildren: expectedSuggestions.map((s, i) => {
|
||||
let expectedClasses = new Set([s.type]);
|
||||
if (i == expectedSelectedIdx) {
|
||||
expectedClasses.add("selected");
|
||||
}
|
||||
return {
|
||||
textContent: s.str,
|
||||
classes: expectedClasses,
|
||||
};
|
||||
}),
|
||||
|
||||
inputValue: expectedInputVal,
|
||||
ariaExpanded: expectedSuggestions.length == 0 ? "false" : "true",
|
||||
};
|
||||
|
||||
SimpleTest.isDeeply(actualState, expectedState, "State");
|
||||
}
|
||||
|
||||
var gMsgMan;
|
||||
|
||||
function promiseTab() {
|
||||
let deferred = Promise.defer();
|
||||
let tab = gBrowser.addTab();
|
||||
registerCleanupFunction(() => gBrowser.removeTab(tab));
|
||||
gBrowser.selectedTab = 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();
|
||||
});
|
||||
}, 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(msg) {
|
||||
info("Received " + name + " message " + msg.data.type + "\n");
|
||||
if (msg.data.type == type) {
|
||||
msgMan.removeMessageListener(name, onMsg);
|
||||
deferred.resolve(msg);
|
||||
}
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function promiseNewEngine(basename) {
|
||||
info("Waiting for engine to be added: " + basename);
|
||||
let addDeferred = Promise.defer();
|
||||
let url = getRootDirectory(gTestPath) + basename;
|
||||
Services.search.addEngine(url, Ci.nsISearchEngine.TYPE_MOZSEARCH, "", false, {
|
||||
onSuccess: function (engine) {
|
||||
info("Search engine added: " + basename);
|
||||
registerCleanupFunction(() => Services.search.removeEngine(engine));
|
||||
addDeferred.resolve(engine);
|
||||
},
|
||||
onError: function (errCode) {
|
||||
ok(false, "addEngine failed with error code " + errCode);
|
||||
addDeferred.reject();
|
||||
},
|
||||
});
|
||||
return addDeferred.promise;
|
||||
}
|
@ -9,12 +9,13 @@
|
||||
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js">
|
||||
</script>
|
||||
<script type="application/javascript;version=1.8"
|
||||
src="chrome://browser/content/searchSuggestionUI.js">
|
||||
src="chrome://browser/content/contentSearchUI.js">
|
||||
</script>
|
||||
<link rel="stylesheet" href="chrome://browser/content/contentSearchUI.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<input>
|
||||
<div id="container" style="position: relative;"><input type="text" value=""/></div>
|
||||
|
||||
</body>
|
||||
</html>
|
189
browser/base/content/test/general/contentSearchUI.js
Normal file
189
browser/base/content/test/general/contentSearchUI.js
Normal file
@ -0,0 +1,189 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
(function () {
|
||||
|
||||
const TEST_MSG = "ContentSearchUIControllerTest";
|
||||
const ENGINE_NAME = "browser_searchSuggestionEngine searchSuggestionEngine.xml";
|
||||
var gController;
|
||||
|
||||
addMessageListener(TEST_MSG, msg => {
|
||||
messageHandlers[msg.data.type](msg.data.data);
|
||||
});
|
||||
|
||||
let messageHandlers = {
|
||||
|
||||
init: function() {
|
||||
Services.search.currentEngine = Services.search.getEngineByName(ENGINE_NAME);
|
||||
let input = content.document.querySelector("input");
|
||||
gController =
|
||||
new content.ContentSearchUIController(input, input.parentNode, "test", "test");
|
||||
content.addEventListener("ContentSearchService", function listener(aEvent) {
|
||||
if (aEvent.detail.type == "State" &&
|
||||
gController.defaultEngine.name == ENGINE_NAME) {
|
||||
content.removeEventListener("ContentSearchService", listener);
|
||||
ack("init");
|
||||
}
|
||||
});
|
||||
gController.remoteTimeout = 5000;
|
||||
},
|
||||
|
||||
key: function (arg) {
|
||||
let keyName = typeof(arg) == "string" ? arg : arg.key;
|
||||
content.synthesizeKey(keyName, arg.modifiers || {});
|
||||
let wait = arg.waitForSuggestions ? waitForSuggestions : cb => cb();
|
||||
wait(ack.bind(null, "key"));
|
||||
},
|
||||
|
||||
startComposition: function (arg) {
|
||||
content.synthesizeComposition({ type: "compositionstart", data: "" });
|
||||
ack("startComposition");
|
||||
},
|
||||
|
||||
changeComposition: function (arg) {
|
||||
let data = typeof(arg) == "string" ? arg : arg.data;
|
||||
content.synthesizeCompositionChange({
|
||||
composition: {
|
||||
string: data,
|
||||
clauses: [
|
||||
{ length: data.length, attr: content.COMPOSITION_ATTR_RAW_CLAUSE }
|
||||
]
|
||||
},
|
||||
caret: { start: data.length, length: 0 }
|
||||
});
|
||||
let wait = arg.waitForSuggestions ? waitForSuggestions : cb => cb();
|
||||
wait(ack.bind(null, "changeComposition"));
|
||||
},
|
||||
|
||||
commitComposition: function () {
|
||||
content.synthesizeComposition({ type: "compositioncommitasis" });
|
||||
ack("commitComposition");
|
||||
},
|
||||
|
||||
focus: function () {
|
||||
gController.input.focus();
|
||||
ack("focus");
|
||||
},
|
||||
|
||||
blur: function () {
|
||||
gController.input.blur();
|
||||
ack("blur");
|
||||
},
|
||||
|
||||
waitForSearch: function () {
|
||||
waitForContentSearchEvent("Search", aData => ack("waitForSearch", aData));
|
||||
},
|
||||
|
||||
waitForSearchSettings: function () {
|
||||
waitForContentSearchEvent("ManageEngines",
|
||||
aData => ack("waitForSearchSettings", aData));
|
||||
},
|
||||
|
||||
mousemove: function (itemIndex) {
|
||||
let row;
|
||||
if (itemIndex == -1) {
|
||||
row = gController._table.firstChild;
|
||||
}
|
||||
else {
|
||||
let allElts = [...gController._suggestionsList.children,
|
||||
...gController._oneOffButtons,
|
||||
content.document.getElementById("contentSearchSettingsButton")];
|
||||
row = allElts[itemIndex];
|
||||
}
|
||||
let event = {
|
||||
type: "mousemove",
|
||||
clickcount: 0,
|
||||
}
|
||||
content.synthesizeMouseAtCenter(row, event);
|
||||
ack("mousemove");
|
||||
},
|
||||
|
||||
click: function (arg) {
|
||||
let eltIdx = typeof(arg) == "object" ? arg.eltIdx : arg;
|
||||
let row;
|
||||
if (eltIdx == -1) {
|
||||
row = gController._table.firstChild;
|
||||
}
|
||||
else {
|
||||
let allElts = [...gController._suggestionsList.children,
|
||||
...gController._oneOffButtons,
|
||||
content.document.getElementById("contentSearchSettingsButton")];
|
||||
row = allElts[eltIdx];
|
||||
}
|
||||
let event = arg.modifiers || {};
|
||||
// synthesizeMouseAtCenter defaults to sending a mousedown followed by a
|
||||
// mouseup if the event type is not specified.
|
||||
content.synthesizeMouseAtCenter(row, event);
|
||||
ack("click");
|
||||
},
|
||||
|
||||
addInputValueToFormHistory: function () {
|
||||
gController.addInputValueToFormHistory();
|
||||
ack("addInputValueToFormHistory");
|
||||
},
|
||||
|
||||
reset: function () {
|
||||
// Reset both the input and suggestions by select all + delete.
|
||||
gController.input.focus();
|
||||
content.synthesizeKey("a", { accelKey: true });
|
||||
content.synthesizeKey("VK_DELETE", {});
|
||||
ack("reset");
|
||||
},
|
||||
};
|
||||
|
||||
function ack(aType, aData) {
|
||||
sendAsyncMessage(TEST_MSG, { type: aType, data: aData || currentState() });
|
||||
}
|
||||
|
||||
function waitForSuggestions(cb) {
|
||||
let observer = new content.MutationObserver(() => {
|
||||
if (gController.input.getAttribute("aria-expanded") == "true") {
|
||||
observer.disconnect();
|
||||
cb();
|
||||
}
|
||||
});
|
||||
observer.observe(gController.input, {
|
||||
attributes: true,
|
||||
attributeFilter: ["aria-expanded"],
|
||||
});
|
||||
}
|
||||
|
||||
function waitForContentSearchEvent(messageType, cb) {
|
||||
let mm = content.SpecialPowers.Cc["@mozilla.org/globalmessagemanager;1"].
|
||||
getService(content.SpecialPowers.Ci.nsIMessageListenerManager);
|
||||
mm.addMessageListener("ContentSearch", function listener(aMsg) {
|
||||
if (aMsg.data.type != messageType) {
|
||||
return;
|
||||
}
|
||||
mm.removeMessageListener("ContentSearch", listener);
|
||||
cb(aMsg.data.data);
|
||||
});
|
||||
}
|
||||
|
||||
function currentState() {
|
||||
let state = {
|
||||
selectedIndex: gController.selectedIndex,
|
||||
numSuggestions: gController._table.hidden ? 0 : gController.numSuggestions,
|
||||
suggestionAtIndex: [],
|
||||
isFormHistorySuggestionAtIndex: [],
|
||||
|
||||
tableHidden: gController._table.hidden,
|
||||
|
||||
inputValue: gController.input.value,
|
||||
ariaExpanded: gController.input.getAttribute("aria-expanded"),
|
||||
};
|
||||
|
||||
if (state.numSuggestions) {
|
||||
for (let i = 0; i < gController.numSuggestions; i++) {
|
||||
state.suggestionAtIndex.push(gController.suggestionAtIndex(i));
|
||||
state.isFormHistorySuggestionAtIndex.push(
|
||||
gController.isFormHistorySuggestionAtIndex(i));
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
})();
|
@ -5,5 +5,5 @@
|
||||
<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
|
||||
<ShortName>browser_searchSuggestionEngine searchSuggestionEngine.xml</ShortName>
|
||||
<Url type="application/x-suggestions+json" method="GET" template="http://mochi.test:8888/browser/browser/base/content/test/general/searchSuggestionEngine.sjs?{searchTerms}"/>
|
||||
<Url type="text/html" method="GET" template="http://www.browser-searchSuggestionEngine.com/searchSuggestionEngine" rel="searchform"/>
|
||||
<Url type="text/html" method="GET" template="http://www.browser-searchSuggestionEngine.com/searchSuggestionEngine&terms={searchTerms}" rel="searchform"/>
|
||||
</SearchPlugin>
|
||||
|
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
|
||||
<ShortName>browser_searchSuggestionEngine searchSuggestionEngine2.xml</ShortName>
|
||||
<Url type="application/x-suggestions+json" method="GET" template="http://mochi.test:8888/browser/browser/base/content/test/general/searchSuggestionEngine.sjs?{searchTerms}"/>
|
||||
<Url type="text/html" method="GET" template="http://www.browser-searchSuggestionEngine.com/searchSuggestionEngine2&terms={searchTerms}" rel="searchform"/>
|
||||
</SearchPlugin>
|
@ -1,158 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
(function () {
|
||||
|
||||
const TEST_MSG = "SearchSuggestionUIControllerTest";
|
||||
const ENGINE_NAME = "browser_searchSuggestionEngine searchSuggestionEngine.xml";
|
||||
|
||||
let input = content.document.querySelector("input");
|
||||
let gController =
|
||||
new content.SearchSuggestionUIController(input, input.parentNode);
|
||||
gController.engineName = ENGINE_NAME;
|
||||
gController.remoteTimeout = 5000;
|
||||
|
||||
addMessageListener(TEST_MSG, msg => {
|
||||
messageHandlers[msg.data.type](msg.data.data);
|
||||
});
|
||||
|
||||
let messageHandlers = {
|
||||
|
||||
key: function (arg) {
|
||||
let keyName = typeof(arg) == "string" ? arg : arg.key;
|
||||
content.synthesizeKey(keyName, {});
|
||||
let wait = arg.waitForSuggestions ? waitForSuggestions : cb => cb();
|
||||
wait(ack);
|
||||
},
|
||||
|
||||
startComposition: function (arg) {
|
||||
content.synthesizeComposition({ type: "compositionstart", data: "" });
|
||||
ack();
|
||||
},
|
||||
|
||||
changeComposition: function (arg) {
|
||||
let data = typeof(arg) == "string" ? arg : arg.data;
|
||||
content.synthesizeCompositionChange({
|
||||
composition: {
|
||||
string: data,
|
||||
clauses: [
|
||||
{ length: data.length, attr: content.COMPOSITION_ATTR_RAW_CLAUSE }
|
||||
]
|
||||
},
|
||||
caret: { start: data.length, length: 0 }
|
||||
});
|
||||
let wait = arg.waitForSuggestions ? waitForSuggestions : cb => cb();
|
||||
wait(ack);
|
||||
},
|
||||
|
||||
focus: function () {
|
||||
gController.input.focus();
|
||||
ack();
|
||||
},
|
||||
|
||||
blur: function () {
|
||||
gController.input.blur();
|
||||
ack();
|
||||
},
|
||||
|
||||
mousemove: function (suggestionIdx) {
|
||||
// Copied from widget/tests/test_panel_mouse_coords.xul and
|
||||
// browser/base/content/test/newtab/head.js
|
||||
let row = gController._table.children[suggestionIdx];
|
||||
let rect = row.getBoundingClientRect();
|
||||
let left = content.mozInnerScreenX + rect.left;
|
||||
let x = left + rect.width / 2;
|
||||
let y = content.mozInnerScreenY + rect.top + rect.height / 2;
|
||||
|
||||
let utils = content.SpecialPowers.getDOMWindowUtils(content);
|
||||
let scale = utils.screenPixelsPerCSSPixel;
|
||||
|
||||
let widgetToolkit = content.SpecialPowers.
|
||||
Cc["@mozilla.org/xre/app-info;1"].
|
||||
getService(content.SpecialPowers.Ci.nsIXULRuntime).
|
||||
widgetToolkit;
|
||||
let nativeMsg = widgetToolkit == "cocoa" ? 5 : // NSMouseMoved
|
||||
widgetToolkit == "windows" ? 1 : // MOUSEEVENTF_MOVE
|
||||
3; // GDK_MOTION_NOTIFY
|
||||
|
||||
row.addEventListener("mousemove", function onMove() {
|
||||
row.removeEventListener("mousemove", onMove);
|
||||
ack();
|
||||
});
|
||||
utils.sendNativeMouseEvent(x * scale, y * scale, nativeMsg, 0, null);
|
||||
},
|
||||
|
||||
mousedown: function (suggestionIdx) {
|
||||
gController.onClick = () => {
|
||||
gController.onClick = null;
|
||||
ack();
|
||||
};
|
||||
let row = gController._table.children[suggestionIdx];
|
||||
content.sendMouseEvent({ type: "mousedown" }, row);
|
||||
},
|
||||
|
||||
addInputValueToFormHistory: function () {
|
||||
gController.addInputValueToFormHistory();
|
||||
ack();
|
||||
},
|
||||
|
||||
reset: function () {
|
||||
// Reset both the input and suggestions by select all + delete.
|
||||
gController.input.focus();
|
||||
content.synthesizeKey("a", { accelKey: true });
|
||||
content.synthesizeKey("VK_DELETE", {});
|
||||
ack();
|
||||
},
|
||||
};
|
||||
|
||||
function ack() {
|
||||
sendAsyncMessage(TEST_MSG, currentState());
|
||||
}
|
||||
|
||||
function waitForSuggestions(cb) {
|
||||
let observer = new content.MutationObserver(() => {
|
||||
if (gController.input.getAttribute("aria-expanded") == "true") {
|
||||
observer.disconnect();
|
||||
cb();
|
||||
}
|
||||
});
|
||||
observer.observe(gController.input, {
|
||||
attributes: true,
|
||||
attributeFilter: ["aria-expanded"],
|
||||
});
|
||||
}
|
||||
|
||||
function currentState() {
|
||||
let state = {
|
||||
selectedIndex: gController.selectedIndex,
|
||||
numSuggestions: gController.numSuggestions,
|
||||
suggestionAtIndex: [],
|
||||
isFormHistorySuggestionAtIndex: [],
|
||||
|
||||
tableHidden: gController._table.hidden,
|
||||
tableChildrenLength: gController._table.children.length,
|
||||
tableChildren: [],
|
||||
|
||||
inputValue: gController.input.value,
|
||||
ariaExpanded: gController.input.getAttribute("aria-expanded"),
|
||||
};
|
||||
|
||||
for (let i = 0; i < gController.numSuggestions; i++) {
|
||||
state.suggestionAtIndex.push(gController.suggestionAtIndex(i));
|
||||
state.isFormHistorySuggestionAtIndex.push(
|
||||
gController.isFormHistorySuggestionAtIndex(i));
|
||||
}
|
||||
|
||||
for (let child of gController._table.children) {
|
||||
state.tableChildren.push({
|
||||
textContent: child.textContent,
|
||||
classes: new Set(child.className.split(/\s+/)),
|
||||
});
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
})();
|
@ -76,13 +76,6 @@ let runTaskifiedTests = Task.async(function* () {
|
||||
info("Adding search event listener");
|
||||
getContentWindow().addEventListener(SERVICE_EVENT_NAME, searchEventListener);
|
||||
|
||||
let panel = searchPanel();
|
||||
is(panel.state, "closed", "Search panel should be closed initially");
|
||||
|
||||
// The panel's animation often is not finished when the test clicks on panel
|
||||
// children, which makes the test click the wrong children, so disable it.
|
||||
panel.setAttribute("animate", "false");
|
||||
|
||||
// Add the engine without any logos and switch to it.
|
||||
let noLogoEngine = yield promiseNewSearchEngine(ENGINE_NO_LOGO);
|
||||
Services.search.currentEngine = noLogoEngine;
|
||||
@ -113,19 +106,6 @@ let runTaskifiedTests = Task.async(function* () {
|
||||
yield promiseSearchEvents(["CurrentEngine"]);
|
||||
yield checkCurrentEngine(ENGINE_1X_2X_LOGO);
|
||||
|
||||
// Click the logo to open the search panel.
|
||||
yield Promise.all([
|
||||
promisePanelShown(panel),
|
||||
promiseClick(logoImg()),
|
||||
]);
|
||||
|
||||
let manageBox = $("manage");
|
||||
ok(!!manageBox, "The Manage Engines box should be present in the document");
|
||||
is(panel.childNodes.length, 1, "Search panel should only contain the Manage Engines entry");
|
||||
is(panel.childNodes[0], manageBox, "Search panel should contain the Manage Engines entry");
|
||||
|
||||
panel.hidePopup();
|
||||
|
||||
// Add the engine that provides search suggestions and switch to it.
|
||||
let suggestionEngine = yield promiseNewSearchEngine(ENGINE_SUGGESTIONS);
|
||||
Services.search.currentEngine = suggestionEngine;
|
||||
@ -133,7 +113,7 @@ let runTaskifiedTests = Task.async(function* () {
|
||||
yield checkCurrentEngine(ENGINE_SUGGESTIONS);
|
||||
|
||||
// Avoid intermittent failures.
|
||||
gSearch()._suggestionController.remoteTimeout = 5000;
|
||||
gSearch().remoteTimeout = 5000;
|
||||
|
||||
// Type an X in the search input. This is only a smoke test. See
|
||||
// browser_searchSuggestionUI.js for comprehensive content search suggestion
|
||||
@ -309,21 +289,10 @@ let checkCurrentEngine = Task.async(function* ({name: basename, logoPrefix1x, lo
|
||||
" basename=" + basename);
|
||||
|
||||
// gSearch.currentEngineName
|
||||
is(gSearch().currentEngineName, engine.name,
|
||||
is(gSearch().defaultEngine.name, engine.name,
|
||||
"currentEngineName: " + engine.name);
|
||||
});
|
||||
|
||||
function promisePanelShown(panel) {
|
||||
let deferred = Promise.defer();
|
||||
info("Waiting for popupshown");
|
||||
panel.addEventListener("popupshown", function onEvent() {
|
||||
panel.removeEventListener("popupshown", onEvent);
|
||||
is(panel.state, "open", "Panel state");
|
||||
deferred.resolve();
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function promiseClick(node) {
|
||||
let deferred = Promise.defer();
|
||||
let win = getContentWindow();
|
||||
@ -334,16 +303,12 @@ function promiseClick(node) {
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function searchPanel() {
|
||||
return $("panel");
|
||||
}
|
||||
|
||||
function logoImg() {
|
||||
return $("logo");
|
||||
}
|
||||
|
||||
function gSearch() {
|
||||
return getContentWindow().gSearch;
|
||||
return getContentWindow().gSearch._contentSearchController;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -722,14 +722,23 @@ function whenPagesUpdated(aCallback = TestRunner.next) {
|
||||
*/
|
||||
function whenSearchInitDone() {
|
||||
let deferred = Promise.defer();
|
||||
if (getContentWindow().gSearch._initialStateReceived) {
|
||||
let searchController = getContentWindow().gSearch._contentSearchController;
|
||||
if (searchController.defaultEngine) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
let eventName = "ContentSearchService";
|
||||
getContentWindow().addEventListener(eventName, function onEvent(event) {
|
||||
if (event.detail.type == "State") {
|
||||
getContentWindow().removeEventListener(eventName, onEvent);
|
||||
deferred.resolve();
|
||||
// Wait for the search controller to receive the event, then resolve.
|
||||
let resolver = function() {
|
||||
if (searchController.defaultEngine) {
|
||||
deferred.resolve();
|
||||
return;
|
||||
}
|
||||
executeSoon(resolver);
|
||||
}
|
||||
executeSoon(resolver);
|
||||
}
|
||||
});
|
||||
return deferred.promise;
|
||||
|
@ -30,7 +30,9 @@ add_task(function* test_mozLoop_getSelectedTabMetadata() {
|
||||
Assert.strictEqual(metadata.url, null, "URL should be empty for about:home");
|
||||
Assert.strictEqual(metadata.favicon, null, "Favicon should be empty for about:home");
|
||||
Assert.ok(metadata.title, "Title should be set for about:home");
|
||||
Assert.deepEqual(metadata.previews, [], "No previews available for about:home");
|
||||
// Filter out null elements in the previews - contentSearchUI adds some img
|
||||
// elements with chrome:// srcs, which show up as null in metadata.previews.
|
||||
Assert.deepEqual(metadata.previews.filter(e => e), [], "No previews available for about:home");
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
|
@ -673,7 +673,7 @@ let DirectoryLinksProvider = {
|
||||
let pastImpressions;
|
||||
// Check if the suggested tile was shown
|
||||
if (action == "view") {
|
||||
sites.slice(0, triggeringSiteIndex + 1).forEach(site => {
|
||||
sites.slice(0, triggeringSiteIndex + 1).filter(s => s).forEach(site => {
|
||||
let {targetedSite, url} = site.link;
|
||||
if (targetedSite) {
|
||||
this._addFrequencyCapView(url);
|
||||
|
@ -94,7 +94,8 @@ add_task(function* search() {
|
||||
let data = {
|
||||
engineName: engine.name,
|
||||
searchString: "ContentSearchTest",
|
||||
whence: "ContentSearchTest",
|
||||
healthReportKey: "ContentSearchTest",
|
||||
searchPurpose: "ContentSearchTest",
|
||||
};
|
||||
gMsgMan.sendAsyncMessage(TEST_MSG, {
|
||||
type: "Search",
|
||||
@ -116,7 +117,8 @@ add_task(function* searchInBackgroundTab() {
|
||||
let data = {
|
||||
engineName: engine.name,
|
||||
searchString: "ContentSearchTest",
|
||||
whence: "ContentSearchTest",
|
||||
healthReportKey: "ContentSearchTest",
|
||||
searchPurpose: "ContentSearchTest",
|
||||
};
|
||||
gMsgMan.sendAsyncMessage(TEST_MSG, {
|
||||
type: "Search",
|
||||
|
Loading…
Reference in New Issue
Block a user