mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-13 18:57:29 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
7
browser/components/search/test/.eslintrc.js
Normal file
7
browser/components/search/test/.eslintrc.js
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"../../../../testing/mochitest/browser.eslintrc.js"
|
||||
]
|
||||
};
|
||||
11
browser/components/search/test/426329.xml
Normal file
11
browser/components/search/test/426329.xml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/"
|
||||
xmlns:moz="http://www.mozilla.org/2006/browser/search/">
|
||||
<ShortName>Bug 426329</ShortName>
|
||||
<Description>426329 Search</Description>
|
||||
<InputEncoding>utf-8</InputEncoding>
|
||||
<Image width="16" height="16">data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGklEQVQoz2NgGB6AnZ1dUlJSXl4eSDIyMhLW4Ovr%2B%2Fr168uXL69Zs4YoG%2BLi4i5dusTExMTGxsbNzd3f37937976%2BnpmZmagbHR09J49e5YvX66kpATVEBYW9ubNm2nTphkbG7e2tp44cQLIuHfvXm5urpaWFlDKysqqu7v73LlzECMYIiIiHj58mJCQoKKicvXq1bS0NKBgW1vbjh074uPjgeqAXE1NzSdPnvDz84M0AEUvXLgAsW379u1z5swBen3jxo2zZ892cHB4%2BvQp0KlAfwI1cHJyghQFBwfv2rULokFXV%2FfixYu7d%2B8GGqGgoMDKyrpu3br9%2B%2FcDuXl5eVA%2FAEWBfoWHAdAYoNuAYQ0XAeoUERFhGDYAAPoUaT2dfWJuAAAAAElFTkSuQmCC</Image>
|
||||
<Url type="text/html" method="GET" template="http://mochi.test:8888/browser/browser/components/search/test/test.html">
|
||||
<Param name="test" value="{searchTerms}"/>
|
||||
</Url>
|
||||
<moz:SearchForm>http://mochi.test:8888/browser/browser/components/search/test/test.html</moz:SearchForm>
|
||||
</OpenSearchDescription>
|
||||
10
browser/components/search/test/483086-1.xml
Normal file
10
browser/components/search/test/483086-1.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/"
|
||||
xmlns:moz="http://www.mozilla.org/2006/browser/search/">
|
||||
<ShortName>483086a</ShortName>
|
||||
<Description>Bug 483086 Test 1</Description>
|
||||
<Image width="16" height="16">data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGklEQVQoz2NgGB6AnZ1dUlJSXl4eSDIyMhLW4Ovr%2B%2Fr168uXL69Zs4YoG%2BLi4i5dusTExMTGxsbNzd3f37937976%2BnpmZmagbHR09J49e5YvX66kpATVEBYW9ubNm2nTphkbG7e2tp44cQLIuHfvXm5urpaWFlDKysqqu7v73LlzECMYIiIiHj58mJCQoKKicvXq1bS0NKBgW1vbjh074uPjgeqAXE1NzSdPnvDz84M0AEUvXLgAsW379u1z5swBen3jxo2zZ892cHB4%2BvQp0KlAfwI1cHJyghQFBwfv2rULokFXV%2FfixYu7d%2B8GGqGgoMDKyrpu3br9%2B%2FcDuXl5eVA%2FAEWBfoWHAdAYoNuAYQ0XAeoUERFhGDYAAPoUaT2dfWJuAAAAAElFTkSuQmCC</Image>
|
||||
<Url type="text/html" method="GET" template="http://mochi.test:8888/browser/browser/components/search/test/?search">
|
||||
<Param name="test" value="{searchTerms}"/>
|
||||
</Url>
|
||||
<moz:SearchForm>foo://example.com</moz:SearchForm>
|
||||
</OpenSearchDescription>
|
||||
10
browser/components/search/test/483086-2.xml
Normal file
10
browser/components/search/test/483086-2.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/"
|
||||
xmlns:moz="http://www.mozilla.org/2006/browser/search/">
|
||||
<ShortName>483086b</ShortName>
|
||||
<Description>Bug 483086 Test 2</Description>
|
||||
<Image width="16" height="16">data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGklEQVQoz2NgGB6AnZ1dUlJSXl4eSDIyMhLW4Ovr%2B%2Fr168uXL69Zs4YoG%2BLi4i5dusTExMTGxsbNzd3f37937976%2BnpmZmagbHR09J49e5YvX66kpATVEBYW9ubNm2nTphkbG7e2tp44cQLIuHfvXm5urpaWFlDKysqqu7v73LlzECMYIiIiHj58mJCQoKKicvXq1bS0NKBgW1vbjh074uPjgeqAXE1NzSdPnvDz84M0AEUvXLgAsW379u1z5swBen3jxo2zZ892cHB4%2BvQp0KlAfwI1cHJyghQFBwfv2rULokFXV%2FfixYu7d%2B8GGqGgoMDKyrpu3br9%2B%2FcDuXl5eVA%2FAEWBfoWHAdAYoNuAYQ0XAeoUERFhGDYAAPoUaT2dfWJuAAAAAElFTkSuQmCC</Image>
|
||||
<Url type="text/html" method="GET" template="http://mochi.test:8888/browser/browser/components/search/test/?search">
|
||||
<Param name="test" value="{searchTerms}"/>
|
||||
</Url>
|
||||
<moz:SearchForm>http://example.com</moz:SearchForm>
|
||||
</OpenSearchDescription>
|
||||
44
browser/components/search/test/browser.ini
Normal file
44
browser/components/search/test/browser.ini
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
[DEFAULT]
|
||||
support-files =
|
||||
426329.xml
|
||||
483086-1.xml
|
||||
483086-2.xml
|
||||
head.js
|
||||
opensearch.html
|
||||
test.html
|
||||
testEngine.xml
|
||||
testEngine_diacritics.xml
|
||||
testEngine_dupe.xml
|
||||
testEngine_mozsearch.xml
|
||||
webapi.html
|
||||
|
||||
[browser_426329.js]
|
||||
[browser_483086.js]
|
||||
[browser_addEngine.js]
|
||||
[browser_amazon.js]
|
||||
[browser_amazon_behavior.js]
|
||||
[browser_bing.js]
|
||||
[browser_bing_behavior.js]
|
||||
[browser_contextmenu.js]
|
||||
[browser_contextSearchTabPosition.js]
|
||||
skip-if = os == "mac" # bug 967013
|
||||
[browser_google.js]
|
||||
[browser_google_codes.js]
|
||||
[browser_google_behavior.js]
|
||||
[browser_healthreport.js]
|
||||
[browser_hiddenOneOffs_cleanup.js]
|
||||
[browser_hiddenOneOffs_diacritics.js]
|
||||
[browser_oneOffContextMenu.js]
|
||||
[browser_oneOffContextMenu_setDefault.js]
|
||||
[browser_oneOffHeader.js]
|
||||
[browser_private_search_perwindowpb.js]
|
||||
[browser_yahoo.js]
|
||||
[browser_yahoo_behavior.js]
|
||||
[browser_abouthome_behavior.js]
|
||||
skip-if = true # Bug ??????, Bug 1100301 - leaks windows until shutdown when --run-by-dir
|
||||
[browser_aboutSearchReset.js]
|
||||
[browser_searchbar_openpopup.js]
|
||||
skip-if = os == "linux" # Linux has different focus behaviours.
|
||||
[browser_searchbar_keyboard_navigation.js]
|
||||
[browser_searchbar_smallpanel_keyboard_navigation.js]
|
||||
[browser_webapi.js]
|
||||
250
browser/components/search/test/browser_426329.js
Normal file
250
browser/components/search/test/browser_426329.js
Normal file
|
|
@ -0,0 +1,250 @@
|
|||
XPCOMUtils.defineLazyModuleGetter(this, "FormHistory",
|
||||
"resource://gre/modules/FormHistory.jsm");
|
||||
|
||||
function expectedURL(aSearchTerms) {
|
||||
const ENGINE_HTML_BASE = "http://mochi.test:8888/browser/browser/components/search/test/test.html";
|
||||
var textToSubURI = Cc["@mozilla.org/intl/texttosuburi;1"].
|
||||
getService(Ci.nsITextToSubURI);
|
||||
var searchArg = textToSubURI.ConvertAndEscape("utf-8", aSearchTerms);
|
||||
return ENGINE_HTML_BASE + "?test=" + searchArg;
|
||||
}
|
||||
|
||||
function simulateClick(aEvent, aTarget) {
|
||||
var event = document.createEvent("MouseEvent");
|
||||
var ctrlKeyArg = aEvent.ctrlKey || false;
|
||||
var altKeyArg = aEvent.altKey || false;
|
||||
var shiftKeyArg = aEvent.shiftKey || false;
|
||||
var metaKeyArg = aEvent.metaKey || false;
|
||||
var buttonArg = aEvent.button || 0;
|
||||
event.initMouseEvent("click", true, true, window,
|
||||
0, 0, 0, 0, 0,
|
||||
ctrlKeyArg, altKeyArg, shiftKeyArg, metaKeyArg,
|
||||
buttonArg, null);
|
||||
aTarget.dispatchEvent(event);
|
||||
}
|
||||
|
||||
// modified from toolkit/components/satchel/test/test_form_autocomplete.html
|
||||
function checkMenuEntries(expectedValues) {
|
||||
var actualValues = getMenuEntries();
|
||||
is(actualValues.length, expectedValues.length, "Checking length of expected menu");
|
||||
for (var i = 0; i < expectedValues.length; i++)
|
||||
is(actualValues[i], expectedValues[i], "Checking menu entry #" + i);
|
||||
}
|
||||
|
||||
function getMenuEntries() {
|
||||
var entries = [];
|
||||
var autocompleteMenu = searchBar.textbox.popup;
|
||||
// Could perhaps pull values directly from the controller, but it seems
|
||||
// more reliable to test the values that are actually in the tree?
|
||||
var column = autocompleteMenu.tree.columns[0];
|
||||
var numRows = autocompleteMenu.tree.view.rowCount;
|
||||
for (var i = 0; i < numRows; i++) {
|
||||
entries.push(autocompleteMenu.tree.view.getValueAt(i, column));
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
function countEntries(name, value) {
|
||||
return new Promise(resolve => {
|
||||
let count = 0;
|
||||
let obj = name && value ? {fieldname: name, value: value} : {};
|
||||
FormHistory.count(obj,
|
||||
{ handleResult: function(result) { count = result; },
|
||||
handleError: function(error) { throw error; },
|
||||
handleCompletion: function(reason) {
|
||||
if (!reason) {
|
||||
resolve(count);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
var searchBar;
|
||||
var searchButton;
|
||||
var searchEntries = ["test"];
|
||||
function promiseSetEngine() {
|
||||
return new Promise(resolve => {
|
||||
var ss = Services.search;
|
||||
|
||||
function observer(aSub, aTopic, aData) {
|
||||
switch (aData) {
|
||||
case "engine-added":
|
||||
var engine = ss.getEngineByName("Bug 426329");
|
||||
ok(engine, "Engine was added.");
|
||||
ss.currentEngine = engine;
|
||||
break;
|
||||
case "engine-current":
|
||||
ok(ss.currentEngine.name == "Bug 426329", "currentEngine set");
|
||||
searchBar = BrowserSearch.searchBar;
|
||||
searchButton = document.getAnonymousElementByAttribute(searchBar,
|
||||
"anonid", "search-go-button");
|
||||
ok(searchButton, "got search-go-button");
|
||||
searchBar.value = "test";
|
||||
|
||||
Services.obs.removeObserver(observer, "browser-search-engine-modified");
|
||||
resolve();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Services.obs.addObserver(observer, "browser-search-engine-modified", false);
|
||||
ss.addEngine("http://mochi.test:8888/browser/browser/components/search/test/426329.xml",
|
||||
null, "data:image/x-icon,%00", false);
|
||||
});
|
||||
}
|
||||
|
||||
function promiseRemoveEngine() {
|
||||
return new Promise(resolve => {
|
||||
var ss = Services.search;
|
||||
|
||||
function observer(aSub, aTopic, aData) {
|
||||
if (aData == "engine-removed") {
|
||||
Services.obs.removeObserver(observer, "browser-search-engine-modified");
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
|
||||
Services.obs.addObserver(observer, "browser-search-engine-modified", false);
|
||||
var engine = ss.getEngineByName("Bug 426329");
|
||||
ss.removeEngine(engine);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
var preSelectedBrowser;
|
||||
var preTabNo;
|
||||
function* prepareTest() {
|
||||
preSelectedBrowser = gBrowser.selectedBrowser;
|
||||
preTabNo = gBrowser.tabs.length;
|
||||
searchBar = BrowserSearch.searchBar;
|
||||
|
||||
yield SimpleTest.promiseFocus();
|
||||
|
||||
if (document.activeElement == searchBar)
|
||||
return;
|
||||
|
||||
let focusPromise = BrowserTestUtils.waitForEvent(searchBar, "focus");
|
||||
gURLBar.focus();
|
||||
searchBar.focus();
|
||||
yield focusPromise;
|
||||
}
|
||||
|
||||
add_task(function* testSetupEngine() {
|
||||
yield promiseSetEngine();
|
||||
});
|
||||
|
||||
add_task(function* testReturn() {
|
||||
yield* prepareTest();
|
||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
|
||||
is(gBrowser.tabs.length, preTabNo, "Return key did not open new tab");
|
||||
is(gBrowser.currentURI.spec, expectedURL(searchBar.value), "testReturn opened correct search page");
|
||||
});
|
||||
|
||||
add_task(function* testAltReturn() {
|
||||
yield* prepareTest();
|
||||
yield BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
|
||||
EventUtils.synthesizeKey("VK_RETURN", { altKey: true });
|
||||
});
|
||||
|
||||
is(gBrowser.tabs.length, preTabNo + 1, "Alt+Return key added new tab");
|
||||
is(gBrowser.currentURI.spec, expectedURL(searchBar.value), "testAltReturn opened correct search page");
|
||||
});
|
||||
|
||||
// Shift key has no effect for now, so skip it
|
||||
add_task(function* testShiftAltReturn() {
|
||||
return;
|
||||
/*
|
||||
yield* prepareTest();
|
||||
|
||||
let url = expectedURL(searchBar.value);
|
||||
|
||||
let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser, url);
|
||||
EventUtils.synthesizeKey("VK_RETURN", { shiftKey: true, altKey: true });
|
||||
yield newTabPromise;
|
||||
|
||||
is(gBrowser.tabs.length, preTabNo + 1, "Shift+Alt+Return key added new tab");
|
||||
is(gBrowser.currentURI.spec, url, "testShiftAltReturn opened correct search page");
|
||||
*/
|
||||
});
|
||||
|
||||
add_task(function* testLeftClick() {
|
||||
yield* prepareTest();
|
||||
simulateClick({ button: 0 }, searchButton);
|
||||
yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
is(gBrowser.tabs.length, preTabNo, "LeftClick did not open new tab");
|
||||
is(gBrowser.currentURI.spec, expectedURL(searchBar.value), "testLeftClick opened correct search page");
|
||||
});
|
||||
|
||||
add_task(function* testMiddleClick() {
|
||||
yield* prepareTest();
|
||||
yield BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
|
||||
simulateClick({ button: 1 }, searchButton);
|
||||
});
|
||||
is(gBrowser.tabs.length, preTabNo + 1, "MiddleClick added new tab");
|
||||
is(gBrowser.currentURI.spec, expectedURL(searchBar.value), "testMiddleClick opened correct search page");
|
||||
});
|
||||
|
||||
add_task(function* testShiftMiddleClick() {
|
||||
yield* prepareTest();
|
||||
|
||||
let url = expectedURL(searchBar.value);
|
||||
|
||||
let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser, url);
|
||||
simulateClick({ button: 1, shiftKey: true }, searchButton);
|
||||
let newTab = yield newTabPromise;
|
||||
|
||||
is(gBrowser.tabs.length, preTabNo + 1, "Shift+MiddleClick added new tab");
|
||||
is(newTab.linkedBrowser.currentURI.spec, url, "testShiftMiddleClick opened correct search page");
|
||||
});
|
||||
|
||||
add_task(function* testRightClick() {
|
||||
preTabNo = gBrowser.tabs.length;
|
||||
gBrowser.selectedBrowser.loadURI("about:blank");
|
||||
yield new Promise(resolve => {
|
||||
setTimeout(function() {
|
||||
is(gBrowser.tabs.length, preTabNo, "RightClick did not open new tab");
|
||||
is(gBrowser.currentURI.spec, "about:blank", "RightClick did nothing");
|
||||
resolve();
|
||||
}, 5000);
|
||||
simulateClick({ button: 2 }, searchButton);
|
||||
});
|
||||
// The click in the searchbox focuses it, which opens the suggestion
|
||||
// panel. Clean up after ourselves.
|
||||
searchBar.textbox.popup.hidePopup();
|
||||
});
|
||||
|
||||
add_task(function* testSearchHistory() {
|
||||
var textbox = searchBar._textbox;
|
||||
for (var i = 0; i < searchEntries.length; i++) {
|
||||
let count = yield countEntries(textbox.getAttribute("autocompletesearchparam"), searchEntries[i]);
|
||||
ok(count > 0, "form history entry '" + searchEntries[i] + "' should exist");
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* testAutocomplete() {
|
||||
var popup = searchBar.textbox.popup;
|
||||
let popupShownPromise = BrowserTestUtils.waitForEvent(popup, "popupshown");
|
||||
searchBar.textbox.showHistoryPopup();
|
||||
yield popupShownPromise;
|
||||
checkMenuEntries(searchEntries);
|
||||
});
|
||||
|
||||
add_task(function* testClearHistory() {
|
||||
let controller = searchBar.textbox.controllers.getControllerForCommand("cmd_clearhistory")
|
||||
ok(controller.isCommandEnabled("cmd_clearhistory"), "Clear history command enabled");
|
||||
controller.doCommand("cmd_clearhistory");
|
||||
let count = yield countEntries();
|
||||
ok(count == 0, "History cleared");
|
||||
});
|
||||
|
||||
add_task(function* asyncCleanup() {
|
||||
searchBar.value = "";
|
||||
while (gBrowser.tabs.length != 1) {
|
||||
gBrowser.removeTab(gBrowser.tabs[0], {animate: false});
|
||||
}
|
||||
gBrowser.selectedBrowser.loadURI("about:blank");
|
||||
yield promiseRemoveEngine();
|
||||
});
|
||||
49
browser/components/search/test/browser_483086.js
Normal file
49
browser/components/search/test/browser_483086.js
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
var gSS = Services.search;
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
function observer(aSubject, aTopic, aData) {
|
||||
switch (aData) {
|
||||
case "engine-added":
|
||||
let engine = gSS.getEngineByName("483086a");
|
||||
ok(engine, "Test engine 1 installed");
|
||||
isnot(engine.searchForm, "foo://example.com",
|
||||
"Invalid SearchForm URL dropped");
|
||||
gSS.removeEngine(engine);
|
||||
break;
|
||||
case "engine-removed":
|
||||
Services.obs.removeObserver(observer, "browser-search-engine-modified");
|
||||
test2();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Services.obs.addObserver(observer, "browser-search-engine-modified", false);
|
||||
gSS.addEngine("http://mochi.test:8888/browser/browser/components/search/test/483086-1.xml",
|
||||
null, "data:image/x-icon;%00", false);
|
||||
}
|
||||
|
||||
function test2() {
|
||||
function observer(aSubject, aTopic, aData) {
|
||||
switch (aData) {
|
||||
case "engine-added":
|
||||
let engine = gSS.getEngineByName("483086b");
|
||||
ok(engine, "Test engine 2 installed");
|
||||
is(engine.searchForm, "http://example.com", "SearchForm is correct");
|
||||
gSS.removeEngine(engine);
|
||||
break;
|
||||
case "engine-removed":
|
||||
Services.obs.removeObserver(observer, "browser-search-engine-modified");
|
||||
finish();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Services.obs.addObserver(observer, "browser-search-engine-modified", false);
|
||||
gSS.addEngine("http://mochi.test:8888/browser/browser/components/search/test/483086-2.xml",
|
||||
null, "data:image/x-icon;%00", false);
|
||||
}
|
||||
159
browser/components/search/test/browser_aboutSearchReset.js
Normal file
159
browser/components/search/test/browser_aboutSearchReset.js
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
const TELEMETRY_RESULT_ENUM = {
|
||||
RESTORED_DEFAULT: 0,
|
||||
KEPT_CURRENT: 1,
|
||||
CHANGED_ENGINE: 2,
|
||||
CLOSED_PAGE: 3,
|
||||
OPENED_SETTINGS: 4
|
||||
};
|
||||
|
||||
const kSearchStr = "a search";
|
||||
const kSearchPurpose = "searchbar";
|
||||
|
||||
const kTestEngine = "testEngine.xml";
|
||||
|
||||
function checkTelemetryRecords(expectedValue) {
|
||||
let histogram = Services.telemetry.getHistogramById("SEARCH_RESET_RESULT");
|
||||
let snapshot = histogram.snapshot();
|
||||
// The probe is declared with 5 values, but we get 6 back from .counts
|
||||
let expectedCounts = [0, 0, 0, 0, 0, 0];
|
||||
if (expectedValue != null) {
|
||||
expectedCounts[expectedValue] = 1;
|
||||
}
|
||||
Assert.deepEqual(snapshot.counts, expectedCounts,
|
||||
"histogram has expected content");
|
||||
histogram.clear();
|
||||
}
|
||||
|
||||
function promiseStoppedLoad(expectedURL) {
|
||||
return new Promise(resolve => {
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
let original = browser.loadURIWithFlags;
|
||||
browser.loadURIWithFlags = function(URI) {
|
||||
if (URI == expectedURL) {
|
||||
browser.loadURIWithFlags = original;
|
||||
ok(true, "loaded expected url: " + URI);
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
original.apply(browser, arguments);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
var gTests = [
|
||||
|
||||
{
|
||||
desc: "Test the 'Keep Current Settings' button.",
|
||||
run: function* () {
|
||||
let engine = yield promiseNewEngine(kTestEngine, {setAsCurrent: true});
|
||||
|
||||
let expectedURL = engine.
|
||||
getSubmission(kSearchStr, null, kSearchPurpose).
|
||||
uri.spec;
|
||||
|
||||
let rawEngine = engine.wrappedJSObject;
|
||||
let initialHash = rawEngine.getAttr("loadPathHash");
|
||||
rawEngine.setAttr("loadPathHash", "broken");
|
||||
|
||||
let loadPromise = promiseStoppedLoad(expectedURL);
|
||||
gBrowser.contentDocument.getElementById("searchResetKeepCurrent").click();
|
||||
yield loadPromise;
|
||||
|
||||
is(engine, Services.search.currentEngine,
|
||||
"the custom engine is still default");
|
||||
is(rawEngine.getAttr("loadPathHash"), initialHash,
|
||||
"the loadPathHash has been fixed");
|
||||
|
||||
checkTelemetryRecords(TELEMETRY_RESULT_ENUM.KEPT_CURRENT);
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
desc: "Test the 'Restore Search Defaults' button.",
|
||||
run: function* () {
|
||||
let currentEngine = Services.search.currentEngine;
|
||||
let originalEngine = Services.search.originalDefaultEngine;
|
||||
let doc = gBrowser.contentDocument;
|
||||
let defaultEngineSpan = doc.getElementById("defaultEngine");
|
||||
is(defaultEngineSpan.textContent, originalEngine.name,
|
||||
"the name of the original default engine is displayed");
|
||||
|
||||
let expectedURL = originalEngine.
|
||||
getSubmission(kSearchStr, null, kSearchPurpose).
|
||||
uri.spec;
|
||||
let loadPromise = promiseStoppedLoad(expectedURL);
|
||||
let button = doc.getElementById("searchResetChangeEngine");
|
||||
is(doc.activeElement, button,
|
||||
"the 'Change Search Engine' button is focused");
|
||||
button.click();
|
||||
yield loadPromise;
|
||||
|
||||
is(originalEngine, Services.search.currentEngine,
|
||||
"the default engine is back to the original one");
|
||||
|
||||
checkTelemetryRecords(TELEMETRY_RESULT_ENUM.RESTORED_DEFAULT);
|
||||
Services.search.currentEngine = currentEngine;
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
desc: "Click the settings link.",
|
||||
run: function* () {
|
||||
let loadPromise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser,
|
||||
false,
|
||||
"about:preferences#search")
|
||||
gBrowser.contentDocument.getElementById("linkSettingsPage").click();
|
||||
yield loadPromise;
|
||||
|
||||
checkTelemetryRecords(TELEMETRY_RESULT_ENUM.OPENED_SETTINGS);
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
desc: "Load another page without clicking any of the buttons.",
|
||||
run: function* () {
|
||||
yield promiseTabLoadEvent(gBrowser.selectedTab, "about:mozilla");
|
||||
|
||||
checkTelemetryRecords(TELEMETRY_RESULT_ENUM.CLOSED_PAGE);
|
||||
}
|
||||
},
|
||||
|
||||
];
|
||||
|
||||
function test()
|
||||
{
|
||||
waitForExplicitFinish();
|
||||
Task.spawn(function* () {
|
||||
let oldCanRecord = Services.telemetry.canRecordExtended;
|
||||
Services.telemetry.canRecordExtended = true;
|
||||
checkTelemetryRecords();
|
||||
|
||||
for (let test of gTests) {
|
||||
info(test.desc);
|
||||
|
||||
// Create a tab to run the test.
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab("about:blank");
|
||||
|
||||
// Start loading about:searchreset and wait for it to complete.
|
||||
let url = "about:searchreset?data=" + encodeURIComponent(kSearchStr) +
|
||||
"&purpose=" + kSearchPurpose;
|
||||
yield promiseTabLoadEvent(tab, url);
|
||||
|
||||
info("Running test");
|
||||
yield test.run();
|
||||
|
||||
info("Cleanup");
|
||||
gBrowser.removeCurrentTab();
|
||||
}
|
||||
|
||||
Services.telemetry.canRecordExtended = oldCanRecord;
|
||||
}).then(finish, ex => {
|
||||
ok(false, "Unexpected Exception: " + ex);
|
||||
finish();
|
||||
});
|
||||
}
|
||||
144
browser/components/search/test/browser_abouthome_behavior.js
Normal file
144
browser/components/search/test/browser_abouthome_behavior.js
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/*
|
||||
* Test home page search for all plugin URLs
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
function test() {
|
||||
// Bug 992270: Ignore uncaught about:home exceptions (related to snippets from IndexedDB)
|
||||
ignoreAllUncaughtExceptions(true);
|
||||
|
||||
let previouslySelectedEngine = Services.search.currentEngine;
|
||||
|
||||
function replaceUrl(base) {
|
||||
return base;
|
||||
}
|
||||
|
||||
let gMutationObserver = null;
|
||||
|
||||
function verify_about_home_search(engine_name) {
|
||||
let engine = Services.search.getEngineByName(engine_name);
|
||||
ok(engine, engine_name + " is installed");
|
||||
|
||||
Services.search.currentEngine = engine;
|
||||
|
||||
// load about:home, but remove the listener first so it doesn't
|
||||
// get in the way
|
||||
gBrowser.removeProgressListener(listener);
|
||||
gBrowser.loadURI("about:home");
|
||||
info("Waiting for about:home load");
|
||||
tab.linkedBrowser.addEventListener("load", function load(event) {
|
||||
if (event.originalTarget != tab.linkedBrowser.contentDocument ||
|
||||
event.target.location.href == "about:blank") {
|
||||
info("skipping spurious load event");
|
||||
return;
|
||||
}
|
||||
tab.linkedBrowser.removeEventListener("load", load, true);
|
||||
|
||||
// Observe page setup
|
||||
let doc = gBrowser.contentDocument;
|
||||
gMutationObserver = new MutationObserver(function (mutations) {
|
||||
for (let mutation of mutations) {
|
||||
if (mutation.attributeName == "searchEngineName") {
|
||||
// Re-add the listener, and perform a search
|
||||
gBrowser.addProgressListener(listener);
|
||||
gMutationObserver.disconnect()
|
||||
gMutationObserver = null;
|
||||
executeSoon(function() {
|
||||
doc.getElementById("searchText").value = "foo";
|
||||
doc.getElementById("searchSubmit").click();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
gMutationObserver.observe(doc.documentElement, { attributes: true });
|
||||
}, true);
|
||||
}
|
||||
waitForExplicitFinish();
|
||||
|
||||
let gCurrTest;
|
||||
let gTests = [
|
||||
{
|
||||
name: "Search with Bing from about:home",
|
||||
searchURL: replaceUrl("http://www.bing.com/search?q=foo&pc=MOZI&form=MOZSPG"),
|
||||
run: function () {
|
||||
verify_about_home_search("Bing");
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "Search with Yahoo from about:home",
|
||||
searchURL: replaceUrl("https://search.yahoo.com/search?p=foo&ei=UTF-8&fr=moz35"),
|
||||
run: function () {
|
||||
verify_about_home_search("Yahoo");
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "Search with Google from about:home",
|
||||
searchURL: replaceUrl("https://www.google.com/search?q=foo&ie=utf-8&oe=utf-8"),
|
||||
run: function () {
|
||||
verify_about_home_search("Google");
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "Search with Amazon.com from about:home",
|
||||
searchURL: replaceUrl("https://www.amazon.com/exec/obidos/external-search/?field-keywords=foo&mode=blended&tag=mozilla-20&sourceid=Mozilla-search"),
|
||||
run: function () {
|
||||
verify_about_home_search("Amazon.com");
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
function nextTest() {
|
||||
if (gTests.length) {
|
||||
gCurrTest = gTests.shift();
|
||||
info("Running : " + gCurrTest.name);
|
||||
executeSoon(gCurrTest.run);
|
||||
} else {
|
||||
// Make sure we listen again for uncaught exceptions in the next test or cleanup.
|
||||
executeSoon(finish);
|
||||
}
|
||||
}
|
||||
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab();
|
||||
|
||||
let listener = {
|
||||
onStateChange: function onStateChange(webProgress, req, flags, status) {
|
||||
info("onStateChange");
|
||||
// Only care about top-level document starts
|
||||
let docStart = Ci.nsIWebProgressListener.STATE_IS_DOCUMENT |
|
||||
Ci.nsIWebProgressListener.STATE_START;
|
||||
if (!(flags & docStart) || !webProgress.isTopLevel)
|
||||
return;
|
||||
|
||||
if (req.originalURI.spec == "about:blank")
|
||||
return;
|
||||
|
||||
info("received document start");
|
||||
|
||||
ok(req instanceof Ci.nsIChannel, "req is a channel");
|
||||
is(req.originalURI.spec, gCurrTest.searchURL, "search URL was loaded");
|
||||
info("Actual URI: " + req.URI.spec);
|
||||
|
||||
req.cancel(Components.results.NS_ERROR_FAILURE);
|
||||
|
||||
executeSoon(nextTest);
|
||||
}
|
||||
}
|
||||
|
||||
registerCleanupFunction(function () {
|
||||
Services.search.currentEngine = previouslySelectedEngine;
|
||||
gBrowser.removeProgressListener(listener);
|
||||
gBrowser.removeTab(tab);
|
||||
if (gMutationObserver)
|
||||
gMutationObserver.disconnect();
|
||||
});
|
||||
|
||||
tab.linkedBrowser.addEventListener("load", function load() {
|
||||
tab.linkedBrowser.removeEventListener("load", load, true);
|
||||
gBrowser.addProgressListener(listener);
|
||||
nextTest();
|
||||
}, true);
|
||||
}
|
||||
105
browser/components/search/test/browser_addEngine.js
Normal file
105
browser/components/search/test/browser_addEngine.js
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
var gSS = Services.search;
|
||||
|
||||
function observer(aSubject, aTopic, aData) {
|
||||
if (!gCurrentTest) {
|
||||
info("Observer called with no test active");
|
||||
return;
|
||||
}
|
||||
|
||||
let engine = aSubject.QueryInterface(Ci.nsISearchEngine);
|
||||
info("Observer: " + aData + " for " + engine.name);
|
||||
let method;
|
||||
switch (aData) {
|
||||
case "engine-added":
|
||||
if (gCurrentTest.added)
|
||||
method = "added"
|
||||
break;
|
||||
case "engine-current":
|
||||
if (gCurrentTest.current)
|
||||
method = "current";
|
||||
break;
|
||||
case "engine-removed":
|
||||
if (gCurrentTest.removed)
|
||||
method = "removed";
|
||||
break;
|
||||
}
|
||||
|
||||
if (method)
|
||||
gCurrentTest[method](engine);
|
||||
}
|
||||
|
||||
function checkEngine(checkObj, engineObj) {
|
||||
info("Checking engine");
|
||||
for (var prop in checkObj)
|
||||
is(checkObj[prop], engineObj[prop], prop + " is correct");
|
||||
}
|
||||
|
||||
var gTests = [
|
||||
{
|
||||
name: "opensearch install",
|
||||
engine: {
|
||||
name: "Foo",
|
||||
alias: null,
|
||||
description: "Foo Search",
|
||||
searchForm: "http://mochi.test:8888/browser/browser/components/search/test/"
|
||||
},
|
||||
run: function () {
|
||||
Services.obs.addObserver(observer, "browser-search-engine-modified", false);
|
||||
|
||||
gSS.addEngine("http://mochi.test:8888/browser/browser/components/search/test/testEngine.xml",
|
||||
null, "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGklEQVQoz2NgGB6AnZ1dUlJSXl4eSDIyMhLW4Ovr%2B%2Fr168uXL69Zs4YoG%2BLi4i5dusTExMTGxsbNzd3f37937976%2BnpmZmagbHR09J49e5YvX66kpATVEBYW9ubNm2nTphkbG7e2tp44cQLIuHfvXm5urpaWFlDKysqqu7v73LlzECMYIiIiHj58mJCQoKKicvXq1bS0NKBgW1vbjh074uPjgeqAXE1NzSdPnvDz84M0AEUvXLgAsW379u1z5swBen3jxo2zZ892cHB4%2BvQp0KlAfwI1cHJyghQFBwfv2rULokFXV%2FfixYu7d%2B8GGqGgoMDKyrpu3br9%2B%2FcDuXl5eVA%2FAEWBfoWHAdAYoNuAYQ0XAeoUERFhGDYAAPoUaT2dfWJuAAAAAElFTkSuQmCC",
|
||||
false);
|
||||
},
|
||||
added: function (engine) {
|
||||
ok(engine, "engine was added.");
|
||||
|
||||
checkEngine(this.engine, engine);
|
||||
|
||||
let engineFromSS = gSS.getEngineByName(this.engine.name);
|
||||
is(engine, engineFromSS, "engine is obtainable via getEngineByName");
|
||||
|
||||
let aEngine = gSS.getEngineByAlias("fooalias");
|
||||
ok(!aEngine, "Alias was not parsed from engine description");
|
||||
|
||||
gSS.currentEngine = engine;
|
||||
},
|
||||
current: function (engine) {
|
||||
let currentEngine = gSS.currentEngine;
|
||||
is(engine, currentEngine, "engine is current");
|
||||
is(engine.name, this.engine.name, "current engine was changed successfully");
|
||||
|
||||
gSS.removeEngine(engine);
|
||||
},
|
||||
removed: function (engine) {
|
||||
// Remove the observer before calling the currentEngine getter,
|
||||
// as that getter will set the currentEngine to the original default
|
||||
// which will trigger a notification causing the test to loop over all
|
||||
// engines.
|
||||
Services.obs.removeObserver(observer, "browser-search-engine-modified");
|
||||
|
||||
let currentEngine = gSS.currentEngine;
|
||||
ok(currentEngine, "An engine is present.");
|
||||
isnot(currentEngine.name, this.engine.name, "Current engine reset after removal");
|
||||
|
||||
nextTest();
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
var gCurrentTest = null;
|
||||
function nextTest() {
|
||||
if (gTests.length) {
|
||||
gCurrentTest = gTests.shift();
|
||||
info("Running " + gCurrentTest.name);
|
||||
gCurrentTest.run();
|
||||
} else
|
||||
executeSoon(finish);
|
||||
}
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
nextTest();
|
||||
}
|
||||
82
browser/components/search/test/browser_amazon.js
Normal file
82
browser/components/search/test/browser_amazon.js
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/*
|
||||
* Test Amazon search plugin URLs
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const BROWSER_SEARCH_PREF = "browser.search.";
|
||||
|
||||
function test() {
|
||||
let engine = Services.search.getEngineByName("Amazon.com");
|
||||
ok(engine, "Amazon.com");
|
||||
|
||||
let base = "https://www.amazon.com/exec/obidos/external-search/?field-keywords=foo&ie=UTF-8&mode=blended&tag=mozilla-20&sourceid=Mozilla-search";
|
||||
let url;
|
||||
|
||||
// Test search URLs (including purposes).
|
||||
url = engine.getSubmission("foo").uri.spec;
|
||||
is(url, base, "Check search URL for 'foo'");
|
||||
|
||||
// Check search suggestion URL.
|
||||
url = engine.getSubmission("foo", "application/x-suggestions+json").uri.spec;
|
||||
is(url, "https://completion.amazon.com/search/complete?q=foo&search-alias=aps&mkt=1", "Check search suggestion URL for 'foo'");
|
||||
|
||||
// Check all other engine properties.
|
||||
const EXPECTED_ENGINE = {
|
||||
name: "Amazon.com",
|
||||
alias: null,
|
||||
description: "Amazon.com Search",
|
||||
searchForm: "https://www.amazon.com/exec/obidos/external-search/?field-keywords=&ie=UTF-8&mode=blended&tag=mozilla-20&sourceid=Mozilla-search",
|
||||
hidden: false,
|
||||
wrappedJSObject: {
|
||||
queryCharset: "UTF-8",
|
||||
"_iconURL": "data:image/x-icon;base64,AAABAAIAEBAAAAAAAAC0AQAAJgAAACAgAAAAAAAA6QIAANoBAACJUE5HDQoaCgAAAA1JSERSAAAAEAAAABAIBgAAAB/z/2EAAAF7SURBVDjLlZPLasJAFIaFRF+iVV+h6hO0GF+gVB9AaHwDt64qCG03tQgtdCFIuyhUelmGli66MXThSt24kNiFBUlAYi6ezjnNxSuawB/ITP7v/HNmJgQAEaZzpgHs/gwcTyTEXuXl2U6nA8ViEbK5HKler28CVRAwnB9ptVrAh8MrQuCaZ4iA8fzIqSgCxwzpTIaSuN/RWGwdYLwCUBQFZFkGSZLgqdmEE7YEN8VOAKyaSKUW4nNBAFmnYiKZpDRX1WqwBBzP089n5f/NEQsFL4WqqtsBWJlzDAJr5PwSMM1awEzzdxIbGI3Hvc6jCZeVFgRQRwpY7Qcw3ktgfpR8wLRxCPaot/X4GS95MppfF6DX9n2A3f+kAZycaT8bAZjU6r6B/duD6d3BYg9wQq/tkYzHY1blEiz5lmQyGc95mrO6r2CxgpjCBXgNsJVviolpXJiraeOIjJRE10juUa4sR8V+mO17VvmGqtuOcdNlwut8zTQJcJ0njifyB2bgTdKh6w4BAAAAAElFTkSuQmCCiVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACsElEQVRYw71XQWsTURBe2LQgeNKLB+tVemt6txcteNSD/QGC6VEIGDx5s+eKPQqFgJhLNdFLBWMP7cU0oSAWjB70koC9WHbVQ5SO8+XtS14mr7svyaYDH9m87Jv55puZt1nPi4yIzjMeMj7T9OwjI88455nGC1cZX+nsDESumJmPFDwIAqrX6z00Gg1qt9vjkJgFgUeuO16Vy3RjeZkyMzM9+MY1fsM9I9h9zyV7ZAznZrA4FAoFVwJ1z+WuOysrg1lnMolkHJX4k0igzI5sARYWF7vEZEk0rvO6iyUSuJfLJUqM7zYSqRDIra4OOUZPmNZsNrsl8UVTpkJAjh1GzmaSpJ8mAWmYeZB5urHRhW5SNOfUCCDo47W1bvPZsp2qAhipy3Nz1kaLG8dUCEBqM5AvpgElqFar01NgIZsdco7Zb7VasU2YigIYL5tjqCL7Q5YkFQXKlcqQ7DbHthIALk/IWAKor82xPIhshxWABCYioDMz51sexcVi0XoG4DPLIyvJjkTArK3scDQnRvO0MdTrUHGiKZCP4tNgO6BAEI08EQH9Z2Qow0hyPypJGIa9p6JWKCn4SA8jSKmJIDgyRvPJkcRxjfUwNGr/i8+Mo32iHzWiThBD4NM60bet9P77/ubA728RlTjMiwiH6zEEfvIrwdZFtQmMJ7W/ofIDBZD5m3mVZGwJcOP2kmILIlCkE45HoPWurwCSg0+UQRD4ZyXxId+T7gQb9+4q9sioY5ltrOG3L5vqXiiJffDx/aUi83ZJ7jr2ohcEu8Hh6/m+I7OWGiVxbWKHsz+O3vSOakqFQdsFgQeJUiKD7Wv9YKXBgCeSUC3v2kM5EJhlHDh3NcgcPlG1BXZu98sDmTuBa4fsMnz9fniJUaGzs+eMC540XuR0aDO2L8Y3qPyMcdOM+R/8XcqRA3qp9gAAAABJRU5ErkJggg==",
|
||||
_urls : [
|
||||
{
|
||||
type: "application/x-suggestions+json",
|
||||
method: "GET",
|
||||
template: "https://completion.amazon.com/search/complete?q={searchTerms}&search-alias=aps&mkt=1",
|
||||
params: "",
|
||||
},
|
||||
{
|
||||
type: "text/html",
|
||||
method: "GET",
|
||||
template: "https://www.amazon.com/exec/obidos/external-search/",
|
||||
params: [
|
||||
{
|
||||
name: "field-keywords",
|
||||
value: "{searchTerms}",
|
||||
purpose: undefined,
|
||||
},
|
||||
{
|
||||
name: "ie",
|
||||
value: "{inputEncoding}",
|
||||
purpose: undefined,
|
||||
},
|
||||
{
|
||||
name: "mode",
|
||||
value: "blended",
|
||||
purpose: undefined,
|
||||
},
|
||||
{
|
||||
name: "tag",
|
||||
value: "mozilla-20",
|
||||
purpose: undefined,
|
||||
},
|
||||
{
|
||||
name: "sourceid",
|
||||
value: "Mozilla-search",
|
||||
purpose: undefined,
|
||||
},
|
||||
],
|
||||
mozparams: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
isSubObjectOf(EXPECTED_ENGINE, engine, "Amazon");
|
||||
}
|
||||
166
browser/components/search/test/browser_amazon_behavior.js
Normal file
166
browser/components/search/test/browser_amazon_behavior.js
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/*
|
||||
* Test Amazon search plugin URLs
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const BROWSER_SEARCH_PREF = "browser.search.";
|
||||
|
||||
|
||||
function test() {
|
||||
let engine = Services.search.getEngineByName("Amazon.com");
|
||||
ok(engine, "Amazon is installed");
|
||||
|
||||
let previouslySelectedEngine = Services.search.currentEngine;
|
||||
Services.search.currentEngine = engine;
|
||||
engine.alias = "a";
|
||||
|
||||
let base = "https://www.amazon.com/exec/obidos/external-search/?field-keywords=foo&ie=UTF-8&mode=blended&tag=mozilla-20&sourceid=Mozilla-search";
|
||||
let url;
|
||||
|
||||
// Test search URLs (including purposes).
|
||||
url = engine.getSubmission("foo").uri.spec;
|
||||
is(url, base, "Check search URL for 'foo'");
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
var gCurrTest;
|
||||
var gTests = [
|
||||
{
|
||||
name: "context menu search",
|
||||
searchURL: base,
|
||||
run: function () {
|
||||
// Simulate a contextmenu search
|
||||
// FIXME: This is a bit "low-level"...
|
||||
BrowserSearch.loadSearch("foo", false, "contextmenu");
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "keyword search",
|
||||
searchURL: base,
|
||||
run: function () {
|
||||
gURLBar.value = "? foo";
|
||||
gURLBar.focus();
|
||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "keyword search",
|
||||
searchURL: base,
|
||||
run: function () {
|
||||
gURLBar.value = "a foo";
|
||||
gURLBar.focus();
|
||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "search bar search",
|
||||
searchURL: base,
|
||||
run: function () {
|
||||
let sb = BrowserSearch.searchBar;
|
||||
sb.focus();
|
||||
sb.value = "foo";
|
||||
registerCleanupFunction(function () {
|
||||
sb.value = "";
|
||||
});
|
||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "new tab search",
|
||||
searchURL: base,
|
||||
run: function () {
|
||||
function doSearch(doc) {
|
||||
// Re-add the listener, and perform a search
|
||||
gBrowser.addProgressListener(listener);
|
||||
doc.getElementById("newtab-search-text").value = "foo";
|
||||
doc.getElementById("newtab-search-submit").click();
|
||||
}
|
||||
|
||||
// load about:newtab, but remove the listener first so it doesn't
|
||||
// get in the way
|
||||
gBrowser.removeProgressListener(listener);
|
||||
gBrowser.loadURI("about:newtab");
|
||||
info("Waiting for about:newtab load");
|
||||
tab.linkedBrowser.addEventListener("load", function load(event) {
|
||||
if (event.originalTarget != tab.linkedBrowser.contentDocument ||
|
||||
event.target.location.href == "about:blank") {
|
||||
info("skipping spurious load event");
|
||||
return;
|
||||
}
|
||||
tab.linkedBrowser.removeEventListener("load", load, true);
|
||||
|
||||
// Observe page setup
|
||||
let win = gBrowser.contentWindow;
|
||||
if (win.gSearch.currentEngineName ==
|
||||
Services.search.currentEngine.name) {
|
||||
doSearch(win.document);
|
||||
}
|
||||
else {
|
||||
info("Waiting for newtab search init");
|
||||
win.addEventListener("ContentSearchService", function done(event) {
|
||||
info("Got newtab search event " + event.detail.type);
|
||||
if (event.detail.type == "State") {
|
||||
win.removeEventListener("ContentSearchService", done);
|
||||
// Let gSearch respond to the event before continuing.
|
||||
executeSoon(() => doSearch(win.document));
|
||||
}
|
||||
});
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
function nextTest() {
|
||||
if (gTests.length) {
|
||||
gCurrTest = gTests.shift();
|
||||
info("Running : " + gCurrTest.name);
|
||||
executeSoon(gCurrTest.run);
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab();
|
||||
|
||||
let listener = {
|
||||
onStateChange: function onStateChange(webProgress, req, flags, status) {
|
||||
info("onStateChange");
|
||||
// Only care about top-level document starts
|
||||
let docStart = Ci.nsIWebProgressListener.STATE_IS_DOCUMENT |
|
||||
Ci.nsIWebProgressListener.STATE_START;
|
||||
if (!(flags & docStart) || !webProgress.isTopLevel)
|
||||
return;
|
||||
|
||||
if (req.originalURI.spec == "about:blank")
|
||||
return;
|
||||
|
||||
info("received document start");
|
||||
|
||||
ok(req instanceof Ci.nsIChannel, "req is a channel");
|
||||
is(req.originalURI.spec, gCurrTest.searchURL, "search URL was loaded");
|
||||
info("Actual URI: " + req.URI.spec);
|
||||
|
||||
req.cancel(Components.results.NS_ERROR_FAILURE);
|
||||
|
||||
executeSoon(nextTest);
|
||||
}
|
||||
}
|
||||
|
||||
registerCleanupFunction(function () {
|
||||
engine.alias = undefined;
|
||||
gBrowser.removeProgressListener(listener);
|
||||
gBrowser.removeTab(tab);
|
||||
Services.search.currentEngine = previouslySelectedEngine;
|
||||
});
|
||||
|
||||
tab.linkedBrowser.addEventListener("load", function load() {
|
||||
tab.linkedBrowser.removeEventListener("load", load, true);
|
||||
gBrowser.addProgressListener(listener);
|
||||
nextTest();
|
||||
}, true);
|
||||
}
|
||||
118
browser/components/search/test/browser_bing.js
Normal file
118
browser/components/search/test/browser_bing.js
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/*
|
||||
* Test Bing search plugin URLs
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const BROWSER_SEARCH_PREF = "browser.search.";
|
||||
|
||||
function test() {
|
||||
let engine = Services.search.getEngineByName("Bing");
|
||||
ok(engine, "Bing");
|
||||
|
||||
let base = "https://www.bing.com/search?q=foo&pc=MOZI";
|
||||
let url;
|
||||
|
||||
// Test search URLs (including purposes).
|
||||
url = engine.getSubmission("foo").uri.spec;
|
||||
is(url, base + "&form=MOZSBR", "Check search URL for 'foo'");
|
||||
url = engine.getSubmission("foo", null, "contextmenu").uri.spec;
|
||||
is(url, base + "&form=MOZCON", "Check context menu search URL for 'foo'");
|
||||
url = engine.getSubmission("foo", null, "keyword").uri.spec;
|
||||
is(url, base + "&form=MOZLBR", "Check keyword search URL for 'foo'");
|
||||
url = engine.getSubmission("foo", null, "searchbar").uri.spec;
|
||||
is(url, base + "&form=MOZSBR", "Check search bar search URL for 'foo'");
|
||||
url = engine.getSubmission("foo", null, "homepage").uri.spec;
|
||||
is(url, base + "&form=MOZSPG", "Check homepage search URL for 'foo'");
|
||||
url = engine.getSubmission("foo", null, "newtab").uri.spec;
|
||||
is(url, base + "&form=MOZTSB", "Check newtab search URL for 'foo'");
|
||||
|
||||
// Check search suggestion URL.
|
||||
url = engine.getSubmission("foo", "application/x-suggestions+json").uri.spec;
|
||||
is(url, "https://www.bing.com/osjson.aspx?query=foo&form=OSDJAS&language=" + getLocale(), "Check search suggestion URL for 'foo'");
|
||||
|
||||
// Check all other engine properties.
|
||||
const EXPECTED_ENGINE = {
|
||||
name: "Bing",
|
||||
alias: null,
|
||||
description: "Bing. Search by Microsoft.",
|
||||
searchForm: "https://www.bing.com/search?q=&pc=MOZI&form=MOZSBR",
|
||||
hidden: false,
|
||||
wrappedJSObject: {
|
||||
queryCharset: "UTF-8",
|
||||
"_iconURL": "data:image/x-icon;base64,AAABAAIAICAAAAEACACoCAAAJgAAABAQAAABAAgAaAUAAM4IAAAoAAAAIAAAAEAAAAABAAgAAAAAAIAEAAAAAAAAAAAAAAABAAAAAAAAhIQMAI+PIwCXlzEAn59BAKioUwCurl8AtbVuAL6+fwDJyZMA0tKlANjYsgDe3r4A5eXMAOzs2QDy8uUA+fnzAP///wAAGi8AAC1QAAA/cAAAUZAAAGOwAAB2zwAAiPAAEZj/ADGm/wBRs/8AccH/AJHP/wCx3f8A0ev/AP///wAAAAAAACwvAABLUAAAaHAAAIaQAAClsAAAw88AAOHwABHv/wAx8f8AUfP/AHH1/wCR9/8Asfn/ANH7/wD///8AAAAAAAAvIQAAUDcAAHBMAACQYwAAsHkAAM+PAADwpgAR/7QAMf++AFH/yABx/9MAkf/cALH/5QDR//AA////AAAAAAAALw4AAFAYAABwIgAAkCwAALA2AADPQAAA8EoAEf9bADH/cQBR/4cAcf+dAJH/sgCx/8kA0f/fAP///wAAAAAAAi8AAARQAAAGcAAACJAAAAqwAAALzwAADvAAACD/EgA9/zEAW/9RAHn/cQCY/5EAtf+xANT/0QD///8AAAAAABQvAAAiUAAAMHAAAD2QAABMsAAAWc8AAGfwAAB4/xEAiv8xAJz/UQCu/3EAwP+RANL/sQDk/9EA////AAAAAAAmLwAAQFAAAFpwAAB0kAAAjrAAAKnPAADC8AAA0f8RANj/MQDe/1EA4/9xAOn/kQDv/7EA9v/RAP///wAAAAAALyYAAFBBAABwWwAAkHQAALCOAADPqQAA8MMAAP/SEQD/2DEA/91RAP/kcQD/6pEA//CxAP/20QD///8AAAAAAC8UAABQIgAAcDAAAJA+AACwTQAAz1sAAPBpAAD/eREA/4oxAP+dUQD/r3EA/8GRAP/SsQD/5dEA////AAAAAAAvAwAAUAQAAHAGAACQCQAAsAoAAM8MAADwDgAA/yASAP8+MQD/XFEA/3pxAP+XkQD/trEA/9TRAP///wAAAAAALwAOAFAAFwBwACEAkAArALAANgDPAEAA8ABJAP8RWgD/MXAA/1GGAP9xnAD/kbIA/7HIAP/R3wD///8AAAAAAC8AIABQADYAcABMAJAAYgCwAHgAzwCOAPAApAD/EbMA/zG+AP9RxwD/cdEA/5HcAP+x5QD/0fAA////AAAAAAAsAC8ASwBQAGkAcACHAJAApQCwAMQAzwDhAPAA8BH/APIx/wD0Uf8A9nH/APeR/wD5sf8A+9H/AP///wAAAAAAGwAvAC0AUAA/AHAAUgCQAGMAsAB2AM8AiADwAJkR/wCmMf8AtFH/AMJx/wDPkf8A3LH/AOvR/wD///8AAAAAAAgALwAOAFAAFQBwABsAkAAhALAAJgDPACwA8AA+Ef8AWDH/AHFR/wCMcf8AppH/AL+x/wDa0f8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBggCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAsQEA0HAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwkPEBAQEBALBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEMEBAQEBAQEBAPCQMAAAAAAAAAAAAAAAAAAAAAAAAAAQ0QEBAQEBAQEBAQDQgBAAAAAAAAAAAAAAAAAAAAAAABDRAQEBAQEBAQEBAQEA0GAQAAAAAAAAAAAAAAAAAAAAENEBAQDgcLEBAQEBAQEBALBAAAAAAAAAAAAAAAAAAAAQ0QEBANAQEHDRAQEBAQEBAOCAAAAAAAAAAAAAAAAAABDRAQEA4BAAACCA4QEBAQEBANAQAAAAAAAAAAAAAAAAENEBAQDgEAAAAABAsQEBAQEA0BAAAAAAAAAAAAAAAAAQ0QEBAOAQAAAAABBw4QEBAQDQEAAAAAAAAAAAAAAAABDRAQEA4BAAABBw0QEBAQEBANAQAAAAAAAAAAAAAAAAENEBAQDgEAAAcQEBAQEBAQEA0BAAAAAAAAAAAAAAAAAQ0QEBAOAQABCxAQEBAQEBANBwAAAAAAAAAAAAAAAAABDRAQEA4BAAQPEBAQEA0IBAEAAAAAAAAAAAAAAAAAAAENEBAQDgEACRAQDQkGAQAAAAAAAAAAAAAAAAAAAAAAAQ0QEBAOAQILCgYCAAAAAAAAAAAAAAAAAAAAAAAAAAABDRAQEA4BAQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAENEBAQDgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQ0QEBAOAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABDRAQEA4BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAENEBAQDgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQ0QEBAOAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABDRAQEA0BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAENEA0IBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQcFAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAQAAAAIAAAAAEACAAAAAAAQAEAAAAAAAAAAAAAAAEAAAAAAACEhAAAjIwAAJKSFgCZmSgAqqpRALKyYgC+vnsAxsaKAM3NmQDU1KgA4ODBAOjozwDw8OEA+fnyAP///wD///8AAAAAAAAaLwAALVAAAD9wAABRkAAAY7AAAHbPAACI8AARmP8AMab/AFGz/wBxwf8Akc//ALHd/wDR6/8A////AAAAAAAALC8AAEtQAABocAAAhpAAAKWwAADDzwAA4fAAEe//ADHx/wBR8/8AcfX/AJH3/wCx+f8A0fv/AP///wAAAAAAAC8hAABQNwAAcEwAAJBjAACweQAAz48AAPCmABH/tAAx/74AUf/IAHH/0wCR/9wAsf/lANH/8AD///8AAAAAAAAvDgAAUBgAAHAiAACQLAAAsDYAAM9AAADwSgAR/1sAMf9xAFH/hwBx/50Akf+yALH/yQDR/98A////AAAAAAACLwAABFAAAAZwAAAIkAAACrAAAAvPAAAO8AAAIP8SAD3/MQBb/1EAef9xAJj/kQC1/7EA1P/RAP///wAAAAAAFC8AACJQAAAwcAAAPZAAAEywAABZzwAAZ/AAAHj/EQCK/zEAnP9RAK7/cQDA/5EA0v+xAOT/0QD///8AAAAAACYvAABAUAAAWnAAAHSQAACOsAAAqc8AAMLwAADR/xEA2P8xAN7/UQDj/3EA6f+RAO//sQD2/9EA////AAAAAAAvJgAAUEEAAHBbAACQdAAAsI4AAM+pAADwwwAA/9IRAP/YMQD/3VEA/+RxAP/qkQD/8LEA//bRAP///wAAAAAALxQAAFAiAABwMAAAkD4AALBNAADPWwAA8GkAAP95EQD/ijEA/51RAP+vcQD/wZEA/9KxAP/l0QD///8AAAAAAC8DAABQBAAAcAYAAJAJAACwCgAAzwwAAPAOAAD/IBIA/z4xAP9cUQD/enEA/5eRAP+2sQD/1NEA////AAAAAAAvAA4AUAAXAHAAIQCQACsAsAA2AM8AQADwAEkA/xFaAP8xcAD/UYYA/3GcAP+RsgD/scgA/9HfAP///wAAAAAALwAgAFAANgBwAEwAkABiALAAeADPAI4A8ACkAP8RswD/Mb4A/1HHAP9x0QD/kdwA/7HlAP/R8AD///8AAAAAACwALwBLAFAAaQBwAIcAkAClALAAxADPAOEA8ADwEf8A8jH/APRR/wD2cf8A95H/APmx/wD70f8A////AAAAAAAbAC8ALQBQAD8AcABSAJAAYwCwAHYAzwCIAPAAmRH/AKYx/wC0Uf8AwnH/AM+R/wDcsf8A69H/AP///wAAAAAACAAvAA4AUAAVAHAAGwCQACEAsAAmAM8ALADwAD4R/wBYMf8AcVH/AIxx/wCmkf8Av7H/ANrR/wD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMAAAAAAAAAAAAAAAACBgwMBwIAAAAAAAAAAAAABg4ODg4MBgIAAAAAAAAAAAYODQoODg4KBAAAAAAAAAAGDgwDBQsODg4FAAAAAAAABg4MAgADCg4OBgAAAAAAAAYODAICCg4ODgYAAAAAAAAGDgwCBg4OCwcCAAAAAAAABg4MAwkIBAIAAAAAAAAAAAYODAICAAAAAAAAAAAAAAAGDgwCAAAAAAAAAAAAAAAABg4MAgAAAAAAAAAAAAAAAAYMCAEAAAAAAAAAAAAAAAACAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
|
||||
_urls : [
|
||||
{
|
||||
type: "application/x-suggestions+json",
|
||||
method: "GET",
|
||||
template: "https://www.bing.com/osjson.aspx",
|
||||
params: [
|
||||
{
|
||||
name: "query",
|
||||
value: "{searchTerms}",
|
||||
purpose: undefined,
|
||||
},
|
||||
{
|
||||
name: "form",
|
||||
value: "OSDJAS",
|
||||
purpose: undefined,
|
||||
},
|
||||
{
|
||||
name: "language",
|
||||
value: "{moz:locale}",
|
||||
purpose: undefined,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "text/html",
|
||||
method: "GET",
|
||||
template: "https://www.bing.com/search",
|
||||
params: [
|
||||
{
|
||||
name: "q",
|
||||
value: "{searchTerms}",
|
||||
purpose: undefined,
|
||||
},
|
||||
{
|
||||
name: "pc",
|
||||
value: "MOZI",
|
||||
purpose: undefined,
|
||||
},
|
||||
{
|
||||
name: "form",
|
||||
value: "MOZCON",
|
||||
purpose: "contextmenu",
|
||||
},
|
||||
{
|
||||
name: "form",
|
||||
value: "MOZSBR",
|
||||
purpose: "searchbar",
|
||||
},
|
||||
{
|
||||
name: "form",
|
||||
value: "MOZSPG",
|
||||
purpose: "homepage",
|
||||
},
|
||||
{
|
||||
name: "form",
|
||||
value: "MOZLBR",
|
||||
purpose:"keyword",
|
||||
},
|
||||
{
|
||||
name: "form",
|
||||
value: "MOZTSB",
|
||||
purpose: "newtab",
|
||||
},
|
||||
],
|
||||
mozparams: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
isSubObjectOf(EXPECTED_ENGINE, engine, "Bing");
|
||||
}
|
||||
166
browser/components/search/test/browser_bing_behavior.js
Normal file
166
browser/components/search/test/browser_bing_behavior.js
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/*
|
||||
* Test Bing search plugin URLs
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const BROWSER_SEARCH_PREF = "browser.search.";
|
||||
|
||||
|
||||
function test() {
|
||||
let engine = Services.search.getEngineByName("Bing");
|
||||
ok(engine, "Bing is installed");
|
||||
|
||||
let previouslySelectedEngine = Services.search.currentEngine;
|
||||
Services.search.currentEngine = engine;
|
||||
engine.alias = "b";
|
||||
|
||||
let base = "https://www.bing.com/search?q=foo&pc=MOZI";
|
||||
let url;
|
||||
|
||||
// Test search URLs (including purposes).
|
||||
url = engine.getSubmission("foo").uri.spec;
|
||||
is(url, base + "&form=MOZSBR", "Check search URL for 'foo'");
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
var gCurrTest;
|
||||
var gTests = [
|
||||
{
|
||||
name: "context menu search",
|
||||
searchURL: base + "&form=MOZCON",
|
||||
run: function () {
|
||||
// Simulate a contextmenu search
|
||||
// FIXME: This is a bit "low-level"...
|
||||
BrowserSearch.loadSearch("foo", false, "contextmenu");
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "keyword search",
|
||||
searchURL: base + "&form=MOZLBR",
|
||||
run: function () {
|
||||
gURLBar.value = "? foo";
|
||||
gURLBar.focus();
|
||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "keyword search with alias",
|
||||
searchURL: base + "&form=MOZLBR",
|
||||
run: function () {
|
||||
gURLBar.value = "b foo";
|
||||
gURLBar.focus();
|
||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "search bar search",
|
||||
searchURL: base + "&form=MOZSBR",
|
||||
run: function () {
|
||||
let sb = BrowserSearch.searchBar;
|
||||
sb.focus();
|
||||
sb.value = "foo";
|
||||
registerCleanupFunction(function () {
|
||||
sb.value = "";
|
||||
});
|
||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "new tab search",
|
||||
searchURL: base + "&form=MOZTSB",
|
||||
run: function () {
|
||||
function doSearch(doc) {
|
||||
// Re-add the listener, and perform a search
|
||||
gBrowser.addProgressListener(listener);
|
||||
doc.getElementById("newtab-search-text").value = "foo";
|
||||
doc.getElementById("newtab-search-submit").click();
|
||||
}
|
||||
|
||||
// load about:newtab, but remove the listener first so it doesn't
|
||||
// get in the way
|
||||
gBrowser.removeProgressListener(listener);
|
||||
gBrowser.loadURI("about:newtab");
|
||||
info("Waiting for about:newtab load");
|
||||
tab.linkedBrowser.addEventListener("load", function load(event) {
|
||||
if (event.originalTarget != tab.linkedBrowser.contentDocument ||
|
||||
event.target.location.href == "about:blank") {
|
||||
info("skipping spurious load event");
|
||||
return;
|
||||
}
|
||||
tab.linkedBrowser.removeEventListener("load", load, true);
|
||||
|
||||
// Observe page setup
|
||||
let win = gBrowser.contentWindow;
|
||||
if (win.gSearch.currentEngineName ==
|
||||
Services.search.currentEngine.name) {
|
||||
doSearch(win.document);
|
||||
}
|
||||
else {
|
||||
info("Waiting for newtab search init");
|
||||
win.addEventListener("ContentSearchService", function done(event) {
|
||||
info("Got newtab search event " + event.detail.type);
|
||||
if (event.detail.type == "State") {
|
||||
win.removeEventListener("ContentSearchService", done);
|
||||
// Let gSearch respond to the event before continuing.
|
||||
executeSoon(() => doSearch(win.document));
|
||||
}
|
||||
});
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
function nextTest() {
|
||||
if (gTests.length) {
|
||||
gCurrTest = gTests.shift();
|
||||
info("Running : " + gCurrTest.name);
|
||||
executeSoon(gCurrTest.run);
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab();
|
||||
|
||||
let listener = {
|
||||
onStateChange: function onStateChange(webProgress, req, flags, status) {
|
||||
info("onStateChange");
|
||||
// Only care about top-level document starts
|
||||
let docStart = Ci.nsIWebProgressListener.STATE_IS_DOCUMENT |
|
||||
Ci.nsIWebProgressListener.STATE_START;
|
||||
if (!(flags & docStart) || !webProgress.isTopLevel)
|
||||
return;
|
||||
|
||||
if (req.originalURI.spec == "about:blank")
|
||||
return;
|
||||
|
||||
info("received document start");
|
||||
|
||||
ok(req instanceof Ci.nsIChannel, "req is a channel");
|
||||
is(req.originalURI.spec, gCurrTest.searchURL, "search URL was loaded");
|
||||
info("Actual URI: " + req.URI.spec);
|
||||
|
||||
req.cancel(Components.results.NS_ERROR_FAILURE);
|
||||
|
||||
executeSoon(nextTest);
|
||||
}
|
||||
}
|
||||
|
||||
registerCleanupFunction(function () {
|
||||
engine.alias = undefined;
|
||||
gBrowser.removeProgressListener(listener);
|
||||
gBrowser.removeTab(tab);
|
||||
Services.search.currentEngine = previouslySelectedEngine;
|
||||
});
|
||||
|
||||
tab.linkedBrowser.addEventListener("load", function load() {
|
||||
tab.linkedBrowser.removeEventListener("load", load, true);
|
||||
gBrowser.addProgressListener(listener);
|
||||
nextTest();
|
||||
}, true);
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
add_task(function* test() {
|
||||
yield SpecialPowers.pushPrefEnv({set: [["toolkit.telemetry.enabled", true]]});
|
||||
let engine = yield promiseNewEngine("testEngine.xml");
|
||||
let histogramKey = "other-" + engine.name + ".contextmenu";
|
||||
let numSearchesBefore = 0;
|
||||
|
||||
try {
|
||||
let hs = Services.telemetry.getKeyedHistogramById("SEARCH_COUNTS").snapshot();
|
||||
if (histogramKey in hs) {
|
||||
numSearchesBefore = hs[histogramKey].sum;
|
||||
}
|
||||
} catch (ex) {
|
||||
// No searches performed yet, not a problem, |numSearchesBefore| is 0.
|
||||
}
|
||||
|
||||
let tabs = [];
|
||||
let tabsLoadedDeferred = new Deferred();
|
||||
|
||||
function tabAdded(event) {
|
||||
let tab = event.target;
|
||||
tabs.push(tab);
|
||||
|
||||
// We wait for the blank tab and the two context searches tabs to open.
|
||||
if (tabs.length == 3) {
|
||||
tabsLoadedDeferred.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
let container = gBrowser.tabContainer;
|
||||
container.addEventListener("TabOpen", tabAdded, false);
|
||||
|
||||
gBrowser.addTab("about:blank");
|
||||
BrowserSearch.loadSearchFromContext("mozilla");
|
||||
BrowserSearch.loadSearchFromContext("firefox");
|
||||
|
||||
// Wait for all the tabs to open.
|
||||
yield tabsLoadedDeferred.promise;
|
||||
|
||||
is(tabs[0], gBrowser.tabs[3], "blank tab has been pushed to the end");
|
||||
is(tabs[1], gBrowser.tabs[1], "first search tab opens next to the current tab");
|
||||
is(tabs[2], gBrowser.tabs[2], "second search tab opens next to the first search tab");
|
||||
|
||||
container.removeEventListener("TabOpen", tabAdded, false);
|
||||
tabs.forEach(gBrowser.removeTab, gBrowser);
|
||||
|
||||
// Make sure that the context searches are correctly recorded.
|
||||
let hs = Services.telemetry.getKeyedHistogramById("SEARCH_COUNTS").snapshot();
|
||||
Assert.ok(histogramKey in hs, "The histogram must contain the correct key");
|
||||
Assert.equal(hs[histogramKey].sum, numSearchesBefore + 2,
|
||||
"The histogram must contain the correct search count");
|
||||
});
|
||||
|
||||
function Deferred() {
|
||||
this.promise = new Promise((resolve, reject) => {
|
||||
this.resolve = resolve;
|
||||
this.reject = reject;
|
||||
});
|
||||
}
|
||||
101
browser/components/search/test/browser_contextmenu.js
Normal file
101
browser/components/search/test/browser_contextmenu.js
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* * http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
/*
|
||||
* Test searching for the selected text using the context menu
|
||||
*/
|
||||
|
||||
add_task(function* () {
|
||||
const ss = Services.search;
|
||||
const ENGINE_NAME = "Foo";
|
||||
var contextMenu;
|
||||
|
||||
// We want select events to be fired.
|
||||
yield new Promise(resolve => SpecialPowers.pushPrefEnv({"set": [["dom.select_events.enabled", true]]}, resolve));
|
||||
|
||||
let envService = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
|
||||
let originalValue = envService.get("XPCSHELL_TEST_PROFILE_DIR");
|
||||
envService.set("XPCSHELL_TEST_PROFILE_DIR", "1");
|
||||
|
||||
let url = "chrome://mochitests/content/browser/browser/components/search/test/";
|
||||
let resProt = Services.io.getProtocolHandler("resource")
|
||||
.QueryInterface(Ci.nsIResProtocolHandler);
|
||||
let originalSubstitution = resProt.getSubstitution("search-plugins");
|
||||
resProt.setSubstitution("search-plugins",
|
||||
Services.io.newURI(url, null, null));
|
||||
|
||||
let searchDonePromise;
|
||||
yield new Promise(resolve => {
|
||||
function observer(aSub, aTopic, aData) {
|
||||
switch (aData) {
|
||||
case "engine-added":
|
||||
var engine = ss.getEngineByName(ENGINE_NAME);
|
||||
ok(engine, "Engine was added.");
|
||||
ss.currentEngine = engine;
|
||||
envService.set("XPCSHELL_TEST_PROFILE_DIR", originalValue);
|
||||
resProt.setSubstitution("search-plugins", originalSubstitution);
|
||||
break;
|
||||
case "engine-current":
|
||||
is(ss.currentEngine.name, ENGINE_NAME, "currentEngine set");
|
||||
resolve();
|
||||
break;
|
||||
case "engine-removed":
|
||||
Services.obs.removeObserver(observer, "browser-search-engine-modified");
|
||||
if (searchDonePromise) {
|
||||
searchDonePromise();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Services.obs.addObserver(observer, "browser-search-engine-modified", false);
|
||||
ss.addEngine("resource://search-plugins/testEngine_mozsearch.xml",
|
||||
null, "data:image/x-icon,%00", false);
|
||||
});
|
||||
|
||||
contextMenu = document.getElementById("contentAreaContextMenu");
|
||||
ok(contextMenu, "Got context menu XUL");
|
||||
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "data:text/plain;charset=utf8,test%20search");
|
||||
|
||||
yield ContentTask.spawn(tab.linkedBrowser, "", function*() {
|
||||
return new Promise(resolve => {
|
||||
content.document.addEventListener("selectionchange", function selectionChanged() {
|
||||
content.document.removeEventListener("selectionchange", selectionChanged);
|
||||
resolve();
|
||||
});
|
||||
content.document.getSelection().selectAllChildren(content.document.body);
|
||||
});
|
||||
});
|
||||
|
||||
var eventDetails = { type: "contextmenu", button: 2 };
|
||||
|
||||
let popupPromise = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
|
||||
BrowserTestUtils.synthesizeMouseAtCenter("body", eventDetails, gBrowser.selectedBrowser);
|
||||
yield popupPromise;
|
||||
|
||||
info("checkContextMenu");
|
||||
var searchItem = contextMenu.getElementsByAttribute("id", "context-searchselect")[0];
|
||||
ok(searchItem, "Got search context menu item");
|
||||
is(searchItem.label, 'Search ' + ENGINE_NAME + ' for \u201ctest search\u201d', "Check context menu label");
|
||||
is(searchItem.disabled, false, "Check that search context menu item is enabled");
|
||||
|
||||
yield BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
|
||||
searchItem.click();
|
||||
});
|
||||
|
||||
is(gBrowser.currentURI.spec,
|
||||
"http://mochi.test:8888/browser/browser/components/search/test/?test=test+search&ie=utf-8&channel=contextsearch",
|
||||
"Checking context menu search URL");
|
||||
|
||||
contextMenu.hidePopup();
|
||||
|
||||
// Remove the tab opened by the search
|
||||
gBrowser.removeCurrentTab();
|
||||
|
||||
yield new Promise(resolve => {
|
||||
searchDonePromise = resolve;
|
||||
ss.removeEngine(ss.currentEngine);
|
||||
});
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
100
browser/components/search/test/browser_google.js
Normal file
100
browser/components/search/test/browser_google.js
Normal file
File diff suppressed because one or more lines are too long
165
browser/components/search/test/browser_google_behavior.js
Normal file
165
browser/components/search/test/browser_google_behavior.js
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/*
|
||||
* Test Google search plugin URLs
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
function test() {
|
||||
let engine = Services.search.getEngineByName("Google");
|
||||
ok(engine, "Google is installed");
|
||||
|
||||
let previouslySelectedEngine = Services.search.currentEngine;
|
||||
Services.search.currentEngine = engine;
|
||||
engine.alias = "g";
|
||||
|
||||
let base = "https://www.google.com/search?q=foo&ie=utf-8&oe=utf-8&client=firefox-b";
|
||||
let keywordBase = base + "-ab";
|
||||
|
||||
let url;
|
||||
|
||||
// Test search URLs (including purposes).
|
||||
url = engine.getSubmission("foo").uri.spec;
|
||||
is(url, base, "Check search URL for 'foo'");
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
var gCurrTest;
|
||||
var gTests = [
|
||||
{
|
||||
name: "context menu search",
|
||||
searchURL: base,
|
||||
run: function () {
|
||||
// Simulate a contextmenu search
|
||||
// FIXME: This is a bit "low-level"...
|
||||
BrowserSearch.loadSearch("foo", false, "contextmenu");
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "keyword search",
|
||||
searchURL: keywordBase,
|
||||
run: function () {
|
||||
gURLBar.value = "? foo";
|
||||
gURLBar.focus();
|
||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "keyword search",
|
||||
searchURL: keywordBase,
|
||||
run: function () {
|
||||
gURLBar.value = "g foo";
|
||||
gURLBar.focus();
|
||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "search bar search",
|
||||
searchURL: base,
|
||||
run: function () {
|
||||
let sb = BrowserSearch.searchBar;
|
||||
sb.focus();
|
||||
sb.value = "foo";
|
||||
registerCleanupFunction(function () {
|
||||
sb.value = "";
|
||||
});
|
||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "new tab search",
|
||||
searchURL: base,
|
||||
run: function () {
|
||||
function doSearch(doc) {
|
||||
// Re-add the listener, and perform a search
|
||||
gBrowser.addProgressListener(listener);
|
||||
doc.getElementById("newtab-search-text").value = "foo";
|
||||
doc.getElementById("newtab-search-submit").click();
|
||||
}
|
||||
|
||||
// load about:newtab, but remove the listener first so it doesn't
|
||||
// get in the way
|
||||
gBrowser.removeProgressListener(listener);
|
||||
gBrowser.loadURI("about:newtab");
|
||||
info("Waiting for about:newtab load");
|
||||
tab.linkedBrowser.addEventListener("load", function load(event) {
|
||||
if (event.originalTarget != tab.linkedBrowser.contentDocument ||
|
||||
event.target.location.href == "about:blank") {
|
||||
info("skipping spurious load event");
|
||||
return;
|
||||
}
|
||||
tab.linkedBrowser.removeEventListener("load", load, true);
|
||||
|
||||
// Observe page setup
|
||||
let win = gBrowser.contentWindow;
|
||||
if (win.gSearch.currentEngineName ==
|
||||
Services.search.currentEngine.name) {
|
||||
doSearch(win.document);
|
||||
}
|
||||
else {
|
||||
info("Waiting for newtab search init");
|
||||
win.addEventListener("ContentSearchService", function done(event) {
|
||||
info("Got newtab search event " + event.detail.type);
|
||||
if (event.detail.type == "State") {
|
||||
win.removeEventListener("ContentSearchService", done);
|
||||
// Let gSearch respond to the event before continuing.
|
||||
executeSoon(() => doSearch(win.document));
|
||||
}
|
||||
});
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
function nextTest() {
|
||||
if (gTests.length) {
|
||||
gCurrTest = gTests.shift();
|
||||
info("Running : " + gCurrTest.name);
|
||||
executeSoon(gCurrTest.run);
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab();
|
||||
|
||||
let listener = {
|
||||
onStateChange: function onStateChange(webProgress, req, flags, status) {
|
||||
info("onStateChange");
|
||||
// Only care about top-level document starts
|
||||
let docStart = Ci.nsIWebProgressListener.STATE_IS_DOCUMENT |
|
||||
Ci.nsIWebProgressListener.STATE_START;
|
||||
if (!(flags & docStart) || !webProgress.isTopLevel)
|
||||
return;
|
||||
|
||||
if (req.originalURI.spec == "about:blank")
|
||||
return;
|
||||
|
||||
info("received document start");
|
||||
|
||||
ok(req instanceof Ci.nsIChannel, "req is a channel");
|
||||
is(req.originalURI.spec, gCurrTest.searchURL, "search URL was loaded");
|
||||
info("Actual URI: " + req.URI.spec);
|
||||
|
||||
req.cancel(Components.results.NS_ERROR_FAILURE);
|
||||
|
||||
executeSoon(nextTest);
|
||||
}
|
||||
}
|
||||
|
||||
registerCleanupFunction(function () {
|
||||
engine.alias = undefined;
|
||||
gBrowser.removeProgressListener(listener);
|
||||
gBrowser.removeTab(tab);
|
||||
Services.search.currentEngine = previouslySelectedEngine;
|
||||
});
|
||||
|
||||
tab.linkedBrowser.addEventListener("load", function load() {
|
||||
tab.linkedBrowser.removeEventListener("load", load, true);
|
||||
gBrowser.addProgressListener(listener);
|
||||
nextTest();
|
||||
}, true);
|
||||
}
|
||||
161
browser/components/search/test/browser_google_codes.js
Normal file
161
browser/components/search/test/browser_google_codes.js
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const kUrlPref = "geoSpecificDefaults.url";
|
||||
const BROWSER_SEARCH_PREF = "browser.search.";
|
||||
|
||||
var originalGeoURL;
|
||||
|
||||
/**
|
||||
* Clean the profile of any cache file left from a previous run.
|
||||
* Returns a boolean indicating if the cache file existed.
|
||||
*/
|
||||
function removeCacheFile()
|
||||
{
|
||||
const CACHE_FILENAME = "search.json.mozlz4";
|
||||
|
||||
let file = Services.dirsvc.get("ProfD", Ci.nsIFile);
|
||||
file.append(CACHE_FILENAME);
|
||||
if (file.exists()) {
|
||||
file.remove(false);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a promise that is resolved when an observer notification from the
|
||||
* search service fires with the specified data.
|
||||
*
|
||||
* @param aExpectedData
|
||||
* The value the observer notification sends that causes us to resolve
|
||||
* the promise.
|
||||
*/
|
||||
function waitForSearchNotification(aExpectedData, aCallback) {
|
||||
const SEARCH_SERVICE_TOPIC = "browser-search-service";
|
||||
Services.obs.addObserver(function observer(aSubject, aTopic, aData) {
|
||||
if (aData != aExpectedData)
|
||||
return;
|
||||
|
||||
Services.obs.removeObserver(observer, SEARCH_SERVICE_TOPIC);
|
||||
aCallback();
|
||||
}, SEARCH_SERVICE_TOPIC, false);
|
||||
}
|
||||
|
||||
function asyncInit() {
|
||||
return new Promise(resolve => {
|
||||
Services.search.init(function() {
|
||||
ok(Services.search.isInitialized, "search service should be initialized");
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function asyncReInit() {
|
||||
const kLocalePref = "general.useragent.locale";
|
||||
|
||||
let promise = new Promise(resolve => {
|
||||
waitForSearchNotification("reinit-complete", resolve);
|
||||
});
|
||||
|
||||
Services.search.QueryInterface(Ci.nsIObserver)
|
||||
.observe(null, "nsPref:changed", kLocalePref);
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
let gEngineCount;
|
||||
|
||||
add_task(function* preparation() {
|
||||
// ContentSearch is interferring with our async re-initializations of the
|
||||
// search service: once _initServicePromise has resolved, it will access
|
||||
// the search service, thus causing unpredictable behavior due to
|
||||
// synchronous initializations of the service.
|
||||
let originalContentSearchPromise = ContentSearch._initServicePromise;
|
||||
ContentSearch._initServicePromise = new Promise(resolve => {
|
||||
registerCleanupFunction(() => {
|
||||
ContentSearch._initServicePromise = originalContentSearchPromise;
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
yield asyncInit();
|
||||
gEngineCount = Services.search.getVisibleEngines().length;
|
||||
|
||||
waitForSearchNotification("uninit-complete", () => {
|
||||
// Verify search service is not initialized
|
||||
is(Services.search.isInitialized, false, "Search service should NOT be initialized");
|
||||
|
||||
removeCacheFile();
|
||||
|
||||
// Geo specific defaults won't be fetched if there's no country code.
|
||||
Services.prefs.setCharPref("browser.search.geoip.url",
|
||||
'data:application/json,{"country_code": "US"}');
|
||||
|
||||
Services.prefs.setBoolPref("browser.search.geoSpecificDefaults", true);
|
||||
|
||||
// Make the new Google the only engine
|
||||
originalGeoURL = Services.prefs.getCharPref(BROWSER_SEARCH_PREF + kUrlPref);
|
||||
let geoUrl = 'data:application/json,{"interval": 31536000, "settings": {"searchDefault": "Google", "visibleDefaultEngines": ["google"]}}';
|
||||
Services.prefs.getDefaultBranch(BROWSER_SEARCH_PREF).setCharPref(kUrlPref, geoUrl);
|
||||
});
|
||||
|
||||
yield asyncReInit();
|
||||
|
||||
yield new Promise(resolve => {
|
||||
waitForSearchNotification("write-cache-to-disk-complete", resolve);
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function* tests() {
|
||||
let engines = Services.search.getEngines();
|
||||
is(Services.search.currentEngine.name, "Google", "Search engine should be Google");
|
||||
is(engines.length, 1, "There should only be one engine");
|
||||
|
||||
let engine = Services.search.getEngineByName("Google");
|
||||
ok(engine, "Google");
|
||||
|
||||
let base = "https://www.google.com/search?q=foo&ie=utf-8&oe=utf-8&client=firefox-b";
|
||||
|
||||
// Keyword uses a slightly different code
|
||||
let keywordBase = base + "-ab";
|
||||
|
||||
let url;
|
||||
|
||||
// Test search URLs (including purposes).
|
||||
url = engine.getSubmission("foo", null, "contextmenu").uri.spec;
|
||||
is(url, base, "Check context menu search URL for 'foo'");
|
||||
url = engine.getSubmission("foo", null, "keyword").uri.spec;
|
||||
is(url, keywordBase, "Check keyword search URL for 'foo'");
|
||||
url = engine.getSubmission("foo", null, "searchbar").uri.spec;
|
||||
is(url, base, "Check search bar search URL for 'foo'");
|
||||
url = engine.getSubmission("foo", null, "homepage").uri.spec;
|
||||
is(url, base, "Check homepage search URL for 'foo'");
|
||||
url = engine.getSubmission("foo", null, "newtab").uri.spec;
|
||||
is(url, base, "Check newtab search URL for 'foo'");
|
||||
url = engine.getSubmission("foo", null, "system").uri.spec;
|
||||
is(url, base, "Check system search URL for 'foo'");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* cleanup() {
|
||||
waitForSearchNotification("uninit-complete", () => {
|
||||
// Verify search service is not initialized
|
||||
is(Services.search.isInitialized, false,
|
||||
"Search service should NOT be initialized");
|
||||
removeCacheFile();
|
||||
|
||||
Services.prefs.clearUserPref("browser.search.geoip.url");
|
||||
|
||||
// We can't clear the pref because it's set to false by testing/profiles/prefs_general.js
|
||||
Services.prefs.setBoolPref("browser.search.geoSpecificDefaults", false);
|
||||
|
||||
Services.prefs.getDefaultBranch(BROWSER_SEARCH_PREF).setCharPref(kUrlPref, originalGeoURL);
|
||||
});
|
||||
|
||||
yield asyncReInit();
|
||||
is(gEngineCount, Services.search.getVisibleEngines().length,
|
||||
"correct engine count after cleanup");
|
||||
});
|
||||
82
browser/components/search/test/browser_healthreport.js
Normal file
82
browser/components/search/test/browser_healthreport.js
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
var Preferences = Cu.import("resource://gre/modules/Preferences.jsm", {}).Preferences;
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
resetPreferences();
|
||||
|
||||
function testTelemetry() {
|
||||
// Find the right bucket for the "Foo" engine.
|
||||
let engine = Services.search.getEngineByName("Foo");
|
||||
let histogramKey = (engine.identifier || "other-Foo") + ".searchbar";
|
||||
let numSearchesBefore = 0;
|
||||
try {
|
||||
let hs = Services.telemetry.getKeyedHistogramById("SEARCH_COUNTS").snapshot();
|
||||
if (histogramKey in hs) {
|
||||
numSearchesBefore = hs[histogramKey].sum;
|
||||
}
|
||||
} catch (ex) {
|
||||
// No searches performed yet, not a problem, |numSearchesBefore| is 0.
|
||||
}
|
||||
|
||||
// Now perform a search and ensure the count is incremented.
|
||||
let tab = gBrowser.addTab();
|
||||
gBrowser.selectedTab = tab;
|
||||
let searchBar = BrowserSearch.searchBar;
|
||||
|
||||
searchBar.value = "firefox health report";
|
||||
searchBar.focus();
|
||||
|
||||
function afterSearch() {
|
||||
searchBar.value = "";
|
||||
gBrowser.removeTab(tab);
|
||||
|
||||
// Make sure that the context searches are correctly recorded.
|
||||
let hs = Services.telemetry.getKeyedHistogramById("SEARCH_COUNTS").snapshot();
|
||||
Assert.ok(histogramKey in hs, "The histogram must contain the correct key");
|
||||
Assert.equal(hs[histogramKey].sum, numSearchesBefore + 1,
|
||||
"Performing a search increments the related SEARCH_COUNTS key by 1.");
|
||||
|
||||
let engine = Services.search.getEngineByName("Foo");
|
||||
Services.search.removeEngine(engine);
|
||||
}
|
||||
|
||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
executeSoon(() => executeSoon(afterSearch));
|
||||
}
|
||||
|
||||
function observer(subject, topic, data) {
|
||||
switch (data) {
|
||||
case "engine-added":
|
||||
let engine = Services.search.getEngineByName("Foo");
|
||||
ok(engine, "Engine was added.");
|
||||
Services.search.currentEngine = engine;
|
||||
break;
|
||||
|
||||
case "engine-current":
|
||||
is(Services.search.currentEngine.name, "Foo", "Current engine is Foo");
|
||||
testTelemetry();
|
||||
break;
|
||||
|
||||
case "engine-removed":
|
||||
Services.obs.removeObserver(observer, "browser-search-engine-modified");
|
||||
finish();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Services.obs.addObserver(observer, "browser-search-engine-modified", false);
|
||||
SpecialPowers.pushPrefEnv({set: [["toolkit.telemetry.enabled", true]]}).then(function() {
|
||||
Services.search.addEngine("http://mochi.test:8888/browser/browser/components/search/test/testEngine.xml",
|
||||
null, "data:image/x-icon,%00", false);
|
||||
});
|
||||
}
|
||||
|
||||
function resetPreferences() {
|
||||
Preferences.resetBranch("datareporting.policy.");
|
||||
Preferences.set("datareporting.policy.dataSubmissionPolicyBypassNotification", true);
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
const testPref = "Foo,FooDupe";
|
||||
|
||||
function promiseNewEngine(basename) {
|
||||
return new Promise((resolve, reject) => {
|
||||
info("Waiting for engine to be added: " + basename);
|
||||
Services.search.init({
|
||||
onInitComplete: function() {
|
||||
let url = getRootDirectory(gTestPath) + basename;
|
||||
Services.search.addEngine(url, null, "", false, {
|
||||
onSuccess: function (engine) {
|
||||
info("Search engine added: " + basename);
|
||||
resolve(engine);
|
||||
},
|
||||
onError: function (errCode) {
|
||||
ok(false, "addEngine failed with error code " + errCode);
|
||||
reject();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
add_task(function* test_remove() {
|
||||
yield promiseNewEngine("testEngine_dupe.xml");
|
||||
yield promiseNewEngine("testEngine.xml");
|
||||
Services.prefs.setCharPref("browser.search.hiddenOneOffs", testPref);
|
||||
|
||||
info("Removing testEngine_dupe.xml");
|
||||
Services.search.removeEngine(Services.search.getEngineByName("FooDupe"));
|
||||
|
||||
let hiddenOneOffs =
|
||||
Services.prefs.getCharPref("browser.search.hiddenOneOffs").split(",");
|
||||
|
||||
is(hiddenOneOffs.length, 1,
|
||||
"hiddenOneOffs has the correct engine count post removal.");
|
||||
is(hiddenOneOffs.some(x => x == "FooDupe"), false,
|
||||
"Removed Engine is not in hiddenOneOffs after removal");
|
||||
is(hiddenOneOffs.some(x => x == "Foo"), true,
|
||||
"Current hidden engine is not affected by removal.");
|
||||
|
||||
info("Removing testEngine.xml");
|
||||
Services.search.removeEngine(Services.search.getEngineByName("Foo"));
|
||||
|
||||
is(Services.prefs.getCharPref("browser.search.hiddenOneOffs"), "",
|
||||
"hiddenOneOffs is empty after removing all hidden engines.");
|
||||
});
|
||||
|
||||
add_task(function* test_add() {
|
||||
yield promiseNewEngine("testEngine.xml");
|
||||
info("setting prefs to " + testPref);
|
||||
Services.prefs.setCharPref("browser.search.hiddenOneOffs", testPref);
|
||||
yield promiseNewEngine("testEngine_dupe.xml");
|
||||
|
||||
let hiddenOneOffs =
|
||||
Services.prefs.getCharPref("browser.search.hiddenOneOffs").split(",");
|
||||
|
||||
is(hiddenOneOffs.length, 1,
|
||||
"hiddenOneOffs has the correct number of hidden engines present post add.");
|
||||
is(hiddenOneOffs.some(x => x == "FooDupe"), false,
|
||||
"Added engine is not present in hidden list.");
|
||||
is(hiddenOneOffs.some(x => x == "Foo"), true,
|
||||
"Adding an engine does not remove engines from hidden list.");
|
||||
});
|
||||
|
||||
add_task(function* test_diacritics() {
|
||||
const diacritic_engine = "Foo \u2661";
|
||||
let Preferences =
|
||||
Cu.import("resource://gre/modules/Preferences.jsm", {}).Preferences;
|
||||
|
||||
Preferences.set("browser.search.hiddenOneOffs", diacritic_engine);
|
||||
yield promiseNewEngine("testEngine_diacritics.xml");
|
||||
|
||||
let hiddenOneOffs =
|
||||
Preferences.get("browser.search.hiddenOneOffs").split(",");
|
||||
is(hiddenOneOffs.some(x => x == diacritic_engine), false,
|
||||
"Observer cleans up added hidden engines that include a diacritic.");
|
||||
|
||||
Preferences.set("browser.search.hiddenOneOffs", diacritic_engine);
|
||||
|
||||
info("Removing testEngine_diacritics.xml");
|
||||
Services.search.removeEngine(Services.search.getEngineByName(diacritic_engine));
|
||||
|
||||
hiddenOneOffs =
|
||||
Preferences.get("browser.search.hiddenOneOffs").split(",");
|
||||
is(hiddenOneOffs.some(x => x == diacritic_engine), false,
|
||||
"Observer cleans up removed hidden engines that include a diacritic.");
|
||||
});
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
info("Removing testEngine.xml");
|
||||
Services.search.removeEngine(Services.search.getEngineByName("Foo"));
|
||||
info("Removing testEngine_dupe.xml");
|
||||
Services.search.removeEngine(Services.search.getEngineByName("FooDupe"));
|
||||
Services.prefs.clearUserPref("browser.search.hiddenOneOffs");
|
||||
});
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
// Tests that keyboard navigation in the search panel works as designed.
|
||||
|
||||
const searchbar = document.getElementById("searchbar");
|
||||
const textbox = searchbar._textbox;
|
||||
const searchPopup = document.getElementById("PopupSearchAutoComplete");
|
||||
const searchIcon = document.getAnonymousElementByAttribute(searchbar, "anonid",
|
||||
"searchbar-search-button");
|
||||
|
||||
const diacritic_engine = "Foo \u2661";
|
||||
|
||||
var Preferences =
|
||||
Cu.import("resource://gre/modules/Preferences.jsm", {}).Preferences;
|
||||
|
||||
add_task(function* init() {
|
||||
let currentEngine = Services.search.currentEngine;
|
||||
yield promiseNewEngine("testEngine_diacritics.xml", {setAsCurrent: false});
|
||||
registerCleanupFunction(() => {
|
||||
Services.search.currentEngine = currentEngine;
|
||||
Services.prefs.clearUserPref("browser.search.hiddenOneOffs");
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function* test_hidden() {
|
||||
Preferences.set("browser.search.hiddenOneOffs", diacritic_engine);
|
||||
|
||||
let promise = promiseEvent(searchPopup, "popupshown");
|
||||
info("Opening search panel");
|
||||
EventUtils.synthesizeMouseAtCenter(searchIcon, {});
|
||||
yield promise;
|
||||
|
||||
ok(!getOneOffs().some(x => x.getAttribute("tooltiptext") == diacritic_engine),
|
||||
"Search engines with diacritics are hidden when added to hiddenOneOffs preference.");
|
||||
|
||||
promise = promiseEvent(searchPopup, "popuphidden");
|
||||
info("Closing search panel");
|
||||
EventUtils.synthesizeKey("VK_ESCAPE", {});
|
||||
yield promise;
|
||||
});
|
||||
|
||||
add_task(function* test_shown() {
|
||||
Preferences.set("browser.search.hiddenOneOffs", "");
|
||||
|
||||
let promise = promiseEvent(searchPopup, "popupshown");
|
||||
info("Opening search panel");
|
||||
SimpleTest.executeSoon(() => {
|
||||
EventUtils.synthesizeMouseAtCenter(searchIcon, {});
|
||||
});
|
||||
yield promise;
|
||||
|
||||
ok(getOneOffs().some(x => x.getAttribute("tooltiptext") == diacritic_engine),
|
||||
"Search engines with diacritics are shown when removed from hiddenOneOffs preference.");
|
||||
|
||||
promise = promiseEvent(searchPopup, "popuphidden");
|
||||
searchPopup.hidePopup();
|
||||
yield promise;
|
||||
});
|
||||
105
browser/components/search/test/browser_oneOffContextMenu.js
Normal file
105
browser/components/search/test/browser_oneOffContextMenu.js
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
"use strict";
|
||||
|
||||
const TEST_ENGINE_NAME = "Foo";
|
||||
const TEST_ENGINE_BASENAME = "testEngine.xml";
|
||||
|
||||
const searchbar = document.getElementById("searchbar");
|
||||
const searchPopup = document.getElementById("PopupSearchAutoComplete");
|
||||
const searchIcon = document.getAnonymousElementByAttribute(
|
||||
searchbar, "anonid", "searchbar-search-button"
|
||||
);
|
||||
const oneOffBinding = document.getAnonymousElementByAttribute(
|
||||
searchPopup, "anonid", "search-one-off-buttons"
|
||||
);
|
||||
const contextMenu = document.getAnonymousElementByAttribute(
|
||||
oneOffBinding, "anonid", "search-one-offs-context-menu"
|
||||
);
|
||||
const oneOffButtons = document.getAnonymousElementByAttribute(
|
||||
oneOffBinding, "anonid", "search-panel-one-offs"
|
||||
);
|
||||
const searchInNewTabMenuItem = document.getAnonymousElementByAttribute(
|
||||
oneOffBinding, "anonid", "search-one-offs-context-open-in-new-tab"
|
||||
);
|
||||
|
||||
add_task(function* init() {
|
||||
yield promiseNewEngine(TEST_ENGINE_BASENAME, {
|
||||
setAsCurrent: false,
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function* extendedTelemetryDisabled() {
|
||||
yield SpecialPowers.pushPrefEnv({set: [["toolkit.telemetry.enabled", false]]});
|
||||
yield doTest();
|
||||
checkTelemetry("other");
|
||||
});
|
||||
|
||||
add_task(function* extendedTelemetryEnabled() {
|
||||
yield SpecialPowers.pushPrefEnv({set: [["toolkit.telemetry.enabled", true]]});
|
||||
yield doTest();
|
||||
checkTelemetry("other-" + TEST_ENGINE_NAME);
|
||||
});
|
||||
|
||||
function* doTest() {
|
||||
// Open the popup.
|
||||
let promise = promiseEvent(searchPopup, "popupshown");
|
||||
info("Opening search panel");
|
||||
EventUtils.synthesizeMouseAtCenter(searchIcon, {});
|
||||
yield promise;
|
||||
|
||||
// Get the one-off button for the test engine.
|
||||
let oneOffButton;
|
||||
for (let node of oneOffButtons.childNodes) {
|
||||
if (node.engine && node.engine.name == TEST_ENGINE_NAME) {
|
||||
oneOffButton = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Assert.notEqual(oneOffButton, undefined,
|
||||
"One-off for test engine should exist");
|
||||
|
||||
// Open the context menu on the one-off.
|
||||
promise = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
|
||||
EventUtils.synthesizeMouseAtCenter(oneOffButton, {
|
||||
type: "contextmenu",
|
||||
button: 2,
|
||||
});
|
||||
yield promise;
|
||||
|
||||
// Click the Search in New Tab menu item.
|
||||
promise = BrowserTestUtils.waitForNewTab(gBrowser);
|
||||
EventUtils.synthesizeMouseAtCenter(searchInNewTabMenuItem, {});
|
||||
let tab = yield promise;
|
||||
|
||||
// By default the search will open in the background and the popup will stay open:
|
||||
promise = promiseEvent(searchPopup, "popuphidden");
|
||||
info("Closing search panel");
|
||||
EventUtils.synthesizeKey("VK_ESCAPE", {});
|
||||
yield promise;
|
||||
|
||||
// Check the loaded tab.
|
||||
Assert.equal(tab.linkedBrowser.currentURI.spec,
|
||||
"http://mochi.test:8888/browser/browser/components/search/test/",
|
||||
"Expected search tab should have loaded");
|
||||
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
|
||||
// Move the cursor out of the panel area to avoid messing with other tests.
|
||||
yield EventUtils.synthesizeNativeMouseMove(searchbar);
|
||||
}
|
||||
|
||||
function checkTelemetry(expectedEngineName) {
|
||||
let propertyPath = [
|
||||
"countableEvents",
|
||||
"__DEFAULT__",
|
||||
"search-oneoff",
|
||||
expectedEngineName + ".oneoff-context-searchbar",
|
||||
"unknown",
|
||||
"tab-background",
|
||||
];
|
||||
let telem = BrowserUITelemetry.getToolbarMeasures();
|
||||
for (let prop of propertyPath) {
|
||||
Assert.ok(prop in telem, "Property " + prop + " should be in the telemetry");
|
||||
telem = telem[prop];
|
||||
}
|
||||
Assert.equal(telem, 1, "Click count");
|
||||
}
|
||||
|
|
@ -0,0 +1,195 @@
|
|||
"use strict";
|
||||
|
||||
const TEST_ENGINE_NAME = "Foo";
|
||||
const TEST_ENGINE_BASENAME = "testEngine.xml";
|
||||
const SEARCHBAR_BASE_ID = "searchbar-engine-one-off-item-";
|
||||
const URLBAR_BASE_ID = "urlbar-engine-one-off-item-";
|
||||
const ONEOFF_URLBAR_PREF = "browser.urlbar.oneOffSearches";
|
||||
|
||||
const searchbar = document.getElementById("searchbar");
|
||||
const urlbar = document.getElementById("urlbar");
|
||||
const searchPopup = document.getElementById("PopupSearchAutoComplete");
|
||||
const urlbarPopup = document.getElementById("PopupAutoCompleteRichResult");
|
||||
const searchIcon = document.getAnonymousElementByAttribute(
|
||||
searchbar, "anonid", "searchbar-search-button"
|
||||
);
|
||||
const searchOneOffBinding = document.getAnonymousElementByAttribute(
|
||||
searchPopup, "anonid", "search-one-off-buttons"
|
||||
);
|
||||
const urlBarOneOffBinding = document.getAnonymousElementByAttribute(
|
||||
urlbarPopup, "anonid", "one-off-search-buttons"
|
||||
);
|
||||
|
||||
let originalEngine = Services.search.currentEngine;
|
||||
|
||||
function resetEngine() {
|
||||
Services.search.currentEngine = originalEngine;
|
||||
}
|
||||
|
||||
registerCleanupFunction(resetEngine);
|
||||
|
||||
add_task(function* init() {
|
||||
yield promiseNewEngine(TEST_ENGINE_BASENAME, {
|
||||
setAsCurrent: false,
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function* test_searchBarChangeEngine() {
|
||||
let oneOffButton = yield openPopupAndGetEngineButton(true, searchPopup,
|
||||
searchOneOffBinding,
|
||||
SEARCHBAR_BASE_ID);
|
||||
|
||||
const setDefaultEngineMenuItem = document.getAnonymousElementByAttribute(
|
||||
searchOneOffBinding, "anonid", "search-one-offs-context-set-default"
|
||||
);
|
||||
|
||||
// Click the set default engine menu item.
|
||||
let promise = promiseCurrentEngineChanged();
|
||||
EventUtils.synthesizeMouseAtCenter(setDefaultEngineMenuItem, {});
|
||||
|
||||
// This also checks the engine correctly changed.
|
||||
yield promise;
|
||||
|
||||
Assert.equal(oneOffButton.id, SEARCHBAR_BASE_ID + originalEngine.name,
|
||||
"Should now have the original engine's id for the button");
|
||||
Assert.equal(oneOffButton.getAttribute("tooltiptext"), originalEngine.name,
|
||||
"Should now have the original engine's name for the tooltip");
|
||||
Assert.equal(oneOffButton.image, originalEngine.iconURI.spec,
|
||||
"Should now have the original engine's uri for the image");
|
||||
|
||||
yield promiseClosePopup(searchPopup);
|
||||
});
|
||||
|
||||
add_task(function* test_urlBarChangeEngine() {
|
||||
Services.prefs.setBoolPref(ONEOFF_URLBAR_PREF, true);
|
||||
registerCleanupFunction(function* () {
|
||||
Services.prefs.clearUserPref(ONEOFF_URLBAR_PREF);
|
||||
});
|
||||
|
||||
// Ensure the engine is reset.
|
||||
resetEngine();
|
||||
|
||||
let oneOffButton = yield openPopupAndGetEngineButton(false, urlbarPopup,
|
||||
urlBarOneOffBinding,
|
||||
URLBAR_BASE_ID);
|
||||
|
||||
const setDefaultEngineMenuItem = document.getAnonymousElementByAttribute(
|
||||
urlBarOneOffBinding, "anonid", "search-one-offs-context-set-default"
|
||||
);
|
||||
|
||||
// Click the set default engine menu item.
|
||||
let promise = promiseCurrentEngineChanged();
|
||||
EventUtils.synthesizeMouseAtCenter(setDefaultEngineMenuItem, {});
|
||||
|
||||
// This also checks the engine correctly changed.
|
||||
yield promise;
|
||||
|
||||
let currentEngine = Services.search.currentEngine;
|
||||
|
||||
// For the urlbar, we should keep the new engine's icon.
|
||||
Assert.equal(oneOffButton.id, URLBAR_BASE_ID + currentEngine.name,
|
||||
"Should now have the original engine's id for the button");
|
||||
Assert.equal(oneOffButton.getAttribute("tooltiptext"), currentEngine.name,
|
||||
"Should now have the original engine's name for the tooltip");
|
||||
Assert.equal(oneOffButton.image, currentEngine.iconURI.spec,
|
||||
"Should now have the original engine's uri for the image");
|
||||
|
||||
yield promiseClosePopup(urlbarPopup);
|
||||
});
|
||||
|
||||
/**
|
||||
* Promises that an engine change has happened for the current engine, which
|
||||
* has resulted in the test engine now being the current engine.
|
||||
*
|
||||
* @return {Promise} Resolved once the test engine is set as the current engine.
|
||||
*/
|
||||
function promiseCurrentEngineChanged() {
|
||||
return new Promise(resolve => {
|
||||
function observer(aSub, aTopic, aData) {
|
||||
if (aData == "engine-current") {
|
||||
Assert.ok(Services.search.currentEngine.name, TEST_ENGINE_NAME, "currentEngine set");
|
||||
Services.obs.removeObserver(observer, "browser-search-engine-modified");
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
|
||||
Services.obs.addObserver(observer, "browser-search-engine-modified", false);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the specified urlbar/search popup and gets the test engine from the
|
||||
* one-off buttons.
|
||||
*
|
||||
* @param {Boolean} isSearch true if the search popup should be opened; false
|
||||
* for the urlbar popup.
|
||||
* @param {Object} popup The expected popup.
|
||||
* @param {Object} oneOffBinding The expected one-off-binding for the popup.
|
||||
* @param {String} baseId The expected string for the id of the current
|
||||
* engine button, without the engine name.
|
||||
* @return {Object} Returns an object that represents the one off button for the
|
||||
* test engine.
|
||||
*/
|
||||
function* openPopupAndGetEngineButton(isSearch, popup, oneOffBinding, baseId) {
|
||||
// Open the popup.
|
||||
let promise = promiseEvent(popup, "popupshown");
|
||||
info("Opening panel");
|
||||
|
||||
// We have to open the popups in differnt ways.
|
||||
if (isSearch) {
|
||||
// Use the search icon to avoid hitting the network.
|
||||
EventUtils.synthesizeMouseAtCenter(searchIcon, {});
|
||||
} else {
|
||||
// There's no history at this stage, so we need to press a key.
|
||||
urlbar.focus();
|
||||
EventUtils.synthesizeKey("a", {});
|
||||
}
|
||||
yield promise;
|
||||
|
||||
const contextMenu = document.getAnonymousElementByAttribute(
|
||||
oneOffBinding, "anonid", "search-one-offs-context-menu"
|
||||
);
|
||||
const oneOffButtons = document.getAnonymousElementByAttribute(
|
||||
oneOffBinding, "anonid", "search-panel-one-offs"
|
||||
);
|
||||
|
||||
// Get the one-off button for the test engine.
|
||||
let oneOffButton;
|
||||
for (let node of oneOffButtons.childNodes) {
|
||||
if (node.engine && node.engine.name == TEST_ENGINE_NAME) {
|
||||
oneOffButton = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Assert.notEqual(oneOffButton, undefined,
|
||||
"One-off for test engine should exist");
|
||||
Assert.equal(oneOffButton.getAttribute("tooltiptext"), TEST_ENGINE_NAME,
|
||||
"One-off should have the tooltip set to the engine name");
|
||||
Assert.equal(oneOffButton.id, baseId + TEST_ENGINE_NAME,
|
||||
"Should have the correct id");
|
||||
|
||||
// Open the context menu on the one-off.
|
||||
promise = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
|
||||
EventUtils.synthesizeMouseAtCenter(oneOffButton, {
|
||||
type: "contextmenu",
|
||||
button: 2,
|
||||
});
|
||||
yield promise;
|
||||
|
||||
return oneOffButton;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the popup and moves the mouse away from it.
|
||||
*
|
||||
* @param {Button} popup The popup to close.
|
||||
*/
|
||||
function* promiseClosePopup(popup) {
|
||||
// close the panel using the escape key.
|
||||
let promise = promiseEvent(popup, "popuphidden");
|
||||
EventUtils.synthesizeKey("VK_ESCAPE", {});
|
||||
yield promise;
|
||||
|
||||
// Move the cursor out of the panel area to avoid messing with other tests.
|
||||
yield EventUtils.synthesizeNativeMouseMove(popup);
|
||||
}
|
||||
142
browser/components/search/test/browser_oneOffHeader.js
Normal file
142
browser/components/search/test/browser_oneOffHeader.js
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
// Tests that keyboard navigation in the search panel works as designed.
|
||||
|
||||
const isMac = ("nsILocalFileMac" in Ci);
|
||||
|
||||
const searchbar = document.getElementById("searchbar");
|
||||
const textbox = searchbar._textbox;
|
||||
const searchPopup = document.getElementById("PopupSearchAutoComplete");
|
||||
const searchIcon = document.getAnonymousElementByAttribute(searchbar, "anonid",
|
||||
"searchbar-search-button");
|
||||
|
||||
const oneOffsContainer =
|
||||
document.getAnonymousElementByAttribute(searchPopup, "anonid",
|
||||
"search-one-off-buttons");
|
||||
const searchSettings =
|
||||
document.getAnonymousElementByAttribute(oneOffsContainer, "anonid",
|
||||
"search-settings");
|
||||
var header =
|
||||
document.getAnonymousElementByAttribute(oneOffsContainer, "anonid",
|
||||
"search-panel-one-offs-header");
|
||||
function getHeaderText() {
|
||||
let headerChild = header.selectedPanel;
|
||||
while (headerChild.hasChildNodes()) {
|
||||
headerChild = headerChild.firstChild;
|
||||
}
|
||||
let headerStrings = [];
|
||||
for (let label = headerChild; label; label = label.nextSibling) {
|
||||
headerStrings.push(label.value);
|
||||
}
|
||||
return headerStrings.join("");
|
||||
}
|
||||
|
||||
const msg = isMac ? 5 : 1;
|
||||
const utils = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
const scale = utils.screenPixelsPerCSSPixel;
|
||||
function* synthesizeNativeMouseMove(aElement) {
|
||||
let rect = aElement.getBoundingClientRect();
|
||||
let win = aElement.ownerGlobal;
|
||||
let x = win.mozInnerScreenX + (rect.left + rect.right) / 2;
|
||||
let y = win.mozInnerScreenY + (rect.top + rect.bottom) / 2;
|
||||
|
||||
// Wait for the mouseup event to occur before continuing.
|
||||
return new Promise((resolve, reject) => {
|
||||
function eventOccurred(e)
|
||||
{
|
||||
aElement.removeEventListener("mouseover", eventOccurred, true);
|
||||
resolve();
|
||||
}
|
||||
|
||||
aElement.addEventListener("mouseover", eventOccurred, true);
|
||||
|
||||
utils.sendNativeMouseEvent(x * scale, y * scale, msg, 0, null);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
add_task(function* init() {
|
||||
yield promiseNewEngine("testEngine.xml");
|
||||
});
|
||||
|
||||
add_task(function* test_notext() {
|
||||
let promise = promiseEvent(searchPopup, "popupshown");
|
||||
info("Opening search panel");
|
||||
EventUtils.synthesizeMouseAtCenter(searchIcon, {});
|
||||
yield promise;
|
||||
|
||||
is(header.getAttribute("selectedIndex"), 0,
|
||||
"Header has the correct index selected with no search terms.");
|
||||
|
||||
is(getHeaderText(), "Search with:",
|
||||
"Search header string is correct when no search terms have been entered");
|
||||
|
||||
yield synthesizeNativeMouseMove(searchSettings);
|
||||
is(header.getAttribute("selectedIndex"), 0,
|
||||
"Header has the correct index when no search terms have been entered and the Change Search Settings button is selected.");
|
||||
is(getHeaderText(), "Search with:",
|
||||
"Header has the correct text when no search terms have been entered and the Change Search Settings button is selected.");
|
||||
|
||||
let buttons = getOneOffs();
|
||||
yield synthesizeNativeMouseMove(buttons[0]);
|
||||
is(header.getAttribute("selectedIndex"), 2,
|
||||
"Header has the correct index selected when a search engine has been selected");
|
||||
is(getHeaderText(), "Search " + buttons[0].engine.name,
|
||||
"Is the header text correct when a search engine is selected and no terms have been entered.");
|
||||
|
||||
promise = promiseEvent(searchPopup, "popuphidden");
|
||||
info("Closing search panel");
|
||||
EventUtils.synthesizeKey("VK_ESCAPE", {});
|
||||
yield promise;
|
||||
});
|
||||
|
||||
add_task(function* test_text() {
|
||||
textbox.value = "foo";
|
||||
registerCleanupFunction(() => {
|
||||
textbox.value = "";
|
||||
});
|
||||
|
||||
let promise = promiseEvent(searchPopup, "popupshown");
|
||||
info("Opening search panel");
|
||||
SimpleTest.executeSoon(() => {
|
||||
EventUtils.synthesizeMouseAtCenter(searchIcon, {});
|
||||
});
|
||||
yield promise;
|
||||
|
||||
is(header.getAttribute("selectedIndex"), 1,
|
||||
"Header has the correct index selected with a search term.");
|
||||
is(getHeaderText(), "Search for foo with:",
|
||||
"Search header string is correct when a search term has been entered");
|
||||
|
||||
let buttons = getOneOffs();
|
||||
yield synthesizeNativeMouseMove(buttons[0]);
|
||||
is(header.getAttribute("selectedIndex"), 2,
|
||||
"Header has the correct index selected when a search engine has been selected");
|
||||
is(getHeaderText(), "Search " + buttons[0].engine.name,
|
||||
"Is the header text correct when search terms are entered after a search engine has been selected.");
|
||||
|
||||
yield synthesizeNativeMouseMove(searchSettings);
|
||||
is(header.getAttribute("selectedIndex"), 1,
|
||||
"Header has the correct index selected when search terms have been entered and the Change Search Settings button is selected.");
|
||||
is(getHeaderText(), "Search for foo with:",
|
||||
"Header has the correct text when search terms have been entered and the Change Search Settings button is selected.");
|
||||
|
||||
// Click the "Foo Search" header at the top of the popup and make sure it
|
||||
// loads the search results.
|
||||
let searchbarEngine =
|
||||
document.getAnonymousElementByAttribute(searchPopup, "anonid",
|
||||
"searchbar-engine");
|
||||
|
||||
yield synthesizeNativeMouseMove(searchbarEngine);
|
||||
SimpleTest.executeSoon(() => {
|
||||
EventUtils.synthesizeMouseAtCenter(searchbarEngine, {});
|
||||
});
|
||||
|
||||
let url = Services.search.currentEngine.getSubmission(textbox.value).uri.spec;
|
||||
yield promiseTabLoadEvent(gBrowser.selectedTab, url);
|
||||
|
||||
// Move the cursor out of the panel area to avoid messing with other tests.
|
||||
yield synthesizeNativeMouseMove(searchbar);
|
||||
});
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
// This test performs a search in a public window, then a different
|
||||
// search in a private window, and then checks in the public window
|
||||
// whether there is an autocomplete entry for the private search.
|
||||
|
||||
add_task(function* () {
|
||||
// Don't use about:home as the homepage for new windows
|
||||
Services.prefs.setIntPref("browser.startup.page", 0);
|
||||
registerCleanupFunction(() => Services.prefs.clearUserPref("browser.startup.page"));
|
||||
|
||||
let windowsToClose = [];
|
||||
|
||||
function performSearch(aWin, aIsPrivate) {
|
||||
let searchBar = aWin.BrowserSearch.searchBar;
|
||||
ok(searchBar, "got search bar");
|
||||
|
||||
let loadPromise = BrowserTestUtils.browserLoaded(aWin.gBrowser.selectedBrowser);
|
||||
|
||||
searchBar.value = aIsPrivate ? "private test" : "public test";
|
||||
searchBar.focus();
|
||||
EventUtils.synthesizeKey("VK_RETURN", {}, aWin);
|
||||
|
||||
return loadPromise;
|
||||
}
|
||||
|
||||
function* testOnWindow(aIsPrivate) {
|
||||
let win = yield BrowserTestUtils.openNewBrowserWindow({ private: aIsPrivate });
|
||||
yield SimpleTest.promiseFocus(win);
|
||||
windowsToClose.push(win);
|
||||
return win;
|
||||
}
|
||||
|
||||
yield promiseNewEngine("426329.xml", { iconURL: "data:image/x-icon,%00" });
|
||||
|
||||
let newWindow = yield* testOnWindow(false);
|
||||
yield performSearch(newWindow, false);
|
||||
|
||||
newWindow = yield* testOnWindow(true);
|
||||
yield performSearch(newWindow, true);
|
||||
|
||||
newWindow = yield* testOnWindow(false);
|
||||
|
||||
let searchBar = newWindow.BrowserSearch.searchBar;
|
||||
searchBar.value = "p";
|
||||
searchBar.focus();
|
||||
|
||||
let popup = searchBar.textbox.popup;
|
||||
let popupPromise = BrowserTestUtils.waitForEvent(popup, "popupshown");
|
||||
searchBar.textbox.showHistoryPopup();
|
||||
yield popupPromise;
|
||||
|
||||
let entries = getMenuEntries(searchBar);
|
||||
for (let i = 0; i < entries.length; i++) {
|
||||
isnot(entries[i], "private test",
|
||||
"shouldn't see private autocomplete entries");
|
||||
}
|
||||
|
||||
searchBar.textbox.toggleHistoryPopup();
|
||||
searchBar.value = "";
|
||||
|
||||
windowsToClose.forEach(function(win) {
|
||||
win.close();
|
||||
});
|
||||
});
|
||||
|
||||
function getMenuEntries(searchBar) {
|
||||
let entries = [];
|
||||
let autocompleteMenu = searchBar.textbox.popup;
|
||||
// Could perhaps pull values directly from the controller, but it seems
|
||||
// more reliable to test the values that are actually in the tree?
|
||||
let column = autocompleteMenu.tree.columns[0];
|
||||
let numRows = autocompleteMenu.tree.view.rowCount;
|
||||
for (let i = 0; i < numRows; i++) {
|
||||
entries.push(autocompleteMenu.tree.view.getValueAt(i, column));
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
|
@ -0,0 +1,425 @@
|
|||
// Tests that keyboard navigation in the search panel works as designed.
|
||||
|
||||
const searchbar = document.getElementById("searchbar");
|
||||
const textbox = searchbar._textbox;
|
||||
const searchPopup = document.getElementById("PopupSearchAutoComplete");
|
||||
const oneOffsContainer =
|
||||
document.getAnonymousElementByAttribute(searchPopup, "anonid",
|
||||
"search-one-off-buttons");
|
||||
|
||||
const kValues = ["foo1", "foo2", "foo3"];
|
||||
const kUserValue = "foo";
|
||||
|
||||
function getOpenSearchItems() {
|
||||
let os = [];
|
||||
|
||||
let addEngineList =
|
||||
document.getAnonymousElementByAttribute(oneOffsContainer, "anonid",
|
||||
"add-engines");
|
||||
for (let item = addEngineList.firstChild; item; item = item.nextSibling)
|
||||
os.push(item);
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
add_task(function* init() {
|
||||
yield promiseNewEngine("testEngine.xml");
|
||||
|
||||
// First cleanup the form history in case other tests left things there.
|
||||
yield new Promise((resolve, reject) => {
|
||||
info("cleanup the search history");
|
||||
searchbar.FormHistory.update({op: "remove", fieldname: "searchbar-history"},
|
||||
{handleCompletion: resolve,
|
||||
handleError: reject});
|
||||
});
|
||||
|
||||
yield new Promise((resolve, reject) => {
|
||||
info("adding search history values: " + kValues);
|
||||
let ops = kValues.map(value => { return {op: "add",
|
||||
fieldname: "searchbar-history",
|
||||
value: value}
|
||||
});
|
||||
searchbar.FormHistory.update(ops, {
|
||||
handleCompletion: function() {
|
||||
registerCleanupFunction(() => {
|
||||
info("removing search history values: " + kValues);
|
||||
let ops =
|
||||
kValues.map(value => { return {op: "remove",
|
||||
fieldname: "searchbar-history",
|
||||
value: value}
|
||||
});
|
||||
searchbar.FormHistory.update(ops);
|
||||
});
|
||||
resolve();
|
||||
},
|
||||
handleError: reject
|
||||
});
|
||||
});
|
||||
|
||||
textbox.value = kUserValue;
|
||||
registerCleanupFunction(() => { textbox.value = ""; });
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_arrows() {
|
||||
let promise = promiseEvent(searchPopup, "popupshown");
|
||||
info("Opening search panel");
|
||||
searchbar.focus();
|
||||
yield promise;
|
||||
is(textbox.mController.searchString, kUserValue, "The search string should be 'foo'");
|
||||
|
||||
// Check the initial state of the panel before sending keyboard events.
|
||||
is(searchPopup.view.rowCount, kValues.length, "There should be 3 suggestions");
|
||||
is(searchPopup.selectedIndex, -1, "no suggestion should be selected");
|
||||
|
||||
// The tests will be less meaningful if the first, second, last, and
|
||||
// before-last one-off buttons aren't different. We should always have more
|
||||
// than 4 default engines, but it's safer to check this assumption.
|
||||
let oneOffs = getOneOffs();
|
||||
ok(oneOffs.length >= 4, "we have at least 4 one-off buttons displayed")
|
||||
|
||||
ok(!textbox.selectedButton, "no one-off button should be selected");
|
||||
|
||||
// The down arrow should first go through the suggestions.
|
||||
for (let i = 0; i < kValues.length; ++i) {
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
is(searchPopup.selectedIndex, i,
|
||||
"the suggestion at index " + i + " should be selected");
|
||||
is(textbox.value, kValues[i],
|
||||
"the textfield value should be " + kValues[i]);
|
||||
}
|
||||
|
||||
// Pressing down again should remove suggestion selection and change the text
|
||||
// field value back to what the user typed, and select the first one-off.
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
is(searchPopup.selectedIndex, -1, "no suggestion should be selected");
|
||||
is(textbox.value, kUserValue,
|
||||
"the textfield value should be back to initial value");
|
||||
|
||||
// now cycle through the one-off items, the first one is already selected.
|
||||
for (let i = 0; i < oneOffs.length; ++i) {
|
||||
is(textbox.selectedButton, oneOffs[i],
|
||||
"the one-off button #" + (i + 1) + " should be selected");
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
}
|
||||
|
||||
is(textbox.selectedButton.getAttribute("anonid"), "search-settings",
|
||||
"the settings item should be selected");
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
|
||||
// We should now be back to the initial situation.
|
||||
is(searchPopup.selectedIndex, -1, "no suggestion should be selected");
|
||||
ok(!textbox.selectedButton, "no one-off button should be selected");
|
||||
|
||||
info("now test the up arrow key");
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
is(textbox.selectedButton.getAttribute("anonid"), "search-settings",
|
||||
"the settings item should be selected");
|
||||
|
||||
// cycle through the one-off items, the first one is already selected.
|
||||
for (let i = oneOffs.length; i; --i) {
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
is(textbox.selectedButton, oneOffs[i - 1],
|
||||
"the one-off button #" + i + " should be selected");
|
||||
}
|
||||
|
||||
// Another press on up should clear the one-off selection and select the
|
||||
// last suggestion.
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
ok(!textbox.selectedButton, "no one-off button should be selected");
|
||||
|
||||
for (let i = kValues.length - 1; i >= 0; --i) {
|
||||
is(searchPopup.selectedIndex, i,
|
||||
"the suggestion at index " + i + " should be selected");
|
||||
is(textbox.value, kValues[i],
|
||||
"the textfield value should be " + kValues[i]);
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
}
|
||||
|
||||
is(searchPopup.selectedIndex, -1, "no suggestion should be selected");
|
||||
is(textbox.value, kUserValue,
|
||||
"the textfield value should be back to initial value");
|
||||
});
|
||||
|
||||
add_task(function* test_typing_clears_button_selection() {
|
||||
is(Services.focus.focusedElement, textbox.inputField,
|
||||
"the search bar should be focused"); // from the previous test.
|
||||
ok(!textbox.selectedButton, "no button should be selected");
|
||||
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
is(textbox.selectedButton.getAttribute("anonid"), "search-settings",
|
||||
"the settings item should be selected");
|
||||
|
||||
// Type a character.
|
||||
EventUtils.synthesizeKey("a", {});
|
||||
ok(!textbox.selectedButton, "the settings item should be de-selected");
|
||||
|
||||
// Remove the character.
|
||||
EventUtils.synthesizeKey("VK_BACK_SPACE", {});
|
||||
});
|
||||
|
||||
add_task(function* test_tab() {
|
||||
is(Services.focus.focusedElement, textbox.inputField,
|
||||
"the search bar should be focused"); // from the previous test.
|
||||
|
||||
let oneOffs = getOneOffs();
|
||||
ok(!textbox.selectedButton, "no one-off button should be selected");
|
||||
|
||||
// Pressing tab should select the first one-off without selecting suggestions.
|
||||
// now cycle through the one-off items, the first one is already selected.
|
||||
for (let i = 0; i < oneOffs.length; ++i) {
|
||||
EventUtils.synthesizeKey("VK_TAB", {});
|
||||
is(textbox.selectedButton, oneOffs[i],
|
||||
"the one-off button #" + (i + 1) + " should be selected");
|
||||
}
|
||||
is(searchPopup.selectedIndex, -1, "no suggestion should be selected");
|
||||
is(textbox.value, kUserValue, "the textfield value should be unmodified");
|
||||
|
||||
// One more <tab> selects the settings button.
|
||||
EventUtils.synthesizeKey("VK_TAB", {});
|
||||
is(textbox.selectedButton.getAttribute("anonid"), "search-settings",
|
||||
"the settings item should be selected");
|
||||
|
||||
// Pressing tab again should close the panel...
|
||||
let promise = promiseEvent(searchPopup, "popuphidden");
|
||||
EventUtils.synthesizeKey("VK_TAB", {});
|
||||
yield promise;
|
||||
|
||||
// ... and move the focus out of the searchbox.
|
||||
isnot(Services.focus.focusedElement, textbox.inputField,
|
||||
"the search bar no longer be focused");
|
||||
});
|
||||
|
||||
add_task(function* test_shift_tab() {
|
||||
// First reopen the panel.
|
||||
let promise = promiseEvent(searchPopup, "popupshown");
|
||||
info("Opening search panel");
|
||||
searchbar.focus();
|
||||
yield promise;
|
||||
|
||||
let oneOffs = getOneOffs();
|
||||
ok(!textbox.selectedButton, "no one-off button should be selected");
|
||||
|
||||
// Press up once to select the last button.
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
is(textbox.selectedButton.getAttribute("anonid"), "search-settings",
|
||||
"the settings item should be selected");
|
||||
|
||||
// Press up again to select the last one-off button.
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
|
||||
// Pressing shift+tab should cycle through the one-off items.
|
||||
for (let i = oneOffs.length - 1; i >= 0; --i) {
|
||||
is(textbox.selectedButton, oneOffs[i],
|
||||
"the one-off button #" + (i + 1) + " should be selected");
|
||||
if (i)
|
||||
EventUtils.synthesizeKey("VK_TAB", {shiftKey: true});
|
||||
}
|
||||
is(searchPopup.selectedIndex, -1, "no suggestion should be selected");
|
||||
is(textbox.value, kUserValue, "the textfield value should be unmodified");
|
||||
|
||||
// Pressing shift+tab again should close the panel...
|
||||
promise = promiseEvent(searchPopup, "popuphidden");
|
||||
EventUtils.synthesizeKey("VK_TAB", {shiftKey: true});
|
||||
yield promise;
|
||||
|
||||
// ... and move the focus out of the searchbox.
|
||||
isnot(Services.focus.focusedElement, textbox.inputField,
|
||||
"the search bar no longer be focused");
|
||||
});
|
||||
|
||||
add_task(function* test_alt_down() {
|
||||
// First refocus the panel.
|
||||
let promise = promiseEvent(searchPopup, "popupshown");
|
||||
info("Opening search panel");
|
||||
searchbar.focus();
|
||||
yield promise;
|
||||
|
||||
// close the panel using the escape key.
|
||||
promise = promiseEvent(searchPopup, "popuphidden");
|
||||
EventUtils.synthesizeKey("VK_ESCAPE", {});
|
||||
yield promise;
|
||||
|
||||
// check that alt+down opens the panel...
|
||||
promise = promiseEvent(searchPopup, "popupshown");
|
||||
EventUtils.synthesizeKey("VK_DOWN", {altKey: true});
|
||||
yield promise;
|
||||
|
||||
// ... and does nothing else.
|
||||
ok(!textbox.selectedButton, "no one-off button should be selected");
|
||||
is(searchPopup.selectedIndex, -1, "no suggestion should be selected");
|
||||
is(textbox.value, kUserValue, "the textfield value should be unmodified");
|
||||
|
||||
// Pressing alt+down should select the first one-off without selecting suggestions
|
||||
// and cycle through the one-off items.
|
||||
let oneOffs = getOneOffs();
|
||||
for (let i = 0; i < oneOffs.length; ++i) {
|
||||
EventUtils.synthesizeKey("VK_DOWN", {altKey: true});
|
||||
is(textbox.selectedButton, oneOffs[i],
|
||||
"the one-off button #" + (i + 1) + " should be selected");
|
||||
is(searchPopup.selectedIndex, -1, "no suggestion should be selected");
|
||||
}
|
||||
|
||||
// One more alt+down keypress and nothing should be selected.
|
||||
EventUtils.synthesizeKey("VK_DOWN", {altKey: true});
|
||||
ok(!textbox.selectedButton, "no one-off button should be selected");
|
||||
|
||||
// another one and the first one-off should be selected.
|
||||
EventUtils.synthesizeKey("VK_DOWN", {altKey: true});
|
||||
is(textbox.selectedButton, oneOffs[0],
|
||||
"the first one-off button should be selected");
|
||||
});
|
||||
|
||||
add_task(function* test_alt_up() {
|
||||
// close the panel using the escape key.
|
||||
let promise = promiseEvent(searchPopup, "popuphidden");
|
||||
EventUtils.synthesizeKey("VK_ESCAPE", {});
|
||||
yield promise;
|
||||
|
||||
// check that alt+up opens the panel...
|
||||
promise = promiseEvent(searchPopup, "popupshown");
|
||||
EventUtils.synthesizeKey("VK_UP", {altKey: true});
|
||||
yield promise;
|
||||
|
||||
// ... and does nothing else.
|
||||
ok(!textbox.selectedButton, "no one-off button should be selected");
|
||||
is(searchPopup.selectedIndex, -1, "no suggestion should be selected");
|
||||
is(textbox.value, kUserValue, "the textfield value should be unmodified");
|
||||
|
||||
// Pressing alt+up should select the last one-off without selecting suggestions
|
||||
// and cycle up through the one-off items.
|
||||
let oneOffs = getOneOffs();
|
||||
for (let i = oneOffs.length - 1; i >= 0; --i) {
|
||||
EventUtils.synthesizeKey("VK_UP", {altKey: true});
|
||||
is(textbox.selectedButton, oneOffs[i],
|
||||
"the one-off button #" + (i + 1) + " should be selected");
|
||||
is(searchPopup.selectedIndex, -1, "no suggestion should be selected");
|
||||
}
|
||||
|
||||
// One more alt+down keypress and nothing should be selected.
|
||||
EventUtils.synthesizeKey("VK_UP", {altKey: true});
|
||||
ok(!textbox.selectedButton, "no one-off button should be selected");
|
||||
|
||||
// another one and the last one-off should be selected.
|
||||
EventUtils.synthesizeKey("VK_UP", {altKey: true});
|
||||
is(textbox.selectedButton, oneOffs[oneOffs.length - 1],
|
||||
"the last one-off button should be selected");
|
||||
|
||||
// Cleanup for the next test.
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
is(textbox.selectedButton.getAttribute("anonid"), "search-settings",
|
||||
"the settings item should be selected");
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
ok(!textbox.selectedButton, "no one-off should be selected anymore");
|
||||
});
|
||||
|
||||
add_task(function* test_tab_and_arrows() {
|
||||
// Check the initial state is as expected.
|
||||
ok(!textbox.selectedButton, "no one-off button should be selected");
|
||||
is(searchPopup.selectedIndex, -1, "no suggestion should be selected");
|
||||
is(textbox.value, kUserValue, "the textfield value should be unmodified");
|
||||
|
||||
// After pressing down, the first sugggestion should be selected.
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
is(searchPopup.selectedIndex, 0, "first suggestion should be selected");
|
||||
is(textbox.value, kValues[0], "the textfield value should have changed");
|
||||
ok(!textbox.selectedButton, "no one-off button should be selected");
|
||||
|
||||
// After pressing tab, the first one-off should be selected,
|
||||
// and the first suggestion still selected.
|
||||
let oneOffs = getOneOffs();
|
||||
EventUtils.synthesizeKey("VK_TAB", {});
|
||||
is(textbox.selectedButton, oneOffs[0],
|
||||
"the first one-off button should be selected");
|
||||
is(searchPopup.selectedIndex, 0, "first suggestion should still be selected");
|
||||
|
||||
// After pressing down, the second suggestion should be selected,
|
||||
// and the first one-off still selected.
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
is(textbox.selectedButton, oneOffs[0],
|
||||
"the first one-off button should still be selected");
|
||||
is(searchPopup.selectedIndex, 1, "second suggestion should be selected");
|
||||
|
||||
// After pressing up, the first suggestion should be selected again,
|
||||
// and the first one-off still selected.
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
is(textbox.selectedButton, oneOffs[0],
|
||||
"the first one-off button should still be selected");
|
||||
is(searchPopup.selectedIndex, 0, "second suggestion should be selected again");
|
||||
|
||||
// After pressing up again, we should have no suggestion selected anymore,
|
||||
// the textfield value back to the user-typed value, and still the first one-off
|
||||
// selected.
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
is(searchPopup.selectedIndex, -1, "no suggestion should be selected");
|
||||
is(textbox.value, kUserValue,
|
||||
"the textfield value should be back to user typed value");
|
||||
is(textbox.selectedButton, oneOffs[0],
|
||||
"the first one-off button should still be selected");
|
||||
|
||||
// Now pressing down should select the second one-off.
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
is(textbox.selectedButton, oneOffs[1],
|
||||
"the second one-off button should be selected");
|
||||
is(searchPopup.selectedIndex, -1, "there should still be no selected suggestion");
|
||||
|
||||
// Finally close the panel.
|
||||
let promise = promiseEvent(searchPopup, "popuphidden");
|
||||
searchPopup.hidePopup();
|
||||
yield promise;
|
||||
});
|
||||
|
||||
add_task(function* test_open_search() {
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
yield BrowserTestUtils.openNewForegroundTab(gBrowser, rootDir + "opensearch.html");
|
||||
|
||||
let promise = promiseEvent(searchPopup, "popupshown");
|
||||
info("Opening search panel");
|
||||
searchbar.focus();
|
||||
yield promise;
|
||||
|
||||
let engines = getOpenSearchItems();
|
||||
is(engines.length, 2, "the opensearch.html page exposes 2 engines")
|
||||
|
||||
// Check that there's initially no selection.
|
||||
is(searchPopup.selectedIndex, -1, "no suggestion should be selected");
|
||||
ok(!textbox.selectedButton, "no button should be selected");
|
||||
|
||||
// Pressing up once selects the setting button...
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
is(textbox.selectedButton.getAttribute("anonid"), "search-settings",
|
||||
"the settings item should be selected");
|
||||
|
||||
// ...and then pressing up selects open search engines.
|
||||
for (let i = engines.length; i; --i) {
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
let selectedButton = textbox.selectedButton;
|
||||
is(selectedButton, engines[i - 1],
|
||||
"the engine #" + i + " should be selected");
|
||||
ok(selectedButton.classList.contains("addengine-item"),
|
||||
"the button is themed as an engine item");
|
||||
}
|
||||
|
||||
// Pressing up again should select the last one-off button.
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
is(textbox.selectedButton, getOneOffs().pop(),
|
||||
"the last one-off button should be selected");
|
||||
|
||||
info("now check that the down key navigates open search items as expected");
|
||||
for (let i = 0; i < engines.length; ++i) {
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
is(textbox.selectedButton, engines[i],
|
||||
"the engine #" + (i + 1) + " should be selected");
|
||||
}
|
||||
|
||||
// Pressing down on the last engine item selects the settings button.
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
is(textbox.selectedButton.getAttribute("anonid"), "search-settings",
|
||||
"the settings item should be selected");
|
||||
|
||||
promise = promiseEvent(searchPopup, "popuphidden");
|
||||
searchPopup.hidePopup();
|
||||
yield promise;
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
521
browser/components/search/test/browser_searchbar_openpopup.js
Normal file
521
browser/components/search/test/browser_searchbar_openpopup.js
Normal file
|
|
@ -0,0 +1,521 @@
|
|||
// Tests that the suggestion popup appears at the right times in response to
|
||||
// focus and user events (mouse, keyboard, drop).
|
||||
|
||||
// Instead of loading EventUtils.js into the test scope in browser-test.js for all tests,
|
||||
// we only need EventUtils.js for a few files which is why we are using loadSubScript.
|
||||
var EventUtils = {};
|
||||
this._scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
|
||||
getService(Ci.mozIJSSubScriptLoader);
|
||||
this._scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/EventUtils.js", EventUtils);
|
||||
|
||||
const searchbar = document.getElementById("searchbar");
|
||||
const searchIcon = document.getAnonymousElementByAttribute(searchbar, "anonid", "searchbar-search-button");
|
||||
const goButton = document.getAnonymousElementByAttribute(searchbar, "anonid", "search-go-button");
|
||||
const textbox = searchbar._textbox;
|
||||
const searchPopup = document.getElementById("PopupSearchAutoComplete");
|
||||
const kValues = ["long text", "long text 2", "long text 3"];
|
||||
|
||||
const isWindows = Services.appinfo.OS == "WINNT";
|
||||
const mouseDown = isWindows ? 2 : 1;
|
||||
const mouseUp = isWindows ? 4 : 2;
|
||||
const utils = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
const scale = utils.screenPixelsPerCSSPixel;
|
||||
|
||||
function* synthesizeNativeMouseClick(aElement) {
|
||||
let rect = aElement.getBoundingClientRect();
|
||||
let win = aElement.ownerGlobal;
|
||||
let x = win.mozInnerScreenX + (rect.left + rect.right) / 2;
|
||||
let y = win.mozInnerScreenY + (rect.top + rect.bottom) / 2;
|
||||
|
||||
// Wait for the mouseup event to occur before continuing.
|
||||
return new Promise((resolve, reject) => {
|
||||
function eventOccurred(e)
|
||||
{
|
||||
aElement.removeEventListener("mouseup", eventOccurred, true);
|
||||
resolve();
|
||||
}
|
||||
|
||||
aElement.addEventListener("mouseup", eventOccurred, true);
|
||||
|
||||
utils.sendNativeMouseEvent(x * scale, y * scale, mouseDown, 0, null);
|
||||
utils.sendNativeMouseEvent(x * scale, y * scale, mouseUp, 0, null);
|
||||
});
|
||||
}
|
||||
|
||||
add_task(function* init() {
|
||||
yield promiseNewEngine("testEngine.xml");
|
||||
|
||||
// First cleanup the form history in case other tests left things there.
|
||||
yield new Promise((resolve, reject) => {
|
||||
info("cleanup the search history");
|
||||
searchbar.FormHistory.update({op: "remove", fieldname: "searchbar-history"},
|
||||
{handleCompletion: resolve,
|
||||
handleError: reject});
|
||||
});
|
||||
|
||||
yield new Promise((resolve, reject) => {
|
||||
info("adding search history values: " + kValues);
|
||||
let ops = kValues.map(value => { return {op: "add",
|
||||
fieldname: "searchbar-history",
|
||||
value: value}
|
||||
});
|
||||
searchbar.FormHistory.update(ops, {
|
||||
handleCompletion: function() {
|
||||
registerCleanupFunction(() => {
|
||||
info("removing search history values: " + kValues);
|
||||
let ops =
|
||||
kValues.map(value => { return {op: "remove",
|
||||
fieldname: "searchbar-history",
|
||||
value: value}
|
||||
});
|
||||
searchbar.FormHistory.update(ops);
|
||||
});
|
||||
resolve();
|
||||
},
|
||||
handleError: reject
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Adds a task that shouldn't show the search suggestions popup.
|
||||
function add_no_popup_task(task) {
|
||||
add_task(function*() {
|
||||
let sawPopup = false;
|
||||
function listener() {
|
||||
sawPopup = true;
|
||||
}
|
||||
|
||||
info("Entering test " + task.name);
|
||||
searchPopup.addEventListener("popupshowing", listener, false);
|
||||
yield Task.spawn(task);
|
||||
searchPopup.removeEventListener("popupshowing", listener, false);
|
||||
ok(!sawPopup, "Shouldn't have seen the suggestions popup");
|
||||
info("Leaving test " + task.name);
|
||||
});
|
||||
}
|
||||
|
||||
// Simulates the full set of events for a context click
|
||||
function context_click(target) {
|
||||
for (let event of ["mousedown", "contextmenu", "mouseup"])
|
||||
EventUtils.synthesizeMouseAtCenter(target, { type: event, button: 2 });
|
||||
}
|
||||
|
||||
// Right clicking the icon should not open the popup.
|
||||
add_no_popup_task(function* open_icon_context() {
|
||||
gURLBar.focus();
|
||||
let toolbarPopup = document.getElementById("toolbar-context-menu");
|
||||
|
||||
let promise = promiseEvent(toolbarPopup, "popupshown");
|
||||
context_click(searchIcon);
|
||||
yield promise;
|
||||
|
||||
promise = promiseEvent(toolbarPopup, "popuphidden");
|
||||
toolbarPopup.hidePopup();
|
||||
yield promise;
|
||||
});
|
||||
|
||||
// With no text in the search box left clicking the icon should open the popup.
|
||||
// Clicking the icon again should hide the popup and not show it again.
|
||||
add_task(function* open_empty() {
|
||||
gURLBar.focus();
|
||||
|
||||
let promise = promiseEvent(searchPopup, "popupshown");
|
||||
info("Clicking icon");
|
||||
EventUtils.synthesizeMouseAtCenter(searchIcon, {});
|
||||
yield promise;
|
||||
is(searchPopup.getAttribute("showonlysettings"), "true", "Should only show the settings");
|
||||
is(textbox.mController.searchString, "", "Should be an empty search string");
|
||||
|
||||
// By giving the textbox some text any next attempt to open the search popup
|
||||
// from the click handler will try to search for this text.
|
||||
textbox.value = "foo";
|
||||
|
||||
promise = promiseEvent(searchPopup, "popuphidden");
|
||||
|
||||
info("Hiding popup");
|
||||
yield synthesizeNativeMouseClick(searchIcon);
|
||||
yield promise;
|
||||
|
||||
is(textbox.mController.searchString, "", "Should not have started to search for the new text");
|
||||
|
||||
// Cancel the search if it started.
|
||||
if (textbox.mController.searchString != "") {
|
||||
textbox.mController.stopSearch();
|
||||
}
|
||||
|
||||
textbox.value = "";
|
||||
});
|
||||
|
||||
// With no text in the search box left clicking it should not open the popup.
|
||||
add_no_popup_task(function* click_doesnt_open_popup() {
|
||||
gURLBar.focus();
|
||||
|
||||
EventUtils.synthesizeMouseAtCenter(textbox, {});
|
||||
is(Services.focus.focusedElement, textbox.inputField, "Should have focused the search bar");
|
||||
is(textbox.selectionStart, 0, "Should have selected all of the text");
|
||||
is(textbox.selectionEnd, 0, "Should have selected all of the text");
|
||||
});
|
||||
|
||||
// Left clicking in a non-empty search box when unfocused should focus it and open the popup.
|
||||
add_task(function* click_opens_popup() {
|
||||
gURLBar.focus();
|
||||
textbox.value = "foo";
|
||||
|
||||
let promise = promiseEvent(searchPopup, "popupshown");
|
||||
EventUtils.synthesizeMouseAtCenter(textbox, {});
|
||||
yield promise;
|
||||
isnot(searchPopup.getAttribute("showonlysettings"), "true", "Should show the full popup");
|
||||
|
||||
is(Services.focus.focusedElement, textbox.inputField, "Should have focused the search bar");
|
||||
is(textbox.selectionStart, 0, "Should have selected all of the text");
|
||||
is(textbox.selectionEnd, 3, "Should have selected all of the text");
|
||||
|
||||
promise = promiseEvent(searchPopup, "popuphidden");
|
||||
searchPopup.hidePopup();
|
||||
yield promise;
|
||||
|
||||
textbox.value = "";
|
||||
});
|
||||
|
||||
// Right clicking in a non-empty search box when unfocused should open the edit context menu.
|
||||
add_no_popup_task(function* right_click_doesnt_open_popup() {
|
||||
gURLBar.focus();
|
||||
textbox.value = "foo";
|
||||
|
||||
let contextPopup = document.getAnonymousElementByAttribute(textbox.inputField.parentNode, "anonid", "input-box-contextmenu");
|
||||
let promise = promiseEvent(contextPopup, "popupshown");
|
||||
context_click(textbox);
|
||||
yield promise;
|
||||
|
||||
is(Services.focus.focusedElement, textbox.inputField, "Should have focused the search bar");
|
||||
is(textbox.selectionStart, 0, "Should have selected all of the text");
|
||||
is(textbox.selectionEnd, 3, "Should have selected all of the text");
|
||||
|
||||
promise = promiseEvent(contextPopup, "popuphidden");
|
||||
contextPopup.hidePopup();
|
||||
yield promise;
|
||||
|
||||
textbox.value = "";
|
||||
});
|
||||
|
||||
// Moving focus away from the search box should close the popup
|
||||
add_task(function* focus_change_closes_popup() {
|
||||
gURLBar.focus();
|
||||
textbox.value = "foo";
|
||||
|
||||
let promise = promiseEvent(searchPopup, "popupshown");
|
||||
EventUtils.synthesizeMouseAtCenter(textbox, {});
|
||||
yield promise;
|
||||
isnot(searchPopup.getAttribute("showonlysettings"), "true", "Should show the full popup");
|
||||
|
||||
is(Services.focus.focusedElement, textbox.inputField, "Should have focused the search bar");
|
||||
is(textbox.selectionStart, 0, "Should have selected all of the text");
|
||||
is(textbox.selectionEnd, 3, "Should have selected all of the text");
|
||||
|
||||
promise = promiseEvent(searchPopup, "popuphidden");
|
||||
let promise2 = promiseEvent(searchbar, "blur");
|
||||
EventUtils.synthesizeKey("VK_TAB", { shiftKey: true });
|
||||
yield promise;
|
||||
yield promise2;
|
||||
|
||||
textbox.value = "";
|
||||
});
|
||||
|
||||
// Moving focus away from the search box should close the small popup
|
||||
add_task(function* focus_change_closes_small_popup() {
|
||||
gURLBar.focus();
|
||||
|
||||
let promise = promiseEvent(searchPopup, "popupshown");
|
||||
// For some reason sending the mouse event immediately doesn't open the popup.
|
||||
SimpleTest.executeSoon(() => {
|
||||
EventUtils.synthesizeMouseAtCenter(searchIcon, {});
|
||||
});
|
||||
yield promise;
|
||||
is(searchPopup.getAttribute("showonlysettings"), "true", "Should show the small popup");
|
||||
|
||||
is(Services.focus.focusedElement, textbox.inputField, "Should have focused the search bar");
|
||||
|
||||
promise = promiseEvent(searchPopup, "popuphidden");
|
||||
let promise2 = promiseEvent(searchbar, "blur");
|
||||
EventUtils.synthesizeKey("VK_TAB", { shiftKey: true });
|
||||
yield promise;
|
||||
yield promise2;
|
||||
});
|
||||
|
||||
// Pressing escape should close the popup.
|
||||
add_task(function* escape_closes_popup() {
|
||||
gURLBar.focus();
|
||||
textbox.value = "foo";
|
||||
|
||||
let promise = promiseEvent(searchPopup, "popupshown");
|
||||
EventUtils.synthesizeMouseAtCenter(textbox, {});
|
||||
yield promise;
|
||||
isnot(searchPopup.getAttribute("showonlysettings"), "true", "Should show the full popup");
|
||||
|
||||
is(Services.focus.focusedElement, textbox.inputField, "Should have focused the search bar");
|
||||
is(textbox.selectionStart, 0, "Should have selected all of the text");
|
||||
is(textbox.selectionEnd, 3, "Should have selected all of the text");
|
||||
|
||||
promise = promiseEvent(searchPopup, "popuphidden");
|
||||
EventUtils.synthesizeKey("VK_ESCAPE", {});
|
||||
yield promise;
|
||||
|
||||
textbox.value = "";
|
||||
});
|
||||
|
||||
// Pressing contextmenu should close the popup.
|
||||
add_task(function* contextmenu_closes_popup() {
|
||||
gURLBar.focus();
|
||||
textbox.value = "foo";
|
||||
|
||||
let promise = promiseEvent(searchPopup, "popupshown");
|
||||
EventUtils.synthesizeMouseAtCenter(textbox, {});
|
||||
yield promise;
|
||||
isnot(searchPopup.getAttribute("showonlysettings"), "true", "Should show the full popup");
|
||||
|
||||
is(Services.focus.focusedElement, textbox.inputField, "Should have focused the search bar");
|
||||
is(textbox.selectionStart, 0, "Should have selected all of the text");
|
||||
is(textbox.selectionEnd, 3, "Should have selected all of the text");
|
||||
|
||||
promise = promiseEvent(searchPopup, "popuphidden");
|
||||
|
||||
// synthesizeKey does not work with VK_CONTEXT_MENU (bug 1127368)
|
||||
EventUtils.synthesizeMouseAtCenter(textbox, { type: "contextmenu", button: null });
|
||||
|
||||
yield promise;
|
||||
|
||||
let contextPopup =
|
||||
document.getAnonymousElementByAttribute(textbox.inputField.parentNode,
|
||||
"anonid", "input-box-contextmenu");
|
||||
promise = promiseEvent(contextPopup, "popuphidden");
|
||||
contextPopup.hidePopup();
|
||||
yield promise;
|
||||
|
||||
textbox.value = "";
|
||||
});
|
||||
|
||||
// Tabbing to the search box should open the popup if it contains text.
|
||||
add_task(function* tab_opens_popup() {
|
||||
gURLBar.focus();
|
||||
textbox.value = "foo";
|
||||
|
||||
let promise = promiseEvent(searchPopup, "popupshown");
|
||||
EventUtils.synthesizeKey("VK_TAB", {});
|
||||
yield promise;
|
||||
isnot(searchPopup.getAttribute("showonlysettings"), "true", "Should show the full popup");
|
||||
|
||||
is(Services.focus.focusedElement, textbox.inputField, "Should have focused the search bar");
|
||||
is(textbox.selectionStart, 0, "Should have selected all of the text");
|
||||
is(textbox.selectionEnd, 3, "Should have selected all of the text");
|
||||
|
||||
promise = promiseEvent(searchPopup, "popuphidden");
|
||||
searchPopup.hidePopup();
|
||||
yield promise;
|
||||
|
||||
textbox.value = "";
|
||||
});
|
||||
|
||||
// Tabbing to the search box should not open the popup if it doesn't contain text.
|
||||
add_no_popup_task(function* tab_doesnt_open_popup() {
|
||||
gURLBar.focus();
|
||||
textbox.value = "foo";
|
||||
|
||||
EventUtils.synthesizeKey("VK_TAB", {});
|
||||
|
||||
is(Services.focus.focusedElement, textbox.inputField, "Should have focused the search bar");
|
||||
is(textbox.selectionStart, 0, "Should have selected all of the text");
|
||||
is(textbox.selectionEnd, 3, "Should have selected all of the text");
|
||||
|
||||
textbox.value = "";
|
||||
});
|
||||
|
||||
// Switching back to the window when the search box has focus from mouse should not open the popup.
|
||||
add_task(function* refocus_window_doesnt_open_popup_mouse() {
|
||||
gURLBar.focus();
|
||||
textbox.value = "foo";
|
||||
|
||||
let promise = promiseEvent(searchPopup, "popupshown");
|
||||
EventUtils.synthesizeMouseAtCenter(searchbar, {});
|
||||
yield promise;
|
||||
isnot(searchPopup.getAttribute("showonlysettings"), "true", "Should show the full popup");
|
||||
|
||||
is(Services.focus.focusedElement, textbox.inputField, "Should have focused the search bar");
|
||||
is(textbox.selectionStart, 0, "Should have selected all of the text");
|
||||
is(textbox.selectionEnd, 3, "Should have selected all of the text");
|
||||
|
||||
promise = promiseEvent(searchPopup, "popuphidden");
|
||||
let newWin = OpenBrowserWindow();
|
||||
yield new Promise(resolve => waitForFocus(resolve, newWin));
|
||||
yield promise;
|
||||
|
||||
function listener() {
|
||||
ok(false, "Should not have shown the popup.");
|
||||
}
|
||||
searchPopup.addEventListener("popupshowing", listener, false);
|
||||
|
||||
promise = promiseEvent(searchbar, "focus");
|
||||
newWin.close();
|
||||
yield promise;
|
||||
|
||||
// Wait a few ticks to allow any focus handlers to show the popup if they are going to.
|
||||
yield new Promise(resolve => executeSoon(resolve));
|
||||
yield new Promise(resolve => executeSoon(resolve));
|
||||
yield new Promise(resolve => executeSoon(resolve));
|
||||
|
||||
searchPopup.removeEventListener("popupshowing", listener, false);
|
||||
textbox.value = "";
|
||||
});
|
||||
|
||||
// Switching back to the window when the search box has focus from keyboard should not open the popup.
|
||||
add_task(function* refocus_window_doesnt_open_popup_keyboard() {
|
||||
gURLBar.focus();
|
||||
textbox.value = "foo";
|
||||
|
||||
let promise = promiseEvent(searchPopup, "popupshown");
|
||||
EventUtils.synthesizeKey("VK_TAB", {});
|
||||
yield promise;
|
||||
isnot(searchPopup.getAttribute("showonlysettings"), "true", "Should show the full popup");
|
||||
|
||||
is(Services.focus.focusedElement, textbox.inputField, "Should have focused the search bar");
|
||||
is(textbox.selectionStart, 0, "Should have selected all of the text");
|
||||
is(textbox.selectionEnd, 3, "Should have selected all of the text");
|
||||
|
||||
promise = promiseEvent(searchPopup, "popuphidden");
|
||||
let newWin = OpenBrowserWindow();
|
||||
yield new Promise(resolve => waitForFocus(resolve, newWin));
|
||||
yield promise;
|
||||
|
||||
function listener() {
|
||||
ok(false, "Should not have shown the popup.");
|
||||
}
|
||||
searchPopup.addEventListener("popupshowing", listener, false);
|
||||
|
||||
promise = promiseEvent(searchbar, "focus");
|
||||
newWin.close();
|
||||
yield promise;
|
||||
|
||||
// Wait a few ticks to allow any focus handlers to show the popup if they are going to.
|
||||
yield new Promise(resolve => executeSoon(resolve));
|
||||
yield new Promise(resolve => executeSoon(resolve));
|
||||
yield new Promise(resolve => executeSoon(resolve));
|
||||
|
||||
searchPopup.removeEventListener("popupshowing", listener, false);
|
||||
textbox.value = "";
|
||||
});
|
||||
|
||||
// Clicking the search go button shouldn't open the popup
|
||||
add_no_popup_task(function* search_go_doesnt_open_popup() {
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
|
||||
gURLBar.focus();
|
||||
textbox.value = "foo";
|
||||
searchbar.updateGoButtonVisibility();
|
||||
|
||||
let promise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
EventUtils.synthesizeMouseAtCenter(goButton, {});
|
||||
yield promise;
|
||||
|
||||
textbox.value = "";
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
// Clicks outside the search popup should close the popup but not consume the click.
|
||||
add_task(function* dont_consume_clicks() {
|
||||
gURLBar.focus();
|
||||
textbox.value = "foo";
|
||||
|
||||
let promise = promiseEvent(searchPopup, "popupshown");
|
||||
EventUtils.synthesizeMouseAtCenter(textbox, {});
|
||||
yield promise;
|
||||
isnot(searchPopup.getAttribute("showonlysettings"), "true", "Should show the full popup");
|
||||
|
||||
is(Services.focus.focusedElement, textbox.inputField, "Should have focused the search bar");
|
||||
is(textbox.selectionStart, 0, "Should have selected all of the text");
|
||||
is(textbox.selectionEnd, 3, "Should have selected all of the text");
|
||||
|
||||
promise = promiseEvent(searchPopup, "popuphidden");
|
||||
yield synthesizeNativeMouseClick(gURLBar);
|
||||
yield promise;
|
||||
|
||||
is(Services.focus.focusedElement, gURLBar.inputField, "Should have focused the URL bar");
|
||||
|
||||
textbox.value = "";
|
||||
});
|
||||
|
||||
// Dropping text to the searchbar should open the popup
|
||||
add_task(function* drop_opens_popup() {
|
||||
let promise = promiseEvent(searchPopup, "popupshown");
|
||||
EventUtils.synthesizeDrop(searchIcon, textbox.inputField, [[ {type: "text/plain", data: "foo" } ]], "move", window);
|
||||
yield promise;
|
||||
|
||||
isnot(searchPopup.getAttribute("showonlysettings"), "true", "Should show the full popup");
|
||||
is(Services.focus.focusedElement, textbox.inputField, "Should have focused the search bar");
|
||||
promise = promiseEvent(searchPopup, "popuphidden");
|
||||
searchPopup.hidePopup();
|
||||
yield promise;
|
||||
|
||||
textbox.value = "";
|
||||
});
|
||||
|
||||
// Moving the caret using the cursor keys should not close the popup.
|
||||
add_task(function* dont_rollup_oncaretmove() {
|
||||
gURLBar.focus();
|
||||
textbox.value = "long text";
|
||||
|
||||
let promise = promiseEvent(searchPopup, "popupshown");
|
||||
EventUtils.synthesizeMouseAtCenter(textbox, {});
|
||||
yield promise;
|
||||
|
||||
// Deselect the text
|
||||
EventUtils.synthesizeKey("VK_RIGHT", {});
|
||||
is(textbox.selectionStart, 9, "Should have moved the caret (selectionStart after deselect right)");
|
||||
is(textbox.selectionEnd, 9, "Should have moved the caret (selectionEnd after deselect right)");
|
||||
is(searchPopup.state, "open", "Popup should still be open");
|
||||
|
||||
EventUtils.synthesizeKey("VK_LEFT", {});
|
||||
is(textbox.selectionStart, 8, "Should have moved the caret (selectionStart after left)");
|
||||
is(textbox.selectionEnd, 8, "Should have moved the caret (selectionEnd after left)");
|
||||
is(searchPopup.state, "open", "Popup should still be open");
|
||||
|
||||
EventUtils.synthesizeKey("VK_RIGHT", {});
|
||||
is(textbox.selectionStart, 9, "Should have moved the caret (selectionStart after right)");
|
||||
is(textbox.selectionEnd, 9, "Should have moved the caret (selectionEnd after right)");
|
||||
is(searchPopup.state, "open", "Popup should still be open");
|
||||
|
||||
// Ensure caret movement works while a suggestion is selected.
|
||||
is(textbox.popup.selectedIndex, -1, "No selected item in list");
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
is(textbox.popup.selectedIndex, 0, "Selected item in list");
|
||||
is(textbox.selectionStart, 9, "Should have moved the caret to the end (selectionStart after selection)");
|
||||
is(textbox.selectionEnd, 9, "Should have moved the caret to the end (selectionEnd after selection)");
|
||||
|
||||
EventUtils.synthesizeKey("VK_LEFT", {});
|
||||
is(textbox.selectionStart, 8, "Should have moved the caret again (selectionStart after left)");
|
||||
is(textbox.selectionEnd, 8, "Should have moved the caret again (selectionEnd after left)");
|
||||
is(searchPopup.state, "open", "Popup should still be open");
|
||||
|
||||
EventUtils.synthesizeKey("VK_LEFT", {});
|
||||
is(textbox.selectionStart, 7, "Should have moved the caret (selectionStart after left)");
|
||||
is(textbox.selectionEnd, 7, "Should have moved the caret (selectionEnd after left)");
|
||||
is(searchPopup.state, "open", "Popup should still be open");
|
||||
|
||||
EventUtils.synthesizeKey("VK_RIGHT", {});
|
||||
is(textbox.selectionStart, 8, "Should have moved the caret (selectionStart after right)");
|
||||
is(textbox.selectionEnd, 8, "Should have moved the caret (selectionEnd after right)");
|
||||
is(searchPopup.state, "open", "Popup should still be open");
|
||||
|
||||
if (navigator.platform.indexOf("Mac") == -1) {
|
||||
EventUtils.synthesizeKey("VK_HOME", {});
|
||||
is(textbox.selectionStart, 0, "Should have moved the caret (selectionStart after home)");
|
||||
is(textbox.selectionEnd, 0, "Should have moved the caret (selectionEnd after home)");
|
||||
is(searchPopup.state, "open", "Popup should still be open");
|
||||
}
|
||||
|
||||
// Close the popup again
|
||||
promise = promiseEvent(searchPopup, "popuphidden");
|
||||
EventUtils.synthesizeKey("VK_ESCAPE", {});
|
||||
yield promise;
|
||||
|
||||
textbox.value = "";
|
||||
});
|
||||
|
|
@ -0,0 +1,354 @@
|
|||
// Tests that keyboard navigation in the search panel works as designed.
|
||||
|
||||
const searchbar = document.getElementById("searchbar");
|
||||
const textbox = searchbar._textbox;
|
||||
const searchPopup = document.getElementById("PopupSearchAutoComplete");
|
||||
const oneOffsContainer =
|
||||
document.getAnonymousElementByAttribute(searchPopup, "anonid",
|
||||
"search-one-off-buttons");
|
||||
const searchIcon = document.getAnonymousElementByAttribute(searchbar, "anonid",
|
||||
"searchbar-search-button");
|
||||
|
||||
const kValues = ["foo1", "foo2", "foo3"];
|
||||
|
||||
function getOpenSearchItems() {
|
||||
let os = [];
|
||||
|
||||
let addEngineList =
|
||||
document.getAnonymousElementByAttribute(oneOffsContainer, "anonid",
|
||||
"add-engines");
|
||||
for (let item = addEngineList.firstChild; item; item = item.nextSibling)
|
||||
os.push(item);
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
add_task(function* init() {
|
||||
yield promiseNewEngine("testEngine.xml");
|
||||
|
||||
// First cleanup the form history in case other tests left things there.
|
||||
yield new Promise((resolve, reject) => {
|
||||
info("cleanup the search history");
|
||||
searchbar.FormHistory.update({op: "remove", fieldname: "searchbar-history"},
|
||||
{handleCompletion: resolve,
|
||||
handleError: reject});
|
||||
});
|
||||
|
||||
yield new Promise((resolve, reject) => {
|
||||
info("adding search history values: " + kValues);
|
||||
let ops = kValues.map(value => { return {op: "add",
|
||||
fieldname: "searchbar-history",
|
||||
value: value}
|
||||
});
|
||||
searchbar.FormHistory.update(ops, {
|
||||
handleCompletion: function() {
|
||||
registerCleanupFunction(() => {
|
||||
info("removing search history values: " + kValues);
|
||||
let ops =
|
||||
kValues.map(value => { return {op: "remove",
|
||||
fieldname: "searchbar-history",
|
||||
value: value}
|
||||
});
|
||||
searchbar.FormHistory.update(ops);
|
||||
});
|
||||
resolve();
|
||||
},
|
||||
handleError: reject
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_arrows() {
|
||||
let promise = promiseEvent(searchPopup, "popupshown");
|
||||
info("Opening search panel");
|
||||
EventUtils.synthesizeMouseAtCenter(searchIcon, {});
|
||||
yield promise;
|
||||
info("textbox.mController.searchString = " + textbox.mController.searchString);
|
||||
is(textbox.mController.searchString, "", "The search string should be empty");
|
||||
|
||||
// Check the initial state of the panel before sending keyboard events.
|
||||
is(searchPopup.getAttribute("showonlysettings"), "true", "Should show the small popup");
|
||||
// Having suggestions populated (but hidden) is important, because if there
|
||||
// are none we can't ensure the keyboard events don't reach them.
|
||||
is(searchPopup.view.rowCount, kValues.length, "There should be 3 suggestions");
|
||||
is(searchPopup.selectedIndex, -1, "no suggestion should be selected");
|
||||
|
||||
// The tests will be less meaningful if the first, second, last, and
|
||||
// before-last one-off buttons aren't different. We should always have more
|
||||
// than 4 default engines, but it's safer to check this assumption.
|
||||
let oneOffs = getOneOffs();
|
||||
ok(oneOffs.length >= 4, "we have at least 4 one-off buttons displayed")
|
||||
|
||||
ok(!textbox.selectedButton, "no one-off button should be selected");
|
||||
|
||||
// Pressing should select the first one-off.
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
is(searchPopup.selectedIndex, -1, "no suggestion should be selected");
|
||||
is(textbox.value, "", "the textfield value should be unmodified");
|
||||
|
||||
// now cycle through the one-off items, the first one is already selected.
|
||||
for (let i = 0; i < oneOffs.length; ++i) {
|
||||
is(textbox.selectedButton, oneOffs[i],
|
||||
"the one-off button #" + (i + 1) + " should be selected");
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
}
|
||||
|
||||
is(textbox.selectedButton.getAttribute("anonid"), "search-settings",
|
||||
"the settings item should be selected");
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
|
||||
// We should now be back to the initial situation.
|
||||
is(searchPopup.selectedIndex, -1, "no suggestion should be selected");
|
||||
ok(!textbox.selectedButton, "no one-off button should be selected");
|
||||
|
||||
info("now test the up arrow key");
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
is(textbox.selectedButton.getAttribute("anonid"), "search-settings",
|
||||
"the settings item should be selected");
|
||||
|
||||
// cycle through the one-off items, the first one is already selected.
|
||||
for (let i = oneOffs.length; i; --i) {
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
is(textbox.selectedButton, oneOffs[i - 1],
|
||||
"the one-off button #" + i + " should be selected");
|
||||
}
|
||||
|
||||
// Another press on up should clear the one-off selection.
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
ok(!textbox.selectedButton, "no one-off button should be selected");
|
||||
is(searchPopup.selectedIndex, -1, "no suggestion should be selected");
|
||||
is(textbox.value, "", "the textfield value should be unmodified");
|
||||
});
|
||||
|
||||
add_task(function* test_tab() {
|
||||
is(Services.focus.focusedElement, textbox.inputField,
|
||||
"the search bar should be focused"); // from the previous test.
|
||||
|
||||
let oneOffs = getOneOffs();
|
||||
ok(!textbox.selectedButton, "no one-off button should be selected");
|
||||
|
||||
// Pressing tab should select the first one-off without selecting suggestions.
|
||||
// now cycle through the one-off items, the first one is already selected.
|
||||
for (let i = 0; i < oneOffs.length; ++i) {
|
||||
EventUtils.synthesizeKey("VK_TAB", {});
|
||||
is(textbox.selectedButton, oneOffs[i],
|
||||
"the one-off button #" + (i + 1) + " should be selected");
|
||||
}
|
||||
is(searchPopup.selectedIndex, -1, "no suggestion should be selected");
|
||||
is(textbox.value, "", "the textfield value should be unmodified");
|
||||
|
||||
// One more <tab> selects the settings button.
|
||||
EventUtils.synthesizeKey("VK_TAB", {});
|
||||
is(textbox.selectedButton.getAttribute("anonid"), "search-settings",
|
||||
"the settings item should be selected");
|
||||
|
||||
// Pressing tab again should close the panel...
|
||||
let promise = promiseEvent(searchPopup, "popuphidden");
|
||||
EventUtils.synthesizeKey("VK_TAB", {});
|
||||
yield promise;
|
||||
|
||||
// ... and move the focus out of the searchbox.
|
||||
isnot(Services.focus.focusedElement, textbox.inputField,
|
||||
"the search bar no longer be focused");
|
||||
});
|
||||
|
||||
add_task(function* test_shift_tab() {
|
||||
// First reopen the panel.
|
||||
let promise = promiseEvent(searchPopup, "popupshown");
|
||||
info("Opening search panel");
|
||||
SimpleTest.executeSoon(() => {
|
||||
EventUtils.synthesizeMouseAtCenter(searchIcon, {});
|
||||
});
|
||||
yield promise;
|
||||
|
||||
let oneOffs = getOneOffs();
|
||||
ok(!textbox.selectedButton, "no one-off button should be selected");
|
||||
is(searchPopup.getAttribute("showonlysettings"), "true", "Should show the small popup");
|
||||
|
||||
// Press up once to select the last button.
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
is(textbox.selectedButton.getAttribute("anonid"), "search-settings",
|
||||
"the settings item should be selected");
|
||||
|
||||
// Press up again to select the last one-off button.
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
|
||||
// Pressing shift+tab should cycle through the one-off items.
|
||||
for (let i = oneOffs.length - 1; i >= 0; --i) {
|
||||
is(textbox.selectedButton, oneOffs[i],
|
||||
"the one-off button #" + (i + 1) + " should be selected");
|
||||
if (i)
|
||||
EventUtils.synthesizeKey("VK_TAB", {shiftKey: true});
|
||||
}
|
||||
is(searchPopup.selectedIndex, -1, "no suggestion should be selected");
|
||||
is(textbox.value, "", "the textfield value should be unmodified");
|
||||
|
||||
// Pressing shift+tab again should close the panel...
|
||||
promise = promiseEvent(searchPopup, "popuphidden");
|
||||
EventUtils.synthesizeKey("VK_TAB", {shiftKey: true});
|
||||
yield promise;
|
||||
|
||||
// ... and move the focus out of the searchbox.
|
||||
isnot(Services.focus.focusedElement, textbox.inputField,
|
||||
"the search bar no longer be focused");
|
||||
});
|
||||
|
||||
add_task(function* test_alt_down() {
|
||||
// First reopen the panel.
|
||||
let promise = promiseEvent(searchPopup, "popupshown");
|
||||
info("Opening search panel");
|
||||
SimpleTest.executeSoon(() => {
|
||||
EventUtils.synthesizeMouseAtCenter(searchIcon, {});
|
||||
});
|
||||
yield promise;
|
||||
|
||||
// and check it's in a correct initial state.
|
||||
is(searchPopup.getAttribute("showonlysettings"), "true", "Should show the small popup");
|
||||
ok(!textbox.selectedButton, "no one-off button should be selected");
|
||||
is(searchPopup.selectedIndex, -1, "no suggestion should be selected");
|
||||
is(textbox.value, "", "the textfield value should be unmodified");
|
||||
|
||||
// Pressing alt+down should select the first one-off without selecting suggestions
|
||||
// and cycle through the one-off items.
|
||||
let oneOffs = getOneOffs();
|
||||
for (let i = 0; i < oneOffs.length; ++i) {
|
||||
EventUtils.synthesizeKey("VK_DOWN", {altKey: true});
|
||||
is(textbox.selectedButton, oneOffs[i],
|
||||
"the one-off button #" + (i + 1) + " should be selected");
|
||||
is(searchPopup.selectedIndex, -1, "no suggestion should be selected");
|
||||
}
|
||||
|
||||
// One more alt+down keypress and nothing should be selected.
|
||||
EventUtils.synthesizeKey("VK_DOWN", {altKey: true});
|
||||
ok(!textbox.selectedButton, "no one-off button should be selected");
|
||||
|
||||
// another one and the first one-off should be selected.
|
||||
EventUtils.synthesizeKey("VK_DOWN", {altKey: true});
|
||||
is(textbox.selectedButton, oneOffs[0],
|
||||
"the first one-off button should be selected");
|
||||
|
||||
// Clear the selection with an alt+up keypress
|
||||
EventUtils.synthesizeKey("VK_UP", {altKey: true});
|
||||
ok(!textbox.selectedButton, "no one-off button should be selected");
|
||||
});
|
||||
|
||||
add_task(function* test_alt_up() {
|
||||
// Check the initial state of the panel
|
||||
ok(!textbox.selectedButton, "no one-off button should be selected");
|
||||
is(searchPopup.selectedIndex, -1, "no suggestion should be selected");
|
||||
is(textbox.value, "", "the textfield value should be unmodified");
|
||||
|
||||
// Pressing alt+up should select the last one-off without selecting suggestions
|
||||
// and cycle up through the one-off items.
|
||||
let oneOffs = getOneOffs();
|
||||
for (let i = oneOffs.length - 1; i >= 0; --i) {
|
||||
EventUtils.synthesizeKey("VK_UP", {altKey: true});
|
||||
is(textbox.selectedButton, oneOffs[i],
|
||||
"the one-off button #" + (i + 1) + " should be selected");
|
||||
is(searchPopup.selectedIndex, -1, "no suggestion should be selected");
|
||||
}
|
||||
|
||||
// One more alt+down keypress and nothing should be selected.
|
||||
EventUtils.synthesizeKey("VK_UP", {altKey: true});
|
||||
ok(!textbox.selectedButton, "no one-off button should be selected");
|
||||
|
||||
// another one and the last one-off should be selected.
|
||||
EventUtils.synthesizeKey("VK_UP", {altKey: true});
|
||||
is(textbox.selectedButton, oneOffs[oneOffs.length - 1],
|
||||
"the last one-off button should be selected");
|
||||
|
||||
// Cleanup for the next test.
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
is(textbox.selectedButton.getAttribute("anonid"), "search-settings",
|
||||
"the settings item should be selected");
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
ok(!textbox.selectedButton, "no one-off should be selected anymore");
|
||||
});
|
||||
|
||||
add_task(function* test_tab_and_arrows() {
|
||||
// Check the initial state is as expected.
|
||||
ok(!textbox.selectedButton, "no one-off button should be selected");
|
||||
is(searchPopup.selectedIndex, -1, "no suggestion should be selected");
|
||||
is(textbox.value, "", "the textfield value should be unmodified");
|
||||
|
||||
// After pressing down, the first one-off should be selected.
|
||||
let oneOffs = getOneOffs();
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
is(textbox.selectedButton, oneOffs[0],
|
||||
"the first one-off button should be selected");
|
||||
is(searchPopup.selectedIndex, -1, "no suggestion should be selected");
|
||||
|
||||
// After pressing tab, the second one-off should be selected.
|
||||
EventUtils.synthesizeKey("VK_TAB", {});
|
||||
is(textbox.selectedButton, oneOffs[1],
|
||||
"the second one-off button should be selected");
|
||||
is(searchPopup.selectedIndex, -1, "no suggestion should be selected");
|
||||
|
||||
// After pressing up, the first one-off should be selected again.
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
is(textbox.selectedButton, oneOffs[0],
|
||||
"the first one-off button should be selected");
|
||||
is(searchPopup.selectedIndex, -1, "no suggestion should be selected");
|
||||
|
||||
// Finally close the panel.
|
||||
let promise = promiseEvent(searchPopup, "popuphidden");
|
||||
searchPopup.hidePopup();
|
||||
yield promise;
|
||||
});
|
||||
|
||||
add_task(function* test_open_search() {
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
yield BrowserTestUtils.openNewForegroundTab(gBrowser, rootDir + "opensearch.html");
|
||||
|
||||
let promise = promiseEvent(searchPopup, "popupshown");
|
||||
info("Opening search panel");
|
||||
EventUtils.synthesizeMouseAtCenter(searchIcon, {});
|
||||
yield promise;
|
||||
is(searchPopup.getAttribute("showonlysettings"), "true", "Should show the small popup");
|
||||
|
||||
let engines = getOpenSearchItems();
|
||||
is(engines.length, 2, "the opensearch.html page exposes 2 engines")
|
||||
|
||||
// Check that there's initially no selection.
|
||||
is(searchPopup.selectedIndex, -1, "no suggestion should be selected");
|
||||
ok(!textbox.selectedButton, "no button should be selected");
|
||||
|
||||
// Pressing up once selects the setting button...
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
is(textbox.selectedButton.getAttribute("anonid"), "search-settings",
|
||||
"the settings item should be selected");
|
||||
|
||||
// ...and then pressing up selects open search engines.
|
||||
for (let i = engines.length; i; --i) {
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
let selectedButton = textbox.selectedButton;
|
||||
is(selectedButton, engines[i - 1],
|
||||
"the engine #" + i + " should be selected");
|
||||
ok(selectedButton.classList.contains("addengine-item"),
|
||||
"the button is themed as an engine item");
|
||||
}
|
||||
|
||||
// Pressing up again should select the last one-off button.
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
is(textbox.selectedButton, getOneOffs().pop(),
|
||||
"the last one-off button should be selected");
|
||||
|
||||
info("now check that the down key navigates open search items as expected");
|
||||
for (let i = 0; i < engines.length; ++i) {
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
is(textbox.selectedButton, engines[i],
|
||||
"the engine #" + (i + 1) + " should be selected");
|
||||
}
|
||||
|
||||
// Pressing down on the last engine item selects the settings button.
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
is(textbox.selectedButton.getAttribute("anonid"), "search-settings",
|
||||
"the settings item should be selected");
|
||||
|
||||
promise = promiseEvent(searchPopup, "popuphidden");
|
||||
searchPopup.hidePopup();
|
||||
yield promise;
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
92
browser/components/search/test/browser_webapi.js
Normal file
92
browser/components/search/test/browser_webapi.js
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
var ROOT = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "http://example.com");
|
||||
const searchBundle = Services.strings.createBundle("chrome://global/locale/search/search.properties");
|
||||
const brandBundle = Services.strings.createBundle("chrome://branding/locale/brand.properties");
|
||||
const brandName = brandBundle.GetStringFromName("brandShortName");
|
||||
|
||||
function getString(key, ...params) {
|
||||
return searchBundle.formatStringFromName(key, params, params.length);
|
||||
}
|
||||
|
||||
function AddSearchProvider(...args) {
|
||||
return gBrowser.addTab(ROOT + "webapi.html?" + encodeURIComponent(JSON.stringify(args)));
|
||||
}
|
||||
|
||||
function promiseDialogOpened() {
|
||||
return new Promise((resolve, reject) => {
|
||||
Services.wm.addListener({
|
||||
onOpenWindow: function(xulWin) {
|
||||
Services.wm.removeListener(this);
|
||||
|
||||
let win = xulWin.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindow);
|
||||
waitForFocus(() => {
|
||||
if (win.location == "chrome://global/content/commonDialog.xul")
|
||||
resolve(win)
|
||||
else
|
||||
reject();
|
||||
}, win);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
add_task(function* test_working() {
|
||||
gBrowser.selectedTab = AddSearchProvider(ROOT + "testEngine.xml");
|
||||
|
||||
let dialog = yield promiseDialogOpened();
|
||||
is(dialog.args.promptType, "confirmEx", "Should see the confirmation dialog.");
|
||||
is(dialog.args.text, getString("addEngineConfirmation", "Foo", "example.com"),
|
||||
"Should have seen the right install message");
|
||||
dialog.document.documentElement.cancelDialog();
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
add_task(function* test_HTTP() {
|
||||
gBrowser.selectedTab = AddSearchProvider(ROOT.replace("http:", "HTTP:") + "testEngine.xml");
|
||||
|
||||
let dialog = yield promiseDialogOpened();
|
||||
is(dialog.args.promptType, "confirmEx", "Should see the confirmation dialog.");
|
||||
is(dialog.args.text, getString("addEngineConfirmation", "Foo", "example.com"),
|
||||
"Should have seen the right install message");
|
||||
dialog.document.documentElement.cancelDialog();
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
add_task(function* test_relative() {
|
||||
gBrowser.selectedTab = AddSearchProvider("testEngine.xml");
|
||||
|
||||
let dialog = yield promiseDialogOpened();
|
||||
is(dialog.args.promptType, "confirmEx", "Should see the confirmation dialog.");
|
||||
is(dialog.args.text, getString("addEngineConfirmation", "Foo", "example.com"),
|
||||
"Should have seen the right install message");
|
||||
dialog.document.documentElement.cancelDialog();
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
add_task(function* test_invalid() {
|
||||
gBrowser.selectedTab = AddSearchProvider("z://foobar");
|
||||
|
||||
let dialog = yield promiseDialogOpened();
|
||||
is(dialog.args.promptType, "alert", "Should see the alert dialog.");
|
||||
is(dialog.args.text, getString("error_invalid_engine_msg", brandName),
|
||||
"Should have seen the right error message")
|
||||
dialog.document.documentElement.acceptDialog();
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
add_task(function* test_missing() {
|
||||
let url = ROOT + "foobar.xml";
|
||||
gBrowser.selectedTab = AddSearchProvider(url);
|
||||
|
||||
let dialog = yield promiseDialogOpened();
|
||||
is(dialog.args.promptType, "alert", "Should see the alert dialog.");
|
||||
is(dialog.args.text, getString("error_loading_engine_msg2", brandName, url),
|
||||
"Should have seen the right error message")
|
||||
dialog.document.documentElement.acceptDialog();
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
132
browser/components/search/test/browser_yahoo.js
Normal file
132
browser/components/search/test/browser_yahoo.js
Normal file
File diff suppressed because one or more lines are too long
166
browser/components/search/test/browser_yahoo_behavior.js
Normal file
166
browser/components/search/test/browser_yahoo_behavior.js
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/*
|
||||
* Test Yahoo search plugin URLs
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const BROWSER_SEARCH_PREF = "browser.search.";
|
||||
|
||||
|
||||
function test() {
|
||||
let engine = Services.search.getEngineByName("Yahoo");
|
||||
ok(engine, "Yahoo is installed");
|
||||
|
||||
let previouslySelectedEngine = Services.search.currentEngine;
|
||||
Services.search.currentEngine = engine;
|
||||
engine.alias = "y";
|
||||
|
||||
let base = "https://search.yahoo.com/yhs/search?p=foo&ei=UTF-8&hspart=mozilla";
|
||||
let url;
|
||||
|
||||
// Test search URLs (including purposes).
|
||||
url = engine.getSubmission("foo").uri.spec;
|
||||
is(url, base + "&hsimp=yhs-001", "Check search URL for 'foo'");
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
var gCurrTest;
|
||||
var gTests = [
|
||||
{
|
||||
name: "context menu search",
|
||||
searchURL: base + "&hsimp=yhs-005",
|
||||
run: function () {
|
||||
// Simulate a contextmenu search
|
||||
// FIXME: This is a bit "low-level"...
|
||||
BrowserSearch.loadSearch("foo", false, "contextmenu");
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "keyword search",
|
||||
searchURL: base + "&hsimp=yhs-002",
|
||||
run: function () {
|
||||
gURLBar.value = "? foo";
|
||||
gURLBar.focus();
|
||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "keyword search with alias",
|
||||
searchURL: base + "&hsimp=yhs-002",
|
||||
run: function () {
|
||||
gURLBar.value = "y foo";
|
||||
gURLBar.focus();
|
||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "search bar search",
|
||||
searchURL: base + "&hsimp=yhs-001",
|
||||
run: function () {
|
||||
let sb = BrowserSearch.searchBar;
|
||||
sb.focus();
|
||||
sb.value = "foo";
|
||||
registerCleanupFunction(function () {
|
||||
sb.value = "";
|
||||
});
|
||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "new tab search",
|
||||
searchURL: base + "&hsimp=yhs-004",
|
||||
run: function () {
|
||||
function doSearch(doc) {
|
||||
// Re-add the listener, and perform a search
|
||||
gBrowser.addProgressListener(listener);
|
||||
doc.getElementById("newtab-search-text").value = "foo";
|
||||
doc.getElementById("newtab-search-submit").click();
|
||||
}
|
||||
|
||||
// load about:newtab, but remove the listener first so it doesn't
|
||||
// get in the way
|
||||
gBrowser.removeProgressListener(listener);
|
||||
gBrowser.loadURI("about:newtab");
|
||||
info("Waiting for about:newtab load");
|
||||
tab.linkedBrowser.addEventListener("load", function load(event) {
|
||||
if (event.originalTarget != tab.linkedBrowser.contentDocument ||
|
||||
event.target.location.href == "about:blank") {
|
||||
info("skipping spurious load event");
|
||||
return;
|
||||
}
|
||||
tab.linkedBrowser.removeEventListener("load", load, true);
|
||||
|
||||
// Observe page setup
|
||||
let win = gBrowser.contentWindow;
|
||||
if (win.gSearch.currentEngineName ==
|
||||
Services.search.currentEngine.name) {
|
||||
doSearch(win.document);
|
||||
}
|
||||
else {
|
||||
info("Waiting for newtab search init");
|
||||
win.addEventListener("ContentSearchService", function done(event) {
|
||||
info("Got newtab search event " + event.detail.type);
|
||||
if (event.detail.type == "State") {
|
||||
win.removeEventListener("ContentSearchService", done);
|
||||
// Let gSearch respond to the event before continuing.
|
||||
executeSoon(() => doSearch(win.document));
|
||||
}
|
||||
});
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
function nextTest() {
|
||||
if (gTests.length) {
|
||||
gCurrTest = gTests.shift();
|
||||
info("Running : " + gCurrTest.name);
|
||||
executeSoon(gCurrTest.run);
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab();
|
||||
|
||||
let listener = {
|
||||
onStateChange: function onStateChange(webProgress, req, flags, status) {
|
||||
info("onStateChange");
|
||||
// Only care about top-level document starts
|
||||
let docStart = Ci.nsIWebProgressListener.STATE_IS_DOCUMENT |
|
||||
Ci.nsIWebProgressListener.STATE_START;
|
||||
if (!(flags & docStart) || !webProgress.isTopLevel)
|
||||
return;
|
||||
|
||||
if (req.originalURI.spec == "about:blank")
|
||||
return;
|
||||
|
||||
info("received document start");
|
||||
|
||||
ok(req instanceof Ci.nsIChannel, "req is a channel");
|
||||
is(req.originalURI.spec, gCurrTest.searchURL, "search URL was loaded");
|
||||
info("Actual URI: " + req.URI.spec);
|
||||
|
||||
req.cancel(Components.results.NS_ERROR_FAILURE);
|
||||
|
||||
executeSoon(nextTest);
|
||||
}
|
||||
}
|
||||
|
||||
registerCleanupFunction(function () {
|
||||
engine.alias = undefined;
|
||||
gBrowser.removeProgressListener(listener);
|
||||
gBrowser.removeTab(tab);
|
||||
Services.search.currentEngine = previouslySelectedEngine;
|
||||
});
|
||||
|
||||
tab.linkedBrowser.addEventListener("load", function load() {
|
||||
tab.linkedBrowser.removeEventListener("load", load, true);
|
||||
gBrowser.addProgressListener(listener);
|
||||
nextTest();
|
||||
}, true);
|
||||
}
|
||||
156
browser/components/search/test/head.js
Normal file
156
browser/components/search/test/head.js
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
|
||||
/**
|
||||
* Recursively compare two objects and check that every property of expectedObj has the same value
|
||||
* on actualObj.
|
||||
*/
|
||||
function isSubObjectOf(expectedObj, actualObj, name) {
|
||||
for (let prop in expectedObj) {
|
||||
if (typeof expectedObj[prop] == 'function')
|
||||
continue;
|
||||
if (expectedObj[prop] instanceof Object) {
|
||||
is(actualObj[prop].length, expectedObj[prop].length, name + "[" + prop + "]");
|
||||
isSubObjectOf(expectedObj[prop], actualObj[prop], name + "[" + prop + "]");
|
||||
} else {
|
||||
is(actualObj[prop], expectedObj[prop], name + "[" + prop + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getLocale() {
|
||||
const localePref = "general.useragent.locale";
|
||||
return getLocalizedPref(localePref, Services.prefs.getCharPref(localePref));
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for nsIPrefBranch::getComplexValue.
|
||||
* @param aPrefName
|
||||
* The name of the pref to get.
|
||||
* @returns aDefault if the requested pref doesn't exist.
|
||||
*/
|
||||
function getLocalizedPref(aPrefName, aDefault) {
|
||||
try {
|
||||
return Services.prefs.getComplexValue(aPrefName, Ci.nsIPrefLocalizedString).data;
|
||||
} catch (ex) {
|
||||
return aDefault;
|
||||
}
|
||||
}
|
||||
|
||||
function promiseEvent(aTarget, aEventName, aPreventDefault) {
|
||||
function cancelEvent(event) {
|
||||
if (aPreventDefault) {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return BrowserTestUtils.waitForEvent(aTarget, aEventName, false, cancelEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new search engine to the search service and confirms it completes.
|
||||
*
|
||||
* @param {String} basename The file to load that contains the search engine
|
||||
* details.
|
||||
* @param {Object} [options] Options for the test:
|
||||
* - {String} [iconURL] The icon to use for the search engine.
|
||||
* - {Boolean} [setAsCurrent] Whether to set the new engine to be the
|
||||
* current engine or not.
|
||||
* - {String} [testPath] Used to override the current test path if this
|
||||
* file is used from a different directory.
|
||||
* @returns {Promise} The promise is resolved once the engine is added, or
|
||||
* rejected if the addition failed.
|
||||
*/
|
||||
function promiseNewEngine(basename, options = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// Default the setAsCurrent option to true.
|
||||
let setAsCurrent =
|
||||
options.setAsCurrent == undefined ? true : options.setAsCurrent;
|
||||
info("Waiting for engine to be added: " + basename);
|
||||
Services.search.init({
|
||||
onInitComplete: function() {
|
||||
let url = getRootDirectory(options.testPath || gTestPath) + basename;
|
||||
let current = Services.search.currentEngine;
|
||||
Services.search.addEngine(url, null, options.iconURL || "", false, {
|
||||
onSuccess: function (engine) {
|
||||
info("Search engine added: " + basename);
|
||||
if (setAsCurrent) {
|
||||
Services.search.currentEngine = engine;
|
||||
}
|
||||
registerCleanupFunction(() => {
|
||||
if (setAsCurrent) {
|
||||
Services.search.currentEngine = current;
|
||||
}
|
||||
Services.search.removeEngine(engine);
|
||||
info("Search engine removed: " + basename);
|
||||
});
|
||||
resolve(engine);
|
||||
},
|
||||
onError: function (errCode) {
|
||||
ok(false, "addEngine failed with error code " + errCode);
|
||||
reject();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for a load (or custom) event to finish in a given tab. If provided
|
||||
* load an uri into the tab.
|
||||
*
|
||||
* @param tab
|
||||
* The tab to load into.
|
||||
* @param [optional] url
|
||||
* The url to load, or the current url.
|
||||
* @return {Promise} resolved when the event is handled.
|
||||
* @resolves to the received event
|
||||
* @rejects if a valid load event is not received within a meaningful interval
|
||||
*/
|
||||
function promiseTabLoadEvent(tab, url)
|
||||
{
|
||||
info("Wait tab event: load");
|
||||
|
||||
function handle(loadedUrl) {
|
||||
if (loadedUrl === "about:blank" || (url && loadedUrl !== url)) {
|
||||
info(`Skipping spurious load event for ${loadedUrl}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
info("Tab event received: load");
|
||||
return true;
|
||||
}
|
||||
|
||||
let loaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, handle);
|
||||
|
||||
if (url)
|
||||
BrowserTestUtils.loadURI(tab.linkedBrowser, url);
|
||||
|
||||
return loaded;
|
||||
}
|
||||
|
||||
// Get an array of the one-off buttons.
|
||||
function getOneOffs() {
|
||||
let oneOffs = [];
|
||||
let searchPopup = document.getElementById("PopupSearchAutoComplete");
|
||||
let oneOffsContainer =
|
||||
document.getAnonymousElementByAttribute(searchPopup, "anonid",
|
||||
"search-one-off-buttons");
|
||||
let oneOff =
|
||||
document.getAnonymousElementByAttribute(oneOffsContainer, "anonid",
|
||||
"search-panel-one-offs");
|
||||
for (oneOff = oneOff.firstChild; oneOff; oneOff = oneOff.nextSibling) {
|
||||
if (oneOff.nodeType == Node.ELEMENT_NODE) {
|
||||
if (oneOff.classList.contains("dummy") ||
|
||||
oneOff.classList.contains("search-setting-button-compact"))
|
||||
break;
|
||||
oneOffs.push(oneOff);
|
||||
}
|
||||
}
|
||||
return oneOffs;
|
||||
}
|
||||
9
browser/components/search/test/opensearch.html
Normal file
9
browser/components/search/test/opensearch.html
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="search" type="application/opensearchdescription+xml" title="engine1" href="http://mochi.test:8888/browser/browser/components/search/test/testEngine.xml">
|
||||
<link rel="search" type="application/opensearchdescription+xml" title="engine2" href="http://mochi.test:8888/browser/browser/components/search/test/testEngine_mozsearch.xml">
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
||||
8
browser/components/search/test/test.html
Normal file
8
browser/components/search/test/test.html
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Bug 426329</title>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
||||
12
browser/components/search/test/testEngine.xml
Normal file
12
browser/components/search/test/testEngine.xml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/"
|
||||
xmlns:moz="http://www.mozilla.org/2006/browser/search/">
|
||||
<ShortName>Foo</ShortName>
|
||||
<Description>Foo Search</Description>
|
||||
<InputEncoding>utf-8</InputEncoding>
|
||||
<Image width="16" height="16">data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGklEQVQoz2NgGB6AnZ1dUlJSXl4eSDIyMhLW4Ovr%2B%2Fr168uXL69Zs4YoG%2BLi4i5dusTExMTGxsbNzd3f37937976%2BnpmZmagbHR09J49e5YvX66kpATVEBYW9ubNm2nTphkbG7e2tp44cQLIuHfvXm5urpaWFlDKysqqu7v73LlzECMYIiIiHj58mJCQoKKicvXq1bS0NKBgW1vbjh074uPjgeqAXE1NzSdPnvDz84M0AEUvXLgAsW379u1z5swBen3jxo2zZ892cHB4%2BvQp0KlAfwI1cHJyghQFBwfv2rULokFXV%2FfixYu7d%2B8GGqGgoMDKyrpu3br9%2B%2FcDuXl5eVA%2FAEWBfoWHAdAYoNuAYQ0XAeoUERFhGDYAAPoUaT2dfWJuAAAAAElFTkSuQmCC</Image>
|
||||
<Url type="text/html" method="GET" template="http://mochi.test:8888/browser/browser/components/search/test/?search">
|
||||
<Param name="test" value="{searchTerms}"/>
|
||||
</Url>
|
||||
<moz:SearchForm>http://mochi.test:8888/browser/browser/components/search/test/</moz:SearchForm>
|
||||
<moz:Alias>fooalias</moz:Alias>
|
||||
</OpenSearchDescription>
|
||||
12
browser/components/search/test/testEngine_diacritics.xml
Normal file
12
browser/components/search/test/testEngine_diacritics.xml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/"
|
||||
xmlns:moz="http://www.mozilla.org/2006/browser/search/">
|
||||
<ShortName>Foo ♡</ShortName>
|
||||
<Description>Engine whose ShortName contains non-BMP Unicode characters</Description>
|
||||
<InputEncoding>utf-8</InputEncoding>
|
||||
<Image width="16" height="16">data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGklEQVQoz2NgGB6AnZ1dUlJSXl4eSDIyMhLW4Ovr%2B%2Fr168uXL69Zs4YoG%2BLi4i5dusTExMTGxsbNzd3f37937976%2BnpmZmagbHR09J49e5YvX66kpATVEBYW9ubNm2nTphkbG7e2tp44cQLIuHfvXm5urpaWFlDKysqqu7v73LlzECMYIiIiHj58mJCQoKKicvXq1bS0NKBgW1vbjh074uPjgeqAXE1NzSdPnvDz84M0AEUvXLgAsW379u1z5swBen3jxo2zZ892cHB4%2BvQp0KlAfwI1cHJyghQFBwfv2rULokFXV%2FfixYu7d%2B8GGqGgoMDKyrpu3br9%2B%2FcDuXl5eVA%2FAEWBfoWHAdAYoNuAYQ0XAeoUERFhGDYAAPoUaT2dfWJuAAAAAElFTkSuQmCC</Image>
|
||||
<Url type="text/html" method="GET" template="http://mochi.test:8888/browser/browser/components/search/test/?search">
|
||||
<Param name="test" value="{searchTerms}"/>
|
||||
</Url>
|
||||
<moz:SearchForm>http://mochi.test:8888/browser/browser/components/search/test/</moz:SearchForm>
|
||||
<moz:Alias>diacriticalias</moz:Alias>
|
||||
</OpenSearchDescription>
|
||||
12
browser/components/search/test/testEngine_dupe.xml
Normal file
12
browser/components/search/test/testEngine_dupe.xml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/"
|
||||
xmlns:moz="http://www.mozilla.org/2006/browser/search/">
|
||||
<ShortName>FooDupe</ShortName>
|
||||
<Description>Second Engine Search</Description>
|
||||
<InputEncoding>utf-8</InputEncoding>
|
||||
<Image width="16" height="16">data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGklEQVQoz2NgGB6AnZ1dUlJSXl4eSDIyMhLW4Ovr%2B%2Fr168uXL69Zs4YoG%2BLi4i5dusTExMTGxsbNzd3f37937976%2BnpmZmagbHR09J49e5YvX66kpATVEBYW9ubNm2nTphkbG7e2tp44cQLIuHfvXm5urpaWFlDKysqqu7v73LlzECMYIiIiHj58mJCQoKKicvXq1bS0NKBgW1vbjh074uPjgeqAXE1NzSdPnvDz84M0AEUvXLgAsW379u1z5swBen3jxo2zZ892cHB4%2BvQp0KlAfwI1cHJyghQFBwfv2rULokFXV%2FfixYu7d%2B8GGqGgoMDKyrpu3br9%2B%2FcDuXl5eVA%2FAEWBfoWHAdAYoNuAYQ0XAeoUERFhGDYAAPoUaT2dfWJuAAAAAElFTkSuQmCC</Image>
|
||||
<Url type="text/html" method="GET" template="http://mochi.test:8888/browser/browser/components/search/test/?search">
|
||||
<Param name="test" value="{searchTerms}"/>
|
||||
</Url>
|
||||
<moz:SearchForm>http://mochi.test:8888/browser/browser/components/search/test/</moz:SearchForm>
|
||||
<moz:Alias>secondalias</moz:Alias>
|
||||
</OpenSearchDescription>
|
||||
14
browser/components/search/test/testEngine_mozsearch.xml
Normal file
14
browser/components/search/test/testEngine_mozsearch.xml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
|
||||
<ShortName>Foo</ShortName>
|
||||
<Description>Foo Search</Description>
|
||||
<InputEncoding>utf-8</InputEncoding>
|
||||
<Image width="16" height="16">data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGklEQVQoz2NgGB6AnZ1dUlJSXl4eSDIyMhLW4Ovr%2B%2Fr168uXL69Zs4YoG%2BLi4i5dusTExMTGxsbNzd3f37937976%2BnpmZmagbHR09J49e5YvX66kpATVEBYW9ubNm2nTphkbG7e2tp44cQLIuHfvXm5urpaWFlDKysqqu7v73LlzECMYIiIiHj58mJCQoKKicvXq1bS0NKBgW1vbjh074uPjgeqAXE1NzSdPnvDz84M0AEUvXLgAsW379u1z5swBen3jxo2zZ892cHB4%2BvQp0KlAfwI1cHJyghQFBwfv2rULokFXV%2FfixYu7d%2B8GGqGgoMDKyrpu3br9%2B%2FcDuXl5eVA%2FAEWBfoWHAdAYoNuAYQ0XAeoUERFhGDYAAPoUaT2dfWJuAAAAAElFTkSuQmCC</Image>
|
||||
<Url type="application/x-suggestions+json" method="GET" template="http://mochi.test:8888/browser/browser/components/search/test/?suggestions&locale={moz:locale}&test={searchTerms}"/>
|
||||
<Url type="text/html" method="GET" template="http://mochi.test:8888/browser/browser/components/search/test/">
|
||||
<Param name="test" value="{searchTerms}"/>
|
||||
<Param name="ie" value="utf-8"/>
|
||||
<MozParam name="channel" condition="purpose" purpose="keyword" value="keywordsearch"/>
|
||||
<MozParam name="channel" condition="purpose" purpose="contextmenu" value="contextsearch"/>
|
||||
</Url>
|
||||
<SearchForm>http://mochi.test:8888/browser/browser/components/search/test/</SearchForm>
|
||||
</SearchPlugin>
|
||||
16
browser/components/search/test/webapi.html
Normal file
16
browser/components/search/test/webapi.html
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
function installEngine() {
|
||||
var query = window.location.search.substring(1);
|
||||
var args = JSON.parse(decodeURIComponent(query));
|
||||
|
||||
window.external.AddSearchProvider(...args);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="installEngine()">
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue