fune/browser/base/content/test/newtab/browser_newtab_search.js
2016-08-31 12:53:24 -04:00

306 lines
11 KiB
JavaScript

/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// See browser/components/search/test/browser_*_behavior.js for tests of actual
// searches.
Cu.import("resource://gre/modules/Task.jsm");
const ENGINE_NO_LOGO = {
name: "searchEngineNoLogo.xml",
numLogos: 0,
};
const ENGINE_FAVICON = {
name: "searchEngineFavicon.xml",
logoPrefix1x: "data:image/png;base64,AAABAAIAICAAAAEAIACoEAAAJgAAABAQAAABACAAaAQAAM4QAAAoAAAAIAAAAEAAAAABACAAAAAAAAAQAAATCwAAEwsA",
numLogos: 1,
};
ENGINE_FAVICON.logoPrefix2x = ENGINE_FAVICON.logoPrefix1x;
const ENGINE_1X_LOGO = {
name: "searchEngine1xLogo.xml",
logoPrefix1x: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEEAAAAaCAIAAABn3KYmAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gkTADEw",
numLogos: 1,
};
ENGINE_1X_LOGO.logoPrefix2x = ENGINE_1X_LOGO.logoPrefix1x;
const ENGINE_2X_LOGO = {
name: "searchEngine2xLogo.xml",
logoPrefix2x: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIIAAAA0CAIAAADJ8nfCAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gkTADMU",
numLogos: 1,
};
ENGINE_2X_LOGO.logoPrefix1x = ENGINE_2X_LOGO.logoPrefix2x;
const ENGINE_1X_2X_LOGO = {
name: "searchEngine1x2xLogo.xml",
logoPrefix1x: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEEAAAAaCAIAAABn3KYmAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gkTADIG",
logoPrefix2x: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIIAAAA0CAIAAADJ8nfCAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gkTADMo",
numLogos: 2,
};
const ENGINE_SUGGESTIONS = {
name: "searchSuggestionEngine.xml",
numLogos: 0,
};
// The test has an expected search event queue and a search event listener.
// Search events that are expected to happen are added to the queue, and the
// listener consumes the queue and ensures that each event it receives is at
// the head of the queue.
let gExpectedSearchEventQueue = [];
let gExpectedSearchEventResolver = null;
let gNewEngines = [];
add_task(function* () {
let oldCurrentEngine = Services.search.currentEngine;
yield* addNewTabPageTab();
// The tab is removed at the end of the test, so there's no need to remove
// this listener at the end of the test.
info("Adding search event listener");
yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
const SERVICE_EVENT_NAME = "ContentSearchService";
content.addEventListener(SERVICE_EVENT_NAME, function (event) {
sendAsyncMessage("test:search-event", { eventType: event.detail.type });
});
});
let mm = gBrowser.selectedBrowser.messageManager;
mm.addMessageListener("test:search-event", function (message) {
let eventType = message.data.eventType;
if (!gExpectedSearchEventResolver) {
ok(false, "Got search event " + eventType + " with no promise assigned");
}
let expectedEventType = gExpectedSearchEventQueue.shift();
is(eventType, expectedEventType, "Got expected search event " + expectedEventType);
if (!gExpectedSearchEventQueue.length) {
gExpectedSearchEventResolver();
gExpectedSearchEventResolver = null;
}
});
// Add the engine without any logos and switch to it.
let noLogoEngine = yield promiseNewSearchEngine(ENGINE_NO_LOGO);
let searchEventsPromise = promiseSearchEvents(["CurrentEngine"]);
Services.search.currentEngine = noLogoEngine;
yield searchEventsPromise;
yield* checkCurrentEngine(ENGINE_NO_LOGO);
// Add the engine with favicon and switch to it.
let faviconEngine = yield promiseNewSearchEngine(ENGINE_FAVICON);
searchEventsPromise = promiseSearchEvents(["CurrentEngine"]);
Services.search.currentEngine = faviconEngine;
yield searchEventsPromise;
yield* checkCurrentEngine(ENGINE_FAVICON);
// Add the engine with a 1x-DPI logo and switch to it.
let logo1xEngine = yield promiseNewSearchEngine(ENGINE_1X_LOGO);
searchEventsPromise = promiseSearchEvents(["CurrentEngine"]);
Services.search.currentEngine = logo1xEngine;
yield searchEventsPromise;
yield* checkCurrentEngine(ENGINE_1X_LOGO);
// Add the engine with a 2x-DPI logo and switch to it.
let logo2xEngine = yield promiseNewSearchEngine(ENGINE_2X_LOGO);
searchEventsPromise = promiseSearchEvents(["CurrentEngine"]);
Services.search.currentEngine = logo2xEngine;
yield searchEventsPromise;
yield* checkCurrentEngine(ENGINE_2X_LOGO);
// Add the engine with 1x- and 2x-DPI logos and switch to it.
let logo1x2xEngine = yield promiseNewSearchEngine(ENGINE_1X_2X_LOGO);
searchEventsPromise = promiseSearchEvents(["CurrentEngine"]);
Services.search.currentEngine = logo1x2xEngine;
yield searchEventsPromise;
yield* checkCurrentEngine(ENGINE_1X_2X_LOGO);
// Add the engine that provides search suggestions and switch to it.
let suggestionEngine = yield promiseNewSearchEngine(ENGINE_SUGGESTIONS);
searchEventsPromise = promiseSearchEvents(["CurrentEngine"]);
Services.search.currentEngine = suggestionEngine;
yield searchEventsPromise;
yield* checkCurrentEngine(ENGINE_SUGGESTIONS);
// Avoid intermittent failures.
yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
content.gSearch._contentSearchController.remoteTimeout = 5000;
});
// Type an X in the search input. This is only a smoke test. See
// browser_searchSuggestionUI.js for comprehensive content search suggestion
// UI tests.
let suggestionsOpenPromise = new Promise(resolve => {
mm.addMessageListener("test:newtab-suggestions-open", function onResponse(message) {
mm.removeMessageListener("test:newtab-suggestions-open", onResponse);
resolve();
});
});
yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
let table = content.document.getElementById("searchSuggestionTable");
let input = content.document.getElementById("newtab-search-text");
input.focus();
info("Waiting for suggestions table to open");
let observer = new content.MutationObserver(() => {
if (input.getAttribute("aria-expanded") == "true") {
observer.disconnect();
Assert.ok(!table.hidden, "Search suggestion table unhidden");
sendAsyncMessage("test:newtab-suggestions-open", {});
}
});
observer.observe(input, {
attributes: true,
attributeFilter: ["aria-expanded"],
});
});
let suggestionsPromise = promiseSearchEvents(["Suggestions"]);
EventUtils.synthesizeKey("x", {});
// Wait for the search suggestions to become visible and for the Suggestions
// message.
yield suggestionsOpenPromise;
yield suggestionsPromise;
// Empty the search input, causing the suggestions to be hidden.
EventUtils.synthesizeKey("a", { accelKey: true });
EventUtils.synthesizeKey("VK_DELETE", {});
yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
Assert.ok(content.document.getElementById("searchSuggestionTable").hidden,
"Search suggestion table hidden");
});
// Remove the search bar from toolbar
CustomizableUI.removeWidgetFromArea("search-container");
// Focus a different element than the search input from the page.
yield BrowserTestUtils.synthesizeMouseAtCenter("#newtab-customize-button", { }, gBrowser.selectedBrowser);
yield ContentTask.spawn(gBrowser.selectedBrowser, { }, function* () {
let input = content.document.getElementById("newtab-search-text");
Assert.notEqual(input, content.document.activeElement, "Search input should not be focused");
});
// Test that Ctrl/Cmd + K will focus the input field from the page.
let focusPromise = promiseSearchEvents(["FocusInput"]);
EventUtils.synthesizeKey("k", { accelKey: true });
yield focusPromise;
yield ContentTask.spawn(gBrowser.selectedBrowser, { }, function* () {
let input = content.document.getElementById("newtab-search-text");
Assert.equal(input, content.document.activeElement, "Search input should be focused");
});
// Reset changes made to toolbar
CustomizableUI.reset();
// Test that Ctrl/Cmd + K will focus the search bar from toolbar.
EventUtils.synthesizeKey("k", { accelKey: true });
let searchBar = document.getElementById("searchbar");
is(searchBar.textbox.inputField, document.activeElement, "Toolbar's search bar should be focused");
// Test that Ctrl/Cmd + K will focus the search bar from a new about:home page if
// the newtab is disabled from `NewTabUtils.allPages.enabled`.
let tab = yield* addNewTabPageTab();
// Remove the search bar from toolbar
CustomizableUI.removeWidgetFromArea("search-container");
NewTabUtils.allPages.enabled = false;
EventUtils.synthesizeKey("k", { accelKey: true });
let aboutHomeLoaded = new Promise(resolve => {
tab.linkedBrowser.addEventListener("AboutHomeLoadSnippetsCompleted", function loadListener(event) {
tab.linkedBrowser.removeEventListener("AboutHomeLoadSnippetsCompleted", loadListener, true);
resolve();
}, true, true);
});
tab.linkedBrowser.loadURI("about:home");
yield aboutHomeLoaded;
yield ContentTask.spawn(gBrowser.selectedBrowser, { }, function* () {
Assert.equal(content.document.documentURI.toLowerCase(), "about:home",
"New tab's uri should be about:home");
let searchInput = content.document.getElementById("searchText");
Assert.equal(searchInput, content.document.activeElement,
"Search input must be the selected element");
});
NewTabUtils.allPages.enabled = true;
CustomizableUI.reset();
yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
// Done. Revert the current engine and remove the new engines.
searchEventsPromise = promiseSearchEvents(["CurrentEngine"]);
Services.search.currentEngine = oldCurrentEngine;
yield searchEventsPromise;
let events = Array(gNewEngines.length).fill("CurrentState", 0, gNewEngines.length);
searchEventsPromise = promiseSearchEvents(events);
for (let engine of gNewEngines) {
Services.search.removeEngine(engine);
}
yield searchEventsPromise;
});
function promiseSearchEvents(events) {
info("Expecting search events: " + events);
return new Promise(resolve => {
gExpectedSearchEventQueue.push(...events);
gExpectedSearchEventResolver = resolve;
});
}
function promiseNewSearchEngine({name: basename, numLogos}) {
info("Waiting for engine to be added: " + basename);
// Wait for the search events triggered by adding the new engine.
// engine-added engine-loaded
let expectedSearchEvents = ["CurrentState", "CurrentState"];
// engine-changed for each of the logos
for (let i = 0; i < numLogos; i++) {
expectedSearchEvents.push("CurrentState");
}
let eventPromise = promiseSearchEvents(expectedSearchEvents);
// Wait for addEngine().
let addEnginePromise = new Promise((resolve, reject) => {
let url = getRootDirectory(gTestPath) + basename;
Services.search.addEngine(url, null, "", false, {
onSuccess: function (engine) {
info("Search engine added: " + basename);
gNewEngines.push(engine);
resolve(engine);
},
onError: function (errCode) {
ok(false, "addEngine failed with error code " + errCode);
reject();
},
});
});
return Promise.all([addEnginePromise, eventPromise]).then(([newEngine, _]) => {
return newEngine;
});
}
function* checkCurrentEngine(engineInfo)
{
let engine = Services.search.currentEngine;
ok(engine.name.includes(engineInfo.name),
"Sanity check: current engine: engine.name=" + engine.name +
" basename=" + engineInfo.name);
yield ContentTask.spawn(gBrowser.selectedBrowser, { name: engine.name }, function* (args) {
Assert.equal(content.gSearch._contentSearchController.defaultEngine.name,
args.name, "currentEngineName: " + args.name);
});
}