summaryrefslogtreecommitdiffstats
path: root/browser/base/content/test/urlbar
diff options
context:
space:
mode:
Diffstat (limited to 'browser/base/content/test/urlbar')
-rw-r--r--browser/base/content/test/urlbar/.eslintrc.js7
-rw-r--r--browser/base/content/test/urlbar/authenticate.sjs220
-rw-r--r--browser/base/content/test/urlbar/browser.ini101
-rw-r--r--browser/base/content/test/urlbar/browser_URLBarSetURI.js100
-rw-r--r--browser/base/content/test/urlbar/browser_action_keyword.js119
-rw-r--r--browser/base/content/test/urlbar/browser_action_keyword_override.js40
-rw-r--r--browser/base/content/test/urlbar/browser_action_searchengine.js36
-rw-r--r--browser/base/content/test/urlbar/browser_action_searchengine_alias.js35
-rw-r--r--browser/base/content/test/urlbar/browser_autocomplete_a11y_label.js57
-rw-r--r--browser/base/content/test/urlbar/browser_autocomplete_autoselect.js92
-rw-r--r--browser/base/content/test/urlbar/browser_autocomplete_cursor.js17
-rw-r--r--browser/base/content/test/urlbar/browser_autocomplete_edit_completed.js48
-rw-r--r--browser/base/content/test/urlbar/browser_autocomplete_enter_race.js122
-rw-r--r--browser/base/content/test/urlbar/browser_autocomplete_no_title.js15
-rw-r--r--browser/base/content/test/urlbar/browser_autocomplete_tag_star_visibility.js102
-rw-r--r--browser/base/content/test/urlbar/browser_bug1003461-switchtab-override.js61
-rw-r--r--browser/base/content/test/urlbar/browser_bug1024133-switchtab-override-keynav.js37
-rw-r--r--browser/base/content/test/urlbar/browser_bug1025195_switchToTabHavingURI_aOpenParams.js124
-rw-r--r--browser/base/content/test/urlbar/browser_bug1070778.js55
-rw-r--r--browser/base/content/test/urlbar/browser_bug1104165-switchtab-decodeuri.js29
-rw-r--r--browser/base/content/test/urlbar/browser_bug1225194-remotetab.js16
-rw-r--r--browser/base/content/test/urlbar/browser_bug304198.js109
-rw-r--r--browser/base/content/test/urlbar/browser_bug556061.js98
-rw-r--r--browser/base/content/test/urlbar/browser_bug562649.js24
-rw-r--r--browser/base/content/test/urlbar/browser_bug623155.js137
-rw-r--r--browser/base/content/test/urlbar/browser_bug783614.js13
-rw-r--r--browser/base/content/test/urlbar/browser_canonizeURL.js42
-rw-r--r--browser/base/content/test/urlbar/browser_dragdropURL.js15
-rw-r--r--browser/base/content/test/urlbar/browser_locationBarCommand.js218
-rw-r--r--browser/base/content/test/urlbar/browser_locationBarExternalLoad.js65
-rw-r--r--browser/base/content/test/urlbar/browser_moz_action_link.js31
-rw-r--r--browser/base/content/test/urlbar/browser_removeUnsafeProtocolsFromURLBarPaste.js49
-rw-r--r--browser/base/content/test/urlbar/browser_search_favicon.js52
-rw-r--r--browser/base/content/test/urlbar/browser_tabMatchesInAwesomebar.js216
-rw-r--r--browser/base/content/test/urlbar/browser_tabMatchesInAwesomebar_perwindowpb.js84
-rw-r--r--browser/base/content/test/urlbar/browser_urlHighlight.js134
-rw-r--r--browser/base/content/test/urlbar/browser_urlbarAboutHomeLoading.js104
-rw-r--r--browser/base/content/test/urlbar/browser_urlbarAutoFillTrimURLs.js49
-rw-r--r--browser/base/content/test/urlbar/browser_urlbarCopying.js232
-rw-r--r--browser/base/content/test/urlbar/browser_urlbarDecode.js97
-rw-r--r--browser/base/content/test/urlbar/browser_urlbarDelete.js39
-rw-r--r--browser/base/content/test/urlbar/browser_urlbarEnter.js45
-rw-r--r--browser/base/content/test/urlbar/browser_urlbarEnterAfterMouseOver.js69
-rw-r--r--browser/base/content/test/urlbar/browser_urlbarFocusedCmdK.js17
-rw-r--r--browser/base/content/test/urlbar/browser_urlbarHashChangeProxyState.js111
-rw-r--r--browser/base/content/test/urlbar/browser_urlbarKeepStateAcrossTabSwitches.js49
-rw-r--r--browser/base/content/test/urlbar/browser_urlbarOneOffs.js232
-rw-r--r--browser/base/content/test/urlbar/browser_urlbarPrivateBrowsingWindowChange.js41
-rw-r--r--browser/base/content/test/urlbar/browser_urlbarRaceWithTabs.js57
-rw-r--r--browser/base/content/test/urlbar/browser_urlbarRevert.js37
-rw-r--r--browser/base/content/test/urlbar/browser_urlbarSearchSingleWordNotification.js198
-rw-r--r--browser/base/content/test/urlbar/browser_urlbarSearchSuggestions.js66
-rw-r--r--browser/base/content/test/urlbar/browser_urlbarSearchSuggestionsNotification.js254
-rw-r--r--browser/base/content/test/urlbar/browser_urlbarSearchTelemetry.js216
-rw-r--r--browser/base/content/test/urlbar/browser_urlbarStop.js30
-rw-r--r--browser/base/content/test/urlbar/browser_urlbarTrimURLs.js98
-rw-r--r--browser/base/content/test/urlbar/browser_urlbarUpdateForDomainCompletion.js17
-rw-r--r--browser/base/content/test/urlbar/browser_urlbar_autoFill_backspaced.js146
-rw-r--r--browser/base/content/test/urlbar/browser_urlbar_blanking.js35
-rw-r--r--browser/base/content/test/urlbar/browser_urlbar_locationchange_urlbar_edit_dos.js41
-rw-r--r--browser/base/content/test/urlbar/browser_urlbar_remoteness_switch.js39
-rw-r--r--browser/base/content/test/urlbar/browser_urlbar_searchsettings.js30
-rw-r--r--browser/base/content/test/urlbar/browser_urlbar_stop_pending.js138
-rw-r--r--browser/base/content/test/urlbar/browser_wyciwyg_urlbarCopying.js31
-rw-r--r--browser/base/content/test/urlbar/dummy_page.html9
-rw-r--r--browser/base/content/test/urlbar/file_blank_but_not_blank.html2
-rw-r--r--browser/base/content/test/urlbar/file_urlbar_edit_dos.html23
-rw-r--r--browser/base/content/test/urlbar/head.js205
-rw-r--r--browser/base/content/test/urlbar/moz.pngbin0 -> 580 bytes
-rw-r--r--browser/base/content/test/urlbar/print_postdata.sjs22
-rw-r--r--browser/base/content/test/urlbar/redirect_bug623155.sjs16
-rw-r--r--browser/base/content/test/urlbar/searchSuggestionEngine.sjs9
-rw-r--r--browser/base/content/test/urlbar/searchSuggestionEngine.xml9
-rw-r--r--browser/base/content/test/urlbar/slow-page.sjs22
-rw-r--r--browser/base/content/test/urlbar/test_wyciwyg_copying.html13
75 files changed, 5568 insertions, 0 deletions
diff --git a/browser/base/content/test/urlbar/.eslintrc.js b/browser/base/content/test/urlbar/.eslintrc.js
new file mode 100644
index 000000000..7c8021192
--- /dev/null
+++ b/browser/base/content/test/urlbar/.eslintrc.js
@@ -0,0 +1,7 @@
+"use strict";
+
+module.exports = {
+ "extends": [
+ "../../../../../testing/mochitest/browser.eslintrc.js"
+ ]
+};
diff --git a/browser/base/content/test/urlbar/authenticate.sjs b/browser/base/content/test/urlbar/authenticate.sjs
new file mode 100644
index 000000000..58da655cf
--- /dev/null
+++ b/browser/base/content/test/urlbar/authenticate.sjs
@@ -0,0 +1,220 @@
+function handleRequest(request, response)
+{
+ try {
+ reallyHandleRequest(request, response);
+ } catch (e) {
+ response.setStatusLine("1.0", 200, "AlmostOK");
+ response.write("Error handling request: " + e);
+ }
+}
+
+
+function reallyHandleRequest(request, response) {
+ var match;
+ var requestAuth = true, requestProxyAuth = true;
+
+ // Allow the caller to drive how authentication is processed via the query.
+ // Eg, http://localhost:8888/authenticate.sjs?user=foo&realm=bar
+ // The extra ? allows the user/pass/realm checks to succeed if the name is
+ // at the beginning of the query string.
+ var query = "?" + request.queryString;
+
+ var expected_user = "", expected_pass = "", realm = "mochitest";
+ var proxy_expected_user = "", proxy_expected_pass = "", proxy_realm = "mochi-proxy";
+ var huge = false, plugin = false, anonymous = false;
+ var authHeaderCount = 1;
+ // user=xxx
+ match = /[^_]user=([^&]*)/.exec(query);
+ if (match)
+ expected_user = match[1];
+
+ // pass=xxx
+ match = /[^_]pass=([^&]*)/.exec(query);
+ if (match)
+ expected_pass = match[1];
+
+ // realm=xxx
+ match = /[^_]realm=([^&]*)/.exec(query);
+ if (match)
+ realm = match[1];
+
+ // proxy_user=xxx
+ match = /proxy_user=([^&]*)/.exec(query);
+ if (match)
+ proxy_expected_user = match[1];
+
+ // proxy_pass=xxx
+ match = /proxy_pass=([^&]*)/.exec(query);
+ if (match)
+ proxy_expected_pass = match[1];
+
+ // proxy_realm=xxx
+ match = /proxy_realm=([^&]*)/.exec(query);
+ if (match)
+ proxy_realm = match[1];
+
+ // huge=1
+ match = /huge=1/.exec(query);
+ if (match)
+ huge = true;
+
+ // plugin=1
+ match = /plugin=1/.exec(query);
+ if (match)
+ plugin = true;
+
+ // multiple=1
+ match = /multiple=([^&]*)/.exec(query);
+ if (match)
+ authHeaderCount = match[1]+0;
+
+ // anonymous=1
+ match = /anonymous=1/.exec(query);
+ if (match)
+ anonymous = true;
+
+ // Look for an authentication header, if any, in the request.
+ //
+ // EG: Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
+ //
+ // This test only supports Basic auth. The value sent by the client is
+ // "username:password", obscured with base64 encoding.
+
+ var actual_user = "", actual_pass = "", authHeader, authPresent = false;
+ if (request.hasHeader("Authorization")) {
+ authPresent = true;
+ authHeader = request.getHeader("Authorization");
+ match = /Basic (.+)/.exec(authHeader);
+ if (match.length != 2)
+ throw "Couldn't parse auth header: " + authHeader;
+
+ var userpass = base64ToString(match[1]); // no atob() :-(
+ match = /(.*):(.*)/.exec(userpass);
+ if (match.length != 3)
+ throw "Couldn't decode auth header: " + userpass;
+ actual_user = match[1];
+ actual_pass = match[2];
+ }
+
+ var proxy_actual_user = "", proxy_actual_pass = "";
+ if (request.hasHeader("Proxy-Authorization")) {
+ authHeader = request.getHeader("Proxy-Authorization");
+ match = /Basic (.+)/.exec(authHeader);
+ if (match.length != 2)
+ throw "Couldn't parse auth header: " + authHeader;
+
+ var userpass = base64ToString(match[1]); // no atob() :-(
+ match = /(.*):(.*)/.exec(userpass);
+ if (match.length != 3)
+ throw "Couldn't decode auth header: " + userpass;
+ proxy_actual_user = match[1];
+ proxy_actual_pass = match[2];
+ }
+
+ // Don't request authentication if the credentials we got were what we
+ // expected.
+ if (expected_user == actual_user &&
+ expected_pass == actual_pass) {
+ requestAuth = false;
+ }
+ if (proxy_expected_user == proxy_actual_user &&
+ proxy_expected_pass == proxy_actual_pass) {
+ requestProxyAuth = false;
+ }
+
+ if (anonymous) {
+ if (authPresent) {
+ response.setStatusLine("1.0", 400, "Unexpected authorization header found");
+ } else {
+ response.setStatusLine("1.0", 200, "Authorization header not found");
+ }
+ } else {
+ if (requestProxyAuth) {
+ response.setStatusLine("1.0", 407, "Proxy authentication required");
+ for (i = 0; i < authHeaderCount; ++i)
+ response.setHeader("Proxy-Authenticate", "basic realm=\"" + proxy_realm + "\"", true);
+ } else if (requestAuth) {
+ response.setStatusLine("1.0", 401, "Authentication required");
+ for (i = 0; i < authHeaderCount; ++i)
+ response.setHeader("WWW-Authenticate", "basic realm=\"" + realm + "\"", true);
+ } else {
+ response.setStatusLine("1.0", 200, "OK");
+ }
+ }
+
+ response.setHeader("Content-Type", "application/xhtml+xml", false);
+ response.write("<html xmlns='http://www.w3.org/1999/xhtml'>");
+ response.write("<p>Login: <span id='ok'>" + (requestAuth ? "FAIL" : "PASS") + "</span></p>\n");
+ response.write("<p>Proxy: <span id='proxy'>" + (requestProxyAuth ? "FAIL" : "PASS") + "</span></p>\n");
+ response.write("<p>Auth: <span id='auth'>" + authHeader + "</span></p>\n");
+ response.write("<p>User: <span id='user'>" + actual_user + "</span></p>\n");
+ response.write("<p>Pass: <span id='pass'>" + actual_pass + "</span></p>\n");
+
+ if (huge) {
+ response.write("<div style='display: none'>");
+ for (i = 0; i < 100000; i++) {
+ response.write("123456789\n");
+ }
+ response.write("</div>");
+ response.write("<span id='footnote'>This is a footnote after the huge content fill</span>");
+ }
+
+ if (plugin) {
+ response.write("<embed id='embedtest' style='width: 400px; height: 100px;' " +
+ "type='application/x-test'></embed>\n");
+ }
+
+ response.write("</html>");
+}
+
+
+// base64 decoder
+//
+// Yoinked from extensions/xml-rpc/src/nsXmlRpcClient.js because btoa()
+// doesn't seem to exist. :-(
+/* Convert Base64 data to a string */
+const toBinaryTable = [
+ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
+ 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1, 0,-1,-1,
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
+ 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
+ -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
+ 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
+];
+const base64Pad = '=';
+
+function base64ToString(data) {
+
+ var result = '';
+ var leftbits = 0; // number of bits decoded, but yet to be appended
+ var leftdata = 0; // bits decoded, but yet to be appended
+
+ // Convert one by one.
+ for (var i = 0; i < data.length; i++) {
+ var c = toBinaryTable[data.charCodeAt(i) & 0x7f];
+ var padding = (data[i] == base64Pad);
+ // Skip illegal characters and whitespace
+ if (c == -1) continue;
+
+ // Collect data into leftdata, update bitcount
+ leftdata = (leftdata << 6) | c;
+ leftbits += 6;
+
+ // If we have 8 or more bits, append 8 bits to the result
+ if (leftbits >= 8) {
+ leftbits -= 8;
+ // Append if not padding.
+ if (!padding)
+ result += String.fromCharCode((leftdata >> leftbits) & 0xff);
+ leftdata &= (1 << leftbits) - 1;
+ }
+ }
+
+ // If there are any bits left, the base64 string was corrupted
+ if (leftbits)
+ throw Components.Exception('Corrupted base64 string');
+
+ return result;
+}
diff --git a/browser/base/content/test/urlbar/browser.ini b/browser/base/content/test/urlbar/browser.ini
new file mode 100644
index 000000000..39bc086c9
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser.ini
@@ -0,0 +1,101 @@
+[DEFAULT]
+support-files =
+ dummy_page.html
+ head.js
+
+[browser_URLBarSetURI.js]
+skip-if = (os == "linux" || os == "mac") && debug # bug 970052, bug 970053
+[browser_action_keyword.js]
+skip-if = os == "linux" # Bug 1188154
+support-files =
+ print_postdata.sjs
+[browser_action_keyword_override.js]
+[browser_action_searchengine.js]
+[browser_action_searchengine_alias.js]
+[browser_autocomplete_a11y_label.js]
+[browser_autocomplete_autoselect.js]
+[browser_autocomplete_cursor.js]
+[browser_autocomplete_edit_completed.js]
+[browser_autocomplete_enter_race.js]
+[browser_autocomplete_no_title.js]
+[browser_autocomplete_tag_star_visibility.js]
+[browser_bug1104165-switchtab-decodeuri.js]
+[browser_bug1003461-switchtab-override.js]
+[browser_bug1024133-switchtab-override-keynav.js]
+[browser_bug1025195_switchToTabHavingURI_aOpenParams.js]
+[browser_bug1070778.js]
+[browser_bug1225194-remotetab.js]
+[browser_bug304198.js]
+[browser_bug556061.js]
+subsuite = clipboard
+[browser_bug562649.js]
+[browser_bug623155.js]
+support-files =
+ redirect_bug623155.sjs
+[browser_bug783614.js]
+[browser_canonizeURL.js]
+[browser_dragdropURL.js]
+[browser_locationBarCommand.js]
+[browser_locationBarExternalLoad.js]
+[browser_moz_action_link.js]
+[browser_removeUnsafeProtocolsFromURLBarPaste.js]
+subsuite = clipboard
+[browser_search_favicon.js]
+[browser_tabMatchesInAwesomebar.js]
+support-files =
+ moz.png
+[browser_tabMatchesInAwesomebar_perwindowpb.js]
+skip-if = os == 'linux' # Bug 1104755
+[browser_urlbarAboutHomeLoading.js]
+[browser_urlbarAutoFillTrimURLs.js]
+[browser_urlbarCopying.js]
+subsuite = clipboard
+support-files =
+ authenticate.sjs
+[browser_urlbarDecode.js]
+[browser_urlbarDelete.js]
+[browser_urlbarEnter.js]
+[browser_urlbarEnterAfterMouseOver.js]
+skip-if = os == "linux" # Bug 1073339 - Investigate autocomplete test unreliability on Linux/e10s
+[browser_urlbarFocusedCmdK.js]
+[browser_urlbarHashChangeProxyState.js]
+[browser_urlbarKeepStateAcrossTabSwitches.js]
+[browser_urlbarOneOffs.js]
+[browser_urlbarPrivateBrowsingWindowChange.js]
+[browser_urlbarRaceWithTabs.js]
+[browser_urlbarRevert.js]
+[browser_urlbarSearchSingleWordNotification.js]
+[browser_urlbarSearchSuggestions.js]
+support-files =
+ searchSuggestionEngine.xml
+ searchSuggestionEngine.sjs
+[browser_urlbarSearchSuggestionsNotification.js]
+support-files =
+ searchSuggestionEngine.xml
+ searchSuggestionEngine.sjs
+[browser_urlbarSearchTelemetry.js]
+support-files =
+ searchSuggestionEngine.xml
+ searchSuggestionEngine.sjs
+[browser_urlbarStop.js]
+[browser_urlbarTrimURLs.js]
+subsuite = clipboard
+[browser_urlbarUpdateForDomainCompletion.js]
+[browser_urlbar_autoFill_backspaced.js]
+[browser_urlbar_blanking.js]
+support-files =
+ file_blank_but_not_blank.html
+[browser_urlbar_locationchange_urlbar_edit_dos.js]
+support-files =
+ file_urlbar_edit_dos.html
+[browser_urlbar_searchsettings.js]
+[browser_urlbar_stop_pending.js]
+support-files =
+ slow-page.sjs
+[browser_urlbar_remoteness_switch.js]
+run-if = e10s
+[browser_urlHighlight.js]
+[browser_wyciwyg_urlbarCopying.js]
+subsuite = clipboard
+support-files =
+ test_wyciwyg_copying.html
diff --git a/browser/base/content/test/urlbar/browser_URLBarSetURI.js b/browser/base/content/test/urlbar/browser_URLBarSetURI.js
new file mode 100644
index 000000000..ac8352f1a
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_URLBarSetURI.js
@@ -0,0 +1,100 @@
+/* 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/. */
+
+function test() {
+ waitForExplicitFinish();
+
+ // avoid prompting about phishing
+ Services.prefs.setIntPref(phishyUserPassPref, 32);
+ registerCleanupFunction(function () {
+ Services.prefs.clearUserPref(phishyUserPassPref);
+ });
+
+ nextTest();
+}
+
+const phishyUserPassPref = "network.http.phishy-userpass-length";
+
+function nextTest() {
+ let test = tests.shift();
+ if (test) {
+ test(function () {
+ executeSoon(nextTest);
+ });
+ } else {
+ executeSoon(finish);
+ }
+}
+
+var tests = [
+ function revert(next) {
+ loadTabInWindow(window, function (tab) {
+ gURLBar.handleRevert();
+ is(gURLBar.textValue, "example.com", "URL bar had user/pass stripped after reverting");
+ gBrowser.removeTab(tab);
+ next();
+ });
+ },
+ function customize(next) {
+ // Need to wait for delayedStartup for the customization part of the test,
+ // since that's where BrowserToolboxCustomizeDone is set.
+ BrowserTestUtils.openNewBrowserWindow().then(function(win) {
+ loadTabInWindow(win, function () {
+ openToolbarCustomizationUI(function () {
+ closeToolbarCustomizationUI(function () {
+ is(win.gURLBar.textValue, "example.com", "URL bar had user/pass stripped after customize");
+ win.close();
+ next();
+ }, win);
+ }, win);
+ });
+ });
+ },
+ function pageloaderror(next) {
+ loadTabInWindow(window, function (tab) {
+ // Load a new URL and then immediately stop it, to simulate a page load
+ // error.
+ tab.linkedBrowser.loadURI("http://test1.example.com");
+ tab.linkedBrowser.stop();
+ is(gURLBar.textValue, "example.com", "URL bar had user/pass stripped after load error");
+ gBrowser.removeTab(tab);
+ next();
+ });
+ }
+];
+
+function loadTabInWindow(win, callback) {
+ info("Loading tab");
+ let url = "http://user:pass@example.com/";
+ let tab = win.gBrowser.selectedTab = win.gBrowser.addTab(url);
+ BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, url).then(() => {
+ info("Tab loaded");
+ is(win.gURLBar.textValue, "example.com", "URL bar had user/pass stripped initially");
+ callback(tab);
+ }, true);
+}
+
+function openToolbarCustomizationUI(aCallback, aBrowserWin) {
+ if (!aBrowserWin)
+ aBrowserWin = window;
+
+ aBrowserWin.gCustomizeMode.enter();
+
+ aBrowserWin.gNavToolbox.addEventListener("customizationready", function UI_loaded() {
+ aBrowserWin.gNavToolbox.removeEventListener("customizationready", UI_loaded);
+ executeSoon(function() {
+ aCallback(aBrowserWin)
+ });
+ });
+}
+
+function closeToolbarCustomizationUI(aCallback, aBrowserWin) {
+ aBrowserWin.gNavToolbox.addEventListener("aftercustomization", function unloaded() {
+ aBrowserWin.gNavToolbox.removeEventListener("aftercustomization", unloaded);
+ executeSoon(aCallback);
+ });
+
+ aBrowserWin.gCustomizeMode.exit();
+}
+
diff --git a/browser/base/content/test/urlbar/browser_action_keyword.js b/browser/base/content/test/urlbar/browser_action_keyword.js
new file mode 100644
index 000000000..854a7b82f
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_action_keyword.js
@@ -0,0 +1,119 @@
+function* promise_first_result(inputText) {
+ yield promiseAutocompleteResultPopup(inputText);
+
+ let firstResult = gURLBar.popup.richlistbox.firstChild;
+ return firstResult;
+}
+
+const TEST_URL = "http://mochi.test:8888/browser/browser/base/content/test/urlbar/print_postdata.sjs";
+
+add_task(function* setup() {
+ yield PlacesUtils.keywords.insert({ keyword: "get",
+ url: TEST_URL + "?q=%s" });
+ yield PlacesUtils.keywords.insert({ keyword: "post",
+ url: TEST_URL,
+ postData: "q=%s" });
+ registerCleanupFunction(function* () {
+ yield PlacesUtils.keywords.remove("get");
+ yield PlacesUtils.keywords.remove("post");
+ while (gBrowser.tabs.length > 1) {
+ yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
+ }
+ });
+});
+
+add_task(function* get_keyword() {
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:mozilla");
+
+ let result = yield promise_first_result("get something");
+ isnot(result, null, "Expect a keyword result");
+
+ let types = new Set(result.getAttribute("type").split(/\s+/));
+ Assert.ok(types.has("keyword"));
+ is(result.getAttribute("actiontype"), "keyword", "Expect correct `actiontype` attribute");
+ is(result.getAttribute("title"), "mochi.test:8888", "Expect correct title");
+
+ // We need to make a real URI out of this to ensure it's normalised for
+ // comparison.
+ let uri = NetUtil.newURI(result.getAttribute("url"));
+ is(uri.spec, PlacesUtils.mozActionURI("keyword",
+ { url: TEST_URL + "?q=something",
+ input: "get something"}),
+ "Expect correct url");
+
+ let titleHbox = result._titleText.parentNode.parentNode;
+ ok(titleHbox.classList.contains("ac-title"), "Title hbox element sanity check");
+ is_element_visible(titleHbox, "Title element should be visible");
+ is(result._titleText.textContent, "mochi.test:8888: something",
+ "Node should contain the name of the bookmark and query");
+
+ let urlHbox = result._urlText.parentNode.parentNode;
+ ok(urlHbox.classList.contains("ac-url"), "URL hbox element sanity check");
+ is_element_hidden(urlHbox, "URL element should be hidden");
+
+ let actionHbox = result._actionText.parentNode.parentNode;
+ ok(actionHbox.classList.contains("ac-action"), "Action hbox element sanity check");
+ is_element_visible(actionHbox, "Action element should be visible");
+ is(result._actionText.textContent, "", "Action text should be empty");
+
+ // Click on the result
+ info("Normal click on result");
+ let tabPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+ EventUtils.synthesizeMouseAtCenter(result, {});
+ yield tabPromise;
+ is(tab.linkedBrowser.currentURI.spec, TEST_URL + "?q=something",
+ "Tab should have loaded from clicking on result");
+
+ // Middle-click on the result
+ info("Middle-click on result");
+ result = yield promise_first_result("get somethingmore");
+ isnot(result, null, "Expect a keyword result");
+ // We need to make a real URI out of this to ensure it's normalised for
+ // comparison.
+ uri = NetUtil.newURI(result.getAttribute("url"));
+ is(uri.spec, PlacesUtils.mozActionURI("keyword",
+ { url: TEST_URL + "?q=somethingmore",
+ input: "get somethingmore" }),
+ "Expect correct url");
+
+ tabPromise = BrowserTestUtils.waitForEvent(gBrowser.tabContainer, "TabOpen");
+ EventUtils.synthesizeMouseAtCenter(result, {button: 1});
+ let tabOpenEvent = yield tabPromise;
+ let newTab = tabOpenEvent.target;
+ yield BrowserTestUtils.browserLoaded(newTab.linkedBrowser);
+ is(newTab.linkedBrowser.currentURI.spec,
+ TEST_URL + "?q=somethingmore",
+ "Tab should have loaded from middle-clicking on result");
+});
+
+
+add_task(function* post_keyword() {
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:mozilla");
+
+ let result = yield promise_first_result("post something");
+ isnot(result, null, "Expect a keyword result");
+
+ let types = new Set(result.getAttribute("type").split(/\s+/));
+ Assert.ok(types.has("keyword"));
+ is(result.getAttribute("actiontype"), "keyword", "Expect correct `actiontype` attribute");
+ is(result.getAttribute("title"), "mochi.test:8888", "Expect correct title");
+
+ is(result.getAttribute("url"),
+ PlacesUtils.mozActionURI("keyword", { url: TEST_URL,
+ input: "post something",
+ "postData": "q=something" }),
+ "Expect correct url");
+
+ // Click on the result
+ info("Normal click on result");
+ let tabPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+ EventUtils.synthesizeMouseAtCenter(result, {});
+ yield tabPromise;
+ is(tab.linkedBrowser.currentURI.spec, TEST_URL,
+ "Tab should have loaded from clicking on result");
+
+ let postData = yield ContentTask.spawn(tab.linkedBrowser, null, function* () {
+ return content.document.body.textContent;
+ });
+ is(postData, "q=something", "post data was submitted correctly");
+});
diff --git a/browser/base/content/test/urlbar/browser_action_keyword_override.js b/browser/base/content/test/urlbar/browser_action_keyword_override.js
new file mode 100644
index 000000000..f5a865678
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_action_keyword_override.js
@@ -0,0 +1,40 @@
+add_task(function*() {
+ let bm = yield PlacesUtils.bookmarks.insert({ parentGuid: PlacesUtils.bookmarks.unfiledGuid,
+ url: "http://example.com/?q=%s",
+ title: "test" });
+ yield PlacesUtils.keywords.insert({ keyword: "keyword",
+ url: "http://example.com/?q=%s" })
+
+ registerCleanupFunction(function* () {
+ yield PlacesUtils.bookmarks.remove(bm);
+ });
+
+ yield promiseAutocompleteResultPopup("keyword search");
+ let result = gURLBar.popup.richlistbox.children[0];
+
+ info("Before override");
+ let titleHbox = result._titleText.parentNode.parentNode;
+ ok(titleHbox.classList.contains("ac-title"), "Title hbox element sanity check");
+ is_element_visible(titleHbox, "Title element should be visible");
+
+ let urlHbox = result._urlText.parentNode.parentNode;
+ ok(urlHbox.classList.contains("ac-url"), "URL hbox element sanity check");
+ is_element_hidden(urlHbox, "URL element should be hidden");
+
+ let actionHbox = result._actionText.parentNode.parentNode;
+ ok(actionHbox.classList.contains("ac-action"), "Action hbox element sanity check");
+ is_element_visible(actionHbox, "Action element should be visible");
+ is(result._actionText.textContent, "", "Action text should be empty");
+
+ info("During override");
+ EventUtils.synthesizeKey("VK_SHIFT", { type: "keydown" });
+ is_element_visible(titleHbox, "Title element should be visible");
+ is_element_hidden(urlHbox, "URL element should be hidden");
+ is_element_visible(actionHbox, "Action element should be visible");
+ is(result._actionText.textContent, "", "Action text should be empty");
+
+ EventUtils.synthesizeKey("VK_SHIFT", { type: "keyup" });
+
+ gURLBar.popup.hidePopup();
+ yield promisePopupHidden(gURLBar.popup);
+});
diff --git a/browser/base/content/test/urlbar/browser_action_searchengine.js b/browser/base/content/test/urlbar/browser_action_searchengine.js
new file mode 100644
index 000000000..d2115abba
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_action_searchengine.js
@@ -0,0 +1,36 @@
+add_task(function* () {
+ Services.search.addEngineWithDetails("MozSearch", "", "", "", "GET",
+ "http://example.com/?q={searchTerms}");
+ let engine = Services.search.getEngineByName("MozSearch");
+ let originalEngine = Services.search.currentEngine;
+ Services.search.currentEngine = engine;
+
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:mozilla");
+
+ registerCleanupFunction(() => {
+ Services.search.currentEngine = originalEngine;
+ let engine = Services.search.getEngineByName("MozSearch");
+ Services.search.removeEngine(engine);
+
+ try {
+ gBrowser.removeTab(tab);
+ } catch (ex) { /* tab may have already been closed in case of failure */ }
+
+ return PlacesTestUtils.clearHistory();
+ });
+
+ yield promiseAutocompleteResultPopup("open a search");
+ let result = gURLBar.popup.richlistbox.firstChild;
+
+ isnot(result, null, "Should have a result");
+ is(result.getAttribute("url"),
+ `moz-action:searchengine,{"engineName":"MozSearch","input":"open%20a%20search","searchQuery":"open%20a%20search"}`,
+ "Result should be a moz-action: for the correct search engine");
+ is(result.hasAttribute("image"), false, "Result shouldn't have an image attribute");
+
+ let tabPromise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+ result.click();
+ yield tabPromise;
+
+ is(gBrowser.selectedBrowser.currentURI.spec, "http://example.com/?q=open+a+search", "Correct URL should be loaded");
+});
diff --git a/browser/base/content/test/urlbar/browser_action_searchengine_alias.js b/browser/base/content/test/urlbar/browser_action_searchengine_alias.js
new file mode 100644
index 000000000..1967d178a
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_action_searchengine_alias.js
@@ -0,0 +1,35 @@
+add_task(function* () {
+ let iconURI = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGklEQVQoz2NgGB6AnZ1dUlJSXl4eSDIyMhLW4Ovr%2B%2Fr168uXL69Zs4YoG%2BLi4i5dusTExMTGxsbNzd3f37937976%2BnpmZmagbHR09J49e5YvX66kpATVEBYW9ubNm2nTphkbG7e2tp44cQLIuHfvXm5urpaWFlDKysqqu7v73LlzECMYIiIiHj58mJCQoKKicvXq1bS0NKBgW1vbjh074uPjgeqAXE1NzSdPnvDz84M0AEUvXLgAsW379u1z5swBen3jxo2zZ892cHB4%2BvQp0KlAfwI1cHJyghQFBwfv2rULokFXV%2FfixYu7d%2B8GGqGgoMDKyrpu3br9%2B%2FcDuXl5eVA%2FAEWBfoWHAdAYoNuAYQ0XAeoUERFhGDYAAPoUaT2dfWJuAAAAAElFTkSuQmCC";
+ Services.search.addEngineWithDetails("MozSearch", iconURI, "moz", "", "GET",
+ "http://example.com/?q={searchTerms}");
+ let engine = Services.search.getEngineByName("MozSearch");
+ let originalEngine = Services.search.currentEngine;
+ Services.search.currentEngine = engine;
+
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:mozilla");
+
+ registerCleanupFunction(() => {
+ Services.search.currentEngine = originalEngine;
+ let engine = Services.search.getEngineByName("MozSearch");
+ Services.search.removeEngine(engine);
+
+ try {
+ gBrowser.removeTab(tab);
+ } catch (ex) { /* tab may have already been closed in case of failure */ }
+
+ return PlacesTestUtils.clearHistory();
+ });
+
+ yield promiseAutocompleteResultPopup("moz open a search");
+
+ let result = gURLBar.popup.richlistbox.children[0];
+ ok(result.hasAttribute("image"), "Result should have an image attribute");
+ ok(result.getAttribute("image") === engine.iconURI.spec,
+ "Image attribute should have the search engine's icon");
+
+ let tabPromise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+ EventUtils.synthesizeKey("VK_RETURN", { });
+ yield tabPromise;
+
+ is(gBrowser.selectedBrowser.currentURI.spec, "http://example.com/?q=open+a+search");
+});
diff --git a/browser/base/content/test/urlbar/browser_autocomplete_a11y_label.js b/browser/base/content/test/urlbar/browser_autocomplete_a11y_label.js
new file mode 100644
index 000000000..a27f9672e
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_autocomplete_a11y_label.js
@@ -0,0 +1,57 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const SUGGEST_ALL_PREF = "browser.search.suggest.enabled";
+const SUGGEST_URLBAR_PREF = "browser.urlbar.suggest.searches";
+const TEST_ENGINE_BASENAME = "searchSuggestionEngine.xml";
+
+add_task(function* switchToTab() {
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:about");
+
+ yield promiseAutocompleteResultPopup("% about");
+
+ ok(gURLBar.popup.richlistbox.children.length > 1, "Should get at least 2 results");
+ let result = gURLBar.popup.richlistbox.children[1];
+ is(result.getAttribute("type"), "switchtab", "Expect right type attribute");
+ is(result.label, "about:about about:about Tab", "Result a11y label should be: <title> <url> Tab");
+
+ gURLBar.popup.hidePopup();
+ yield promisePopupHidden(gURLBar.popup);
+ gBrowser.removeTab(tab);
+});
+
+add_task(function* searchSuggestions() {
+ let engine = yield promiseNewSearchEngine(TEST_ENGINE_BASENAME);
+ let oldCurrentEngine = Services.search.currentEngine;
+ Services.search.currentEngine = engine;
+ Services.prefs.setBoolPref(SUGGEST_ALL_PREF, true);
+ Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, true);
+ registerCleanupFunction(function () {
+ Services.search.currentEngine = oldCurrentEngine;
+ Services.prefs.clearUserPref(SUGGEST_ALL_PREF);
+ Services.prefs.clearUserPref(SUGGEST_URLBAR_PREF);
+ });
+
+ yield promiseAutocompleteResultPopup("foo");
+ // Don't assume that the search doesn't match history or bookmarks left around
+ // by earlier tests.
+ Assert.ok(gURLBar.popup.richlistbox.children.length >= 3,
+ "Should get at least heuristic result + two search suggestions");
+ // The first expected search is the search term itself since the heuristic
+ // result will come before the search suggestions.
+ let expectedSearches = [
+ "foo",
+ "foofoo",
+ "foobar",
+ ];
+ for (let child of gURLBar.popup.richlistbox.children) {
+ if (child.getAttribute("type").split(/\s+/).indexOf("searchengine") >= 0) {
+ Assert.ok(expectedSearches.length > 0);
+ let suggestion = expectedSearches.shift();
+ Assert.equal(child.label, suggestion + " browser_searchSuggestionEngine searchSuggestionEngine.xml Search",
+ "Result label should be: <search term> <engine name> Search");
+ }
+ }
+ Assert.ok(expectedSearches.length == 0);
+ gURLBar.closePopup();
+});
diff --git a/browser/base/content/test/urlbar/browser_autocomplete_autoselect.js b/browser/base/content/test/urlbar/browser_autocomplete_autoselect.js
new file mode 100644
index 000000000..e4e0daa8e
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_autocomplete_autoselect.js
@@ -0,0 +1,92 @@
+const ONEOFF_URLBAR_PREF = "browser.urlbar.oneOffSearches";
+
+function repeat(limit, func) {
+ for (let i = 0; i < limit; i++) {
+ func(i);
+ }
+}
+
+function is_selected(index) {
+ is(gURLBar.popup.richlistbox.selectedIndex, index, `Item ${index + 1} should be selected`);
+
+ // This is true because although both the listbox and the one-offs can have
+ // selections, the test doesn't check that.
+ is(gURLBar.popup.oneOffSearchButtons.selectedButton, null,
+ "A result is selected, so the one-offs should not have a selection");
+}
+
+function is_selected_one_off(index) {
+ is(gURLBar.popup.oneOffSearchButtons.selectedButtonIndex, index,
+ "Expected one-off button should be selected");
+
+ // This is true because although both the listbox and the one-offs can have
+ // selections, the test doesn't check that.
+ is(gURLBar.popup.richlistbox.selectedIndex, -1,
+ "A one-off is selected, so the listbox should not have a selection");
+}
+
+add_task(function*() {
+ let maxResults = Services.prefs.getIntPref("browser.urlbar.maxRichResults");
+
+ Services.prefs.setBoolPref(ONEOFF_URLBAR_PREF, true);
+ registerCleanupFunction(function* () {
+ yield PlacesTestUtils.clearHistory();
+ Services.prefs.clearUserPref(ONEOFF_URLBAR_PREF);
+ });
+
+ let visits = [];
+ repeat(maxResults, i => {
+ visits.push({
+ uri: makeURI("http://example.com/autocomplete/?" + i),
+ });
+ });
+ yield PlacesTestUtils.addVisits(visits);
+
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:mozilla");
+ yield promiseAutocompleteResultPopup("example.com/autocomplete");
+
+ let popup = gURLBar.popup;
+ let results = popup.richlistbox.children;
+ is(results.length, maxResults,
+ "Should get maxResults=" + maxResults + " results");
+ is_selected(0);
+
+ info("Key Down to select the next item");
+ EventUtils.synthesizeKey("VK_DOWN", {});
+ is_selected(1);
+
+ info("Key Down maxResults-1 times should select the first one-off");
+ repeat(maxResults - 1, () => EventUtils.synthesizeKey("VK_DOWN", {}));
+ is_selected_one_off(0);
+
+ info("Key Down numButtons-1 should select the last one-off");
+ let numButtons =
+ gURLBar.popup.oneOffSearchButtons.getSelectableButtons(true).length;
+ repeat(numButtons - 1, () => EventUtils.synthesizeKey("VK_DOWN", {}));
+ is_selected_one_off(numButtons - 1);
+
+ info("Key Down twice more should select the second result");
+ repeat(2, () => EventUtils.synthesizeKey("VK_DOWN", {}));
+ is_selected(1);
+
+ info("Key Down maxResults + numButtons times should wrap around");
+ repeat(maxResults + numButtons,
+ () => EventUtils.synthesizeKey("VK_DOWN", {}));
+ is_selected(1);
+
+ info("Key Up maxResults + numButtons times should wrap around the other way");
+ repeat(maxResults + numButtons, () => EventUtils.synthesizeKey("VK_UP", {}));
+ is_selected(1);
+
+ info("Page Up will go up the list, but not wrap");
+ EventUtils.synthesizeKey("VK_PAGE_UP", {})
+ is_selected(0);
+
+ info("Page Up again will wrap around to the end of the list");
+ EventUtils.synthesizeKey("VK_PAGE_UP", {})
+ is_selected(maxResults - 1);
+
+ EventUtils.synthesizeKey("VK_ESCAPE", {});
+ yield promisePopupHidden(gURLBar.popup);
+ gBrowser.removeTab(tab);
+});
diff --git a/browser/base/content/test/urlbar/browser_autocomplete_cursor.js b/browser/base/content/test/urlbar/browser_autocomplete_cursor.js
new file mode 100644
index 000000000..9cc2c6eac
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_autocomplete_cursor.js
@@ -0,0 +1,17 @@
+add_task(function*() {
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:mozilla");
+ yield promiseAutocompleteResultPopup("www.mozilla.org");
+
+ gURLBar.selectTextRange(4, 4);
+
+ is(gURLBar.popup.state, "open", "Popup should be open");
+ is(gURLBar.popup.richlistbox.selectedIndex, 0, "Should have selected something");
+
+ EventUtils.synthesizeKey("VK_RIGHT", {});
+ yield promisePopupHidden(gURLBar.popup);
+
+ is(gURLBar.selectionStart, 5, "Should have moved the cursor");
+ is(gURLBar.selectionEnd, 5, "And not selected anything");
+
+ gBrowser.removeTab(tab);
+});
diff --git a/browser/base/content/test/urlbar/browser_autocomplete_edit_completed.js b/browser/base/content/test/urlbar/browser_autocomplete_edit_completed.js
new file mode 100644
index 000000000..19db1a368
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_autocomplete_edit_completed.js
@@ -0,0 +1,48 @@
+add_task(function*() {
+ yield PlacesTestUtils.clearHistory();
+
+ yield PlacesTestUtils.addVisits([
+ { uri: makeURI("http://example.com/foo") },
+ { uri: makeURI("http://example.com/foo/bar") },
+ ]);
+
+ registerCleanupFunction(function* () {
+ yield PlacesTestUtils.clearHistory();
+ });
+
+ gBrowser.selectedTab = gBrowser.addTab("about:blank");
+ gURLBar.focus();
+
+ yield promiseAutocompleteResultPopup("http://example.com");
+
+ let popup = gURLBar.popup;
+ let list = popup.richlistbox;
+ let initialIndex = list.selectedIndex;
+
+ info("Key Down to select the next item.");
+ EventUtils.synthesizeKey("VK_DOWN", {});
+
+ let nextIndex = initialIndex + 1;
+ let nextValue = gURLBar.controller.getFinalCompleteValueAt(nextIndex);
+ is(list.selectedIndex, nextIndex, "The next item is selected.");
+ is(gURLBar.value, nextValue, "The selected URL is completed.");
+
+ info("Press backspace");
+ EventUtils.synthesizeKey("VK_BACK_SPACE", {});
+ yield promiseSearchComplete();
+
+ let editedValue = gURLBar.textValue;
+ is(list.selectedIndex, initialIndex, "The initial index is selected again.");
+ isnot(editedValue, nextValue, "The URL has changed.");
+
+ let docLoad = waitForDocLoadAndStopIt("http://" + editedValue);
+
+ info("Press return to load edited URL.");
+ EventUtils.synthesizeKey("VK_RETURN", {});
+ yield Promise.all([
+ promisePopupHidden(gURLBar.popup),
+ docLoad,
+ ]);
+
+ gBrowser.removeTab(gBrowser.selectedTab);
+});
diff --git a/browser/base/content/test/urlbar/browser_autocomplete_enter_race.js b/browser/base/content/test/urlbar/browser_autocomplete_enter_race.js
new file mode 100644
index 000000000..4e3c8943c
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_autocomplete_enter_race.js
@@ -0,0 +1,122 @@
+// The order of these tests matters!
+
+add_task(function* setup () {
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser);
+ let bm = yield PlacesUtils.bookmarks.insert({ parentGuid: PlacesUtils.bookmarks.unfiledGuid,
+ url: "http://example.com/?q=%s",
+ title: "test" });
+ registerCleanupFunction(function* () {
+ yield PlacesUtils.bookmarks.remove(bm);
+ yield BrowserTestUtils.removeTab(tab);
+ });
+ yield PlacesUtils.keywords.insert({ keyword: "keyword",
+ url: "http://example.com/?q=%s" });
+ // Needs at least one success.
+ ok(true, "Setup complete");
+});
+
+add_task(function* test_keyword() {
+ yield promiseAutocompleteResultPopup("keyword bear");
+ gURLBar.focus();
+ EventUtils.synthesizeKey("d", {});
+ EventUtils.synthesizeKey("VK_RETURN", {});
+ info("wait for the page to load");
+ yield BrowserTestUtils.browserLoaded(gBrowser.selectedTab.linkedBrowser,
+ false, "http://example.com/?q=beard");
+});
+
+add_task(function* test_sametext() {
+ yield promiseAutocompleteResultPopup("example.com", window, true);
+
+ // Simulate re-entering the same text searched the last time. This may happen
+ // through a copy paste, but clipboard handling is not much reliable, so just
+ // fire an input event.
+ info("synthesize input event");
+ let event = document.createEvent("Events");
+ event.initEvent("input", true, true);
+ gURLBar.dispatchEvent(event);
+ EventUtils.synthesizeKey("VK_RETURN", {});
+
+ info("wait for the page to load");
+ yield BrowserTestUtils.browserLoaded(gBrowser.selectedTab.linkedBrowser,
+ false, "http://example.com/");
+});
+
+add_task(function* test_after_empty_search() {
+ yield promiseAutocompleteResultPopup("");
+ gURLBar.focus();
+ gURLBar.value = "e";
+ EventUtils.synthesizeKey("x", {});
+ EventUtils.synthesizeKey("VK_RETURN", {});
+
+ info("wait for the page to load");
+ yield BrowserTestUtils.browserLoaded(gBrowser.selectedTab.linkedBrowser,
+ false, "http://example.com/");
+});
+
+add_task(function* test_disabled_ac() {
+ // Disable autocomplete.
+ let suggestHistory = Preferences.get("browser.urlbar.suggest.history");
+ Preferences.set("browser.urlbar.suggest.history", false);
+ let suggestBookmarks = Preferences.get("browser.urlbar.suggest.bookmark");
+ Preferences.set("browser.urlbar.suggest.bookmark", false);
+ let suggestOpenPages = Preferences.get("browser.urlbar.suggest.openpage");
+ Preferences.set("browser.urlbar.suggest.openpages", false);
+
+ Services.search.addEngineWithDetails("MozSearch", "", "", "", "GET",
+ "http://example.com/?q={searchTerms}");
+ let engine = Services.search.getEngineByName("MozSearch");
+ let originalEngine = Services.search.currentEngine;
+ Services.search.currentEngine = engine;
+
+ function* cleanup() {
+ Preferences.set("browser.urlbar.suggest.history", suggestHistory);
+ Preferences.set("browser.urlbar.suggest.bookmark", suggestBookmarks);
+ Preferences.set("browser.urlbar.suggest.openpage", suggestOpenPages);
+
+ Services.search.currentEngine = originalEngine;
+ let engine = Services.search.getEngineByName("MozSearch");
+ if (engine) {
+ Services.search.removeEngine(engine);
+ }
+ }
+ registerCleanupFunction(cleanup);
+
+ gURLBar.focus();
+ gURLBar.value = "e";
+ EventUtils.synthesizeKey("x", {});
+ EventUtils.synthesizeKey("VK_RETURN", {});
+
+ info("wait for the page to load");
+ yield BrowserTestUtils.browserLoaded(gBrowser.selectedTab.linkedBrowser,
+ false, "http://example.com/?q=ex");
+ yield cleanup();
+});
+
+add_task(function* test_delay() {
+ const TIMEOUT = 10000;
+ // Set a large delay.
+ let delay = Preferences.get("browser.urlbar.delay");
+ Preferences.set("browser.urlbar.delay", TIMEOUT);
+
+ registerCleanupFunction(function* () {
+ Preferences.set("browser.urlbar.delay", delay);
+ });
+
+ // This is needed to clear the current value, otherwise autocomplete may think
+ // the user removed text from the end.
+ let start = Date.now();
+ yield promiseAutocompleteResultPopup("");
+ Assert.ok((Date.now() - start) < TIMEOUT);
+
+ start = Date.now();
+ gURLBar.closePopup();
+ gURLBar.focus();
+ gURLBar.value = "e";
+ EventUtils.synthesizeKey("x", {});
+ EventUtils.synthesizeKey("VK_RETURN", {});
+ info("wait for the page to load");
+ yield BrowserTestUtils.browserLoaded(gBrowser.selectedTab.linkedBrowser,
+ false, "http://example.com/");
+ Assert.ok((Date.now() - start) < TIMEOUT);
+});
diff --git a/browser/base/content/test/urlbar/browser_autocomplete_no_title.js b/browser/base/content/test/urlbar/browser_autocomplete_no_title.js
new file mode 100644
index 000000000..8d608550b
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_autocomplete_no_title.js
@@ -0,0 +1,15 @@
+add_task(function*() {
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:mozilla");
+
+ let uri = NetUtil.newURI("http://bug1060642.example.com/beards/are/pretty/great");
+ yield PlacesTestUtils.addVisits([{uri: uri, title: ""}]);
+
+ yield promiseAutocompleteResultPopup("bug1060642");
+ ok(gURLBar.popup.richlistbox.children.length > 1, "Should get at least 2 results");
+ let result = gURLBar.popup.richlistbox.children[1];
+ is(result._titleText.textContent, "bug1060642.example.com", "Result title should be as expected");
+
+ gURLBar.popup.hidePopup();
+ yield promisePopupHidden(gURLBar.popup);
+ gBrowser.removeTab(tab);
+});
diff --git a/browser/base/content/test/urlbar/browser_autocomplete_tag_star_visibility.js b/browser/base/content/test/urlbar/browser_autocomplete_tag_star_visibility.js
new file mode 100644
index 000000000..8a69b4b44
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_autocomplete_tag_star_visibility.js
@@ -0,0 +1,102 @@
+add_task(function*() {
+ registerCleanupFunction(() => {
+ PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId);
+ });
+
+ function* addTagItem(tagName) {
+ let uri = NetUtil.newURI(`http://example.com/this/is/tagged/${tagName}`);
+ PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
+ uri,
+ PlacesUtils.bookmarks.DEFAULT_INDEX,
+ `test ${tagName}`);
+ PlacesUtils.tagging.tagURI(uri, [tagName]);
+ yield PlacesTestUtils.addVisits([{uri: uri, title: `Test page with tag ${tagName}`}]);
+ }
+
+ // We use different tags for each part of the test, as otherwise the
+ // autocomplete code tries to be smart by using the previously cached element
+ // without updating it (since all parameters it knows about are the same).
+
+ let testcases = [{
+ description: "Test with suggest.bookmark=true",
+ tagName: "tagtest1",
+ prefs: {
+ "suggest.bookmark": true,
+ },
+ input: "tagtest1",
+ expected: {
+ type: "bookmark",
+ typeImageVisible: true,
+ },
+ }, {
+ description: "Test with suggest.bookmark=false",
+ tagName: "tagtest2",
+ prefs: {
+ "suggest.bookmark": false,
+ },
+ input: "tagtest2",
+ expected: {
+ type: "tag",
+ typeImageVisible: false,
+ },
+ }, {
+ description: "Test with suggest.bookmark=true (again)",
+ tagName: "tagtest3",
+ prefs: {
+ "suggest.bookmark": true,
+ },
+ input: "tagtest3",
+ expected: {
+ type: "bookmark",
+ typeImageVisible: true,
+ },
+ }, {
+ description: "Test with bookmark restriction token",
+ tagName: "tagtest4",
+ prefs: {
+ "suggest.bookmark": true,
+ },
+ input: "* tagtest4",
+ expected: {
+ type: "bookmark",
+ typeImageVisible: true,
+ },
+ }, {
+ description: "Test with history restriction token",
+ tagName: "tagtest5",
+ prefs: {
+ "suggest.bookmark": true,
+ },
+ input: "^ tagtest5",
+ expected: {
+ type: "tag",
+ typeImageVisible: false,
+ },
+ }];
+
+ for (let testcase of testcases) {
+ info(`Test case: ${testcase.description}`);
+
+ yield addTagItem(testcase.tagName);
+ for (let prefName of Object.keys(testcase.prefs)) {
+ Services.prefs.setBoolPref(`browser.urlbar.${prefName}`, testcase.prefs[prefName]);
+ }
+
+ yield promiseAutocompleteResultPopup(testcase.input);
+ let result = gURLBar.popup.richlistbox.children[1];
+ ok(result && !result.collasped, "Should have result");
+
+ is(result.getAttribute("type"), testcase.expected.type, "Result should have expected type");
+
+ let typeIconStyle = window.getComputedStyle(result._typeIcon);
+ let imageURL = typeIconStyle.listStyleImage;
+ if (testcase.expected.typeImageVisible) {
+ ok(/^url\(.+\)$/.test(imageURL), "Type image should be visible");
+ } else {
+ is(imageURL, "none", "Type image should be hidden");
+ }
+
+ gURLBar.popup.hidePopup();
+ yield promisePopupHidden(gURLBar.popup);
+ }
+});
diff --git a/browser/base/content/test/urlbar/browser_bug1003461-switchtab-override.js b/browser/base/content/test/urlbar/browser_bug1003461-switchtab-override.js
new file mode 100644
index 000000000..89f604491
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_bug1003461-switchtab-override.js
@@ -0,0 +1,61 @@
+/* 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_switchtab_override() {
+ let testURL = "http://example.org/browser/browser/base/content/test/urlbar/dummy_page.html";
+
+ info("Opening first tab");
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, testURL);
+
+ info("Opening and selecting second tab");
+ let secondTab = gBrowser.selectedTab = gBrowser.addTab();
+ registerCleanupFunction(() => {
+ try {
+ gBrowser.removeTab(tab);
+ gBrowser.removeTab(secondTab);
+ } catch (ex) { /* tabs may have already been closed in case of failure */ }
+ });
+
+ info("Wait for autocomplete")
+ let deferred = Promise.defer();
+ let onSearchComplete = gURLBar.onSearchComplete;
+ registerCleanupFunction(() => {
+ gURLBar.onSearchComplete = onSearchComplete;
+ });
+ gURLBar.onSearchComplete = function () {
+ ok(gURLBar.popupOpen, "The autocomplete popup is correctly open");
+ onSearchComplete.apply(gURLBar);
+ deferred.resolve();
+ }
+
+ gURLBar.focus();
+ gURLBar.value = "dummy_pag";
+ EventUtils.synthesizeKey("e", {});
+ yield deferred.promise;
+
+ info("Select second autocomplete popup entry");
+ EventUtils.synthesizeKey("VK_DOWN", {});
+ ok(/moz-action:switchtab/.test(gURLBar.value), "switch to tab entry found");
+
+ info("Override switch-to-tab");
+ deferred = Promise.defer();
+ // In case of failure this would switch tab.
+ let onTabSelect = event => {
+ deferred.reject(new Error("Should have overridden switch to tab"));
+ };
+ gBrowser.tabContainer.addEventListener("TabSelect", onTabSelect, false);
+ registerCleanupFunction(() => {
+ gBrowser.tabContainer.removeEventListener("TabSelect", onTabSelect, false);
+ });
+ // Otherwise it would load the page.
+ BrowserTestUtils.browserLoaded(secondTab.linkedBrowser).then(deferred.resolve);
+
+ EventUtils.synthesizeKey("VK_SHIFT", { type: "keydown" });
+ EventUtils.synthesizeKey("VK_RETURN", { });
+ info(`gURLBar.value = ${gURLBar.value}`);
+ EventUtils.synthesizeKey("VK_SHIFT", { type: "keyup" });
+ yield deferred.promise;
+
+ yield PlacesTestUtils.clearHistory();
+});
diff --git a/browser/base/content/test/urlbar/browser_bug1024133-switchtab-override-keynav.js b/browser/base/content/test/urlbar/browser_bug1024133-switchtab-override-keynav.js
new file mode 100644
index 000000000..2d97ea07b
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_bug1024133-switchtab-override-keynav.js
@@ -0,0 +1,37 @@
+/* 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_switchtab_override_keynav() {
+ let testURL = "http://example.org/browser/browser/base/content/test/urlbar/dummy_page.html";
+
+ info("Opening first tab");
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, testURL);
+
+ info("Opening and selecting second tab");
+ let secondTab = gBrowser.selectedTab = gBrowser.addTab();
+ registerCleanupFunction(() => {
+ try {
+ gBrowser.removeTab(tab);
+ gBrowser.removeTab(secondTab);
+ } catch (ex) { /* tabs may have already been closed in case of failure */ }
+ return PlacesTestUtils.clearHistory();
+ });
+
+ gURLBar.focus();
+ gURLBar.value = "dummy_pag";
+ EventUtils.synthesizeKey("e", {});
+ yield promiseSearchComplete();
+
+ info("Select second autocomplete popup entry");
+ EventUtils.synthesizeKey("VK_DOWN", {});
+ ok(/moz-action:switchtab/.test(gURLBar.value), "switch to tab entry found");
+
+ info("Shift+left on switch-to-tab entry");
+
+ EventUtils.synthesizeKey("VK_SHIFT", { type: "keydown" });
+ EventUtils.synthesizeKey("VK_LEFT", { shiftKey: true });
+ EventUtils.synthesizeKey("VK_SHIFT", { type: "keyup" });
+
+ ok(!/moz-action:switchtab/.test(gURLBar.inputField.value), "switch to tab should be hidden");
+});
diff --git a/browser/base/content/test/urlbar/browser_bug1025195_switchToTabHavingURI_aOpenParams.js b/browser/base/content/test/urlbar/browser_bug1025195_switchToTabHavingURI_aOpenParams.js
new file mode 100644
index 000000000..9e779ade1
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_bug1025195_switchToTabHavingURI_aOpenParams.js
@@ -0,0 +1,124 @@
+/* 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_ignoreFragment() {
+ let tabRefAboutHome =
+ yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:home#1");
+ yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:mozilla");
+ let numTabsAtStart = gBrowser.tabs.length;
+
+ switchTab("about:home#1", true);
+ switchTab("about:mozilla", true);
+
+ let hashChangePromise = ContentTask.spawn(tabRefAboutHome.linkedBrowser, null, function* () {
+ yield ContentTaskUtils.waitForEvent(this, "hashchange", false);
+ });
+ switchTab("about:home#2", true, { ignoreFragment: "whenComparingAndReplace" });
+ is(tabRefAboutHome, gBrowser.selectedTab, "The same about:home tab should be switched to");
+ yield hashChangePromise;
+ is(gBrowser.currentURI.ref, "2", "The ref should be updated to the new ref");
+ switchTab("about:mozilla", true);
+ switchTab("about:home#3", true, { ignoreFragment: "whenComparing" });
+ is(tabRefAboutHome, gBrowser.selectedTab, "The same about:home tab should be switched to");
+ is(gBrowser.currentURI.ref, "2", "The ref should be unchanged since the fragment is only ignored when comparing");
+ switchTab("about:mozilla", true);
+ switchTab("about:home#1", false);
+ isnot(tabRefAboutHome, gBrowser.selectedTab, "Selected tab should not be initial about:blank tab");
+ is(gBrowser.tabs.length, numTabsAtStart + 1, "Should have one new tab opened");
+ switchTab("about:mozilla", true);
+ switchTab("about:home", true, {ignoreFragment: "whenComparingAndReplace"});
+ yield BrowserTestUtils.waitForCondition(function() {
+ return tabRefAboutHome.linkedBrowser.currentURI.spec == "about:home";
+ });
+ is(tabRefAboutHome.linkedBrowser.currentURI.spec, "about:home", "about:home shouldn't have hash");
+ switchTab("about:about", false, { ignoreFragment: "whenComparingAndReplace" });
+ cleanupTestTabs();
+});
+
+add_task(function* test_ignoreQueryString() {
+ let tabRefAboutHome =
+ yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:home?hello=firefox");
+ yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:mozilla");
+
+ switchTab("about:home?hello=firefox", true);
+ switchTab("about:home?hello=firefoxos", false);
+ // Remove the last opened tab to test ignoreQueryString option.
+ gBrowser.removeCurrentTab();
+ switchTab("about:home?hello=firefoxos", true, { ignoreQueryString: true });
+ is(tabRefAboutHome, gBrowser.selectedTab, "Selected tab should be the initial about:home tab");
+ is(gBrowser.currentURI.spec, "about:home?hello=firefox", "The spec should NOT be updated to the new query string");
+ cleanupTestTabs();
+});
+
+add_task(function* test_replaceQueryString() {
+ let tabRefAboutHome =
+ yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:home?hello=firefox");
+ yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:mozilla");
+
+ switchTab("about:home", false);
+ switchTab("about:home?hello=firefox", true);
+ switchTab("about:home?hello=firefoxos", false);
+ // Remove the last opened tab to test replaceQueryString option.
+ gBrowser.removeCurrentTab();
+ switchTab("about:home?hello=firefoxos", true, { replaceQueryString: true });
+ is(tabRefAboutHome, gBrowser.selectedTab, "Selected tab should be the initial about:home tab");
+ // Wait for the tab to load the new URI spec.
+ yield BrowserTestUtils.browserLoaded(tabRefAboutHome.linkedBrowser);
+ is(gBrowser.currentURI.spec, "about:home?hello=firefoxos", "The spec should be updated to the new spec");
+ cleanupTestTabs();
+});
+
+add_task(function* test_replaceQueryStringAndFragment() {
+ let tabRefAboutHome =
+ yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:home?hello=firefox#aaa");
+ let tabRefAboutMozilla =
+ yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:mozilla?hello=firefoxos#aaa");
+
+ switchTab("about:home", false);
+ gBrowser.removeCurrentTab();
+ switchTab("about:home?hello=firefox#aaa", true);
+ is(tabRefAboutHome, gBrowser.selectedTab, "Selected tab should be the initial about:home tab");
+ switchTab("about:mozilla?hello=firefox#bbb", true, { replaceQueryString: true, ignoreFragment: "whenComparingAndReplace" });
+ is(tabRefAboutMozilla, gBrowser.selectedTab, "Selected tab should be the initial about:mozilla tab");
+ switchTab("about:home?hello=firefoxos#bbb", true, { ignoreQueryString: true, ignoreFragment: "whenComparingAndReplace" });
+ is(tabRefAboutHome, gBrowser.selectedTab, "Selected tab should be the initial about:home tab");
+ cleanupTestTabs();
+});
+
+add_task(function* test_ignoreQueryStringIgnoresFragment() {
+ let tabRefAboutHome =
+ yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:home?hello=firefox#aaa");
+ yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:mozilla?hello=firefoxos#aaa");
+
+ switchTab("about:home?hello=firefox#bbb", false, { ignoreQueryString: true });
+ gBrowser.removeCurrentTab();
+ switchTab("about:home?hello=firefoxos#aaa", true, { ignoreQueryString: true });
+ is(tabRefAboutHome, gBrowser.selectedTab, "Selected tab should be the initial about:home tab");
+ cleanupTestTabs();
+});
+
+// Begin helpers
+
+function cleanupTestTabs() {
+ while (gBrowser.tabs.length > 1)
+ gBrowser.removeCurrentTab();
+}
+
+function switchTab(aURI, aShouldFindExistingTab, aOpenParams = {}) {
+ // Build the description before switchToTabHavingURI deletes the object properties.
+ let msg = `Should switch to existing ${aURI} tab if one existed, ` +
+ `${(aOpenParams.ignoreFragment ? "ignoring" : "including")} fragment portion, `;
+ if (aOpenParams.replaceQueryString) {
+ msg += "replacing";
+ } else if (aOpenParams.ignoreQueryString) {
+ msg += "ignoring";
+ } else {
+ msg += "including";
+ }
+ msg += " query string.";
+ let tabFound = switchToTabHavingURI(aURI, true, aOpenParams);
+ is(tabFound, aShouldFindExistingTab, msg);
+}
+
+registerCleanupFunction(cleanupTestTabs);
diff --git a/browser/base/content/test/urlbar/browser_bug1070778.js b/browser/base/content/test/urlbar/browser_bug1070778.js
new file mode 100644
index 000000000..ab88d04d8
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_bug1070778.js
@@ -0,0 +1,55 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function is_selected(index) {
+ is(gURLBar.popup.richlistbox.selectedIndex, index, `Item ${index + 1} should be selected`);
+}
+
+add_task(function*() {
+ let bookmarks = [];
+ bookmarks.push((yield PlacesUtils.bookmarks
+ .insert({ parentGuid: PlacesUtils.bookmarks.unfiledGuid,
+ url: "http://example.com/?q=%s",
+ title: "test" })));
+ yield PlacesUtils.keywords.insert({ keyword: "keyword",
+ url: "http://example.com/?q=%s" });
+
+ // This item only needed so we can select the keyword item, select something
+ // else, then select the keyword item again.
+ bookmarks.push((yield PlacesUtils.bookmarks
+ .insert({ parentGuid: PlacesUtils.bookmarks.unfiledGuid,
+ url: "http://example.com/keyword",
+ title: "keyword abc" })));
+
+ registerCleanupFunction(function* () {
+ for (let bm of bookmarks) {
+ yield PlacesUtils.bookmarks.remove(bm);
+ }
+ });
+
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:mozilla");
+ yield promiseAutocompleteResultPopup("keyword a");
+
+ // First item should already be selected
+ is_selected(0);
+ // Select next one (important!)
+ EventUtils.synthesizeKey("VK_DOWN", {});
+ is_selected(1);
+ // Re-select keyword item
+ EventUtils.synthesizeKey("VK_UP", {});
+ is_selected(0);
+
+ EventUtils.synthesizeKey("b", {});
+ yield promiseSearchComplete();
+
+ is(gURLBar.textValue, "keyword ab", "urlbar should have expected input");
+
+ let result = gURLBar.popup.richlistbox.firstChild;
+ isnot(result, null, "Should have first item");
+ let uri = NetUtil.newURI(result.getAttribute("url"));
+ is(uri.spec, PlacesUtils.mozActionURI("keyword", {url: "http://example.com/?q=ab", input: "keyword ab"}), "Expect correct url");
+
+ EventUtils.synthesizeKey("VK_ESCAPE", {});
+ yield promisePopupHidden(gURLBar.popup);
+ gBrowser.removeTab(tab);
+});
diff --git a/browser/base/content/test/urlbar/browser_bug1104165-switchtab-decodeuri.js b/browser/base/content/test/urlbar/browser_bug1104165-switchtab-decodeuri.js
new file mode 100644
index 000000000..d165d7304
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_bug1104165-switchtab-decodeuri.js
@@ -0,0 +1,29 @@
+add_task(function* test_switchtab_decodeuri() {
+ info("Opening first tab");
+ const TEST_URL = "http://example.org/browser/browser/base/content/test/urlbar/dummy_page.html#test%7C1";
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
+
+ info("Opening and selecting second tab");
+ gBrowser.selectedTab = gBrowser.addTab();
+
+ info("Wait for autocomplete")
+ yield promiseAutocompleteResultPopup("dummy_page");
+
+ info("Select autocomplete popup entry");
+ EventUtils.synthesizeKey("VK_DOWN", {});
+ ok(gURLBar.value.startsWith("moz-action:switchtab"), "switch to tab entry found");
+
+ info("switch-to-tab");
+ yield new Promise((resolve, reject) => {
+ // In case of success it should switch tab.
+ gBrowser.tabContainer.addEventListener("TabSelect", function select() {
+ gBrowser.tabContainer.removeEventListener("TabSelect", select, false);
+ is(gBrowser.selectedTab, tab, "Should have switched to the right tab");
+ resolve();
+ }, false);
+ EventUtils.synthesizeKey("VK_RETURN", { });
+ });
+
+ gBrowser.removeCurrentTab();
+ yield PlacesTestUtils.clearHistory();
+});
diff --git a/browser/base/content/test/urlbar/browser_bug1225194-remotetab.js b/browser/base/content/test/urlbar/browser_bug1225194-remotetab.js
new file mode 100644
index 000000000..3b4a44e76
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_bug1225194-remotetab.js
@@ -0,0 +1,16 @@
+add_task(function* test_remotetab_opens() {
+ const url = "http://example.org/browser/browser/base/content/test/urlbar/dummy_page.html";
+ yield BrowserTestUtils.withNewTab({url: "about:robots", gBrowser}, function* () {
+ // Set the urlbar to include the moz-action
+ gURLBar.value = "moz-action:remotetab," + JSON.stringify({ url });
+ // Focus the urlbar so we can press enter
+ gURLBar.focus();
+
+ // The URL is going to open in the current tab as it is currently about:blank
+ let promiseTabLoaded = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+ EventUtils.synthesizeKey("VK_RETURN", {});
+ yield promiseTabLoaded;
+
+ Assert.equal(gBrowser.selectedTab.linkedBrowser.currentURI.spec, url, "correct URL loaded");
+ });
+});
diff --git a/browser/base/content/test/urlbar/browser_bug304198.js b/browser/base/content/test/urlbar/browser_bug304198.js
new file mode 100644
index 000000000..dc8d39fae
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_bug304198.js
@@ -0,0 +1,109 @@
+/* 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* () {
+ let charsToDelete, deletedURLTab, fullURLTab, partialURLTab, testPartialURL, testURL;
+
+ charsToDelete = 5;
+ deletedURLTab = gBrowser.addTab();
+ fullURLTab = gBrowser.addTab();
+ partialURLTab = gBrowser.addTab();
+ testURL = "http://example.org/browser/browser/base/content/test/urlbar/dummy_page.html";
+
+ let loaded1 = BrowserTestUtils.browserLoaded(deletedURLTab.linkedBrowser, testURL);
+ let loaded2 = BrowserTestUtils.browserLoaded(fullURLTab.linkedBrowser, testURL);
+ let loaded3 = BrowserTestUtils.browserLoaded(partialURLTab.linkedBrowser, testURL);
+ deletedURLTab.linkedBrowser.loadURI(testURL);
+ fullURLTab.linkedBrowser.loadURI(testURL);
+ partialURLTab.linkedBrowser.loadURI(testURL);
+ yield Promise.all([loaded1, loaded2, loaded3]);
+
+ testURL = gURLBar.trimValue(testURL);
+ testPartialURL = testURL.substr(0, (testURL.length - charsToDelete));
+
+ function cleanUp() {
+ gBrowser.removeTab(fullURLTab);
+ gBrowser.removeTab(partialURLTab);
+ gBrowser.removeTab(deletedURLTab);
+ }
+
+ function* cycleTabs() {
+ yield BrowserTestUtils.switchTab(gBrowser, fullURLTab);
+ is(gURLBar.textValue, testURL, 'gURLBar.textValue should be testURL after switching back to fullURLTab');
+
+ yield BrowserTestUtils.switchTab(gBrowser, partialURLTab);
+ is(gURLBar.textValue, testPartialURL, 'gURLBar.textValue should be testPartialURL after switching back to partialURLTab');
+ yield BrowserTestUtils.switchTab(gBrowser, deletedURLTab);
+ is(gURLBar.textValue, '', 'gURLBar.textValue should be "" after switching back to deletedURLTab');
+
+ yield BrowserTestUtils.switchTab(gBrowser, fullURLTab);
+ is(gURLBar.textValue, testURL, 'gURLBar.textValue should be testURL after switching back to fullURLTab');
+ }
+
+ function urlbarBackspace() {
+ return new Promise((resolve, reject) => {
+ gBrowser.selectedBrowser.focus();
+ gURLBar.addEventListener("input", function () {
+ gURLBar.removeEventListener("input", arguments.callee, false);
+ resolve();
+ }, false);
+ gURLBar.focus();
+ if (gURLBar.selectionStart == gURLBar.selectionEnd) {
+ gURLBar.selectionStart = gURLBar.selectionEnd = gURLBar.textValue.length;
+ }
+ EventUtils.synthesizeKey("VK_BACK_SPACE", {});
+ });
+ }
+
+ function* prepareDeletedURLTab() {
+ yield BrowserTestUtils.switchTab(gBrowser, deletedURLTab);
+ is(gURLBar.textValue, testURL, 'gURLBar.textValue should be testURL after initial switch to deletedURLTab');
+
+ // simulate the user removing the whole url from the location bar
+ gPrefService.setBoolPref("browser.urlbar.clickSelectsAll", true);
+
+ yield urlbarBackspace();
+ is(gURLBar.textValue, "", 'gURLBar.textValue should be "" (just set)');
+ if (gPrefService.prefHasUserValue("browser.urlbar.clickSelectsAll")) {
+ gPrefService.clearUserPref("browser.urlbar.clickSelectsAll");
+ }
+ }
+
+ function* prepareFullURLTab() {
+ yield BrowserTestUtils.switchTab(gBrowser, fullURLTab);
+ is(gURLBar.textValue, testURL, 'gURLBar.textValue should be testURL after initial switch to fullURLTab');
+ }
+
+ function* preparePartialURLTab() {
+ yield BrowserTestUtils.switchTab(gBrowser, partialURLTab);
+ is(gURLBar.textValue, testURL, 'gURLBar.textValue should be testURL after initial switch to partialURLTab');
+
+ // simulate the user removing part of the url from the location bar
+ gPrefService.setBoolPref("browser.urlbar.clickSelectsAll", false);
+
+ let deleted = 0;
+ while (deleted < charsToDelete) {
+ yield urlbarBackspace(arguments.callee);
+ deleted++;
+ }
+
+ is(gURLBar.textValue, testPartialURL, "gURLBar.textValue should be testPartialURL (just set)");
+ if (gPrefService.prefHasUserValue("browser.urlbar.clickSelectsAll")) {
+ gPrefService.clearUserPref("browser.urlbar.clickSelectsAll");
+ }
+ }
+
+ // prepare the three tabs required by this test
+
+ // First tab
+ yield* prepareFullURLTab();
+ yield* preparePartialURLTab();
+ yield* prepareDeletedURLTab();
+
+ // now cycle the tabs and make sure everything looks good
+ yield* cycleTabs();
+ cleanUp();
+});
+
+
diff --git a/browser/base/content/test/urlbar/browser_bug556061.js b/browser/base/content/test/urlbar/browser_bug556061.js
new file mode 100644
index 000000000..4c6ac5bf5
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_bug556061.js
@@ -0,0 +1,98 @@
+/* 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 testURL = "http://example.org/browser/browser/base/content/test/urlbar/dummy_page.html";
+var testActionURL = "moz-action:switchtab," + JSON.stringify({url: testURL});
+testURL = gURLBar.trimValue(testURL);
+var testTab;
+
+function runNextTest() {
+ if (tests.length) {
+ let t = tests.shift();
+ waitForClipboard(t.expected, t.setup, function() {
+ t.success();
+ runNextTest();
+ }, cleanup);
+ }
+ else {
+ cleanup();
+ }
+}
+
+function cleanup() {
+ gBrowser.removeTab(testTab);
+ finish();
+}
+
+var tests = [
+ {
+ expected: testURL,
+ setup: function() {
+ gURLBar.value = testActionURL;
+ gURLBar.valueIsTyped = true;
+ is(gURLBar.value, testActionURL, "gURLBar starts with the correct real value");
+ is(gURLBar.textValue, testURL, "gURLBar starts with the correct display value");
+
+ // Focus the urlbar so we can select it all & copy
+ gURLBar.focus();
+ gURLBar.select();
+ goDoCommand("cmd_copy");
+ },
+ success: function() {
+ is(gURLBar.value, testActionURL, "gURLBar.value didn't change when copying");
+ }
+ },
+ {
+ expected: testURL.substring(0, 10),
+ setup: function() {
+ // Set selectionStart/End manually and make sure it matches the substring
+ gURLBar.selectionStart = 0;
+ gURLBar.selectionEnd = 10;
+ goDoCommand("cmd_copy");
+ },
+ success: function() {
+ is(gURLBar.value, testActionURL, "gURLBar.value didn't change when copying");
+ }
+ },
+ {
+ expected: testURL,
+ setup: function() {
+ // Setup for cut test...
+ // Select all
+ gURLBar.select();
+ goDoCommand("cmd_cut");
+ },
+ success: function() {
+ is(gURLBar.value, "", "gURLBar.value is now empty");
+ }
+ },
+ {
+ expected: testURL.substring(testURL.length - 10, testURL.length),
+ setup: function() {
+ // Reset urlbar value
+ gURLBar.value = testActionURL;
+ gURLBar.valueIsTyped = true;
+ // Sanity check that we have the right value
+ is(gURLBar.value, testActionURL, "gURLBar starts with the correct real value");
+ is(gURLBar.textValue, testURL, "gURLBar starts with the correct display value");
+
+ // Now just select part of the value & cut that.
+ gURLBar.selectionStart = testURL.length - 10;
+ gURLBar.selectionEnd = testURL.length;
+ goDoCommand("cmd_cut");
+ },
+ success: function() {
+ is(gURLBar.value, testURL.substring(0, testURL.length - 10), "gURLBar.value has the correct value");
+ }
+ }
+];
+
+function test() {
+ waitForExplicitFinish();
+ testTab = gBrowser.addTab();
+ gBrowser.selectedTab = testTab;
+
+ // Kick off the testing
+ runNextTest();
+}
diff --git a/browser/base/content/test/urlbar/browser_bug562649.js b/browser/base/content/test/urlbar/browser_bug562649.js
new file mode 100644
index 000000000..f56e430ee
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_bug562649.js
@@ -0,0 +1,24 @@
+function test() {
+ const URI = "data:text/plain,bug562649";
+ browserDOMWindow.openURI(makeURI(URI),
+ null,
+ Ci.nsIBrowserDOMWindow.OPEN_NEWTAB,
+ Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL);
+
+ is(gBrowser.userTypedValue, URI, "userTypedValue matches test URI");
+ is(gURLBar.value, URI, "location bar value matches test URI");
+
+ gBrowser.selectedTab = gBrowser.addTab();
+ gBrowser.removeCurrentTab({ skipPermitUnload: true });
+ is(gBrowser.userTypedValue, URI, "userTypedValue matches test URI after switching tabs");
+ is(gURLBar.value, URI, "location bar value matches test URI after switching tabs");
+
+ waitForExplicitFinish();
+ BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser).then(() => {
+ is(gBrowser.userTypedValue, null, "userTypedValue is null as the page has loaded");
+ is(gURLBar.value, URI, "location bar value matches test URI as the page has loaded");
+
+ gBrowser.removeCurrentTab({ skipPermitUnload: true });
+ finish();
+ });
+}
diff --git a/browser/base/content/test/urlbar/browser_bug623155.js b/browser/base/content/test/urlbar/browser_bug623155.js
new file mode 100644
index 000000000..dd6ff8c85
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_bug623155.js
@@ -0,0 +1,137 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const REDIRECT_FROM = "https://example.com/browser/browser/base/content/test/urlbar/" +
+ "redirect_bug623155.sjs";
+
+const REDIRECT_TO = "https://www.bank1.com/"; // Bad-cert host.
+
+function isRedirectedURISpec(aURISpec) {
+ return isRedirectedURI(Services.io.newURI(aURISpec, null, null));
+}
+
+function isRedirectedURI(aURI) {
+ // Compare only their before-hash portion.
+ return Services.io.newURI(REDIRECT_TO, null, null)
+ .equalsExceptRef(aURI);
+}
+
+/*
+ Test.
+
+1. Load
+https://example.com/browser/browser/base/content/test/urlbar/redirect_bug623155.sjs#BG
+ in a background tab.
+
+2. The redirected URI is <https://www.bank1.com/#BG>, which displayes a cert
+ error page.
+
+3. Switch the tab to foreground.
+
+4. Check the URLbar's value, expecting <https://www.bank1.com/#BG>
+
+5. Load
+https://example.com/browser/browser/base/content/test/urlbar/redirect_bug623155.sjs#FG
+ in the foreground tab.
+
+6. The redirected URI is <https://www.bank1.com/#FG>. And this is also
+ a cert-error page.
+
+7. Check the URLbar's value, expecting <https://www.bank1.com/#FG>
+
+8. End.
+
+ */
+
+var gNewTab;
+
+function test() {
+ waitForExplicitFinish();
+
+ // Load a URI in the background.
+ gNewTab = gBrowser.addTab(REDIRECT_FROM + "#BG");
+ gBrowser.getBrowserForTab(gNewTab)
+ .webProgress
+ .addProgressListener(gWebProgressListener,
+ Components.interfaces.nsIWebProgress
+ .NOTIFY_LOCATION);
+}
+
+var gWebProgressListener = {
+ QueryInterface: function(aIID) {
+ if (aIID.equals(Components.interfaces.nsIWebProgressListener) ||
+ aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
+ aIID.equals(Components.interfaces.nsISupports))
+ return this;
+ throw Components.results.NS_NOINTERFACE;
+ },
+
+ // ---------------------------------------------------------------------------
+ // NOTIFY_LOCATION mode should work fine without these methods.
+ //
+ // onStateChange: function() {},
+ // onStatusChange: function() {},
+ // onProgressChange: function() {},
+ // onSecurityChange: function() {},
+ // ----------------------------------------------------------------------------
+
+ onLocationChange: function(aWebProgress, aRequest, aLocation, aFlags) {
+ if (!aRequest) {
+ // This is bug 673752, or maybe initial "about:blank".
+ return;
+ }
+
+ ok(gNewTab, "There is a new tab.");
+ ok(isRedirectedURI(aLocation),
+ "onLocationChange catches only redirected URI.");
+
+ if (aLocation.ref == "BG") {
+ // This is background tab's request.
+ isnot(gNewTab, gBrowser.selectedTab, "This is a background tab.");
+ } else if (aLocation.ref == "FG") {
+ // This is foreground tab's request.
+ is(gNewTab, gBrowser.selectedTab, "This is a foreground tab.");
+ }
+ else {
+ // We shonuld not reach here.
+ ok(false, "This URI hash is not expected:" + aLocation.ref);
+ }
+
+ let isSelectedTab = gNewTab.selected;
+ setTimeout(delayed, 0, isSelectedTab);
+ }
+};
+
+function delayed(aIsSelectedTab) {
+ // Switch tab and confirm URL bar.
+ if (!aIsSelectedTab) {
+ gBrowser.selectedTab = gNewTab;
+ }
+
+ let currentURI = gBrowser.selectedBrowser.currentURI.spec;
+ ok(isRedirectedURISpec(currentURI),
+ "The content area is redirected. aIsSelectedTab:" + aIsSelectedTab);
+ is(gURLBar.value, currentURI,
+ "The URL bar shows the content URI. aIsSelectedTab:" + aIsSelectedTab);
+
+ if (!aIsSelectedTab) {
+ // If this was a background request, go on a foreground request.
+ gBrowser.selectedBrowser.loadURI(REDIRECT_FROM + "#FG");
+ }
+ else {
+ // Othrewise, nothing to do remains.
+ finish();
+ }
+}
+
+/* Cleanup */
+registerCleanupFunction(function() {
+ if (gNewTab) {
+ gBrowser.getBrowserForTab(gNewTab)
+ .webProgress
+ .removeProgressListener(gWebProgressListener);
+
+ gBrowser.removeTab(gNewTab);
+ }
+ gNewTab = null;
+});
diff --git a/browser/base/content/test/urlbar/browser_bug783614.js b/browser/base/content/test/urlbar/browser_bug783614.js
new file mode 100644
index 000000000..ebc62e8fa
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_bug783614.js
@@ -0,0 +1,13 @@
+/* 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/. */
+
+function test() {
+ gURLBar.focus();
+ gURLBar.inputField.value = "https://example.com/";
+ gURLBar.selectionStart = 4;
+ gURLBar.selectionEnd = 5;
+ goDoCommand("cmd_cut");
+ is(gURLBar.inputField.value, "http://example.com/", "location bar value after cutting 's' from https");
+ gURLBar.handleRevert();
+}
diff --git a/browser/base/content/test/urlbar/browser_canonizeURL.js b/browser/base/content/test/urlbar/browser_canonizeURL.js
new file mode 100644
index 000000000..59ab54ca0
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_canonizeURL.js
@@ -0,0 +1,42 @@
+add_task(function*() {
+ let testcases = [
+ ["example", "http://www.example.net/", { shiftKey: true }],
+ // Check that a direct load is not overwritten by a previous canonization.
+ ["http://example.com/test/", "http://example.com/test/", {}],
+ ["ex-ample", "http://www.ex-ample.net/", { shiftKey: true }],
+ [" example ", "http://www.example.net/", { shiftKey: true }],
+ [" example/foo ", "http://www.example.net/foo", { shiftKey: true }],
+ [" example/foo bar ", "http://www.example.net/foo%20bar", { shiftKey: true }],
+ ["example.net", "http://example.net/", { shiftKey: true }],
+ ["http://example", "http://example/", { shiftKey: true }],
+ ["example:8080", "http://example:8080/", { shiftKey: true }],
+ ["ex-ample.foo", "http://ex-ample.foo/", { shiftKey: true }],
+ ["example.foo/bar ", "http://example.foo/bar", { shiftKey: true }],
+ ["1.1.1.1", "http://1.1.1.1/", { shiftKey: true }],
+ ["ftp://example", "ftp://example/", { shiftKey: true }],
+ ["ftp.example.bar", "http://ftp.example.bar/", { shiftKey: true }],
+ ["ex ample", Services.search.defaultEngine.getSubmission("ex ample", null, "keyword").uri.spec, { shiftKey: true }],
+ ];
+
+ // Disable autoFill for this test, since it could mess up the results.
+ let autoFill = Preferences.get("browser.urlbar.autoFill");
+ Preferences.set("browser.urlbar.autoFill", false);
+ registerCleanupFunction(() => {
+ Preferences.set("browser.urlbar.autoFill", autoFill);
+ });
+
+ for (let [inputValue, expectedURL, options] of testcases) {
+ let promiseLoad = waitForDocLoadAndStopIt(expectedURL);
+ gURLBar.focus();
+ if (Object.keys(options).length > 0) {
+ gURLBar.selectionStart = gURLBar.selectionEnd =
+ gURLBar.inputField.value.length;
+ gURLBar.inputField.value = inputValue.slice(0, -1);
+ EventUtils.synthesizeKey(inputValue.slice(-1), {});
+ } else {
+ gURLBar.textValue = inputValue;
+ }
+ EventUtils.synthesizeKey("VK_RETURN", options);
+ yield promiseLoad;
+ }
+});
diff --git a/browser/base/content/test/urlbar/browser_dragdropURL.js b/browser/base/content/test/urlbar/browser_dragdropURL.js
new file mode 100644
index 000000000..ec2906700
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_dragdropURL.js
@@ -0,0 +1,15 @@
+"use strict";
+
+const TEST_URL = "data:text/html,a test page";
+const DRAG_URL = "http://www.example.com/";
+
+add_task(function* checkURLBarUpdateForDrag() {
+ yield BrowserTestUtils.withNewTab(TEST_URL, function* (browser) {
+ // Have to use something other than the URL bar as a source, so picking the
+ // downloads button somewhat arbitrarily:
+ EventUtils.synthesizeDrop(document.getElementById("downloads-button"), gURLBar,
+ [[{type: "text/plain", data: DRAG_URL}]], "copy", window);
+ is(gURLBar.value, TEST_URL, "URL bar value should not have changed");
+ is(gBrowser.selectedBrowser.userTypedValue, null, "Stored URL bar value should not have changed");
+ });
+});
diff --git a/browser/base/content/test/urlbar/browser_locationBarCommand.js b/browser/base/content/test/urlbar/browser_locationBarCommand.js
new file mode 100644
index 000000000..935bdf758
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_locationBarCommand.js
@@ -0,0 +1,218 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const TEST_VALUE = "example.com";
+const START_VALUE = "example.org";
+
+add_task(function* setup() {
+ Services.prefs.setBoolPref("browser.altClickSave", true);
+
+ registerCleanupFunction(() => {
+ Services.prefs.clearUserPref("browser.altClickSave");
+ });
+});
+
+add_task(function* alt_left_click_test() {
+ info("Running test: Alt left click");
+
+ // Monkey patch saveURL() to avoid dealing with file save code paths.
+ let oldSaveURL = saveURL;
+ let saveURLPromise = new Promise(resolve => {
+ saveURL = () => {
+ // Restore old saveURL() value.
+ saveURL = oldSaveURL;
+ resolve();
+ };
+ });
+
+ triggerCommand(true, {altKey: true});
+
+ yield saveURLPromise;
+ ok(true, "SaveURL was called");
+ is(gURLBar.value, "", "Urlbar reverted to original value");
+});
+
+add_task(function* shift_left_click_test() {
+ info("Running test: Shift left click");
+
+ let newWindowPromise = BrowserTestUtils.waitForNewWindow();
+ triggerCommand(true, {shiftKey: true});
+ let win = yield newWindowPromise;
+
+ // Wait for the initial browser to load.
+ let browser = win.gBrowser.selectedBrowser;
+ let destinationURL = "http://" + TEST_VALUE + "/";
+ yield Promise.all([
+ BrowserTestUtils.browserLoaded(browser),
+ BrowserTestUtils.waitForLocationChange(win.gBrowser, destinationURL)
+ ]);
+
+ info("URL should be loaded in a new window");
+ is(gURLBar.value, "", "Urlbar reverted to original value");
+ yield promiseCheckChildNoFocusedElement(gBrowser.selectedBrowser);
+ is(document.activeElement, gBrowser.selectedBrowser, "Content window should be focused");
+ is(win.gURLBar.textValue, TEST_VALUE, "New URL is loaded in new window");
+
+ // Cleanup.
+ yield BrowserTestUtils.closeWindow(win);
+});
+
+add_task(function* right_click_test() {
+ info("Running test: Right click on go button");
+
+ // Add a new tab.
+ yield* promiseOpenNewTab();
+
+ triggerCommand(true, {button: 2});
+
+ // Right click should do nothing (context menu will be shown).
+ is(gURLBar.value, TEST_VALUE, "Urlbar still has the value we entered");
+
+ // Cleanup.
+ gBrowser.removeCurrentTab();
+});
+
+add_task(function* shift_accel_left_click_test() {
+ info("Running test: Shift+Ctrl/Cmd left click on go button");
+
+ // Add a new tab.
+ let tab = yield* promiseOpenNewTab();
+
+ let loadStartedPromise = promiseLoadStarted();
+ triggerCommand(true, {accelKey: true, shiftKey: true});
+ yield loadStartedPromise;
+
+ // Check the load occurred in a new background tab.
+ info("URL should be loaded in a new background tab");
+ is(gURLBar.value, "", "Urlbar reverted to original value");
+ ok(!gURLBar.focused, "Urlbar is no longer focused after urlbar command");
+ is(gBrowser.selectedTab, tab, "Focus did not change to the new tab");
+
+ // Select the new background tab
+ gBrowser.selectedTab = gBrowser.selectedTab.nextSibling;
+ is(gURLBar.value, TEST_VALUE, "New URL is loaded in new tab");
+
+ // Cleanup.
+ gBrowser.removeCurrentTab();
+ gBrowser.removeCurrentTab();
+});
+
+add_task(function* load_in_current_tab_test() {
+ let tests = [
+ {desc: "Simple return keypress"},
+ {desc: "Left click on go button", click: true},
+ {desc: "Ctrl/Cmd+Return keypress", event: {accelKey: true}},
+ {desc: "Alt+Return keypress in a blank tab", event: {altKey: true}}
+ ];
+
+ for (let test of tests) {
+ info(`Running test: ${test.desc}`);
+
+ // Add a new tab.
+ let tab = yield* promiseOpenNewTab();
+
+ // Trigger a load and check it occurs in the current tab.
+ let loadStartedPromise = promiseLoadStarted();
+ triggerCommand(test.click || false, test.event || {});
+ yield loadStartedPromise;
+
+ info("URL should be loaded in the current tab");
+ is(gURLBar.value, TEST_VALUE, "Urlbar still has the value we entered");
+ yield promiseCheckChildNoFocusedElement(gBrowser.selectedBrowser);
+ is(document.activeElement, gBrowser.selectedBrowser, "Content window should be focused");
+ is(gBrowser.selectedTab, tab, "New URL was loaded in the current tab");
+
+ // Cleanup.
+ gBrowser.removeCurrentTab();
+ }
+});
+
+add_task(function* load_in_new_tab_test() {
+ let tests = [
+ {desc: "Ctrl/Cmd left click on go button", click: true, event: {accelKey: true}},
+ {desc: "Alt+Return keypress in a dirty tab", event: {altKey: true}, url: START_VALUE}
+ ];
+
+ for (let test of tests) {
+ info(`Running test: ${test.desc}`);
+
+ // Add a new tab.
+ let tab = yield* promiseOpenNewTab(test.url || "about:blank");
+
+ // Trigger a load and check it occurs in the current tab.
+ let tabSwitchedPromise = promiseNewTabSwitched();
+ triggerCommand(test.click || false, test.event || {});
+ yield tabSwitchedPromise;
+
+ // Check the load occurred in a new tab.
+ info("URL should be loaded in a new focused tab");
+ is(gURLBar.inputField.value, TEST_VALUE, "Urlbar still has the value we entered");
+ yield promiseCheckChildNoFocusedElement(gBrowser.selectedBrowser);
+ is(document.activeElement, gBrowser.selectedBrowser, "Content window should be focused");
+ isnot(gBrowser.selectedTab, tab, "New URL was loaded in a new tab");
+
+ // Cleanup.
+ gBrowser.removeCurrentTab();
+ gBrowser.removeCurrentTab();
+ }
+});
+
+function triggerCommand(shouldClick, event) {
+ gURLBar.value = TEST_VALUE;
+ gURLBar.focus();
+
+ if (shouldClick) {
+ is(gURLBar.getAttribute("pageproxystate"), "invalid",
+ "page proxy state must be invalid for go button to be visible");
+
+ let goButton = document.getElementById("urlbar-go-button");
+ EventUtils.synthesizeMouseAtCenter(goButton, event);
+ } else {
+ EventUtils.synthesizeKey("VK_RETURN", event);
+ }
+}
+
+function promiseLoadStarted() {
+ return new Promise(resolve => {
+ gBrowser.addTabsProgressListener({
+ onStateChange(browser, webProgress, req, flags, status) {
+ if (flags & Ci.nsIWebProgressListener.STATE_START) {
+ gBrowser.removeTabsProgressListener(this);
+ resolve();
+ }
+ }
+ });
+ });
+}
+
+function* promiseOpenNewTab(url = "about:blank") {
+ let tab = gBrowser.addTab(url);
+ let tabSwitchPromise = promiseNewTabSwitched(tab);
+ gBrowser.selectedTab = tab;
+ yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+ yield tabSwitchPromise;
+ return tab;
+}
+
+function promiseNewTabSwitched() {
+ return new Promise(resolve => {
+ gBrowser.addEventListener("TabSwitchDone", function onSwitch() {
+ gBrowser.removeEventListener("TabSwitchDone", onSwitch);
+ executeSoon(resolve);
+ });
+ });
+}
+
+function promiseCheckChildNoFocusedElement(browser)
+{
+ if (!gMultiProcessBrowser) {
+ Assert.equal(Services.focus.focusedElement, null, "There should be no focused element");
+ return null;
+ }
+
+ return ContentTask.spawn(browser, { }, function* () {
+ const fm = Components.classes["@mozilla.org/focus-manager;1"].
+ getService(Components.interfaces.nsIFocusManager);
+ Assert.equal(fm.focusedElement, null, "There should be no focused element");
+ });
+}
diff --git a/browser/base/content/test/urlbar/browser_locationBarExternalLoad.js b/browser/base/content/test/urlbar/browser_locationBarExternalLoad.js
new file mode 100644
index 000000000..31fc84768
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_locationBarExternalLoad.js
@@ -0,0 +1,65 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const url = "data:text/html,<body>hi";
+
+add_task(function*() {
+ yield* testURL(url, urlEnter);
+ yield* testURL(url, urlClick);
+});
+
+function urlEnter(url) {
+ gURLBar.value = url;
+ gURLBar.focus();
+ EventUtils.synthesizeKey("VK_RETURN", {});
+}
+
+function urlClick(url) {
+ gURLBar.value = url;
+ gURLBar.focus();
+ let goButton = document.getElementById("urlbar-go-button");
+ EventUtils.synthesizeMouseAtCenter(goButton, {});
+}
+
+function promiseNewTabSwitched() {
+ return new Promise(resolve => {
+ gBrowser.addEventListener("TabSwitchDone", function onSwitch() {
+ gBrowser.removeEventListener("TabSwitchDone", onSwitch);
+ executeSoon(resolve);
+ });
+ });
+}
+
+function* testURL(url, loadFunc, endFunc) {
+ let tabSwitchedPromise = promiseNewTabSwitched();
+ let tab = gBrowser.selectedTab = gBrowser.addTab();
+ let browser = gBrowser.selectedBrowser;
+
+ let pageshowPromise = BrowserTestUtils.waitForContentEvent(browser, "pageshow");
+
+ yield tabSwitchedPromise;
+ yield pageshowPromise;
+
+ let pagePrincipal = gBrowser.contentPrincipal;
+ loadFunc(url);
+
+ yield BrowserTestUtils.waitForContentEvent(browser, "pageshow");
+
+ yield ContentTask.spawn(browser, { isRemote: gMultiProcessBrowser },
+ function* (arg) {
+ const fm = Components.classes["@mozilla.org/focus-manager;1"].
+ getService(Components.interfaces.nsIFocusManager);
+ Assert.equal(fm.focusedElement, null, "focusedElement not null");
+
+ if (arg.isRemote) {
+ Assert.equal(fm.activeWindow, content, "activeWindow not correct");
+ }
+ });
+
+ is(document.activeElement, browser, "content window should be focused");
+
+ ok(!gBrowser.contentPrincipal.equals(pagePrincipal),
+ "load of " + url + " by " + loadFunc.name + " should produce a page with a different principal");
+
+ gBrowser.removeTab(tab);
+}
diff --git a/browser/base/content/test/urlbar/browser_moz_action_link.js b/browser/base/content/test/urlbar/browser_moz_action_link.js
new file mode 100644
index 000000000..ed2d36ee5
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_moz_action_link.js
@@ -0,0 +1,31 @@
+"use strict";
+
+const kURIs = [
+ "moz-action:foo,",
+ "moz-action:foo",
+];
+
+add_task(function*() {
+ for (let uri of kURIs) {
+ let dataURI = `data:text/html,<a id=a href="${uri}" target=_blank>Link</a>`;
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, dataURI);
+
+ let tabSwitchPromise = BrowserTestUtils.switchTab(gBrowser, function() {});
+ yield ContentTask.spawn(tab.linkedBrowser, null, function*() {
+ content.document.getElementById("a").click();
+ });
+ yield tabSwitchPromise;
+ isnot(gBrowser.selectedTab, tab, "Switched to new tab!");
+ is(gURLBar.value, "about:blank", "URL bar should be displaying about:blank");
+ let newTab = gBrowser.selectedTab;
+ yield BrowserTestUtils.switchTab(gBrowser, tab);
+ yield BrowserTestUtils.switchTab(gBrowser, newTab);
+ is(gBrowser.selectedTab, newTab, "Switched to new tab again!");
+ is(gURLBar.value, "about:blank", "URL bar should be displaying about:blank after tab switch");
+ // Finally, check that directly setting it produces the right results, too:
+ URLBarSetURI(makeURI(uri));
+ is(gURLBar.value, "about:blank", "URL bar should still be displaying about:blank");
+ yield BrowserTestUtils.removeTab(newTab);
+ yield BrowserTestUtils.removeTab(tab);
+ }
+});
diff --git a/browser/base/content/test/urlbar/browser_removeUnsafeProtocolsFromURLBarPaste.js b/browser/base/content/test/urlbar/browser_removeUnsafeProtocolsFromURLBarPaste.js
new file mode 100644
index 000000000..e9ba8d989
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_removeUnsafeProtocolsFromURLBarPaste.js
@@ -0,0 +1,49 @@
+function test() {
+ waitForExplicitFinish();
+ testNext();
+}
+
+var pairs = [
+ ["javascript:", ""],
+ ["javascript:1+1", "1+1"],
+ ["javascript:document.domain", "document.domain"],
+ ["data:text/html,<body>hi</body>", "data:text/html,<body>hi</body>"],
+ // Nested things get confusing because some things don't parse as URIs:
+ ["javascript:javascript:alert('hi!')", "alert('hi!')"],
+ ["data:data:text/html,<body>hi</body>", "data:data:text/html,<body>hi</body>"],
+ ["javascript:data:javascript:alert('hi!')", "data:javascript:alert('hi!')"],
+ ["javascript:data:text/html,javascript:alert('hi!')", "data:text/html,javascript:alert('hi!')"],
+ ["data:data:text/html,javascript:alert('hi!')", "data:data:text/html,javascript:alert('hi!')"],
+];
+
+var clipboardHelper = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper);
+
+function paste(input, cb) {
+ waitForClipboard(input, function() {
+ clipboardHelper.copyString(input);
+ }, function() {
+ document.commandDispatcher.getControllerForCommand("cmd_paste").doCommand("cmd_paste");
+ cb();
+ }, function() {
+ ok(false, "Failed to copy string '" + input + "' to clipboard");
+ cb();
+ });
+}
+
+function testNext() {
+ gURLBar.value = '';
+ if (!pairs.length) {
+ finish();
+ return;
+ }
+
+ let [inputValue, expectedURL] = pairs.shift();
+
+ gURLBar.focus();
+ paste(inputValue, function() {
+ is(gURLBar.textValue, expectedURL, "entering '" + inputValue + "' strips relevant bits.");
+
+ setTimeout(testNext, 0);
+ });
+}
+
diff --git a/browser/base/content/test/urlbar/browser_search_favicon.js b/browser/base/content/test/urlbar/browser_search_favicon.js
new file mode 100644
index 000000000..a8e6dbbcd
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_search_favicon.js
@@ -0,0 +1,52 @@
+var gOriginalEngine;
+var gEngine;
+var gRestyleSearchesPref = "browser.urlbar.restyleSearches";
+
+registerCleanupFunction(() => {
+ Services.prefs.clearUserPref(gRestyleSearchesPref);
+ Services.search.currentEngine = gOriginalEngine;
+ Services.search.removeEngine(gEngine);
+ return PlacesTestUtils.clearHistory();
+});
+
+add_task(function*() {
+ Services.prefs.setBoolPref(gRestyleSearchesPref, true);
+});
+
+add_task(function*() {
+
+ Services.search.addEngineWithDetails("SearchEngine", "", "", "",
+ "GET", "http://s.example.com/search");
+ gEngine = Services.search.getEngineByName("SearchEngine");
+ gEngine.addParam("q", "{searchTerms}", null);
+ gOriginalEngine = Services.search.currentEngine;
+ Services.search.currentEngine = gEngine;
+
+ let uri = NetUtil.newURI("http://s.example.com/search?q=foo&client=1");
+ yield PlacesTestUtils.addVisits({ uri: uri, title: "Foo - SearchEngine Search" });
+
+ yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:mozilla");
+
+ // The first autocomplete result has the action searchengine, while
+ // the second result is the "search favicon" element.
+ yield promiseAutocompleteResultPopup("foo");
+ let result = gURLBar.popup.richlistbox.children[1];
+
+ isnot(result, null, "Expect a search result");
+ is(result.getAttribute("type"), "searchengine", "Expect correct `type` attribute");
+
+ let titleHbox = result._titleText.parentNode.parentNode;
+ ok(titleHbox.classList.contains("ac-title"), "Title hbox sanity check");
+ is_element_visible(titleHbox, "Title element should be visible");
+
+ let urlHbox = result._urlText.parentNode.parentNode;
+ ok(urlHbox.classList.contains("ac-url"), "URL hbox sanity check");
+ is_element_hidden(urlHbox, "URL element should be hidden");
+
+ let actionHbox = result._actionText.parentNode.parentNode;
+ ok(actionHbox.classList.contains("ac-action"), "Action hbox sanity check");
+ is_element_hidden(actionHbox, "Action element should be hidden because it is not selected");
+ is(result._actionText.textContent, "Search with SearchEngine", "Action text should be as expected");
+
+ gBrowser.removeCurrentTab();
+});
diff --git a/browser/base/content/test/urlbar/browser_tabMatchesInAwesomebar.js b/browser/base/content/test/urlbar/browser_tabMatchesInAwesomebar.js
new file mode 100644
index 000000000..d207092d4
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_tabMatchesInAwesomebar.js
@@ -0,0 +1,216 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+ * vim:set ts=2 sw=2 sts=2 et:
+ * 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/. */
+
+requestLongerTimeout(2);
+
+const TEST_URL_BASES = [
+ "http://example.org/browser/browser/base/content/test/urlbar/dummy_page.html#tabmatch",
+ "http://example.org/browser/browser/base/content/test/urlbar/moz.png#tabmatch"
+];
+
+var gController = Cc["@mozilla.org/autocomplete/controller;1"].
+ getService(Ci.nsIAutoCompleteController);
+
+var gTabCounter = 0;
+
+add_task(function* step_1() {
+ info("Running step 1");
+ let maxResults = Services.prefs.getIntPref("browser.urlbar.maxRichResults");
+ let promises = [];
+ for (let i = 0; i < maxResults - 1; i++) {
+ let tab = gBrowser.addTab();
+ promises.push(loadTab(tab, TEST_URL_BASES[0] + (++gTabCounter)));
+ }
+
+ yield Promise.all(promises);
+ yield ensure_opentabs_match_db();
+});
+
+add_task(function* step_2() {
+ info("Running step 2");
+ gBrowser.selectTabAtIndex(1);
+ gBrowser.removeCurrentTab();
+ gBrowser.selectTabAtIndex(1);
+ gBrowser.removeCurrentTab();
+
+ let promises = [];
+ for (let i = 1; i < gBrowser.tabs.length; i++)
+ promises.push(loadTab(gBrowser.tabs[i], TEST_URL_BASES[1] + (++gTabCounter)));
+
+ yield Promise.all(promises);
+ yield ensure_opentabs_match_db();
+});
+
+add_task(function* step_3() {
+ info("Running step 3");
+ let promises = [];
+ for (let i = 1; i < gBrowser.tabs.length; i++)
+ promises.push(loadTab(gBrowser.tabs[i], TEST_URL_BASES[0] + gTabCounter));
+
+ yield Promise.all(promises);
+ yield ensure_opentabs_match_db();
+});
+
+add_task(function* step_4() {
+ info("Running step 4 - ensure we don't register subframes as open pages");
+ let tab = gBrowser.addTab();
+ tab.linkedBrowser.loadURI('data:text/html,<body><iframe src=""></iframe></body>');
+ yield BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+
+ yield ContentTask.spawn(tab.linkedBrowser, null, function* () {
+ let iframe_loaded = ContentTaskUtils.waitForEvent(content.document, "load", true);
+ content.document.querySelector("iframe").src = "http://test2.example.org/";
+ yield iframe_loaded;
+ });
+
+ yield ensure_opentabs_match_db();
+});
+
+add_task(function* step_5() {
+ info("Running step 5 - remove tab immediately");
+ let tab = gBrowser.addTab("about:logo");
+ yield BrowserTestUtils.removeTab(tab);
+ yield ensure_opentabs_match_db();
+});
+
+add_task(function* step_6() {
+ info("Running step 6 - check swapBrowsersAndCloseOther preserves registered switch-to-tab result");
+ let tabToKeep = gBrowser.addTab();
+ let tab = gBrowser.addTab();
+ tab.linkedBrowser.loadURI("about:mozilla");
+ yield BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+
+ gBrowser.updateBrowserRemoteness(tabToKeep.linkedBrowser, tab.linkedBrowser.isRemoteBrowser);
+ gBrowser.swapBrowsersAndCloseOther(tabToKeep, tab);
+
+ yield ensure_opentabs_match_db()
+
+ yield BrowserTestUtils.removeTab(tabToKeep);
+
+ yield ensure_opentabs_match_db();
+});
+
+add_task(function* step_7() {
+ info("Running step 7 - close all tabs");
+
+ Services.prefs.clearUserPref("browser.sessionstore.restore_on_demand");
+
+ gBrowser.addTab("about:blank", {skipAnimation: true});
+ while (gBrowser.tabs.length > 1) {
+ info("Removing tab: " + gBrowser.tabs[0].linkedBrowser.currentURI.spec);
+ gBrowser.selectTabAtIndex(0);
+ gBrowser.removeCurrentTab();
+ }
+
+ yield ensure_opentabs_match_db();
+});
+
+add_task(function* cleanup() {
+ info("Cleaning up");
+
+ yield PlacesTestUtils.clearHistory();
+});
+
+function loadTab(tab, url) {
+ // Because adding visits is async, we will not be notified immediately.
+ let loaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+ let visited = new Promise(resolve => {
+ Services.obs.addObserver(
+ function observer(aSubject, aTopic, aData) {
+ if (url != aSubject.QueryInterface(Ci.nsIURI).spec)
+ return;
+ Services.obs.removeObserver(observer, aTopic);
+ resolve();
+ },
+ "uri-visit-saved",
+ false
+ );
+ });
+
+ info("Loading page: " + url);
+ tab.linkedBrowser.loadURI(url);
+ return Promise.all([ loaded, visited ]);
+}
+
+function ensure_opentabs_match_db() {
+ var tabs = {};
+
+ var winEnum = Services.wm.getEnumerator("navigator:browser");
+ while (winEnum.hasMoreElements()) {
+ let browserWin = winEnum.getNext();
+ // skip closed-but-not-destroyed windows
+ if (browserWin.closed)
+ continue;
+
+ for (let i = 0; i < browserWin.gBrowser.tabContainer.childElementCount; i++) {
+ let browser = browserWin.gBrowser.getBrowserAtIndex(i);
+ let url = browser.currentURI.spec;
+ if (browserWin.isBlankPageURL(url))
+ continue;
+ if (!(url in tabs))
+ tabs[url] = 1;
+ else
+ tabs[url]++;
+ }
+ }
+
+ return new Promise(resolve => {
+ checkAutocompleteResults(tabs, resolve);
+ });
+}
+
+function checkAutocompleteResults(aExpected, aCallback)
+{
+ gController.input = {
+ timeout: 10,
+ textValue: "",
+ searches: ["unifiedcomplete"],
+ searchParam: "enable-actions",
+ popupOpen: false,
+ minResultsForPopup: 0,
+ invalidate: function() {},
+ disableAutoComplete: false,
+ completeDefaultIndex: false,
+ get popup() { return this; },
+ onSearchBegin: function() {},
+ onSearchComplete: function ()
+ {
+ info("Found " + gController.matchCount + " matches.");
+ // Check to see the expected uris and titles match up (in any order)
+ for (let i = 0; i < gController.matchCount; i++) {
+ if (gController.getStyleAt(i).includes("heuristic")) {
+ info("Skip heuristic match");
+ continue;
+ }
+ let action = gURLBar.popup.input._parseActionUrl(gController.getValueAt(i));
+ let uri = action.params.url;
+
+ info("Search for '" + uri + "' in open tabs.");
+ let expected = uri in aExpected;
+ ok(expected, uri + " was found in autocomplete, was " + (expected ? "" : "not ") + "expected");
+ // Remove the found entry from expected results.
+ delete aExpected[uri];
+ }
+
+ // Make sure there is no reported open page that is not open.
+ for (let entry in aExpected) {
+ ok(false, "'" + entry + "' should be found in autocomplete");
+ }
+
+ executeSoon(aCallback);
+ },
+ setSelectedIndex: function() {},
+ get searchCount() { return this.searches.length; },
+ getSearchAt: function(aIndex) { return this.searches[aIndex]; },
+ QueryInterface: XPCOMUtils.generateQI([
+ Ci.nsIAutoCompleteInput,
+ Ci.nsIAutoCompletePopup,
+ ])
+ };
+
+ info("Searching open pages.");
+ gController.startSearch(Services.prefs.getCharPref("browser.urlbar.restrict.openpage"));
+}
diff --git a/browser/base/content/test/urlbar/browser_tabMatchesInAwesomebar_perwindowpb.js b/browser/base/content/test/urlbar/browser_tabMatchesInAwesomebar_perwindowpb.js
new file mode 100644
index 000000000..08a18b38a
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_tabMatchesInAwesomebar_perwindowpb.js
@@ -0,0 +1,84 @@
+let testURL = "http://example.org/browser/browser/base/content/test/urlbar/dummy_page.html";
+
+add_task(function*() {
+ let normalWindow = yield BrowserTestUtils.openNewBrowserWindow();
+ let privateWindow = yield BrowserTestUtils.openNewBrowserWindow({private: true});
+ yield runTest(normalWindow, privateWindow, false);
+ yield BrowserTestUtils.closeWindow(normalWindow);
+ yield BrowserTestUtils.closeWindow(privateWindow);
+
+ normalWindow = yield BrowserTestUtils.openNewBrowserWindow();
+ privateWindow = yield BrowserTestUtils.openNewBrowserWindow({private: true});
+ yield runTest(privateWindow, normalWindow, false);
+ yield BrowserTestUtils.closeWindow(normalWindow);
+ yield BrowserTestUtils.closeWindow(privateWindow);
+
+ privateWindow = yield BrowserTestUtils.openNewBrowserWindow({private: true});
+ yield runTest(privateWindow, privateWindow, false);
+ yield BrowserTestUtils.closeWindow(privateWindow);
+
+ normalWindow = yield BrowserTestUtils.openNewBrowserWindow();
+ yield runTest(normalWindow, normalWindow, true);
+ yield BrowserTestUtils.closeWindow(normalWindow);
+});
+
+function* runTest(aSourceWindow, aDestWindow, aExpectSwitch, aCallback) {
+ yield BrowserTestUtils.openNewForegroundTab(aSourceWindow.gBrowser, testURL);
+ let testTab = yield BrowserTestUtils.openNewForegroundTab(aDestWindow.gBrowser);
+
+ info("waiting for focus on the window");
+ yield SimpleTest.promiseFocus(aDestWindow);
+ info("got focus on the window");
+
+ // Select the testTab
+ aDestWindow.gBrowser.selectedTab = testTab;
+
+ // Ensure that this tab has no history entries
+ let sessionHistoryCount = yield new Promise(resolve => {
+ SessionStore.getSessionHistory(gBrowser.selectedTab, function(sessionHistory) {
+ resolve(sessionHistory.entries.length);
+ });
+ });
+
+ ok(sessionHistoryCount < 2,
+ `The test tab has 1 or fewer history entries. sessionHistoryCount=${sessionHistoryCount}`);
+ // Ensure that this tab is on about:blank
+ is(testTab.linkedBrowser.currentURI.spec, "about:blank",
+ "The test tab is on about:blank");
+ // Ensure that this tab's document has no child nodes
+ yield ContentTask.spawn(testTab.linkedBrowser, null, function*() {
+ ok(!content.document.body.hasChildNodes(),
+ "The test tab has no child nodes");
+ });
+ ok(!testTab.hasAttribute("busy"),
+ "The test tab doesn't have the busy attribute");
+
+ // Wait for the Awesomebar popup to appear.
+ yield promiseAutocompleteResultPopup(testURL, aDestWindow);
+
+ info(`awesomebar popup appeared. aExpectSwitch: ${aExpectSwitch}`);
+ // Make sure the last match is selected.
+ let {controller, popup} = aDestWindow.gURLBar;
+ while (popup.selectedIndex < controller.matchCount - 1) {
+ info("handling key navigation for DOM_VK_DOWN key");
+ controller.handleKeyNavigation(KeyEvent.DOM_VK_DOWN);
+ }
+
+ let awaitTabSwitch;
+ if (aExpectSwitch) {
+ awaitTabSwitch = BrowserTestUtils.removeTab(testTab, {dontRemove: true})
+ }
+
+ // Execute the selected action.
+ controller.handleEnter(true);
+ info("sent Enter command to the controller");
+
+ if (aExpectSwitch) {
+ // If we expect a tab switch then the current tab
+ // will be closed and we switch to the other tab.
+ yield awaitTabSwitch;
+ } else {
+ // If we don't expect a tab switch then wait for the tab to load.
+ yield BrowserTestUtils.browserLoaded(testTab.linkedBrowser);
+ }
+}
diff --git a/browser/base/content/test/urlbar/browser_urlHighlight.js b/browser/base/content/test/urlbar/browser_urlHighlight.js
new file mode 100644
index 000000000..ba1537d91
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_urlHighlight.js
@@ -0,0 +1,134 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function testVal(aExpected) {
+ gURLBar.value = aExpected.replace(/[<>]/g, "");
+
+ let selectionController = gURLBar.editor.selectionController;
+ let selection = selectionController.getSelection(selectionController.SELECTION_URLSECONDARY);
+ let value = gURLBar.editor.rootElement.textContent;
+ let result = "";
+ for (let i = 0; i < selection.rangeCount; i++) {
+ let range = selection.getRangeAt(i).toString();
+ let pos = value.indexOf(range);
+ result += value.substring(0, pos) + "<" + range + ">";
+ value = value.substring(pos + range.length);
+ }
+ result += value;
+ is(result, aExpected,
+ "Correct part of the urlbar contents is highlighted");
+}
+
+function test() {
+ const prefname = "browser.urlbar.formatting.enabled";
+
+ registerCleanupFunction(function () {
+ Services.prefs.clearUserPref(prefname);
+ URLBarSetURI();
+ });
+
+ Services.prefs.setBoolPref(prefname, true);
+
+ gURLBar.focus();
+
+ testVal("https://mozilla.org");
+
+ gBrowser.selectedBrowser.focus();
+
+ testVal("<https://>mozilla.org");
+ testVal("<https://>mözilla.org");
+ testVal("<https://>mozilla.imaginatory");
+
+ testVal("<https://www.>mozilla.org");
+ testVal("<https://sub.>mozilla.org");
+ testVal("<https://sub1.sub2.sub3.>mozilla.org");
+ testVal("<www.>mozilla.org");
+ testVal("<sub.>mozilla.org");
+ testVal("<sub1.sub2.sub3.>mozilla.org");
+ testVal("<mozilla.com.>mozilla.com");
+ testVal("<https://mozilla.com:mozilla.com@>mozilla.com");
+ testVal("<mozilla.com:mozilla.com@>mozilla.com");
+
+ testVal("<ftp.>mozilla.org");
+ testVal("<ftp://ftp.>mozilla.org");
+
+ testVal("<https://sub.>mozilla.org");
+ testVal("<https://sub1.sub2.sub3.>mozilla.org");
+ testVal("<https://user:pass@sub1.sub2.sub3.>mozilla.org");
+ testVal("<https://user:pass@>mozilla.org");
+ testVal("<user:pass@sub1.sub2.sub3.>mozilla.org");
+ testVal("<user:pass@>mozilla.org");
+
+ testVal("<https://>mozilla.org< >");
+ testVal("mozilla.org< >");
+
+ testVal("<https://>mozilla.org</file.ext>");
+ testVal("<https://>mozilla.org</sub/file.ext>");
+ testVal("<https://>mozilla.org</sub/file.ext?foo>");
+ testVal("<https://>mozilla.org</sub/file.ext?foo&bar>");
+ testVal("<https://>mozilla.org</sub/file.ext?foo&bar#top>");
+ testVal("<https://>mozilla.org</sub/file.ext?foo&bar#top>");
+ testVal("foo.bar<?q=test>");
+ testVal("foo.bar<#mozilla.org>");
+ testVal("foo.bar<?somewhere.mozilla.org>");
+ testVal("foo.bar<?@mozilla.org>");
+ testVal("foo.bar<#x@mozilla.org>");
+ testVal("foo.bar<#@x@mozilla.org>");
+ testVal("foo.bar<?x@mozilla.org>");
+ testVal("foo.bar<?@x@mozilla.org>");
+ testVal("<foo.bar@x@>mozilla.org");
+ testVal("<foo.bar@:baz@>mozilla.org");
+ testVal("<foo.bar:@baz@>mozilla.org");
+ testVal("<foo.bar@:ba:z@>mozilla.org");
+ testVal("<foo.:bar:@baz@>mozilla.org");
+
+ testVal("<https://sub.>mozilla.org<:666/file.ext>");
+ testVal("<sub.>mozilla.org<:666/file.ext>");
+ testVal("localhost<:666/file.ext>");
+
+ let IPs = ["192.168.1.1",
+ "[::]",
+ "[::1]",
+ "[1::]",
+ "[::]",
+ "[::1]",
+ "[1::]",
+ "[1:2:3:4:5:6:7::]",
+ "[::1:2:3:4:5:6:7]",
+ "[1:2:a:B:c:D:e:F]",
+ "[1::8]",
+ "[1:2::8]",
+ "[fe80::222:19ff:fe11:8c76]",
+ "[0000:0123:4567:89AB:CDEF:abcd:ef00:0000]",
+ "[::192.168.1.1]",
+ "[1::0.0.0.0]",
+ "[1:2::255.255.255.255]",
+ "[1:2:3::255.255.255.255]",
+ "[1:2:3:4::255.255.255.255]",
+ "[1:2:3:4:5::255.255.255.255]",
+ "[1:2:3:4:5:6:255.255.255.255]"];
+ IPs.forEach(function (IP) {
+ testVal(IP);
+ testVal(IP + "</file.ext>");
+ testVal(IP + "<:666/file.ext>");
+ testVal("<https://>" + IP);
+ testVal("<https://>" + IP + "</file.ext>");
+ testVal("<https://user:pass@>" + IP + "<:666/file.ext>");
+ testVal("<user:pass@>" + IP + "<:666/file.ext>");
+ });
+
+ testVal("mailto:admin@mozilla.org");
+ testVal("gopher://mozilla.org/");
+ testVal("about:config");
+ testVal("jar:http://mozilla.org/example.jar!/");
+ testVal("view-source:http://mozilla.org/");
+ testVal("foo9://mozilla.org/");
+ testVal("foo+://mozilla.org/");
+ testVal("foo.://mozilla.org/");
+ testVal("foo-://mozilla.org/");
+
+ Services.prefs.setBoolPref(prefname, false);
+
+ testVal("https://mozilla.org");
+}
diff --git a/browser/base/content/test/urlbar/browser_urlbarAboutHomeLoading.js b/browser/base/content/test/urlbar/browser_urlbarAboutHomeLoading.js
new file mode 100644
index 000000000..792826eb1
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_urlbarAboutHomeLoading.js
@@ -0,0 +1,104 @@
+"use strict";
+
+const {TabStateFlusher} = Cu.import("resource:///modules/sessionstore/TabStateFlusher.jsm", {});
+
+/**
+ * Test what happens if loading a URL that should clear the
+ * location bar after a parent process URL.
+ */
+add_task(function* clearURLBarAfterParentProcessURL() {
+ let tab = yield new Promise(resolve => {
+ gBrowser.selectedTab = gBrowser.addTab("about:preferences");
+ let newTabBrowser = gBrowser.getBrowserForTab(gBrowser.selectedTab);
+ newTabBrowser.addEventListener("Initialized", function onInit() {
+ newTabBrowser.removeEventListener("Initialized", onInit, true);
+ resolve(gBrowser.selectedTab);
+ }, true);
+ });
+ document.getElementById("home-button").click();
+ yield BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+ is(gURLBar.value, "", "URL bar should be empty");
+ is(tab.linkedBrowser.userTypedValue, null, "The browser should have no recorded userTypedValue");
+ yield BrowserTestUtils.removeTab(tab);
+});
+
+/**
+ * Same as above, but open the tab without passing the URL immediately
+ * which changes behaviour in tabbrowser.xml.
+ */
+add_task(function* clearURLBarAfterParentProcessURLInExistingTab() {
+ let tab = yield new Promise(resolve => {
+ gBrowser.selectedTab = gBrowser.addTab();
+ let newTabBrowser = gBrowser.getBrowserForTab(gBrowser.selectedTab);
+ newTabBrowser.addEventListener("Initialized", function onInit() {
+ newTabBrowser.removeEventListener("Initialized", onInit, true);
+ resolve(gBrowser.selectedTab);
+ }, true);
+ newTabBrowser.loadURI("about:preferences");
+ });
+ document.getElementById("home-button").click();
+ yield BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+ is(gURLBar.value, "", "URL bar should be empty");
+ is(tab.linkedBrowser.userTypedValue, null, "The browser should have no recorded userTypedValue");
+ yield BrowserTestUtils.removeTab(tab);
+});
+
+/**
+ * Load about:home directly from an about:newtab page. Because it is an
+ * 'initial' page, we need to treat this specially if the user actually
+ * loads a page like this from the URL bar.
+ */
+add_task(function* clearURLBarAfterManuallyLoadingAboutHome() {
+ let promiseTabOpenedAndSwitchedTo = BrowserTestUtils.switchTab(gBrowser, () => {});
+ // This opens about:newtab:
+ BrowserOpenTab();
+ let tab = yield promiseTabOpenedAndSwitchedTo;
+ is(gURLBar.value, "", "URL bar should be empty");
+ is(tab.linkedBrowser.userTypedValue, null, "userTypedValue should be null");
+
+ gURLBar.value = "about:home";
+ gURLBar.select();
+ let aboutHomeLoaded = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser, false, "about:home");
+ EventUtils.sendKey("return");
+ yield aboutHomeLoaded;
+
+ is(gURLBar.value, "", "URL bar should be empty");
+ is(tab.linkedBrowser.userTypedValue, null, "userTypedValue should be null");
+ yield BrowserTestUtils.removeTab(tab);
+});
+
+/**
+ * Ensure we don't show 'about:home' in the URL bar temporarily in new tabs
+ * while we're switching remoteness (when the URL we're loading and the
+ * default content principal are different).
+ */
+add_task(function* dontTemporarilyShowAboutHome() {
+ yield SpecialPowers.pushPrefEnv({set: [["browser.startup.page", 1]]});
+ let windowOpenedPromise = BrowserTestUtils.waitForNewWindow();
+ let win = OpenBrowserWindow();
+ yield windowOpenedPromise;
+ let promiseTabSwitch = BrowserTestUtils.switchTab(win.gBrowser, () => {});
+ win.BrowserOpenTab();
+ yield promiseTabSwitch;
+ yield TabStateFlusher.flush(win.gBrowser.selectedBrowser);
+ yield BrowserTestUtils.closeWindow(win);
+ ok(SessionStore.getClosedWindowCount(), "Should have a closed window");
+
+ windowOpenedPromise = BrowserTestUtils.waitForNewWindow();
+ win = SessionStore.undoCloseWindow(0);
+ yield windowOpenedPromise;
+ let wpl = {
+ onLocationChange(wpl, request, location, flags) {
+ is(win.gURLBar.value, "", "URL bar value should stay empty.");
+ },
+ };
+ win.gBrowser.addProgressListener(wpl);
+ let otherTab = win.gBrowser.selectedTab.previousSibling;
+ let tabLoaded = BrowserTestUtils.browserLoaded(otherTab.linkedBrowser, false, "about:home");
+ yield BrowserTestUtils.switchTab(win.gBrowser, otherTab);
+ yield tabLoaded;
+ win.gBrowser.removeProgressListener(wpl);
+ is(win.gURLBar.value, "", "URL bar value should be empty.");
+
+ yield BrowserTestUtils.closeWindow(win);
+});
diff --git a/browser/base/content/test/urlbar/browser_urlbarAutoFillTrimURLs.js b/browser/base/content/test/urlbar/browser_urlbarAutoFillTrimURLs.js
new file mode 100644
index 000000000..8101c101d
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_urlbarAutoFillTrimURLs.js
@@ -0,0 +1,49 @@
+// This test ensures that autoFilled values are not trimmed, unless the user
+// selects from the autocomplete popup.
+
+add_task(function* setup() {
+ const PREF_TRIMURL = "browser.urlbar.trimURLs";
+ const PREF_AUTOFILL = "browser.urlbar.autoFill";
+
+ registerCleanupFunction(function* () {
+ Services.prefs.clearUserPref(PREF_TRIMURL);
+ Services.prefs.clearUserPref(PREF_AUTOFILL);
+ yield PlacesTestUtils.clearHistory();
+ gURLBar.handleRevert();
+ });
+ Services.prefs.setBoolPref(PREF_TRIMURL, true);
+ Services.prefs.setBoolPref(PREF_AUTOFILL, true);
+
+ // Adding a tab would hit switch-to-tab, so it's safer to just add a visit.
+ yield PlacesTestUtils.addVisits({
+ uri: "http://www.autofilltrimurl.com/whatever",
+ transition: Ci.nsINavHistoryService.TRANSITION_TYPED,
+ });
+});
+
+function* promiseSearch(searchtext) {
+ gURLBar.focus();
+ gURLBar.inputField.value = searchtext.substr(0, searchtext.length -1);
+ EventUtils.synthesizeKey(searchtext.substr(-1, 1), {});
+ yield promiseSearchComplete();
+}
+
+add_task(function* () {
+ yield promiseSearch("http://");
+ is(gURLBar.inputField.value, "http://", "Autofilled value is as expected");
+});
+
+add_task(function* () {
+ yield promiseSearch("http://au");
+ is(gURLBar.inputField.value, "http://autofilltrimurl.com/", "Autofilled value is as expected");
+});
+
+add_task(function* () {
+ yield promiseSearch("http://www.autofilltrimurl.com");
+ is(gURLBar.inputField.value, "http://www.autofilltrimurl.com/", "Autofilled value is as expected");
+
+ // Now ensure selecting from the popup correctly trims.
+ is(gURLBar.controller.matchCount, 2, "Found the expected number of matches");
+ EventUtils.synthesizeKey("VK_DOWN", {});
+ is(gURLBar.inputField.value, "www.autofilltrimurl.com/whatever", "trim was applied correctly");
+});
diff --git a/browser/base/content/test/urlbar/browser_urlbarCopying.js b/browser/base/content/test/urlbar/browser_urlbarCopying.js
new file mode 100644
index 000000000..8d5562b61
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_urlbarCopying.js
@@ -0,0 +1,232 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const trimPref = "browser.urlbar.trimURLs";
+const phishyUserPassPref = "network.http.phishy-userpass-length";
+
+function toUnicode(input) {
+ let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
+ .createInstance(Ci.nsIScriptableUnicodeConverter);
+ converter.charset = "UTF-8";
+
+ return converter.ConvertToUnicode(input);
+}
+
+function test() {
+
+ let tab = gBrowser.selectedTab = gBrowser.addTab();
+
+ registerCleanupFunction(function () {
+ gBrowser.removeTab(tab);
+ Services.prefs.clearUserPref(trimPref);
+ Services.prefs.clearUserPref(phishyUserPassPref);
+ URLBarSetURI();
+ });
+
+ Services.prefs.setBoolPref(trimPref, true);
+ Services.prefs.setIntPref(phishyUserPassPref, 32); // avoid prompting about phishing
+
+ waitForExplicitFinish();
+
+ nextTest();
+}
+
+var tests = [
+ // pageproxystate="invalid"
+ {
+ setURL: "http://example.com/",
+ expectedURL: "example.com",
+ copyExpected: "example.com"
+ },
+ {
+ copyVal: "<e>xample.com",
+ copyExpected: "e"
+ },
+
+ // pageproxystate="valid" from this point on (due to the load)
+ {
+ loadURL: "http://example.com/",
+ expectedURL: "example.com",
+ copyExpected: "http://example.com/"
+ },
+ {
+ copyVal: "<example.co>m",
+ copyExpected: "example.co"
+ },
+ {
+ copyVal: "e<x>ample.com",
+ copyExpected: "x"
+ },
+ {
+ copyVal: "<e>xample.com",
+ copyExpected: "e"
+ },
+
+ {
+ loadURL: "http://example.com/foo",
+ expectedURL: "example.com/foo",
+ copyExpected: "http://example.com/foo"
+ },
+ {
+ copyVal: "<example.com>/foo",
+ copyExpected: "http://example.com"
+ },
+ {
+ copyVal: "<example>.com/foo",
+ copyExpected: "example"
+ },
+
+ // Test that userPass is stripped out
+ {
+ loadURL: "http://user:pass@mochi.test:8888/browser/browser/base/content/test/urlbar/authenticate.sjs?user=user&pass=pass",
+ expectedURL: "mochi.test:8888/browser/browser/base/content/test/urlbar/authenticate.sjs?user=user&pass=pass",
+ copyExpected: "http://mochi.test:8888/browser/browser/base/content/test/urlbar/authenticate.sjs?user=user&pass=pass"
+ },
+
+ // Test escaping
+ {
+ loadURL: "http://example.com/()%28%29%C3%A9",
+ expectedURL: "example.com/()()\xe9",
+ copyExpected: "http://example.com/()%28%29%C3%A9"
+ },
+ {
+ copyVal: "<example.com/(>)()\xe9",
+ copyExpected: "http://example.com/("
+ },
+ {
+ copyVal: "e<xample.com/(>)()\xe9",
+ copyExpected: "xample.com/("
+ },
+
+ {
+ loadURL: "http://example.com/%C3%A9%C3%A9",
+ expectedURL: "example.com/\xe9\xe9",
+ copyExpected: "http://example.com/%C3%A9%C3%A9"
+ },
+ {
+ copyVal: "e<xample.com/\xe9>\xe9",
+ copyExpected: "xample.com/\xe9"
+ },
+ {
+ copyVal: "<example.com/\xe9>\xe9",
+ copyExpected: "http://example.com/\xe9"
+ },
+
+ {
+ loadURL: "http://example.com/?%C3%B7%C3%B7",
+ expectedURL: "example.com/?\xf7\xf7",
+ copyExpected: "http://example.com/?%C3%B7%C3%B7"
+ },
+ {
+ copyVal: "e<xample.com/?\xf7>\xf7",
+ copyExpected: "xample.com/?\xf7"
+ },
+ {
+ copyVal: "<example.com/?\xf7>\xf7",
+ copyExpected: "http://example.com/?\xf7"
+ },
+ {
+ loadURL: "http://example.com/a%20test",
+ expectedURL: "example.com/a test",
+ copyExpected: "http://example.com/a%20test"
+ },
+ {
+ loadURL: "http://example.com/a%E3%80%80test",
+ expectedURL: toUnicode("example.com/a test"),
+ copyExpected: "http://example.com/a%E3%80%80test"
+ },
+ {
+ loadURL: "http://example.com/a%20%C2%A0test",
+ expectedURL: "example.com/a%20%C2%A0test",
+ copyExpected: "http://example.com/a%20%C2%A0test"
+ },
+ {
+ loadURL: "http://example.com/%20%20%20",
+ expectedURL: "example.com/%20%20%20",
+ copyExpected: "http://example.com/%20%20%20"
+ },
+ {
+ loadURL: "http://example.com/%E3%80%80%E3%80%80",
+ expectedURL: "example.com/%E3%80%80%E3%80%80",
+ copyExpected: "http://example.com/%E3%80%80%E3%80%80"
+ },
+
+ // data: and javsacript: URIs shouldn't be encoded
+ {
+ loadURL: "javascript:('%C3%A9%20%25%50')",
+ expectedURL: "javascript:('%C3%A9 %25P')",
+ copyExpected: "javascript:('%C3%A9 %25P')"
+ },
+ {
+ copyVal: "<javascript:(>'%C3%A9 %25P')",
+ copyExpected: "javascript:("
+ },
+
+ {
+ loadURL: "data:text/html,(%C3%A9%20%25%50)",
+ expectedURL: "data:text/html,(%C3%A9 %25P)",
+ copyExpected: "data:text/html,(%C3%A9 %25P)",
+ },
+ {
+ copyVal: "<data:text/html,(>%C3%A9 %25P)",
+ copyExpected: "data:text/html,("
+ },
+ {
+ copyVal: "<data:text/html,(%C3%A9 %25P>)",
+ copyExpected: "data:text/html,(%C3%A9 %25P",
+ }
+];
+
+function nextTest() {
+ let test = tests.shift();
+ if (tests.length == 0)
+ runTest(test, finish);
+ else
+ runTest(test, nextTest);
+}
+
+function runTest(test, cb) {
+ function doCheck() {
+ if (test.setURL || test.loadURL) {
+ gURLBar.valueIsTyped = !!test.setURL;
+ is(gURLBar.textValue, test.expectedURL, "url bar value set");
+ }
+
+ testCopy(test.copyVal, test.copyExpected, cb);
+ }
+
+ if (test.loadURL) {
+ loadURL(test.loadURL, doCheck);
+ } else {
+ if (test.setURL)
+ gURLBar.value = test.setURL;
+ doCheck();
+ }
+}
+
+function testCopy(copyVal, targetValue, cb) {
+ info("Expecting copy of: " + targetValue);
+ waitForClipboard(targetValue, function () {
+ gURLBar.focus();
+ if (copyVal) {
+ let startBracket = copyVal.indexOf("<");
+ let endBracket = copyVal.indexOf(">");
+ if (startBracket == -1 || endBracket == -1 ||
+ startBracket > endBracket ||
+ copyVal.replace("<", "").replace(">", "") != gURLBar.textValue) {
+ ok(false, "invalid copyVal: " + copyVal);
+ }
+ gURLBar.selectionStart = startBracket;
+ gURLBar.selectionEnd = endBracket - 1;
+ } else {
+ gURLBar.select();
+ }
+
+ goDoCommand("cmd_copy");
+ }, cb, cb);
+}
+
+function loadURL(aURL, aCB) {
+ BrowserTestUtils.loadURI(gBrowser.selectedBrowser, aURL);
+ BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser, false, aURL).then(aCB);
+}
diff --git a/browser/base/content/test/urlbar/browser_urlbarDecode.js b/browser/base/content/test/urlbar/browser_urlbarDecode.js
new file mode 100644
index 000000000..6a2c421ef
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_urlbarDecode.js
@@ -0,0 +1,97 @@
+"use strict";
+
+// This test makes sure (1) you can't break the urlbar by typing particular JSON
+// or JS fragments into it, (2) urlbar.textValue shows URLs unescaped, and (3)
+// the urlbar also shows the URLs embedded in action URIs unescaped. See bug
+// 1233672.
+
+add_task(function* injectJSON() {
+ let inputStrs = [
+ 'http://example.com/ ", "url": "bar',
+ 'http://example.com/\\',
+ 'http://example.com/"',
+ 'http://example.com/","url":"evil.com',
+ 'http://mozilla.org/\\u0020',
+ 'http://www.mozilla.org/","url":1e6,"some-key":"foo',
+ 'http://www.mozilla.org/","url":null,"some-key":"foo',
+ 'http://www.mozilla.org/","url":["foo","bar"],"some-key":"foo',
+ ];
+ for (let inputStr of inputStrs) {
+ yield checkInput(inputStr);
+ }
+ gURLBar.value = "";
+ gURLBar.handleRevert();
+ gURLBar.blur();
+});
+
+add_task(function losslessDecode() {
+ let urlNoScheme = "example.com/\u30a2\u30a4\u30a6\u30a8\u30aa";
+ let url = "http://" + urlNoScheme;
+ gURLBar.textValue = url;
+ // Since this is directly setting textValue, it is expected to be trimmed.
+ Assert.equal(gURLBar.inputField.value, urlNoScheme,
+ "The string displayed in the textbox should not be escaped");
+ gURLBar.value = "";
+ gURLBar.handleRevert();
+ gURLBar.blur();
+});
+
+add_task(function* actionURILosslessDecode() {
+ let urlNoScheme = "example.com/\u30a2\u30a4\u30a6\u30a8\u30aa";
+ let url = "http://" + urlNoScheme;
+ yield promiseAutocompleteResultPopup(url);
+
+ // At this point the heuristic result is selected but the urlbar's value is
+ // simply `url`. Key down and back around until the heuristic result is
+ // selected again, and at that point the urlbar's value should be a visiturl
+ // moz-action.
+
+ do {
+ gURLBar.controller.handleKeyNavigation(KeyEvent.DOM_VK_DOWN);
+ } while (gURLBar.popup.selectedIndex != 0);
+
+ let [, type, ] = gURLBar.value.match(/^moz-action:([^,]+),(.*)$/);
+ Assert.equal(type, "visiturl",
+ "visiturl action URI should be in the urlbar");
+
+ Assert.equal(gURLBar.inputField.value, urlNoScheme,
+ "The string displayed in the textbox should not be escaped");
+
+ gURLBar.value = "";
+ gURLBar.handleRevert();
+ gURLBar.blur();
+});
+
+function* checkInput(inputStr) {
+ yield promiseAutocompleteResultPopup(inputStr);
+
+ let item = gURLBar.popup.richlistbox.firstChild;
+ Assert.ok(item, "Should have a result");
+
+ // visiturl matches have their param.urls fixed up.
+ let fixupInfo = Services.uriFixup.getFixupURIInfo(inputStr,
+ Ci.nsIURIFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS |
+ Ci.nsIURIFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP
+ );
+ let expectedVisitURL = fixupInfo.fixedURI.spec;
+
+ let type = "visiturl";
+ let params = {
+ url: expectedVisitURL,
+ input: inputStr,
+ };
+ for (let key in params) {
+ params[key] = encodeURIComponent(params[key]);
+ }
+ let expectedURL = "moz-action:" + type + "," + JSON.stringify(params);
+ Assert.equal(item.getAttribute("url"), expectedURL, "url");
+
+ Assert.equal(item.getAttribute("title"), inputStr.replace("\\", "/"), "title");
+ Assert.equal(item.getAttribute("text"), inputStr, "text");
+
+ let itemType = item.getAttribute("type");
+ Assert.equal(itemType, "visiturl");
+
+ Assert.equal(item._titleText.textContent, inputStr.replace("\\", "/"), "Visible title");
+ Assert.equal(item._actionText.textContent, "Visit", "Visible action");
+}
diff --git a/browser/base/content/test/urlbar/browser_urlbarDelete.js b/browser/base/content/test/urlbar/browser_urlbarDelete.js
new file mode 100644
index 000000000..d4eb6c856
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_urlbarDelete.js
@@ -0,0 +1,39 @@
+add_task(function*() {
+ let bm = yield PlacesUtils.bookmarks.insert({ parentGuid: PlacesUtils.bookmarks.unfiledGuid,
+ url: "http://bug1105244.example.com/",
+ title: "test" });
+
+ registerCleanupFunction(function* () {
+ yield PlacesUtils.bookmarks.remove(bm);
+ });
+
+ yield BrowserTestUtils.withNewTab({ gBrowser, url: "about:blank" }, testDelete);
+});
+
+function sendHome() {
+ // unclear why VK_HOME doesn't work on Mac, but it doesn't...
+ if (Services.appinfo.OS == "Darwin") {
+ EventUtils.synthesizeKey("VK_LEFT", { altKey: true });
+ } else {
+ EventUtils.synthesizeKey("VK_HOME", {});
+ }
+}
+
+function sendDelete() {
+ EventUtils.synthesizeKey("VK_DELETE", {});
+}
+
+function* testDelete() {
+ yield promiseAutocompleteResultPopup("bug1105244");
+
+ // move to the start.
+ sendHome();
+ // delete the first few chars - each delete should operate on the input field.
+ sendDelete();
+ Assert.equal(gURLBar.inputField.value, "ug1105244");
+
+ yield promisePopupShown(gURLBar.popup);
+
+ sendDelete();
+ Assert.equal(gURLBar.inputField.value, "g1105244");
+}
diff --git a/browser/base/content/test/urlbar/browser_urlbarEnter.js b/browser/base/content/test/urlbar/browser_urlbarEnter.js
new file mode 100644
index 000000000..32cbaf2be
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_urlbarEnter.js
@@ -0,0 +1,45 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const TEST_VALUE = "example.com/\xF7?\xF7";
+const START_VALUE = "example.com/%C3%B7?%C3%B7";
+
+add_task(function* () {
+ info("Simple return keypress");
+ let tab = gBrowser.selectedTab = gBrowser.addTab(START_VALUE);
+
+ gURLBar.focus();
+ EventUtils.synthesizeKey("VK_RETURN", {});
+ yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+
+ // Check url bar and selected tab.
+ is(gURLBar.textValue, TEST_VALUE, "Urlbar should preserve the value on return keypress");
+ is(gBrowser.selectedTab, tab, "New URL was loaded in the current tab");
+
+ // Cleanup.
+ yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
+});
+
+add_task(function* () {
+ info("Alt+Return keypress");
+ // due to bug 691608, we must wait for the load event, else isTabEmpty() will
+ // return true on e10s for this tab, so it will be reused even with altKey.
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, START_VALUE);
+
+ let tabOpenPromise = BrowserTestUtils.waitForEvent(gBrowser.tabContainer, "TabOpen");
+ gURLBar.focus();
+ EventUtils.synthesizeKey("VK_RETURN", {altKey: true});
+
+ // wait for the new tab to appear.
+ yield tabOpenPromise;
+
+ // Check url bar and selected tab.
+ is(gURLBar.textValue, TEST_VALUE, "Urlbar should preserve the value on return keypress");
+ isnot(gBrowser.selectedTab, tab, "New URL was loaded in a new tab");
+
+ // Cleanup.
+ yield BrowserTestUtils.removeTab(tab);
+ yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
+});
diff --git a/browser/base/content/test/urlbar/browser_urlbarEnterAfterMouseOver.js b/browser/base/content/test/urlbar/browser_urlbarEnterAfterMouseOver.js
new file mode 100644
index 000000000..22e336f91
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_urlbarEnterAfterMouseOver.js
@@ -0,0 +1,69 @@
+function repeat(limit, func) {
+ for (let i = 0; i < limit; i++) {
+ func(i);
+ }
+}
+
+function* promiseAutoComplete(inputText) {
+ gURLBar.focus();
+ gURLBar.value = inputText.slice(0, -1);
+ EventUtils.synthesizeKey(inputText.slice(-1), {});
+ yield promiseSearchComplete();
+}
+
+function is_selected(index) {
+ is(gURLBar.popup.richlistbox.selectedIndex, index, `Item ${index + 1} should be selected`);
+}
+
+let gMaxResults;
+
+add_task(function*() {
+ registerCleanupFunction(function* () {
+ yield PlacesTestUtils.clearHistory();
+ });
+
+ yield PlacesTestUtils.clearHistory();
+
+ gMaxResults = Services.prefs.getIntPref("browser.urlbar.maxRichResults");
+
+ let visits = [];
+ repeat(gMaxResults, i => {
+ visits.push({
+ uri: makeURI("http://example.com/autocomplete/?" + i),
+ });
+ });
+ yield PlacesTestUtils.addVisits(visits);
+
+ gBrowser.selectedTab = gBrowser.addTab("about:blank");
+ yield promiseAutoComplete("http://example.com/autocomplete/");
+
+ let popup = gURLBar.popup;
+ let results = popup.richlistbox.children;
+ is(results.length, gMaxResults,
+ "Should get gMaxResults=" + gMaxResults + " results");
+
+ let initiallySelected = gURLBar.popup.richlistbox.selectedIndex;
+
+ info("Key Down to select the next item");
+ EventUtils.synthesizeKey("VK_DOWN", {});
+ is_selected(initiallySelected + 1);
+ let expectedURL = gURLBar.controller.getFinalCompleteValueAt(initiallySelected + 1);
+
+ is(gURLBar.value, gURLBar.controller.getValueAt(initiallySelected + 1),
+ "Value in the URL bar should be updated by keyboard selection");
+
+ // Verify that what we're about to do changes the selectedIndex:
+ isnot(initiallySelected + 1, 3, "Shouldn't be changing the selectedIndex to the same index we keyboard-selected.");
+
+ // Would love to use a synthetic mousemove event here, but that doesn't seem to do anything.
+ // EventUtils.synthesizeMouseAtCenter(results[3], {type: "mousemove"});
+ gURLBar.popup.richlistbox.selectedIndex = 3;
+ is_selected(3);
+
+ let autocompletePopupHidden = promisePopupHidden(gURLBar.popup);
+ let openedExpectedPage = waitForDocLoadAndStopIt(expectedURL);
+ EventUtils.synthesizeKey("VK_RETURN", {});
+ yield Promise.all([autocompletePopupHidden, openedExpectedPage]);
+
+ gBrowser.removeCurrentTab();
+});
diff --git a/browser/base/content/test/urlbar/browser_urlbarFocusedCmdK.js b/browser/base/content/test/urlbar/browser_urlbarFocusedCmdK.js
new file mode 100644
index 000000000..8c9e2c9f2
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_urlbarFocusedCmdK.js
@@ -0,0 +1,17 @@
+/* Any copyright is dedicated to the Public Domain.
+* http://creativecommons.org/publicdomain/zero/1.0/ */
+
+add_task(function*() {
+ // Remove the search bar from toolbar
+ CustomizableUI.removeWidgetFromArea("search-container");
+
+ // Test that Ctrl/Cmd + K will focus the url bar
+ let focusPromise = BrowserTestUtils.waitForEvent(gURLBar, "focus");
+ EventUtils.synthesizeKey("k", { accelKey: true });
+ yield focusPromise;
+ Assert.equal(document.activeElement, gURLBar.inputField, "URL Bar should be focused");
+
+ // Reset changes made to toolbar
+ CustomizableUI.reset();
+});
+
diff --git a/browser/base/content/test/urlbar/browser_urlbarHashChangeProxyState.js b/browser/base/content/test/urlbar/browser_urlbarHashChangeProxyState.js
new file mode 100644
index 000000000..152106dad
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_urlbarHashChangeProxyState.js
@@ -0,0 +1,111 @@
+"use strict";
+
+/**
+ * Check that navigating through both the URL bar and using in-page hash- or ref-
+ * based links and back or forward navigation updates the URL bar and identity block correctly.
+ */
+add_task(function* () {
+ let baseURL = "https://example.org/browser/browser/base/content/test/urlbar/dummy_page.html";
+ let url = baseURL + "#foo";
+ yield BrowserTestUtils.withNewTab({ gBrowser, url }, function*(browser) {
+ let identityBox = document.getElementById("identity-box");
+ let expectedURL = url;
+
+ let verifyURLBarState = testType => {
+ is(gURLBar.textValue, expectedURL, "URL bar visible value should be correct " + testType);
+ is(gURLBar.value, expectedURL, "URL bar value should be correct " + testType);
+ ok(identityBox.classList.contains("verifiedDomain"), "Identity box should know we're doing SSL " + testType);
+ is(gURLBar.getAttribute("pageproxystate"), "valid", "URL bar is in valid page proxy state");
+ };
+
+ verifyURLBarState("at the beginning");
+
+ let locationChangePromise;
+ let resolveLocationChangePromise;
+ let expectURL = url => {
+ expectedURL = url;
+ locationChangePromise = new Promise(r => resolveLocationChangePromise = r);
+ };
+ let wpl = {
+ onLocationChange(wpl, request, location, flags) {
+ is(location.spec, expectedURL, "Got the expected URL");
+ resolveLocationChangePromise();
+ },
+ };
+ gBrowser.addProgressListener(wpl);
+
+ expectURL(baseURL + "#foo");
+ gURLBar.select();
+ EventUtils.sendKey("return");
+
+ yield locationChangePromise;
+ verifyURLBarState("after hitting enter on the same URL a second time");
+
+ expectURL(baseURL + "#bar");
+ gURLBar.value = expectedURL;
+ gURLBar.select();
+ EventUtils.sendKey("return");
+
+ yield locationChangePromise;
+ verifyURLBarState("after a URL bar hash navigation");
+
+ expectURL(baseURL + "#foo");
+ yield ContentTask.spawn(browser, null, function() {
+ let a = content.document.createElement("a");
+ a.href = "#foo";
+ a.textContent = "Foo Link";
+ content.document.body.appendChild(a);
+ a.click();
+ });
+
+ yield locationChangePromise;
+ verifyURLBarState("after a page link hash navigation");
+
+ expectURL(baseURL + "#bar");
+ gBrowser.goBack();
+
+ yield locationChangePromise;
+ verifyURLBarState("after going back");
+
+ expectURL(baseURL + "#foo");
+ gBrowser.goForward();
+
+ yield locationChangePromise;
+ verifyURLBarState("after going forward");
+
+ expectURL(baseURL + "#foo");
+ gURLBar.select();
+ EventUtils.sendKey("return");
+
+ yield locationChangePromise;
+ verifyURLBarState("after hitting enter on the same URL");
+
+ gBrowser.removeProgressListener(wpl);
+ });
+});
+
+/**
+ * Check that initial secure loads that swap remoteness
+ * get the correct page icon when finished.
+ */
+add_task(function* () {
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:newtab", false);
+ // NB: CPOW usage because new tab pages can be preloaded, in which case no
+ // load events fire.
+ yield BrowserTestUtils.waitForCondition(() => !tab.linkedBrowser.contentDocument.hidden)
+ let url = "https://example.org/browser/browser/base/content/test/urlbar/dummy_page.html#foo";
+ gURLBar.value = url;
+ gURLBar.select();
+ EventUtils.sendKey("return");
+ yield BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+
+ is(gURLBar.textValue, url, "URL bar visible value should be correct when the page loads from about:newtab");
+ is(gURLBar.value, url, "URL bar value should be correct when the page loads from about:newtab");
+ let identityBox = document.getElementById("identity-box");
+ ok(identityBox.classList.contains("verifiedDomain"),
+ "Identity box should know we're doing SSL when the page loads from about:newtab");
+ is(gURLBar.getAttribute("pageproxystate"), "valid",
+ "URL bar is in valid page proxy state when SSL page with hash loads from about:newtab");
+ yield BrowserTestUtils.removeTab(tab);
+});
+
diff --git a/browser/base/content/test/urlbar/browser_urlbarKeepStateAcrossTabSwitches.js b/browser/base/content/test/urlbar/browser_urlbarKeepStateAcrossTabSwitches.js
new file mode 100644
index 000000000..9c8996059
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_urlbarKeepStateAcrossTabSwitches.js
@@ -0,0 +1,49 @@
+"use strict";
+
+/**
+ * Verify user typed text remains in the URL bar when tab switching, even when
+ * loads fail.
+ */
+add_task(function* () {
+ let input = "i-definitely-dont-exist.example.com";
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:newtab", false);
+ // NB: CPOW usage because new tab pages can be preloaded, in which case no
+ // load events fire.
+ yield BrowserTestUtils.waitForCondition(() => !tab.linkedBrowser.contentDocument.hidden)
+ let errorPageLoaded = BrowserTestUtils.waitForErrorPage(tab.linkedBrowser);
+ gURLBar.value = input;
+ gURLBar.select();
+ EventUtils.sendKey("return");
+ yield errorPageLoaded;
+ is(gURLBar.textValue, input, "Text is still in URL bar");
+ yield BrowserTestUtils.switchTab(gBrowser, tab.previousSibling);
+ yield BrowserTestUtils.switchTab(gBrowser, tab);
+ is(gURLBar.textValue, input, "Text is still in URL bar after tab switch");
+ yield BrowserTestUtils.removeTab(tab);
+});
+
+/**
+ * Invalid URIs fail differently (that is, immediately, in the loadURI call)
+ * if keyword searches are turned off. Test that this works, too.
+ */
+add_task(function* () {
+ let input = "To be or not to be-that is the question";
+ yield new Promise(resolve => SpecialPowers.pushPrefEnv({set: [["keyword.enabled", false]]}, resolve));
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:newtab", false);
+ // NB: CPOW usage because new tab pages can be preloaded, in which case no
+ // load events fire.
+ yield BrowserTestUtils.waitForCondition(() => !tab.linkedBrowser.contentDocument.hidden)
+ let errorPageLoaded = BrowserTestUtils.waitForErrorPage(tab.linkedBrowser);
+ gURLBar.value = input;
+ gURLBar.select();
+ EventUtils.sendKey("return");
+ yield errorPageLoaded;
+ is(gURLBar.textValue, input, "Text is still in URL bar");
+ is(tab.linkedBrowser.userTypedValue, input, "Text still stored on browser");
+ yield BrowserTestUtils.switchTab(gBrowser, tab.previousSibling);
+ yield BrowserTestUtils.switchTab(gBrowser, tab);
+ is(gURLBar.textValue, input, "Text is still in URL bar after tab switch");
+ is(tab.linkedBrowser.userTypedValue, input, "Text still stored on browser");
+ yield BrowserTestUtils.removeTab(tab);
+});
+
diff --git a/browser/base/content/test/urlbar/browser_urlbarOneOffs.js b/browser/base/content/test/urlbar/browser_urlbarOneOffs.js
new file mode 100644
index 000000000..1f58b8edd
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_urlbarOneOffs.js
@@ -0,0 +1,232 @@
+const TEST_ENGINE_BASENAME = "searchSuggestionEngine.xml";
+
+let gMaxResults;
+
+add_task(function* init() {
+ Services.prefs.setBoolPref("browser.urlbar.oneOffSearches", true);
+ gMaxResults = Services.prefs.getIntPref("browser.urlbar.maxRichResults");
+
+ // Add a search suggestion engine and move it to the front so that it appears
+ // as the first one-off.
+ let engine = yield promiseNewSearchEngine(TEST_ENGINE_BASENAME);
+ Services.search.moveEngine(engine, 0);
+
+ registerCleanupFunction(function* () {
+ yield hidePopup();
+ yield PlacesTestUtils.clearHistory();
+ });
+
+ yield PlacesTestUtils.clearHistory();
+
+ let visits = [];
+ for (let i = 0; i < gMaxResults; i++) {
+ visits.push({
+ uri: makeURI("http://example.com/browser_urlbarOneOffs.js/?" + i),
+ // TYPED so that the visit shows up when the urlbar's drop-down arrow is
+ // pressed.
+ transition: Ci.nsINavHistoryService.TRANSITION_TYPED,
+ });
+ }
+ yield PlacesTestUtils.addVisits(visits);
+});
+
+// Keys up and down through the history panel, i.e., the panel that's shown when
+// there's no text in the textbox.
+add_task(function* history() {
+ gURLBar.focus();
+ EventUtils.synthesizeKey("VK_DOWN", {})
+ yield promisePopupShown(gURLBar.popup);
+
+ assertState(-1, -1, "");
+
+ // Key down through each result.
+ for (let i = 0; i < gMaxResults; i++) {
+ EventUtils.synthesizeKey("VK_DOWN", {})
+ assertState(i, -1,
+ "example.com/browser_urlbarOneOffs.js/?" + (gMaxResults - i - 1));
+ }
+
+ // Key down through each one-off.
+ let numButtons =
+ gURLBar.popup.oneOffSearchButtons.getSelectableButtons(true).length;
+ for (let i = 0; i < numButtons; i++) {
+ EventUtils.synthesizeKey("VK_DOWN", {})
+ assertState(-1, i, "");
+ }
+
+ // Key down once more. Nothing should be selected.
+ EventUtils.synthesizeKey("VK_DOWN", {})
+ assertState(-1, -1, "");
+
+ // Once more. The first result should be selected.
+ EventUtils.synthesizeKey("VK_DOWN", {})
+ assertState(0, -1,
+ "example.com/browser_urlbarOneOffs.js/?" + (gMaxResults - 1));
+
+ // Now key up. Nothing should be selected again.
+ EventUtils.synthesizeKey("VK_UP", {})
+ assertState(-1, -1, "");
+
+ // Key up through each one-off.
+ for (let i = numButtons - 1; i >= 0; i--) {
+ EventUtils.synthesizeKey("VK_UP", {})
+ assertState(-1, i, "");
+ }
+
+ // Key up through each result.
+ for (let i = gMaxResults - 1; i >= 0; i--) {
+ EventUtils.synthesizeKey("VK_UP", {})
+ assertState(i, -1,
+ "example.com/browser_urlbarOneOffs.js/?" + (gMaxResults - i - 1));
+ }
+
+ // Key up once more. Nothing should be selected.
+ EventUtils.synthesizeKey("VK_UP", {})
+ assertState(-1, -1, "");
+
+ yield hidePopup();
+});
+
+// Keys up and down through the non-history panel, i.e., the panel that's shown
+// when you type something in the textbox.
+add_task(function* typedValue() {
+ // Use a typed value that returns the visits added above but that doesn't
+ // trigger autofill since that would complicate the test.
+ let typedValue = "browser_urlbarOneOffs";
+ yield promiseAutocompleteResultPopup(typedValue, window, true);
+
+ assertState(0, -1, typedValue);
+
+ // Key down through each result. The first result is already selected, which
+ // is why gMaxResults - 1 is the correct number of times to do this.
+ for (let i = 0; i < gMaxResults - 1; i++) {
+ EventUtils.synthesizeKey("VK_DOWN", {})
+ // i starts at zero so that the textValue passed to assertState is correct.
+ // But that means that i + 1 is the expected selected index, since initially
+ // (when this loop starts) the first result is selected.
+ assertState(i + 1, -1,
+ "example.com/browser_urlbarOneOffs.js/?" + (gMaxResults - i - 1));
+ }
+
+ // Key down through each one-off.
+ let numButtons =
+ gURLBar.popup.oneOffSearchButtons.getSelectableButtons(true).length;
+ for (let i = 0; i < numButtons; i++) {
+ EventUtils.synthesizeKey("VK_DOWN", {})
+ assertState(-1, i, typedValue);
+ }
+
+ // Key down once more. The selection should wrap around to the first result.
+ EventUtils.synthesizeKey("VK_DOWN", {})
+ assertState(0, -1, typedValue);
+
+ // Now key up. The selection should wrap back around to the one-offs. Key
+ // up through all the one-offs.
+ for (let i = numButtons - 1; i >= 0; i--) {
+ EventUtils.synthesizeKey("VK_UP", {})
+ assertState(-1, i, typedValue);
+ }
+
+ // Key up through each non-heuristic result.
+ for (let i = gMaxResults - 2; i >= 0; i--) {
+ EventUtils.synthesizeKey("VK_UP", {})
+ assertState(i + 1, -1,
+ "example.com/browser_urlbarOneOffs.js/?" + (gMaxResults - i - 1));
+ }
+
+ // Key up once more. The heuristic result should be selected.
+ EventUtils.synthesizeKey("VK_UP", {})
+ assertState(0, -1, typedValue);
+
+ yield hidePopup();
+});
+
+// Checks that "Search with Current Search Engine" items are updated to "Search
+// with One-Off Engine" when a one-off is selected.
+add_task(function* searchWith() {
+ let typedValue = "foo";
+ yield promiseAutocompleteResultPopup(typedValue);
+
+ assertState(0, -1, typedValue);
+
+ let item = gURLBar.popup.richlistbox.firstChild;
+ Assert.equal(item._actionText.textContent,
+ "Search with " + Services.search.currentEngine.name,
+ "Sanity check: first result's action text");
+
+ // Alt+Down to the first one-off. Now the first result and the first one-off
+ // should both be selected.
+ EventUtils.synthesizeKey("VK_DOWN", { altKey: true })
+ assertState(0, 0, typedValue);
+
+ let engineName = gURLBar.popup.oneOffSearchButtons.selectedButton.engine.name;
+ Assert.notEqual(engineName, Services.search.currentEngine.name,
+ "Sanity check: First one-off engine should not be " +
+ "the current engine");
+ Assert.equal(item._actionText.textContent,
+ "Search with " + engineName,
+ "First result's action text should be updated");
+
+ yield hidePopup();
+});
+
+// Clicks a one-off.
+add_task(function* oneOffClick() {
+ gBrowser.selectedTab = gBrowser.addTab();
+
+ // We are explicitly using something that looks like a url, to make the test
+ // stricter. Even if it looks like a url, we should search.
+ let typedValue = "foo.bar";
+ yield promiseAutocompleteResultPopup(typedValue);
+
+ assertState(0, -1, typedValue);
+
+ let oneOffs = gURLBar.popup.oneOffSearchButtons.getSelectableButtons(true);
+ let resultsPromise =
+ BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser, false,
+ "http://mochi.test:8888/");
+ EventUtils.synthesizeMouseAtCenter(oneOffs[0], {});
+ yield resultsPromise;
+
+ gBrowser.removeTab(gBrowser.selectedTab);
+});
+
+// Presses the Return key when a one-off is selected.
+add_task(function* oneOffReturn() {
+ gBrowser.selectedTab = gBrowser.addTab();
+
+ // We are explicitly using something that looks like a url, to make the test
+ // stricter. Even if it looks like a url, we should search.
+ let typedValue = "foo.bar";
+ yield promiseAutocompleteResultPopup(typedValue, window, true);
+
+ assertState(0, -1, typedValue);
+
+ // Alt+Down to select the first one-off.
+ EventUtils.synthesizeKey("VK_DOWN", { altKey: true })
+ assertState(0, 0, typedValue);
+
+ let resultsPromise =
+ BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser, false,
+ "http://mochi.test:8888/");
+ EventUtils.synthesizeKey("VK_RETURN", {})
+ yield resultsPromise;
+
+ gBrowser.removeTab(gBrowser.selectedTab);
+});
+
+
+function assertState(result, oneOff, textValue = undefined) {
+ Assert.equal(gURLBar.popup.selectedIndex, result,
+ "Expected result should be selected");
+ Assert.equal(gURLBar.popup.oneOffSearchButtons.selectedButtonIndex, oneOff,
+ "Expected one-off should be selected");
+ if (textValue !== undefined) {
+ Assert.equal(gURLBar.textValue, textValue, "Expected textValue");
+ }
+}
+
+function* hidePopup() {
+ EventUtils.synthesizeKey("VK_ESCAPE", {});
+ yield promisePopupHidden(gURLBar.popup);
+}
diff --git a/browser/base/content/test/urlbar/browser_urlbarPrivateBrowsingWindowChange.js b/browser/base/content/test/urlbar/browser_urlbarPrivateBrowsingWindowChange.js
new file mode 100644
index 000000000..5db0f0ea6
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_urlbarPrivateBrowsingWindowChange.js
@@ -0,0 +1,41 @@
+"use strict";
+
+/**
+ * Test that when opening a private browsing window and typing in it before about:privatebrowsing
+ * loads, we don't clear the URL bar.
+ */
+add_task(function*() {
+ let urlbarTestValue = "Mary had a little lamb";
+ let win = OpenBrowserWindow({private: true});
+ yield BrowserTestUtils.waitForEvent(win, "load");
+ let urlbar = win.document.getElementById("urlbar");
+ urlbar.value = urlbarTestValue;
+ // Need this so the autocomplete controller attaches:
+ let focusEv = new FocusEvent("focus", {});
+ urlbar.dispatchEvent(focusEv);
+ // And so we know input happened:
+ let inputEv = new InputEvent("input", {data: "", view: win, bubbles: true});
+ urlbar.onInput(inputEv);
+ // Check it worked:
+ is(urlbar.value, urlbarTestValue, "URL bar value should be there");
+ is(win.gBrowser.selectedBrowser.userTypedValue, urlbarTestValue, "browser object should know the url bar value");
+
+ let continueTest;
+ let continuePromise = new Promise(resolve => continueTest = resolve);
+ let wpl = {
+ onLocationChange(aWebProgress, aRequest, aLocation) {
+ if (aLocation && aLocation.spec == "about:privatebrowsing") {
+ continueTest();
+ }
+ },
+ };
+ win.gBrowser.addProgressListener(wpl);
+
+ yield continuePromise;
+ is(urlbar.value, urlbarTestValue,
+ "URL bar value should be the same once about:privatebrowsing has loaded");
+ is(win.gBrowser.selectedBrowser.userTypedValue, urlbarTestValue,
+ "browser object should still know url bar value once about:privatebrowsing has loaded");
+ win.gBrowser.removeProgressListener(wpl);
+ yield BrowserTestUtils.closeWindow(win);
+});
diff --git a/browser/base/content/test/urlbar/browser_urlbarRaceWithTabs.js b/browser/base/content/test/urlbar/browser_urlbarRaceWithTabs.js
new file mode 100644
index 000000000..d66514c5a
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_urlbarRaceWithTabs.js
@@ -0,0 +1,57 @@
+const kURL = "http://example.org/browser/browser/base/content/test/urlbar/dummy_page.html";
+
+function* addBookmark(bookmark) {
+ if (bookmark.keyword) {
+ yield PlacesUtils.keywords.insert({
+ keyword: bookmark.keyword,
+ url: bookmark.url,
+ });
+ }
+
+ let bm = yield PlacesUtils.bookmarks.insert({
+ parentGuid: PlacesUtils.bookmarks.unfiledGuid,
+ url: bookmark.url,
+ title: bookmark.title,
+ });
+
+ registerCleanupFunction(function* () {
+ yield PlacesUtils.bookmarks.remove(bm);
+ if (bookmark.keyword) {
+ yield PlacesUtils.keywords.remove(bookmark.keyword);
+ }
+ });
+}
+
+/**
+ * Check that if the user hits enter and ctrl-t at the same time, we open the URL in the right tab.
+ */
+add_task(function* hitEnterLoadInRightTab() {
+ info("Opening new tab");
+ let oldTabCreatedPromise = BrowserTestUtils.waitForEvent(gBrowser.tabContainer, "TabOpen");
+ BrowserOpenTab();
+ let oldTab = (yield oldTabCreatedPromise).target;
+ let oldTabLoadedPromise = BrowserTestUtils.browserLoaded(oldTab.linkedBrowser, false, kURL);
+ oldTabLoadedPromise.then(() => info("Old tab loaded"));
+ let newTabCreatedPromise = BrowserTestUtils.waitForEvent(gBrowser.tabContainer, "TabOpen");
+
+ info("Creating bookmark and keyword");
+ yield addBookmark({title: "Test for keyword bookmark and URL", url: kURL, keyword: "urlbarkeyword"});
+ info("Filling URL bar, sending <return> and opening a tab");
+ gURLBar.value = "urlbarkeyword";
+ gURLBar.select();
+ EventUtils.sendKey("return");
+ BrowserOpenTab();
+ info("Waiting for new tab");
+ let newTab = (yield newTabCreatedPromise).target;
+ info("Created new tab; waiting for either tab to load");
+ let newTabLoadedPromise = BrowserTestUtils.browserLoaded(newTab.linkedBrowser, false, kURL);
+ newTabLoadedPromise.then(() => info("New tab loaded"));
+ yield Promise.race([newTabLoadedPromise, oldTabLoadedPromise]);
+ is(newTab.linkedBrowser.currentURI.spec, "about:newtab", "New tab still has about:newtab");
+ is(oldTab.linkedBrowser.currentURI.spec, kURL, "Old tab loaded URL");
+ info("Closing new tab");
+ yield BrowserTestUtils.removeTab(newTab);
+ info("Closing old tab");
+ yield BrowserTestUtils.removeTab(oldTab);
+ info("Finished");
+});
diff --git a/browser/base/content/test/urlbar/browser_urlbarRevert.js b/browser/base/content/test/urlbar/browser_urlbarRevert.js
new file mode 100644
index 000000000..0ce3c8fac
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_urlbarRevert.js
@@ -0,0 +1,37 @@
+var tab = null;
+
+function test() {
+ waitForExplicitFinish();
+
+ let pageLoaded = {
+ onStateChange: function onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) {
+ if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
+ aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK) {
+ gBrowser.removeProgressListener(this);
+ executeSoon(checkURLBarRevert);
+ }
+ }
+ }
+
+ gBrowser.addProgressListener(pageLoaded);
+ tab = gBrowser.addTab("http://example.com");
+ gBrowser.selectedTab = tab;
+}
+
+function checkURLBarRevert() {
+ let originalValue = gURLBar.value;
+
+ gBrowser.userTypedValue = "foobar";
+ gBrowser.selectedTab = gBrowser.tabs[0];
+ gBrowser.selectedTab = tab;
+ is(gURLBar.value, "foobar", "location bar displays typed value");
+
+ gURLBar.focus();
+
+ EventUtils.synthesizeKey("VK_ESCAPE", {});
+
+ is(gURLBar.value, originalValue, "ESC reverted the location bar value");
+
+ gBrowser.removeTab(tab);
+ finish();
+}
diff --git a/browser/base/content/test/urlbar/browser_urlbarSearchSingleWordNotification.js b/browser/base/content/test/urlbar/browser_urlbarSearchSingleWordNotification.js
new file mode 100644
index 000000000..ee0342055
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_urlbarSearchSingleWordNotification.js
@@ -0,0 +1,198 @@
+"use strict";
+
+var notificationObserver;
+registerCleanupFunction(function() {
+ Services.prefs.clearUserPref("browser.fixup.domainwhitelist.localhost");
+ if (notificationObserver) {
+ notificationObserver.disconnect();
+ }
+});
+
+function promiseNotification(aBrowser, value, expected, input) {
+ let deferred = Promise.defer();
+ let notificationBox = aBrowser.getNotificationBox(aBrowser.selectedBrowser);
+ if (expected) {
+ info("Waiting for " + value + " notification");
+ let checkForNotification = function() {
+ if (notificationBox.getNotificationWithValue(value)) {
+ info("Saw the notification");
+ notificationObserver.disconnect();
+ notificationObserver = null;
+ deferred.resolve();
+ }
+ }
+ if (notificationObserver) {
+ notificationObserver.disconnect();
+ }
+ notificationObserver = new MutationObserver(checkForNotification);
+ notificationObserver.observe(notificationBox, {childList: true});
+ } else {
+ setTimeout(() => {
+ is(notificationBox.getNotificationWithValue(value), null,
+ `We are expecting to not get a notification for ${input}`);
+ deferred.resolve();
+ }, 1000);
+ }
+ return deferred.promise;
+}
+
+function* runURLBarSearchTest({valueToOpen, expectSearch, expectNotification, aWindow=window}) {
+ aWindow.gURLBar.value = valueToOpen;
+ let expectedURI;
+ if (!expectSearch) {
+ expectedURI = "http://" + valueToOpen + "/";
+ } else {
+ yield new Promise(resolve => {
+ Services.search.init(resolve);
+ });
+ expectedURI = Services.search.defaultEngine.getSubmission(valueToOpen, null, "keyword").uri.spec;
+ }
+ aWindow.gURLBar.focus();
+ let docLoadPromise = waitForDocLoadAndStopIt(expectedURI, aWindow.gBrowser.selectedBrowser);
+ EventUtils.synthesizeKey("VK_RETURN", {}, aWindow);
+
+ yield Promise.all([
+ docLoadPromise,
+ promiseNotification(aWindow.gBrowser, "keyword-uri-fixup", expectNotification, valueToOpen)
+ ]);
+}
+
+add_task(function* test_navigate_full_domain() {
+ let tab = gBrowser.selectedTab = gBrowser.addTab("about:blank");
+ yield BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+ yield* runURLBarSearchTest({
+ valueToOpen: "www.mozilla.org",
+ expectSearch: false,
+ expectNotification: false,
+ });
+ gBrowser.removeTab(tab);
+});
+
+add_task(function* test_navigate_decimal_ip() {
+ let tab = gBrowser.selectedTab = gBrowser.addTab("about:blank");
+ yield BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+ yield* runURLBarSearchTest({
+ valueToOpen: "1234",
+ expectSearch: true,
+ expectNotification: false,
+ });
+ gBrowser.removeTab(tab);
+});
+
+add_task(function* test_navigate_decimal_ip_with_path() {
+ let tab = gBrowser.selectedTab = gBrowser.addTab("about:blank");
+ yield BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+ yield* runURLBarSearchTest({
+ valueToOpen: "1234/12",
+ expectSearch: true,
+ expectNotification: false,
+ });
+ gBrowser.removeTab(tab);
+});
+
+add_task(function* test_navigate_large_number() {
+ let tab = gBrowser.selectedTab = gBrowser.addTab("about:blank");
+ yield BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+ yield* runURLBarSearchTest({
+ valueToOpen: "123456789012345",
+ expectSearch: true,
+ expectNotification: false
+ });
+ gBrowser.removeTab(tab);
+});
+
+add_task(function* test_navigate_small_hex_number() {
+ let tab = gBrowser.selectedTab = gBrowser.addTab("about:blank");
+ yield BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+ yield* runURLBarSearchTest({
+ valueToOpen: "0x1f00ffff",
+ expectSearch: true,
+ expectNotification: false
+ });
+ gBrowser.removeTab(tab);
+});
+
+add_task(function* test_navigate_large_hex_number() {
+ let tab = gBrowser.selectedTab = gBrowser.addTab("about:blank");
+ yield BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+ yield* runURLBarSearchTest({
+ valueToOpen: "0x7f0000017f000001",
+ expectSearch: true,
+ expectNotification: false
+ });
+ gBrowser.removeTab(tab);
+});
+
+function get_test_function_for_localhost_with_hostname(hostName, isPrivate) {
+ return function* test_navigate_single_host() {
+ const pref = "browser.fixup.domainwhitelist.localhost";
+ let win;
+ if (isPrivate) {
+ let promiseWin = BrowserTestUtils.waitForNewWindow();
+ win = OpenBrowserWindow({private: true});
+ yield promiseWin;
+ let deferredOpenFocus = Promise.defer();
+ waitForFocus(deferredOpenFocus.resolve, win);
+ yield deferredOpenFocus.promise;
+ } else {
+ win = window;
+ }
+ let browser = win.gBrowser;
+ let tab = yield BrowserTestUtils.openNewForegroundTab(browser);
+
+ Services.prefs.setBoolPref(pref, false);
+ yield* runURLBarSearchTest({
+ valueToOpen: hostName,
+ expectSearch: true,
+ expectNotification: true,
+ aWindow: win,
+ });
+
+ let notificationBox = browser.getNotificationBox(tab.linkedBrowser);
+ let notification = notificationBox.getNotificationWithValue("keyword-uri-fixup");
+ let docLoadPromise = waitForDocLoadAndStopIt("http://" + hostName + "/", tab.linkedBrowser);
+ notification.querySelector(".notification-button-default").click();
+
+ // check pref value
+ let prefValue = Services.prefs.getBoolPref(pref);
+ is(prefValue, !isPrivate, "Pref should have the correct state.");
+
+ yield docLoadPromise;
+ browser.removeTab(tab);
+
+ // Now try again with the pref set.
+ tab = browser.selectedTab = browser.addTab("about:blank");
+ yield BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+ // In a private window, the notification should appear again.
+ yield* runURLBarSearchTest({
+ valueToOpen: hostName,
+ expectSearch: isPrivate,
+ expectNotification: isPrivate,
+ aWindow: win,
+ });
+ browser.removeTab(tab);
+ if (isPrivate) {
+ info("Waiting for private window to close");
+ yield BrowserTestUtils.closeWindow(win);
+ let deferredFocus = Promise.defer();
+ info("Waiting for focus");
+ waitForFocus(deferredFocus.resolve, window);
+ yield deferredFocus.promise;
+ }
+ }
+}
+
+add_task(get_test_function_for_localhost_with_hostname("localhost"));
+add_task(get_test_function_for_localhost_with_hostname("localhost."));
+add_task(get_test_function_for_localhost_with_hostname("localhost", true));
+
+add_task(function* test_navigate_invalid_url() {
+ let tab = gBrowser.selectedTab = gBrowser.addTab("about:blank");
+ yield BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+ yield* runURLBarSearchTest({
+ valueToOpen: "mozilla is awesome",
+ expectSearch: true,
+ expectNotification: false,
+ });
+ gBrowser.removeTab(tab);
+});
diff --git a/browser/base/content/test/urlbar/browser_urlbarSearchSuggestions.js b/browser/base/content/test/urlbar/browser_urlbarSearchSuggestions.js
new file mode 100644
index 000000000..5146ba98c
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_urlbarSearchSuggestions.js
@@ -0,0 +1,66 @@
+const SUGGEST_URLBAR_PREF = "browser.urlbar.suggest.searches";
+const TEST_ENGINE_BASENAME = "searchSuggestionEngine.xml";
+
+// Must run first.
+add_task(function* prepare() {
+ Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, true);
+ let engine = yield promiseNewSearchEngine(TEST_ENGINE_BASENAME);
+ let oldCurrentEngine = Services.search.currentEngine;
+ Services.search.currentEngine = engine;
+ registerCleanupFunction(function* () {
+ Services.prefs.clearUserPref(SUGGEST_URLBAR_PREF);
+ Services.search.currentEngine = oldCurrentEngine;
+
+ // Clicking suggestions causes visits to search results pages, so clear that
+ // history now.
+ yield PlacesTestUtils.clearHistory();
+
+ // Make sure the popup is closed for the next test.
+ gURLBar.blur();
+ Assert.ok(!gURLBar.popup.popupOpen, "popup should be closed");
+ });
+});
+
+add_task(function* clickSuggestion() {
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser);
+ gURLBar.focus();
+ yield promiseAutocompleteResultPopup("foo");
+ let [idx, suggestion, engineName] = yield promiseFirstSuggestion();
+ Assert.equal(engineName,
+ "browser_searchSuggestionEngine%20searchSuggestionEngine.xml",
+ "Expected suggestion engine");
+ let item = gURLBar.popup.richlistbox.getItemAtIndex(idx);
+
+ let uri = Services.search.currentEngine.getSubmission(suggestion).uri;
+ let loadPromise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser,
+ false, uri.spec);
+ item.click();
+ yield loadPromise;
+ yield BrowserTestUtils.removeTab(tab);
+});
+
+function getFirstSuggestion() {
+ let controller = gURLBar.popup.input.controller;
+ let matchCount = controller.matchCount;
+ for (let i = 0; i < matchCount; i++) {
+ let url = controller.getValueAt(i);
+ let mozActionMatch = url.match(/^moz-action:([^,]+),(.*)$/);
+ if (mozActionMatch) {
+ let [, type, paramStr] = mozActionMatch;
+ let params = JSON.parse(paramStr);
+ if (type == "searchengine" && "searchSuggestion" in params) {
+ return [i, params.searchSuggestion, params.engineName];
+ }
+ }
+ }
+ return [-1, null, null];
+}
+
+function* promiseFirstSuggestion() {
+ let tuple = [-1, null, null];
+ yield BrowserTestUtils.waitForCondition(() => {
+ tuple = getFirstSuggestion();
+ return tuple[0] >= 0;
+ });
+ return tuple;
+}
diff --git a/browser/base/content/test/urlbar/browser_urlbarSearchSuggestionsNotification.js b/browser/base/content/test/urlbar/browser_urlbarSearchSuggestionsNotification.js
new file mode 100644
index 000000000..94ae8a3ff
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_urlbarSearchSuggestionsNotification.js
@@ -0,0 +1,254 @@
+const SUGGEST_ALL_PREF = "browser.search.suggest.enabled";
+const SUGGEST_URLBAR_PREF = "browser.urlbar.suggest.searches";
+const CHOICE_PREF = "browser.urlbar.userMadeSearchSuggestionsChoice";
+const TEST_ENGINE_BASENAME = "searchSuggestionEngine.xml";
+
+// Must run first.
+add_task(function* prepare() {
+ let engine = yield promiseNewSearchEngine(TEST_ENGINE_BASENAME);
+ let oldCurrentEngine = Services.search.currentEngine;
+ Services.search.currentEngine = engine;
+ registerCleanupFunction(function* () {
+ Services.search.currentEngine = oldCurrentEngine;
+ Services.prefs.clearUserPref(SUGGEST_ALL_PREF);
+ Services.prefs.clearUserPref(SUGGEST_URLBAR_PREF);
+
+ // Disable the notification for future tests so it doesn't interfere with
+ // them. clearUserPref() won't work because by default the pref is false.
+ yield setUserMadeChoicePref(true);
+
+ // Make sure the popup is closed for the next test.
+ gURLBar.blur();
+ Assert.ok(!gURLBar.popup.popupOpen, "popup should be closed");
+ });
+});
+
+add_task(function* focus() {
+ // Focusing the urlbar used to open the popup in order to show the
+ // notification, but it doesn't anymore. Make sure it does not.
+ Services.prefs.setBoolPref(SUGGEST_ALL_PREF, true);
+ yield setUserMadeChoicePref(false);
+ gURLBar.blur();
+ gURLBar.focus();
+ Assert.ok(!gURLBar.popup.popupOpen, "popup should remain closed");
+});
+
+add_task(function* dismissWithoutResults() {
+ Services.prefs.setBoolPref(SUGGEST_ALL_PREF, true);
+ yield setUserMadeChoicePref(false);
+ gURLBar.blur();
+ gURLBar.focus();
+ let popupPromise = promisePopupShown(gURLBar.popup);
+ gURLBar.openPopup();
+ yield popupPromise;
+ Assert.ok(gURLBar.popup.popupOpen, "popup should be open");
+ assertVisible(true);
+ Assert.equal(gURLBar.popup._matchCount, 0, "popup should have no results");
+ let disableButton = document.getAnonymousElementByAttribute(
+ gURLBar.popup, "anonid", "search-suggestions-notification-disable"
+ );
+ let transitionPromise = promiseTransition();
+ disableButton.click();
+ yield transitionPromise;
+ Assert.ok(!gURLBar.popup.popupOpen, "popup should be closed");
+ gURLBar.blur();
+ gURLBar.focus();
+ Assert.ok(!gURLBar.popup.popupOpen, "popup should remain closed");
+ yield promiseAutocompleteResultPopup("foo");
+ Assert.ok(gURLBar.popup.popupOpen, "popup should be open");
+ assertVisible(false);
+});
+
+add_task(function* dismissWithResults() {
+ Services.prefs.setBoolPref(SUGGEST_ALL_PREF, true);
+ yield setUserMadeChoicePref(false);
+ gURLBar.blur();
+ gURLBar.focus();
+ yield promiseAutocompleteResultPopup("foo");
+ Assert.ok(gURLBar.popup.popupOpen, "popup should be open");
+ assertVisible(true);
+ Assert.ok(gURLBar.popup._matchCount > 0, "popup should have results");
+ let disableButton = document.getAnonymousElementByAttribute(
+ gURLBar.popup, "anonid", "search-suggestions-notification-disable"
+ );
+ let transitionPromise = promiseTransition();
+ disableButton.click();
+ yield transitionPromise;
+ Assert.ok(gURLBar.popup.popupOpen, "popup should remain open");
+ gURLBar.blur();
+ gURLBar.focus();
+ Assert.ok(!gURLBar.popup.popupOpen, "popup should remain closed");
+ yield promiseAutocompleteResultPopup("foo");
+ Assert.ok(gURLBar.popup.popupOpen, "popup should be open");
+ assertVisible(false);
+});
+
+add_task(function* disable() {
+ Services.prefs.setBoolPref(SUGGEST_ALL_PREF, true);
+ yield setUserMadeChoicePref(false);
+ gURLBar.blur();
+ gURLBar.focus();
+ yield promiseAutocompleteResultPopup("foo");
+ Assert.ok(gURLBar.popup.popupOpen, "popup should be open");
+ assertVisible(true);
+ let disableButton = document.getAnonymousElementByAttribute(
+ gURLBar.popup, "anonid", "search-suggestions-notification-disable"
+ );
+ let transitionPromise = promiseTransition();
+ disableButton.click();
+ yield transitionPromise;
+ gURLBar.blur();
+ yield promiseAutocompleteResultPopup("foo");
+ Assert.ok(!suggestionsPresent());
+});
+
+add_task(function* enable() {
+ Services.prefs.setBoolPref(SUGGEST_ALL_PREF, true);
+ Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, false);
+ yield setUserMadeChoicePref(false);
+ gURLBar.blur();
+ gURLBar.focus();
+ yield promiseAutocompleteResultPopup("foo");
+ assertVisible(true);
+ Assert.ok(!suggestionsPresent());
+ let enableButton = document.getAnonymousElementByAttribute(
+ gURLBar.popup, "anonid", "search-suggestions-notification-enable"
+ );
+ let searchPromise = BrowserTestUtils.waitForCondition(suggestionsPresent,
+ "waiting for suggestions");
+ enableButton.click();
+ yield searchPromise;
+ // Clicking Yes should trigger a new search so that suggestions appear
+ // immediately.
+ Assert.ok(suggestionsPresent());
+ gURLBar.blur();
+ gURLBar.focus();
+ // Suggestions should still be present in a new search of course.
+ yield promiseAutocompleteResultPopup("bar");
+ Assert.ok(suggestionsPresent());
+});
+
+add_task(function* privateWindow() {
+ // Since suggestions are disabled in private windows, the notification should
+ // not appear even when suggestions are otherwise enabled.
+ let win = yield BrowserTestUtils.openNewBrowserWindow({ private: true });
+ win.gURLBar.blur();
+ win.gURLBar.focus();
+ yield promiseAutocompleteResultPopup("foo", win);
+ assertVisible(false, win);
+ win.gURLBar.blur();
+ yield BrowserTestUtils.closeWindow(win);
+});
+
+add_task(function* multipleWindows() {
+ // Opening multiple windows, using their urlbars, and then dismissing the
+ // notification in one should dismiss the notification in all.
+ Services.prefs.setBoolPref(SUGGEST_ALL_PREF, true);
+ Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, false);
+ yield setUserMadeChoicePref(false);
+
+ gURLBar.focus();
+ yield promiseAutocompleteResultPopup("win1");
+ assertVisible(true);
+
+ let win2 = yield BrowserTestUtils.openNewBrowserWindow();
+ win2.gURLBar.focus();
+ yield promiseAutocompleteResultPopup("win2", win2);
+ assertVisible(true, win2);
+
+ let win3 = yield BrowserTestUtils.openNewBrowserWindow();
+ win3.gURLBar.focus();
+ yield promiseAutocompleteResultPopup("win3", win3);
+ assertVisible(true, win3);
+
+ let enableButton = win3.document.getAnonymousElementByAttribute(
+ win3.gURLBar.popup, "anonid", "search-suggestions-notification-enable"
+ );
+ let transitionPromise = promiseTransition(win3);
+ enableButton.click();
+ yield transitionPromise;
+ assertVisible(false, win3);
+
+ win2.gURLBar.focus();
+ yield promiseAutocompleteResultPopup("win2done", win2);
+ assertVisible(false, win2);
+
+ gURLBar.focus();
+ yield promiseAutocompleteResultPopup("win1done");
+ assertVisible(false);
+
+ yield BrowserTestUtils.closeWindow(win2);
+ yield BrowserTestUtils.closeWindow(win3);
+});
+
+add_task(function* enableOutsideNotification() {
+ // Setting the suggest.searches pref outside the notification (e.g., by
+ // ticking the checkbox in the preferences window) should hide it.
+ Services.prefs.setBoolPref(SUGGEST_ALL_PREF, true);
+ Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, false);
+ yield setUserMadeChoicePref(false);
+
+ Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, true);
+ gURLBar.focus();
+ yield promiseAutocompleteResultPopup("foo");
+ assertVisible(false);
+});
+
+/**
+ * Setting the choice pref triggers a pref observer in the urlbar, which hides
+ * the notification if it's present. This function returns a promise that's
+ * resolved once the observer fires.
+ *
+ * @param userMadeChoice A boolean, the pref's new value.
+ * @return A Promise that's resolved when the observer fires -- or, if the pref
+ * is currently the given value, that's resolved immediately.
+ */
+function setUserMadeChoicePref(userMadeChoice) {
+ return new Promise(resolve => {
+ let currentUserMadeChoice = Services.prefs.getBoolPref(CHOICE_PREF);
+ if (currentUserMadeChoice != userMadeChoice) {
+ Services.prefs.addObserver(CHOICE_PREF, function obs(subj, topic, data) {
+ Services.prefs.removeObserver(CHOICE_PREF, obs);
+ resolve();
+ }, false);
+ }
+ Services.prefs.setBoolPref(CHOICE_PREF, userMadeChoice);
+ if (currentUserMadeChoice == userMadeChoice) {
+ resolve();
+ }
+ });
+}
+
+function suggestionsPresent() {
+ let controller = gURLBar.popup.input.controller;
+ let matchCount = controller.matchCount;
+ for (let i = 0; i < matchCount; i++) {
+ let url = controller.getValueAt(i);
+ let mozActionMatch = url.match(/^moz-action:([^,]+),(.*)$/);
+ if (mozActionMatch) {
+ let [, type, paramStr] = mozActionMatch;
+ let params = JSON.parse(paramStr);
+ if (type == "searchengine" && "searchSuggestion" in params) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+function assertVisible(visible, win=window) {
+ let style =
+ win.getComputedStyle(win.gURLBar.popup.searchSuggestionsNotification);
+ Assert.equal(style.visibility, visible ? "visible" : "collapse");
+}
+
+function promiseTransition(win=window) {
+ return new Promise(resolve => {
+ win.gURLBar.popup.addEventListener("transitionend", function onEnd() {
+ win.gURLBar.popup.removeEventListener("transitionend", onEnd, true);
+ // The urlbar needs to handle the transitionend first, but that happens
+ // naturally since promises are resolved at the end of the current tick.
+ resolve();
+ }, true);
+ });
+}
diff --git a/browser/base/content/test/urlbar/browser_urlbarSearchTelemetry.js b/browser/base/content/test/urlbar/browser_urlbarSearchTelemetry.js
new file mode 100644
index 000000000..8c28401ea
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_urlbarSearchTelemetry.js
@@ -0,0 +1,216 @@
+"use strict";
+
+Cu.import("resource:///modules/BrowserUITelemetry.jsm");
+
+const SUGGEST_URLBAR_PREF = "browser.urlbar.suggest.searches";
+const TEST_ENGINE_BASENAME = "searchSuggestionEngine.xml";
+
+// Must run first.
+add_task(function* prepare() {
+ Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, true);
+ let engine = yield promiseNewSearchEngine(TEST_ENGINE_BASENAME);
+ let oldCurrentEngine = Services.search.currentEngine;
+ Services.search.currentEngine = engine;
+
+ registerCleanupFunction(function* () {
+ Services.prefs.clearUserPref(SUGGEST_URLBAR_PREF);
+ Services.search.currentEngine = oldCurrentEngine;
+
+ // Clicking urlbar results causes visits to their associated pages, so clear
+ // that history now.
+ yield PlacesTestUtils.clearHistory();
+
+ // Make sure the popup is closed for the next test.
+ gURLBar.blur();
+ Assert.ok(!gURLBar.popup.popupOpen, "popup should be closed");
+ });
+
+ // Move the mouse away from the urlbar one-offs so that a one-off engine is
+ // not inadvertently selected.
+ yield new Promise(resolve => {
+ EventUtils.synthesizeNativeMouseMove(window.document.documentElement, 0, 0,
+ resolve);
+ });
+});
+
+add_task(function* heuristicResultMouse() {
+ yield compareCounts(function* () {
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser);
+ gURLBar.focus();
+ yield promiseAutocompleteResultPopup("heuristicResult");
+ let action = getActionAtIndex(0);
+ Assert.ok(!!action, "there should be an action at index 0");
+ Assert.equal(action.type, "searchengine", "type should be searchengine");
+ let loadPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+ gURLBar.popup.richlistbox.getItemAtIndex(0).click();
+ yield loadPromise;
+ yield BrowserTestUtils.removeTab(tab);
+ });
+});
+
+add_task(function* heuristicResultKeyboard() {
+ yield compareCounts(function* () {
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser);
+ gURLBar.focus();
+ yield promiseAutocompleteResultPopup("heuristicResult");
+ let action = getActionAtIndex(0);
+ Assert.ok(!!action, "there should be an action at index 0");
+ Assert.equal(action.type, "searchengine", "type should be searchengine");
+ let loadPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+ EventUtils.sendKey("return");
+ yield loadPromise;
+ yield BrowserTestUtils.removeTab(tab);
+ });
+});
+
+add_task(function* searchSuggestionMouse() {
+ yield compareCounts(function* () {
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser);
+ gURLBar.focus();
+ yield promiseAutocompleteResultPopup("searchSuggestion");
+ let idx = getFirstSuggestionIndex();
+ Assert.ok(idx >= 0, "there should be a first suggestion");
+ let loadPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+ gURLBar.popup.richlistbox.getItemAtIndex(idx).click();
+ yield loadPromise;
+ yield BrowserTestUtils.removeTab(tab);
+ });
+});
+
+add_task(function* searchSuggestionKeyboard() {
+ yield compareCounts(function* () {
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser);
+ gURLBar.focus();
+ yield promiseAutocompleteResultPopup("searchSuggestion");
+ let idx = getFirstSuggestionIndex();
+ Assert.ok(idx >= 0, "there should be a first suggestion");
+ let loadPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+ while (idx--) {
+ EventUtils.sendKey("down");
+ }
+ EventUtils.sendKey("return");
+ yield loadPromise;
+ yield BrowserTestUtils.removeTab(tab);
+ });
+});
+
+/**
+ * This does three things: gets current telemetry/FHR counts, calls
+ * clickCallback, gets telemetry/FHR counts again to compare them to the old
+ * counts.
+ *
+ * @param clickCallback Use this to open the urlbar popup and choose and click a
+ * result.
+ */
+function* compareCounts(clickCallback) {
+ // Search events triggered by clicks (not the Return key in the urlbar) are
+ // recorded in three places:
+ // * BrowserUITelemetry
+ // * Telemetry histogram named "SEARCH_COUNTS"
+ // * FHR
+
+ let engine = Services.search.currentEngine;
+ let engineID = "org.mozilla.testsearchsuggestions";
+
+ // First, get the current counts.
+
+ // BrowserUITelemetry
+ let uiTelemCount = 0;
+ let bucket = BrowserUITelemetry.currentBucket;
+ let events = BrowserUITelemetry.getToolbarMeasures().countableEvents;
+ if (events[bucket] &&
+ events[bucket].search &&
+ events[bucket].search.urlbar) {
+ uiTelemCount = events[bucket].search.urlbar;
+ }
+
+ // telemetry histogram SEARCH_COUNTS
+ let histogramCount = 0;
+ let histogramKey = engineID + ".urlbar";
+ let histogram;
+ try {
+ histogram = Services.telemetry.getKeyedHistogramById("SEARCH_COUNTS");
+ } catch (ex) {
+ // No searches performed yet, not a problem.
+ }
+ if (histogram) {
+ let snapshot = histogram.snapshot();
+ if (histogramKey in snapshot) {
+ histogramCount = snapshot[histogramKey].sum;
+ }
+ }
+
+ // FHR -- first make sure the engine has an identifier so that FHR is happy.
+ Object.defineProperty(engine.wrappedJSObject, "identifier",
+ { value: engineID });
+
+ gURLBar.focus();
+ yield clickCallback();
+
+ // Now get the new counts and compare them to the old.
+
+ // BrowserUITelemetry
+ events = BrowserUITelemetry.getToolbarMeasures().countableEvents;
+ Assert.ok(bucket in events, "bucket should be recorded");
+ events = events[bucket];
+ Assert.ok("search" in events, "search should be recorded");
+ events = events.search;
+ Assert.ok("urlbar" in events, "urlbar should be recorded");
+ Assert.equal(events.urlbar, uiTelemCount + 1,
+ "clicked suggestion should be recorded");
+
+ // telemetry histogram SEARCH_COUNTS
+ histogram = Services.telemetry.getKeyedHistogramById("SEARCH_COUNTS");
+ let snapshot = histogram.snapshot();
+ Assert.ok(histogramKey in snapshot, "histogram with key should be recorded");
+ Assert.equal(snapshot[histogramKey].sum, histogramCount + 1,
+ "histogram sum should be incremented");
+}
+
+/**
+ * Returns the "action" object at the given index in the urlbar results:
+ * { type, params: {}}
+ *
+ * @param index The index in the urlbar results.
+ * @return An action object, or null if index >= number of results.
+ */
+function getActionAtIndex(index) {
+ let controller = gURLBar.popup.input.controller;
+ if (controller.matchCount <= index) {
+ return null;
+ }
+ let url = controller.getValueAt(index);
+ let mozActionMatch = url.match(/^moz-action:([^,]+),(.*)$/);
+ if (!mozActionMatch) {
+ let msg = "result at index " + index + " is not a moz-action: " + url;
+ Assert.ok(false, msg);
+ throw new Error(msg);
+ }
+ let [, type, paramStr] = mozActionMatch;
+ return {
+ type: type,
+ params: JSON.parse(paramStr),
+ };
+}
+
+/**
+ * Returns the index of the first search suggestion in the urlbar results.
+ *
+ * @return An index, or -1 if there are no search suggestions.
+ */
+function getFirstSuggestionIndex() {
+ let controller = gURLBar.popup.input.controller;
+ let matchCount = controller.matchCount;
+ for (let i = 0; i < matchCount; i++) {
+ let url = controller.getValueAt(i);
+ let mozActionMatch = url.match(/^moz-action:([^,]+),(.*)$/);
+ if (mozActionMatch) {
+ let [, type, paramStr] = mozActionMatch;
+ let params = JSON.parse(paramStr);
+ if (type == "searchengine" && "searchSuggestion" in params) {
+ return i;
+ }
+ }
+ }
+ return -1;
+}
diff --git a/browser/base/content/test/urlbar/browser_urlbarStop.js b/browser/base/content/test/urlbar/browser_urlbarStop.js
new file mode 100644
index 000000000..8cf9d8017
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_urlbarStop.js
@@ -0,0 +1,30 @@
+"use strict";
+
+const goodURL = "http://mochi.test:8888/";
+const badURL = "http://mochi.test:8888/whatever.html";
+
+add_task(function* () {
+ gBrowser.selectedTab = gBrowser.addTab(goodURL);
+ yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+ is(gURLBar.textValue, gURLBar.trimValue(goodURL), "location bar reflects loaded page");
+
+ yield typeAndSubmitAndStop(badURL);
+ is(gURLBar.textValue, gURLBar.trimValue(goodURL), "location bar reflects loaded page after stop()");
+ gBrowser.removeCurrentTab();
+
+ gBrowser.selectedTab = gBrowser.addTab("about:blank");
+ is(gURLBar.textValue, "", "location bar is empty");
+
+ yield typeAndSubmitAndStop(badURL);
+ is(gURLBar.textValue, gURLBar.trimValue(badURL), "location bar reflects stopped page in an empty tab");
+ gBrowser.removeCurrentTab();
+});
+
+function* typeAndSubmitAndStop(url) {
+ yield promiseAutocompleteResultPopup(url, window, true);
+ is(gURLBar.textValue, gURLBar.trimValue(url), "location bar reflects loading page");
+
+ let promise = waitForDocLoadAndStopIt(url, gBrowser.selectedBrowser, false);
+ gURLBar.handleCommand();
+ yield promise;
+}
diff --git a/browser/base/content/test/urlbar/browser_urlbarTrimURLs.js b/browser/base/content/test/urlbar/browser_urlbarTrimURLs.js
new file mode 100644
index 000000000..913e99a8e
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_urlbarTrimURLs.js
@@ -0,0 +1,98 @@
+add_task(function* () {
+ const PREF_TRIMURLS = "browser.urlbar.trimURLs";
+
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser);
+
+ registerCleanupFunction(function* () {
+ yield BrowserTestUtils.removeTab(tab);
+ Services.prefs.clearUserPref(PREF_TRIMURLS);
+ URLBarSetURI();
+ });
+
+ Services.prefs.setBoolPref(PREF_TRIMURLS, true);
+
+ testVal("http://mozilla.org/", "mozilla.org");
+ testVal("https://mozilla.org/", "https://mozilla.org");
+ testVal("http://mözilla.org/", "mözilla.org");
+ testVal("http://mozilla.imaginatory/", "mozilla.imaginatory");
+ testVal("http://www.mozilla.org/", "www.mozilla.org");
+ testVal("http://sub.mozilla.org/", "sub.mozilla.org");
+ testVal("http://sub1.sub2.sub3.mozilla.org/", "sub1.sub2.sub3.mozilla.org");
+ testVal("http://mozilla.org/file.ext", "mozilla.org/file.ext");
+ testVal("http://mozilla.org/sub/", "mozilla.org/sub/");
+
+ testVal("http://ftp.mozilla.org/", "ftp.mozilla.org");
+ testVal("http://ftp1.mozilla.org/", "ftp1.mozilla.org");
+ testVal("http://ftp42.mozilla.org/", "ftp42.mozilla.org");
+ testVal("http://ftpx.mozilla.org/", "ftpx.mozilla.org");
+ testVal("ftp://ftp.mozilla.org/", "ftp://ftp.mozilla.org");
+ testVal("ftp://ftp1.mozilla.org/", "ftp://ftp1.mozilla.org");
+ testVal("ftp://ftp42.mozilla.org/", "ftp://ftp42.mozilla.org");
+ testVal("ftp://ftpx.mozilla.org/", "ftp://ftpx.mozilla.org");
+
+ testVal("https://user:pass@mozilla.org/", "https://user:pass@mozilla.org");
+ testVal("https://user@mozilla.org/", "https://user@mozilla.org");
+ testVal("http://user:pass@mozilla.org/", "user:pass@mozilla.org");
+ testVal("http://user@mozilla.org/", "user@mozilla.org");
+ testVal("http://sub.mozilla.org:666/", "sub.mozilla.org:666");
+
+ testVal("https://[fe80::222:19ff:fe11:8c76]/file.ext");
+ testVal("http://[fe80::222:19ff:fe11:8c76]/", "[fe80::222:19ff:fe11:8c76]");
+ testVal("https://user:pass@[fe80::222:19ff:fe11:8c76]:666/file.ext");
+ testVal("http://user:pass@[fe80::222:19ff:fe11:8c76]:666/file.ext", "user:pass@[fe80::222:19ff:fe11:8c76]:666/file.ext");
+
+ testVal("mailto:admin@mozilla.org");
+ testVal("gopher://mozilla.org/");
+ testVal("about:config");
+ testVal("jar:http://mozilla.org/example.jar!/");
+ testVal("view-source:http://mozilla.org/");
+
+ // Behaviour for hosts with no dots depends on the whitelist:
+ let fixupWhitelistPref = "browser.fixup.domainwhitelist.localhost";
+ Services.prefs.setBoolPref(fixupWhitelistPref, false);
+ testVal("http://localhost");
+ Services.prefs.setBoolPref(fixupWhitelistPref, true);
+ testVal("http://localhost", "localhost");
+ Services.prefs.clearUserPref(fixupWhitelistPref);
+
+ testVal("http:// invalid url");
+
+ testVal("http://someotherhostwithnodots");
+ testVal("http://localhost/ foo bar baz");
+ testVal("http://localhost.localdomain/ foo bar baz", "localhost.localdomain/ foo bar baz");
+
+ Services.prefs.setBoolPref(PREF_TRIMURLS, false);
+
+ testVal("http://mozilla.org/");
+
+ Services.prefs.setBoolPref(PREF_TRIMURLS, true);
+
+ let promiseLoaded = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser,
+ false, "http://example.com/");
+ gBrowser.loadURI("http://example.com/");
+ yield promiseLoaded;
+
+ yield testCopy("example.com", "http://example.com/")
+
+ SetPageProxyState("invalid");
+ gURLBar.valueIsTyped = true;
+ yield testCopy("example.com", "example.com");
+});
+
+function testVal(originalValue, targetValue) {
+ gURLBar.value = originalValue;
+ gURLBar.valueIsTyped = false;
+ is(gURLBar.textValue, targetValue || originalValue, "url bar value set");
+}
+
+function testCopy(originalValue, targetValue) {
+ return new Promise((resolve, reject) => {
+ waitForClipboard(targetValue, function () {
+ is(gURLBar.textValue, originalValue, "url bar copy value set");
+
+ gURLBar.focus();
+ gURLBar.select();
+ goDoCommand("cmd_copy");
+ }, resolve, reject);
+ });
+}
diff --git a/browser/base/content/test/urlbar/browser_urlbarUpdateForDomainCompletion.js b/browser/base/content/test/urlbar/browser_urlbarUpdateForDomainCompletion.js
new file mode 100644
index 000000000..c3cdf507f
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_urlbarUpdateForDomainCompletion.js
@@ -0,0 +1,17 @@
+"use strict";
+
+/**
+ * Disable keyword.enabled (so no keyword search), and check that when you type in
+ * "example" and hit enter, the browser loads and the URL bar is updated accordingly.
+ */
+add_task(function* () {
+ yield new Promise(resolve => SpecialPowers.pushPrefEnv({set: [["keyword.enabled", false]]}, resolve));
+ yield BrowserTestUtils.withNewTab({ gBrowser, url: "about:blank" }, function* (browser) {
+ gURLBar.value = "example";
+ gURLBar.select();
+ let loadPromise = BrowserTestUtils.browserLoaded(browser, false, url => url == "http://www.example.com/");
+ EventUtils.sendKey("return");
+ yield loadPromise;
+ is(gURLBar.textValue, "www.example.com");
+ });
+});
diff --git a/browser/base/content/test/urlbar/browser_urlbar_autoFill_backspaced.js b/browser/base/content/test/urlbar/browser_urlbar_autoFill_backspaced.js
new file mode 100644
index 000000000..7fefd3f77
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_urlbar_autoFill_backspaced.js
@@ -0,0 +1,146 @@
+/* This test ensures that backspacing autoFilled values still allows to
+ * confirm the remaining value.
+ */
+
+function* test_autocomplete(data) {
+ let {desc, typed, autofilled, modified, keys, action, onAutoFill} = data;
+ info(desc);
+
+ yield promiseAutocompleteResultPopup(typed);
+ is(gURLBar.textValue, autofilled, "autofilled value is as expected");
+ if (onAutoFill)
+ onAutoFill()
+
+ keys.forEach(key => EventUtils.synthesizeKey(key, {}));
+
+ is(gURLBar.textValue, modified, "backspaced value is as expected");
+
+ yield promiseSearchComplete();
+
+ ok(gURLBar.popup.richlistbox.children.length > 0, "Should get at least 1 result");
+ let result = gURLBar.popup.richlistbox.children[0];
+ let type = result.getAttribute("type");
+ let types = type.split(/\s+/);
+ ok(types.indexOf(action) >= 0, `The type attribute "${type}" includes the expected action "${action}"`);
+
+ gURLBar.popup.hidePopup();
+ yield promisePopupHidden(gURLBar.popup);
+ gURLBar.blur();
+}
+
+add_task(function* () {
+ registerCleanupFunction(function* () {
+ Services.prefs.clearUserPref("browser.urlbar.autoFill");
+ gURLBar.handleRevert();
+ yield PlacesTestUtils.clearHistory();
+ });
+ Services.prefs.setBoolPref("browser.urlbar.autoFill", true);
+
+ // Add a typed visit, so it will be autofilled.
+ yield PlacesTestUtils.addVisits({
+ uri: NetUtil.newURI("http://example.com/"),
+ transition: Ci.nsINavHistoryService.TRANSITION_TYPED
+ });
+
+ yield test_autocomplete({ desc: "DELETE the autofilled part should search",
+ typed: "exam",
+ autofilled: "example.com/",
+ modified: "exam",
+ keys: ["VK_DELETE"],
+ action: "searchengine"
+ });
+ yield test_autocomplete({ desc: "DELETE the final slash should visit",
+ typed: "example.com",
+ autofilled: "example.com/",
+ modified: "example.com",
+ keys: ["VK_DELETE"],
+ action: "visiturl"
+ });
+
+ yield test_autocomplete({ desc: "BACK_SPACE the autofilled part should search",
+ typed: "exam",
+ autofilled: "example.com/",
+ modified: "exam",
+ keys: ["VK_BACK_SPACE"],
+ action: "searchengine"
+ });
+ yield test_autocomplete({ desc: "BACK_SPACE the final slash should visit",
+ typed: "example.com",
+ autofilled: "example.com/",
+ modified: "example.com",
+ keys: ["VK_BACK_SPACE"],
+ action: "visiturl"
+ });
+
+ yield test_autocomplete({ desc: "DELETE the autofilled part, then BACK_SPACE, should search",
+ typed: "exam",
+ autofilled: "example.com/",
+ modified: "exa",
+ keys: ["VK_DELETE", "VK_BACK_SPACE"],
+ action: "searchengine"
+ });
+ yield test_autocomplete({ desc: "DELETE the final slash, then BACK_SPACE, should search",
+ typed: "example.com",
+ autofilled: "example.com/",
+ modified: "example.co",
+ keys: ["VK_DELETE", "VK_BACK_SPACE"],
+ action: "visiturl"
+ });
+
+ yield test_autocomplete({ desc: "BACK_SPACE the autofilled part, then BACK_SPACE, should search",
+ typed: "exam",
+ autofilled: "example.com/",
+ modified: "exa",
+ keys: ["VK_BACK_SPACE", "VK_BACK_SPACE"],
+ action: "searchengine"
+ });
+ yield test_autocomplete({ desc: "BACK_SPACE the final slash, then BACK_SPACE, should search",
+ typed: "example.com",
+ autofilled: "example.com/",
+ modified: "example.co",
+ keys: ["VK_BACK_SPACE", "VK_BACK_SPACE"],
+ action: "visiturl"
+ });
+
+ yield test_autocomplete({ desc: "BACK_SPACE after blur should search",
+ typed: "ex",
+ autofilled: "example.com/",
+ modified: "e",
+ keys: ["VK_BACK_SPACE"],
+ action: "searchengine",
+ onAutoFill: () => {
+ gURLBar.blur();
+ gURLBar.focus();
+ gURLBar.selectionStart = 1;
+ gURLBar.selectionEnd = 12;
+ }
+ });
+ yield test_autocomplete({ desc: "DELETE after blur should search",
+ typed: "ex",
+ autofilled: "example.com/",
+ modified: "e",
+ keys: ["VK_DELETE"],
+ action: "searchengine",
+ onAutoFill: () => {
+ gURLBar.blur();
+ gURLBar.focus();
+ gURLBar.selectionStart = 1;
+ gURLBar.selectionEnd = 12;
+ }
+ });
+ yield test_autocomplete({ desc: "double BACK_SPACE after blur should search",
+ typed: "ex",
+ autofilled: "example.com/",
+ modified: "e",
+ keys: ["VK_BACK_SPACE", "VK_BACK_SPACE"],
+ action: "searchengine",
+ onAutoFill: () => {
+ gURLBar.blur();
+ gURLBar.focus();
+ gURLBar.selectionStart = 2;
+ gURLBar.selectionEnd = 12;
+ }
+ });
+
+ yield PlacesTestUtils.clearHistory();
+});
diff --git a/browser/base/content/test/urlbar/browser_urlbar_blanking.js b/browser/base/content/test/urlbar/browser_urlbar_blanking.js
new file mode 100644
index 000000000..13660edab
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_urlbar_blanking.js
@@ -0,0 +1,35 @@
+"use strict";
+
+add_task(function*() {
+ for (let page of gInitialPages) {
+ if (page == "about:newtab") {
+ // New tab preloading makes this a pain to test, so skip
+ continue;
+ }
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, page);
+ ok(!gURLBar.value, "The URL bar should be empty if we load a plain " + page + " page.");
+ yield BrowserTestUtils.removeTab(tab);
+ }
+});
+
+add_task(function*() {
+ const URI = "http://www.example.com/browser/browser/base/content/test/urlbar/file_blank_but_not_blank.html";
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, URI);
+ is(gURLBar.value, URI, "The URL bar should match the URI");
+ let browserLoaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+ ContentTask.spawn(tab.linkedBrowser, null, function() {
+ content.document.querySelector('a').click();
+ });
+ yield browserLoaded;
+ ok(gURLBar.value.startsWith("javascript"), "The URL bar should have the JS URI");
+ // When reloading, the javascript: uri we're using will throw an exception.
+ // That's deliberate, so we need to tell mochitest to ignore it:
+ SimpleTest.expectUncaughtException(true);
+ yield ContentTask.spawn(tab.linkedBrowser, null, function*() {
+ // This is sync, so by the time we return we should have changed the URL bar.
+ content.location.reload();
+ });
+ ok(!!gURLBar.value, "URL bar should not be blank.");
+ yield BrowserTestUtils.removeTab(tab);
+ SimpleTest.expectUncaughtException(false);
+});
diff --git a/browser/base/content/test/urlbar/browser_urlbar_locationchange_urlbar_edit_dos.js b/browser/base/content/test/urlbar/browser_urlbar_locationchange_urlbar_edit_dos.js
new file mode 100644
index 000000000..63ed58a62
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_urlbar_locationchange_urlbar_edit_dos.js
@@ -0,0 +1,41 @@
+"use strict";
+
+function* checkURLBarValueStays(browser) {
+ gURLBar.select();
+ EventUtils.synthesizeKey("a", {});
+ is(gURLBar.value, "a", "URL bar value should match after sending a key");
+ yield new Promise(resolve => {
+ let listener = {
+ onLocationChange(aWebProgress, aRequest, aLocation, aFlags) {
+ ok(aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT,
+ "Should only get a same document location change");
+ gBrowser.selectedBrowser.removeProgressListener(filter);
+ filter = null;
+ resolve();
+ },
+ };
+ let filter = Cc["@mozilla.org/appshell/component/browser-status-filter;1"]
+ .createInstance(Ci.nsIWebProgress);
+ filter.addProgressListener(listener, Ci.nsIWebProgress.NOTIFY_ALL);
+ gBrowser.selectedBrowser.addProgressListener(filter);
+ });
+ is(gURLBar.value, "a", "URL bar should not have been changed by location changes.");
+}
+
+add_task(function*() {
+ yield BrowserTestUtils.withNewTab({
+ gBrowser,
+ url: "http://example.com/browser/browser/base/content/test/urlbar/file_urlbar_edit_dos.html"
+ }, function*(browser) {
+ yield ContentTask.spawn(browser, "", function() {
+ content.wrappedJSObject.dos_hash();
+ });
+ yield checkURLBarValueStays(browser);
+ yield ContentTask.spawn(browser, "", function() {
+ content.clearTimeout(content.wrappedJSObject.dos_timeout);
+ content.wrappedJSObject.dos_pushState();
+ });
+ yield checkURLBarValueStays(browser);
+ });
+});
+
diff --git a/browser/base/content/test/urlbar/browser_urlbar_remoteness_switch.js b/browser/base/content/test/urlbar/browser_urlbar_remoteness_switch.js
new file mode 100644
index 000000000..9a1df0505
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_urlbar_remoteness_switch.js
@@ -0,0 +1,39 @@
+"use strict";
+
+/**
+ * Verify that when loading and going back/forward through history between URLs
+ * loaded in the content process, and URLs loaded in the parent process, we
+ * don't set the URL for the tab to about:blank inbetween the loads.
+ */
+add_task(function*() {
+ let url = "http://www.example.com/foo.html";
+ yield BrowserTestUtils.withNewTab({gBrowser, url}, function*(browser) {
+ let wpl = {
+ onLocationChange(wpl, request, location, flags) {
+ if (location.schemeIs("about")) {
+ is(location.spec, "about:config", "Only about: location change should be for about:preferences");
+ } else {
+ is(location.spec, url, "Only non-about: location change should be for the http URL we're dealing with.");
+ }
+ },
+ };
+ gBrowser.addProgressListener(wpl);
+
+ let didLoad = BrowserTestUtils.browserLoaded(browser, null, function(loadedURL) {
+ return loadedURL == "about:config";
+ });
+ yield BrowserTestUtils.loadURI(browser, "about:config");
+ yield didLoad;
+
+ gBrowser.goBack();
+ yield BrowserTestUtils.browserLoaded(browser, null, function(loadedURL) {
+ return url == loadedURL;
+ });
+ gBrowser.goForward();
+ yield BrowserTestUtils.browserLoaded(browser, null, function(loadedURL) {
+ return loadedURL == "about:config";
+ });
+ gBrowser.removeProgressListener(wpl);
+ });
+});
+
diff --git a/browser/base/content/test/urlbar/browser_urlbar_searchsettings.js b/browser/base/content/test/urlbar/browser_urlbar_searchsettings.js
new file mode 100644
index 000000000..04b1c508b
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_urlbar_searchsettings.js
@@ -0,0 +1,30 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+add_task(function*() {
+ let button = document.getElementById("urlbar-search-settings");
+ if (!button) {
+ ok("Skipping test");
+ return;
+ }
+
+ yield BrowserTestUtils.withNewTab({ gBrowser, url: "about:blank" }, function* () {
+ let popupopened = BrowserTestUtils.waitForEvent(gURLBar.popup, "popupshown");
+
+ gURLBar.focus();
+ EventUtils.synthesizeKey("a", {});
+ yield popupopened;
+
+ // Since the current tab is blank the preferences pane will load there
+ let loaded = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+ let popupclosed = BrowserTestUtils.waitForEvent(gURLBar.popup, "popuphidden");
+ EventUtils.synthesizeMouseAtCenter(button, {});
+ yield loaded;
+ yield popupclosed;
+
+ is(gBrowser.selectedBrowser.currentURI.spec, "about:preferences#search",
+ "Should have loaded the right page");
+ });
+});
diff --git a/browser/base/content/test/urlbar/browser_urlbar_stop_pending.js b/browser/base/content/test/urlbar/browser_urlbar_stop_pending.js
new file mode 100644
index 000000000..6b6a10ea3
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_urlbar_stop_pending.js
@@ -0,0 +1,138 @@
+"use strict";
+
+const SLOW_PAGE = "http://www.example.com/browser/browser/base/content/test/urlbar/slow-page.sjs";
+const SLOW_PAGE2 = "http://mochi.test:8888/browser/browser/base/content/test/urlbar/slow-page.sjs?faster";
+
+/**
+ * Check that if we:
+ * 1) have a loaded page
+ * 2) load a separate URL
+ * 3) before the URL for step 2 has finished loading, load a third URL
+ * we don't revert to the URL from (1).
+ */
+add_task(function*() {
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com", true, true);
+
+ let expectedURLBarChange = SLOW_PAGE;
+ let sawChange = false;
+ let handler = e => {
+ sawChange = true;
+ is(gURLBar.value, expectedURLBarChange, "Should not change URL bar value!");
+ };
+
+ let obs = new MutationObserver(handler);
+
+ obs.observe(gURLBar, {attributes: true});
+ gURLBar.value = SLOW_PAGE;
+ gURLBar.handleCommand();
+
+ // If this ever starts going intermittent, we've broken this.
+ yield new Promise(resolve => setTimeout(resolve, 200));
+ expectedURLBarChange = SLOW_PAGE2;
+ let pageLoadPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+ gURLBar.value = expectedURLBarChange;
+ gURLBar.handleCommand();
+ is(gURLBar.value, expectedURLBarChange, "Should not have changed URL bar value synchronously.");
+ yield pageLoadPromise;
+ ok(sawChange, "The URL bar change handler should have been called by the time the page was loaded");
+ obs.disconnect();
+ obs = null;
+ yield BrowserTestUtils.removeTab(tab);
+});
+
+/**
+ * Check that if we:
+ * 1) middle-click a link to a separate page whose server doesn't respond
+ * 2) we switch to that tab and stop the request
+ *
+ * The URL bar continues to contain the URL of the page we wanted to visit.
+ */
+add_task(function*() {
+ let socket = Cc["@mozilla.org/network/server-socket;1"].createInstance(Ci.nsIServerSocket);
+ socket.init(-1, true, -1);
+ const PORT = socket.port;
+ registerCleanupFunction(() => { socket.close(); });
+
+ const TEST_PATH = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "https://example.com");
+ const BASE_PAGE = TEST_PATH + "dummy_page.html";
+ const SLOW_HOST = `https://localhost:${PORT}/`;
+ info("Using URLs: " + SLOW_HOST);
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, BASE_PAGE);
+ info("opened tab");
+ yield ContentTask.spawn(tab.linkedBrowser, SLOW_HOST, URL => {
+ let link = content.document.createElement("a");
+ link.href = URL;
+ link.textContent = "click me to open a slow page";
+ link.id = "clickme"
+ content.document.body.appendChild(link);
+ });
+ info("added link");
+ let newTabPromise = BrowserTestUtils.waitForEvent(gBrowser.tabContainer, "TabOpen");
+ // Middle click the link:
+ yield BrowserTestUtils.synthesizeMouseAtCenter("#clickme", { button: 1 }, tab.linkedBrowser);
+ // get new tab, switch to it
+ let newTab = (yield newTabPromise).target;
+ yield BrowserTestUtils.switchTab(gBrowser, newTab);
+ is(gURLBar.value, SLOW_HOST, "Should have slow page in URL bar");
+ let browserStoppedPromise = BrowserTestUtils.browserStopped(newTab.linkedBrowser);
+ BrowserStop();
+ yield browserStoppedPromise;
+
+ is(gURLBar.value, SLOW_HOST, "Should still have slow page in URL bar after stop");
+ yield BrowserTestUtils.removeTab(newTab);
+ yield BrowserTestUtils.removeTab(tab);
+});
+/**
+ * Check that if we:
+ * 1) middle-click a link to a separate page whose server doesn't respond
+ * 2) we alter the URL on that page to some other server that doesn't respond
+ * 3) we stop the request
+ *
+ * The URL bar continues to contain the second URL.
+ */
+add_task(function*() {
+ let socket = Cc["@mozilla.org/network/server-socket;1"].createInstance(Ci.nsIServerSocket);
+ socket.init(-1, true, -1);
+ const PORT1 = socket.port;
+ let socket2 = Cc["@mozilla.org/network/server-socket;1"].createInstance(Ci.nsIServerSocket);
+ socket2.init(-1, true, -1);
+ const PORT2 = socket2.port;
+ registerCleanupFunction(() => { socket.close(); socket2.close(); });
+
+ const TEST_PATH = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "https://example.com");
+ const BASE_PAGE = TEST_PATH + "dummy_page.html";
+ const SLOW_HOST1 = `https://localhost:${PORT1}/`;
+ const SLOW_HOST2 = `https://localhost:${PORT2}/`;
+ info("Using URLs: " + SLOW_HOST1 + " and " + SLOW_HOST2);
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, BASE_PAGE);
+ info("opened tab");
+ yield ContentTask.spawn(tab.linkedBrowser, SLOW_HOST1, URL => {
+ let link = content.document.createElement("a");
+ link.href = URL;
+ link.textContent = "click me to open a slow page";
+ link.id = "clickme"
+ content.document.body.appendChild(link);
+ });
+ info("added link");
+ let newTabPromise = BrowserTestUtils.waitForEvent(gBrowser.tabContainer, "TabOpen");
+ // Middle click the link:
+ yield BrowserTestUtils.synthesizeMouseAtCenter("#clickme", { button: 1 }, tab.linkedBrowser);
+ // get new tab, switch to it
+ let newTab = (yield newTabPromise).target;
+ yield BrowserTestUtils.switchTab(gBrowser, newTab);
+ is(gURLBar.value, SLOW_HOST1, "Should have slow page in URL bar");
+ let browserStoppedPromise = BrowserTestUtils.browserStopped(newTab.linkedBrowser);
+ gURLBar.value = SLOW_HOST2;
+ gURLBar.handleCommand();
+ yield browserStoppedPromise;
+
+ is(gURLBar.value, SLOW_HOST2, "Should have second slow page in URL bar");
+ browserStoppedPromise = BrowserTestUtils.browserStopped(newTab.linkedBrowser);
+ BrowserStop();
+ yield browserStoppedPromise;
+
+ is(gURLBar.value, SLOW_HOST2, "Should still have second slow page in URL bar after stop");
+ yield BrowserTestUtils.removeTab(newTab);
+ yield BrowserTestUtils.removeTab(tab);
+});
+
diff --git a/browser/base/content/test/urlbar/browser_wyciwyg_urlbarCopying.js b/browser/base/content/test/urlbar/browser_wyciwyg_urlbarCopying.js
new file mode 100644
index 000000000..54b174aa8
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_wyciwyg_urlbarCopying.js
@@ -0,0 +1,31 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function testURLBarCopy(targetValue) {
+ return new Promise((resolve, reject) => {
+ info("Expecting copy of: " + targetValue);
+ waitForClipboard(targetValue, function () {
+ gURLBar.focus();
+ gURLBar.select();
+
+ goDoCommand("cmd_copy");
+ }, resolve, () => {
+ ok(false, "Clipboard copy failed");
+ reject();
+ });
+ });
+}
+
+add_task(function* () {
+ const url = "http://mochi.test:8888/browser/browser/base/content/test/urlbar/test_wyciwyg_copying.html";
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, url);
+
+ yield BrowserTestUtils.synthesizeMouseAtCenter("#btn", {}, tab.linkedBrowser);
+ let currentURL = gBrowser.currentURI.spec;
+ ok(/^wyciwyg:\/\//i.test(currentURL), currentURL + " is a wyciwyg URI");
+
+ yield testURLBarCopy(url);
+
+ while (gBrowser.tabs.length > 1)
+ gBrowser.removeCurrentTab();
+});
diff --git a/browser/base/content/test/urlbar/dummy_page.html b/browser/base/content/test/urlbar/dummy_page.html
new file mode 100644
index 000000000..1a87e2840
--- /dev/null
+++ b/browser/base/content/test/urlbar/dummy_page.html
@@ -0,0 +1,9 @@
+<html>
+<head>
+<title>Dummy test page</title>
+<meta http-equiv="Content-Type" content="text/html;charset=utf-8"></meta>
+</head>
+<body>
+<p>Dummy test page</p>
+</body>
+</html>
diff --git a/browser/base/content/test/urlbar/file_blank_but_not_blank.html b/browser/base/content/test/urlbar/file_blank_but_not_blank.html
new file mode 100644
index 000000000..1f5fea8dc
--- /dev/null
+++ b/browser/base/content/test/urlbar/file_blank_but_not_blank.html
@@ -0,0 +1,2 @@
+<script>var q = "1";</script>
+<a href="javascript:q">Click me</a>
diff --git a/browser/base/content/test/urlbar/file_urlbar_edit_dos.html b/browser/base/content/test/urlbar/file_urlbar_edit_dos.html
new file mode 100644
index 000000000..5a6e7d109
--- /dev/null
+++ b/browser/base/content/test/urlbar/file_urlbar_edit_dos.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Try editing the URL bar</title>
+<meta http-equiv="Content-Type" content="text/html;charset=utf-8"></meta>
+</head>
+<body>
+<script>
+var dos_timeout = null;
+function dos_hash() {
+ dos_timeout = setTimeout(function() {
+ location.hash = "#";
+ }, 50);
+}
+
+function dos_pushState() {
+ dos_timeout = setTimeout(function() {
+ history.pushState({}, "Some title", "");
+ }, 50);
+}
+</script>
+</body>
+</html>
diff --git a/browser/base/content/test/urlbar/head.js b/browser/base/content/test/urlbar/head.js
new file mode 100644
index 000000000..427dba080
--- /dev/null
+++ b/browser/base/content/test/urlbar/head.js
@@ -0,0 +1,205 @@
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "Promise",
+ "resource://gre/modules/Promise.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Task",
+ "resource://gre/modules/Task.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
+ "resource://gre/modules/PlacesUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "PlacesTestUtils",
+ "resource://testing-common/PlacesTestUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Preferences",
+ "resource://gre/modules/Preferences.jsm");
+
+/**
+ * Waits for the next top-level document load in the current browser. The URI
+ * of the document is compared against aExpectedURL. The load is then stopped
+ * before it actually starts.
+ *
+ * @param aExpectedURL
+ * The URL of the document that is expected to load.
+ * @param aStopFromProgressListener
+ * Whether to cancel the load directly from the progress listener. Defaults to true.
+ * If you're using this method to avoid hitting the network, you want the default (true).
+ * However, the browser UI will behave differently for loads stopped directly from
+ * the progress listener (effectively in the middle of a call to loadURI) and so there
+ * are cases where you may want to avoid stopping the load directly from within the
+ * progress listener callback.
+ * @return promise
+ */
+function waitForDocLoadAndStopIt(aExpectedURL, aBrowser=gBrowser.selectedBrowser, aStopFromProgressListener=true) {
+ function content_script(aStopFromProgressListener) {
+ let { interfaces: Ci, utils: Cu } = Components;
+ Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+ let wp = docShell.QueryInterface(Ci.nsIWebProgress);
+
+ function stopContent(now, uri) {
+ if (now) {
+ /* Hammer time. */
+ content.stop();
+
+ /* Let the parent know we're done. */
+ sendAsyncMessage("Test:WaitForDocLoadAndStopIt", { uri });
+ } else {
+ setTimeout(stopContent.bind(null, true, uri), 0);
+ }
+ }
+
+ let progressListener = {
+ onStateChange: function (webProgress, req, flags, status) {
+ dump("waitForDocLoadAndStopIt: onStateChange " + flags.toString(16) + ": " + req.name + "\n");
+
+ if (webProgress.isTopLevel &&
+ flags & Ci.nsIWebProgressListener.STATE_START) {
+ wp.removeProgressListener(progressListener);
+
+ let chan = req.QueryInterface(Ci.nsIChannel);
+ dump(`waitForDocLoadAndStopIt: Document start: ${chan.URI.spec}\n`);
+
+ stopContent(aStopFromProgressListener, chan.originalURI.spec);
+ }
+ },
+ QueryInterface: XPCOMUtils.generateQI(["nsISupportsWeakReference"])
+ };
+ wp.addProgressListener(progressListener, wp.NOTIFY_STATE_WINDOW);
+
+ /**
+ * As |this| is undefined and we can't extend |docShell|, adding an unload
+ * event handler is the easiest way to ensure the weakly referenced
+ * progress listener is kept alive as long as necessary.
+ */
+ addEventListener("unload", function () {
+ try {
+ wp.removeProgressListener(progressListener);
+ } catch (e) { /* Will most likely fail. */ }
+ });
+ }
+
+ return new Promise((resolve, reject) => {
+ function complete({ data }) {
+ is(data.uri, aExpectedURL, "waitForDocLoadAndStopIt: The expected URL was loaded");
+ mm.removeMessageListener("Test:WaitForDocLoadAndStopIt", complete);
+ resolve();
+ }
+
+ let mm = aBrowser.messageManager;
+ mm.loadFrameScript("data:,(" + content_script.toString() + ")(" + aStopFromProgressListener + ");", true);
+ mm.addMessageListener("Test:WaitForDocLoadAndStopIt", complete);
+ info("waitForDocLoadAndStopIt: Waiting for URL: " + aExpectedURL);
+ });
+}
+
+function is_hidden(element) {
+ var style = element.ownerGlobal.getComputedStyle(element);
+ if (style.display == "none")
+ return true;
+ if (style.visibility != "visible")
+ return true;
+ if (style.display == "-moz-popup")
+ return ["hiding", "closed"].indexOf(element.state) != -1;
+
+ // Hiding a parent element will hide all its children
+ if (element.parentNode != element.ownerDocument)
+ return is_hidden(element.parentNode);
+
+ return false;
+}
+
+function is_visible(element) {
+ var style = element.ownerGlobal.getComputedStyle(element);
+ if (style.display == "none")
+ return false;
+ if (style.visibility != "visible")
+ return false;
+ if (style.display == "-moz-popup" && element.state != "open")
+ return false;
+
+ // Hiding a parent element will hide all its children
+ if (element.parentNode != element.ownerDocument)
+ return is_visible(element.parentNode);
+
+ return true;
+}
+
+function is_element_visible(element, msg) {
+ isnot(element, null, "Element should not be null, when checking visibility");
+ ok(is_visible(element), msg || "Element should be visible");
+}
+
+function is_element_hidden(element, msg) {
+ isnot(element, null, "Element should not be null, when checking visibility");
+ ok(is_hidden(element), msg || "Element should be hidden");
+}
+
+function promisePopupEvent(popup, eventSuffix) {
+ let endState = {shown: "open", hidden: "closed"}[eventSuffix];
+
+ if (popup.state == endState)
+ return Promise.resolve();
+
+ let eventType = "popup" + eventSuffix;
+ let deferred = Promise.defer();
+ popup.addEventListener(eventType, function onPopupShown(event) {
+ popup.removeEventListener(eventType, onPopupShown);
+ deferred.resolve();
+ });
+
+ return deferred.promise;
+}
+
+function promisePopupShown(popup) {
+ return promisePopupEvent(popup, "shown");
+}
+
+function promisePopupHidden(popup) {
+ return promisePopupEvent(popup, "hidden");
+}
+
+function promiseSearchComplete(win = window) {
+ return promisePopupShown(win.gURLBar.popup).then(() => {
+ function searchIsComplete() {
+ return win.gURLBar.controller.searchStatus >=
+ Ci.nsIAutoCompleteController.STATUS_COMPLETE_NO_MATCH;
+ }
+
+ // Wait until there are at least two matches.
+ return BrowserTestUtils.waitForCondition(searchIsComplete, "waiting urlbar search to complete");
+ });
+}
+
+function promiseAutocompleteResultPopup(inputText,
+ win = window,
+ fireInputEvent = false) {
+ waitForFocus(() => {
+ win.gURLBar.focus();
+ win.gURLBar.value = inputText;
+ if (fireInputEvent) {
+ // This is necessary to get the urlbar to set gBrowser.userTypedValue.
+ let event = document.createEvent("Events");
+ event.initEvent("input", true, true);
+ win.gURLBar.dispatchEvent(event);
+ }
+ win.gURLBar.controller.startSearch(inputText);
+ }, win);
+
+ return promiseSearchComplete(win);
+}
+
+function promiseNewSearchEngine(basename) {
+ return new Promise((resolve, reject) => {
+ info("Waiting for engine to be added: " + basename);
+ let url = getRootDirectory(gTestPath) + basename;
+ Services.search.addEngine(url, null, "", false, {
+ onSuccess: function (engine) {
+ info("Search engine added: " + basename);
+ registerCleanupFunction(() => Services.search.removeEngine(engine));
+ resolve(engine);
+ },
+ onError: function (errCode) {
+ Assert.ok(false, "addEngine failed with error code " + errCode);
+ reject();
+ },
+ });
+ });
+}
+
diff --git a/browser/base/content/test/urlbar/moz.png b/browser/base/content/test/urlbar/moz.png
new file mode 100644
index 000000000..769c63634
--- /dev/null
+++ b/browser/base/content/test/urlbar/moz.png
Binary files differ
diff --git a/browser/base/content/test/urlbar/print_postdata.sjs b/browser/base/content/test/urlbar/print_postdata.sjs
new file mode 100644
index 000000000..4175a2480
--- /dev/null
+++ b/browser/base/content/test/urlbar/print_postdata.sjs
@@ -0,0 +1,22 @@
+const CC = Components.Constructor;
+const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
+ "nsIBinaryInputStream",
+ "setInputStream");
+
+function handleRequest(request, response) {
+ response.setHeader("Content-Type", "text/plain", false);
+ if (request.method == "GET") {
+ response.write(request.queryString);
+ } else {
+ var body = new BinaryInputStream(request.bodyInputStream);
+
+ var avail;
+ var bytes = [];
+
+ while ((avail = body.available()) > 0)
+ Array.prototype.push.apply(bytes, body.readByteArray(avail));
+
+ var data = String.fromCharCode.apply(null, bytes);
+ response.bodyOutputStream.write(data, data.length);
+ }
+}
diff --git a/browser/base/content/test/urlbar/redirect_bug623155.sjs b/browser/base/content/test/urlbar/redirect_bug623155.sjs
new file mode 100644
index 000000000..64c6f143b
--- /dev/null
+++ b/browser/base/content/test/urlbar/redirect_bug623155.sjs
@@ -0,0 +1,16 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+const REDIRECT_TO = "https://www.bank1.com/"; // Bad-cert host.
+
+function handleRequest(aRequest, aResponse) {
+ // Set HTTP Status
+ aResponse.setStatusLine(aRequest.httpVersion, 301, "Moved Permanently");
+
+ // Set redirect URI, mirroring the hash value.
+ let hash = (/\#.+/.test(aRequest.path))?
+ "#" + aRequest.path.split("#")[1]:
+ "";
+ aResponse.setHeader("Location", REDIRECT_TO + hash);
+}
diff --git a/browser/base/content/test/urlbar/searchSuggestionEngine.sjs b/browser/base/content/test/urlbar/searchSuggestionEngine.sjs
new file mode 100644
index 000000000..1978b4f66
--- /dev/null
+++ b/browser/base/content/test/urlbar/searchSuggestionEngine.sjs
@@ -0,0 +1,9 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function handleRequest(req, resp) {
+ let suffixes = ["foo", "bar"];
+ let data = [req.queryString, suffixes.map(s => req.queryString + s)];
+ resp.setHeader("Content-Type", "application/json", false);
+ resp.write(JSON.stringify(data));
+}
diff --git a/browser/base/content/test/urlbar/searchSuggestionEngine.xml b/browser/base/content/test/urlbar/searchSuggestionEngine.xml
new file mode 100644
index 000000000..a5659792e
--- /dev/null
+++ b/browser/base/content/test/urlbar/searchSuggestionEngine.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Any copyright is dedicated to the Public Domain.
+ - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
+<ShortName>browser_searchSuggestionEngine searchSuggestionEngine.xml</ShortName>
+<Url type="application/x-suggestions+json" method="GET" template="http://mochi.test:8888/browser/browser/base/content/test/urlbar/searchSuggestionEngine.sjs?{searchTerms}"/>
+<Url type="text/html" method="GET" template="http://mochi.test:8888/" rel="searchform"/>
+</SearchPlugin>
diff --git a/browser/base/content/test/urlbar/slow-page.sjs b/browser/base/content/test/urlbar/slow-page.sjs
new file mode 100644
index 000000000..f428d66e4
--- /dev/null
+++ b/browser/base/content/test/urlbar/slow-page.sjs
@@ -0,0 +1,22 @@
+"use strict";
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+let timer;
+
+const DELAY_MS = 5000;
+function handleRequest(request, response) {
+ if (request.queryString.endsWith("faster")) {
+ response.setHeader("Content-Type", "text/html", false);
+ response.write("<body>Not so slow!</body>");
+ return;
+ }
+ response.processAsync();
+ timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+ timer.init(() => {
+ response.setHeader("Content-Type", "text/html", false);
+ response.write("<body>This was the slow load. You should never see this.</body>");
+ response.finish();
+ }, DELAY_MS, Ci.nsITimer.TYPE_ONE_SHOT);
+}
diff --git a/browser/base/content/test/urlbar/test_wyciwyg_copying.html b/browser/base/content/test/urlbar/test_wyciwyg_copying.html
new file mode 100644
index 000000000..3a8c3a150
--- /dev/null
+++ b/browser/base/content/test/urlbar/test_wyciwyg_copying.html
@@ -0,0 +1,13 @@
+<html>
+<body>
+<script>
+ function go() {
+ var w = window.open();
+ w.document.open();
+ w.document.write("<html><body>test document</body></html>");
+ w.document.close();
+ }
+</script>
+<button id="btn" onclick="go();">test</button>
+</body>
+</html>