Bug 1125117 - Use the new keywords API in autocomplete. r=ttaubert
authorMarco Bonardo <mbonardo@mozilla.com>
Thu, 26 Mar 2015 21:16:07 +0100
changeset 235889 e4496ef0ca0b05b619e3691cde6291fe7135fd10
parent 235888 08cef2ba28a035bddc5af21cfe2b8fc146642aa6
child 235890 ca43c59519767a8bc22ecb3cc88df98e2eb7eefe
push id12014
push usermak77@bonardo.net
push dateThu, 26 Mar 2015 23:51:26 +0000
treeherderfx-team@e4496ef0ca0b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersttaubert
bugs1125117
milestone39.0a1
Bug 1125117 - Use the new keywords API in autocomplete. r=ttaubert
browser/base/content/test/general/browser_action_keyword.js
browser/base/content/test/general/browser_action_keyword_override.js
browser/base/content/test/general/browser_action_searchengine.js
browser/base/content/test/general/browser_action_searchengine_alias.js
browser/base/content/test/general/browser_autocomplete_a11y_label.js
browser/base/content/test/general/browser_autocomplete_autoselect.js
browser/base/content/test/general/browser_autocomplete_enter_race.js
browser/base/content/test/general/browser_autocomplete_no_title.js
browser/base/content/test/general/browser_autocomplete_oldschool_wrap.js
browser/base/content/test/general/browser_bug1003461-switchtab-override.js
browser/base/content/test/general/browser_bug1070778.js
browser/base/content/test/general/browser_urlbarEnterAfterMouseOver.js
toolkit/components/places/UnifiedComplete.js
toolkit/components/places/nsPlacesAutoComplete.js
toolkit/components/places/tests/autocomplete/test_keyword_search.js
toolkit/components/places/tests/inline/head_autocomplete.js
toolkit/components/places/tests/inline/test_autocomplete_functional.js
toolkit/components/places/tests/inline/test_casing.js
toolkit/components/places/tests/inline/test_do_not_trim.js
toolkit/components/places/tests/inline/test_keywords.js
toolkit/components/places/tests/inline/test_queryurl.js
toolkit/components/places/tests/inline/test_trimming.js
toolkit/components/places/tests/inline/test_typed.js
toolkit/components/places/tests/inline/test_zero_frecency.js
toolkit/components/places/tests/unifiedcomplete/head_autocomplete.js
toolkit/components/places/tests/unifiedcomplete/test_keyword_search.js
toolkit/components/places/tests/unifiedcomplete/test_keyword_search_actions.js
--- a/browser/base/content/test/general/browser_action_keyword.js
+++ b/browser/base/content/test/general/browser_action_keyword.js
@@ -8,56 +8,56 @@ function* promise_first_result(inputText
 
   let firstResult = gURLBar.popup.richlistbox.firstChild;
   return firstResult;
 }
 
 
 add_task(function*() {
   // This test is only relevant if UnifiedComplete is enabled.
-  if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete")) {
-    todo(false, "Stop supporting old autocomplete components.");
-    return;
-  }
+  let ucpref = Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete");
+  Services.prefs.setBoolPref("browser.urlbar.unifiedcomplete", true);
+  registerCleanupFunction(() => {
+    Services.prefs.setBoolPref("browser.urlbar.unifiedcomplete", ucpref);
+  });
 
   let tab = gBrowser.selectedTab = gBrowser.addTab("about:mozilla");
   let tabs = [tab];
-  registerCleanupFunction(() => {
+  registerCleanupFunction(function* () {
     for (let tab of tabs)
       gBrowser.removeTab(tab);
-    PlacesUtils.bookmarks.removeItem(itemId);
+    yield PlacesUtils.bookmarks.remove(bm);
   });
 
   yield promiseTabLoadEvent(tab);
 
-  let itemId =
-    PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
-                                         NetUtil.newURI("http://example.com/?q=%s"),
-                                         PlacesUtils.bookmarks.DEFAULT_INDEX,
-                                         "test");
-  PlacesUtils.bookmarks.setKeywordForBookmark(itemId, "keyword");
+  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" });
 
   let result = yield promise_first_result("keyword something");
   isnot(result, null, "Expect a keyword result");
 
   is(result.getAttribute("type"), "action keyword", "Expect correct  `type` attribute");
   is(result.getAttribute("actiontype"), "keyword", "Expect correct `actiontype` attribute");
-  is(result.getAttribute("title"), "test", "Expect correct title");
+  is(result.getAttribute("title"), "example.com", "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, makeActionURI("keyword", {url: "http://example.com/?q=something", input: "keyword something"}).spec, "Expect correct url");
 
   is_element_visible(result._title, "Title element should be visible");
   is(result._title.childNodes.length, 1, "Title element should have 1 child");
   is(result._title.childNodes[0].nodeName, "#text", "That child should be a text node");
-  is(result._title.childNodes[0].data, "test", "Node should contain the name of the bookmark");
+  is(result._title.childNodes[0].data, "example.com", "Node should contain the name of the bookmark");
 
-  is_element_visible(result._extra, "Extra element should be visible");
+  is_element_visible(result._extraBox, "Extra element should be visible");
   is(result._extra.childNodes.length, 1, "Title element should have 1 child");
   is(result._extra.childNodes[0].nodeName, "span", "That child should be a span node");
   let span = result._extra.childNodes[0];
   is(span.childNodes.length, 1, "span element should have 1 child");
   is(span.childNodes[0].nodeName, "#text", "That child should be a text node");
   is(span.childNodes[0].data, "something", "Node should contain the query for the keyword");
 
   is_element_hidden(result._url, "URL element should be hidden");
--- a/browser/base/content/test/general/browser_action_keyword_override.js
+++ b/browser/base/content/test/general/browser_action_keyword_override.js
@@ -1,35 +1,35 @@
 add_task(function*() {
   // This test is only relevant if UnifiedComplete is enabled.
-  if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete")) {
-    todo(false, "Stop supporting old autocomplete components.");
-    return;
-  }
+  let ucpref = Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete");
+  Services.prefs.setBoolPref("browser.urlbar.unifiedcomplete", true);
+  registerCleanupFunction(() => {
+    Services.prefs.setBoolPref("browser.urlbar.unifiedcomplete", ucpref);
+  });
 
-  let itemId =
-    PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
-                                         NetUtil.newURI("http://example.com/?q=%s"),
-                                         PlacesUtils.bookmarks.DEFAULT_INDEX,
-                                         "test");
-  PlacesUtils.bookmarks.setKeywordForBookmark(itemId, "keyword");
+  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(() => {
-    PlacesUtils.bookmarks.removeItem(itemId);
+  registerCleanupFunction(function* () {
+    yield PlacesUtils.bookmarks.remove(bm);
   });
 
   yield promiseAutocompleteResultPopup("keyword search");
   let result = gURLBar.popup.richlistbox.children[0];
 
   info("Before override");
   is_element_hidden(result._url, "URL element should be hidden");
-  is_element_visible(result._extra, "Extra element should be visible");
+  is_element_visible(result._extraBox, "Extra element should be visible");
 
   info("During override");
   EventUtils.synthesizeKey("VK_SHIFT" , { type: "keydown" });
   is_element_hidden(result._url, "URL element should be hidden");
-  is_element_visible(result._extra, "Extra element should be visible");
+  is_element_visible(result._extraBox, "Extra element should be visible");
 
   EventUtils.synthesizeKey("VK_SHIFT" , { type: "keyup" });
 
   gURLBar.popup.hidePopup();
   yield promisePopupHidden(gURLBar.popup);
 });
--- a/browser/base/content/test/general/browser_action_searchengine.js
+++ b/browser/base/content/test/general/browser_action_searchengine.js
@@ -1,17 +1,18 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 add_task(function* () {
   // This test is only relevant if UnifiedComplete is enabled.
-  if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete")) {
-    todo(false, "Stop supporting old autocomplete components.");
-    return;
-  }
+  let ucpref = Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete");
+  Services.prefs.setBoolPref("browser.urlbar.unifiedcomplete", true);
+  registerCleanupFunction(() => {
+    Services.prefs.setBoolPref("browser.urlbar.unifiedcomplete", ucpref);
+  });
 
   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 = gBrowser.selectedTab = gBrowser.addTab("about:mozilla", {animate: false});
--- a/browser/base/content/test/general/browser_action_searchengine_alias.js
+++ b/browser/base/content/test/general/browser_action_searchengine_alias.js
@@ -1,31 +1,35 @@
 /**
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  **/
 
 add_task(function* () {
+  // This test is only relevant if UnifiedComplete is enabled.
+  let ucpref = Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete");
   Services.prefs.setBoolPref("browser.urlbar.unifiedcomplete", true);
+  registerCleanupFunction(() => {
+    Services.prefs.setBoolPref("browser.urlbar.unifiedcomplete", ucpref);
+  });
 
   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 = gBrowser.selectedTab = gBrowser.addTab("about:mozilla", {animate: false});
   yield promiseTabLoaded(gBrowser.selectedTab);
 
   registerCleanupFunction(() => {
     Services.search.currentEngine = originalEngine;
     let engine = Services.search.getEngineByName("MozSearch");
     Services.search.removeEngine(engine);
-    Services.prefs.clearUserPref("browser.urlbar.unifiedcomplete");
 
     try {
       gBrowser.removeTab(tab);
     } catch(ex) { /* tab may have already been closed in case of failure */ }
 
     return PlacesTestUtils.clearHistory();
   });
 
--- a/browser/base/content/test/general/browser_autocomplete_a11y_label.js
+++ b/browser/base/content/test/general/browser_autocomplete_a11y_label.js
@@ -1,17 +1,18 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 add_task(function*() {
   // This test is only relevant if UnifiedComplete is enabled.
-  if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete")) {
-    todo(false, "Stop supporting old autocomplete components.");
-    return;
-  }
+  let ucpref = Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete");
+  Services.prefs.setBoolPref("browser.urlbar.unifiedcomplete", true);
+  registerCleanupFunction(() => {
+    Services.prefs.setBoolPref("browser.urlbar.unifiedcomplete", ucpref);
+  });
 
   let tab = gBrowser.addTab("about:about");
   yield promiseTabLoaded(tab);
 
   let actionURL = makeActionURI("switchtab", {url: "about:about"}).spec;
   yield promiseAutocompleteResultPopup("% about");
 
   ok(gURLBar.popup.richlistbox.children.length > 1, "Should get at least 2 results");
--- a/browser/base/content/test/general/browser_autocomplete_autoselect.js
+++ b/browser/base/content/test/general/browser_autocomplete_autoselect.js
@@ -5,22 +5,25 @@ function repeat(limit, func) {
 }
 
 function is_selected(index) {
   is(gURLBar.popup.richlistbox.selectedIndex, index, `Item ${index + 1} should be selected`);
 }
 
 add_task(function*() {
   // This test is only relevant if UnifiedComplete is enabled.
-  if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete")) {
-    todo(false, "Stop supporting old autocomplete components.");
-    return;
-  }
+  let ucpref = Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete");
+  Services.prefs.setBoolPref("browser.urlbar.unifiedcomplete", true);
+  registerCleanupFunction(() => {
+    Services.prefs.setBoolPref("browser.urlbar.unifiedcomplete", ucpref);
+  });
 
-  registerCleanupFunction(() => PlacesTestUtils.clearHistory());
+  registerCleanupFunction(function* () {
+    yield PlacesTestUtils.clearHistory();
+  });
 
   let visits = [];
   repeat(10, i => {
     visits.push({
       uri: makeURI("http://example.com/autocomplete/?" + i),
     });
   });
   yield PlacesTestUtils.addVisits(visits);
--- a/browser/base/content/test/general/browser_autocomplete_enter_race.js
+++ b/browser/base/content/test/general/browser_autocomplete_enter_race.js
@@ -1,23 +1,22 @@
 add_task(function*() {
   // This test is only relevant if UnifiedComplete is enabled.
   Services.prefs.setBoolPref("browser.urlbar.unifiedcomplete", true);
 
-  registerCleanupFunction(() => {
-    PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId);
+  registerCleanupFunction(function* () {
     Services.prefs.clearUserPref("browser.urlbar.unifiedcomplete");
+    yield PlacesUtils.bookmarks.remove(bm);
   });
 
-  let itemId =
-    PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
-                                         NetUtil.newURI("http://example.com/?q=%s"),
-                                         PlacesUtils.bookmarks.DEFAULT_INDEX,
-                                         "test");
-  PlacesUtils.bookmarks.setKeywordForBookmark(itemId, "keyword");
+  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" });
 
   yield new Promise(resolve => waitForFocus(resolve, window));
 
   yield promiseAutocompleteResultPopup("keyword bear");
   gURLBar.focus();
   EventUtils.synthesizeKey("d", {});
   EventUtils.synthesizeKey("VK_RETURN", {});
 
--- a/browser/base/content/test/general/browser_autocomplete_no_title.js
+++ b/browser/base/content/test/general/browser_autocomplete_no_title.js
@@ -1,17 +1,18 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 add_task(function*() {
   // This test is only relevant if UnifiedComplete is enabled.
-  if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete")) {
-    todo(false, "Stop supporting old autocomplete components.");
-    return;
-  }
+  let ucpref = Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete");
+  Services.prefs.setBoolPref("browser.urlbar.unifiedcomplete", true);
+  registerCleanupFunction(() => {
+    Services.prefs.setBoolPref("browser.urlbar.unifiedcomplete", ucpref);
+  });
 
   let tab = gBrowser.selectedTab = gBrowser.addTab("about:mozilla", {animate: false});
   yield promiseTabLoaded(tab);
 
   let uri = NetUtil.newURI("http://bug1060642.example.com/beards/are/pretty/great");
   yield PlacesTestUtils.addVisits([{uri: uri, title: ""}]);
 
   yield promiseAutocompleteResultPopup("bug1060642");
--- a/browser/base/content/test/general/browser_autocomplete_oldschool_wrap.js
+++ b/browser/base/content/test/general/browser_autocomplete_oldschool_wrap.js
@@ -10,33 +10,37 @@ function is_selected(index) {
 
 add_task(function*() {
   // This test is only relevant if UnifiedComplete is *disabled*.
   if (Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete")) {
     ok(true, "Don't run this test with UnifiedComplete enabled.")
     return;
   }
 
-  registerCleanupFunction(() => PlacesTestUtils.clearHistory());
-
+  yield PlacesTestUtils.clearHistory();
   let visits = [];
   repeat(10, i => {
     visits.push({
       uri: makeURI("http://example.com/autocomplete/?" + i),
     });
   });
   yield PlacesTestUtils.addVisits(visits);
 
+  registerCleanupFunction(function* () {
+    yield PlacesTestUtils.clearHistory();
+  });
+
   let tab = gBrowser.selectedTab = gBrowser.addTab("about:mozilla", {animate: false});
   yield promiseTabLoaded(tab);
   yield promiseAutocompleteResultPopup("example.com/autocomplete");
 
   let popup = gURLBar.popup;
-  let results = popup.richlistbox.children;
-  is(results.length, 10, "Should get 11 results");
+  let results = popup.richlistbox.children.filter(is_visible);
+
+  is(results.length, 10, "Should get 10 results");
   is_selected(-1);
 
   info("Key Down to select the next item");
   EventUtils.synthesizeKey("VK_DOWN", {});
   is_selected(0);
 
   info("Key Up to select the previous item");
   EventUtils.synthesizeKey("VK_UP", {});
--- a/browser/base/content/test/general/browser_bug1003461-switchtab-override.js
+++ b/browser/base/content/test/general/browser_bug1003461-switchtab-override.js
@@ -1,18 +1,19 @@
 /* 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() {
   // This test is only relevant if UnifiedComplete is enabled.
-  if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete")) {
-    todo(false, "Stop supporting old autocomplete components.");
-    return;
-  }
+  let ucpref = Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete");
+  Services.prefs.setBoolPref("browser.urlbar.unifiedcomplete", true);
+  registerCleanupFunction(() => {
+    Services.prefs.setBoolPref("browser.urlbar.unifiedcomplete", ucpref);
+  });
 
   let testURL = "http://example.org/browser/browser/base/content/test/general/dummy_page.html";
 
   info("Opening first tab");
   let tab = gBrowser.addTab(testURL);
   let deferred = Promise.defer();
   whenTabLoaded(tab, deferred.resolve);
   yield deferred.promise;
--- a/browser/base/content/test/general/browser_bug1070778.js
+++ b/browser/base/content/test/general/browser_bug1070778.js
@@ -2,39 +2,42 @@
  * 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*() {
   // This test is only relevant if UnifiedComplete is enabled.
-  if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete")) {
-    todo(false, "Stop supporting old autocomplete components.");
-    return;
-  }
-
+  let ucpref = Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete");
+  Services.prefs.setBoolPref("browser.urlbar.unifiedcomplete", true);
   registerCleanupFunction(() => {
-    PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId);
+    Services.prefs.setBoolPref("browser.urlbar.unifiedcomplete", ucpref);
   });
 
-  let itemId =
-    PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
-                                         NetUtil.newURI("http://example.com/?q=%s"),
-                                         PlacesUtils.bookmarks.DEFAULT_INDEX,
-                                         "test");
-  PlacesUtils.bookmarks.setKeywordForBookmark(itemId, "keyword");
+  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.
-  itemId =
-    PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
-                                         NetUtil.newURI("http://example.com/keyword"),
-                                         PlacesUtils.bookmarks.DEFAULT_INDEX,
-                                         "keyword abc");
+  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 = gBrowser.selectedTab = gBrowser.addTab("about:mozilla", {animate: false});
   yield promiseTabLoaded(tab);
   yield promiseAutocompleteResultPopup("keyword a");
 
   // First item should already be selected
   is_selected(0);
   // Select next one (important!)
--- a/browser/base/content/test/general/browser_urlbarEnterAfterMouseOver.js
+++ b/browser/base/content/test/general/browser_urlbarEnterAfterMouseOver.js
@@ -11,17 +11,19 @@ function* promiseAutoComplete(inputText)
   yield promiseSearchComplete();
 }
 
 function is_selected(index) {
   is(gURLBar.popup.richlistbox.selectedIndex, index, `Item ${index + 1} should be selected`);
 }
 
 add_task(function*() {
-  registerCleanupFunction(() => PlacesTestUtils.clearHistory());
+  registerCleanupFunction(function* () {
+    yield PlacesTestUtils.clearHistory();
+  });
 
   yield PlacesTestUtils.clearHistory();
   let tabCount = gBrowser.tabs.length;
 
   let visits = [];
   repeat(10, i => {
     visits.push({
       uri: makeURI("http://example.com/autocomplete/?" + i),
--- a/toolkit/components/places/UnifiedComplete.js
+++ b/toolkit/components/places/UnifiedComplete.js
@@ -41,35 +41,34 @@ const PREF_SUGGEST_HISTORY_ONLYTYPED = [
 const MATCH_ANYWHERE = Ci.mozIPlacesAutoComplete.MATCH_ANYWHERE;
 const MATCH_BOUNDARY_ANYWHERE = Ci.mozIPlacesAutoComplete.MATCH_BOUNDARY_ANYWHERE;
 const MATCH_BOUNDARY = Ci.mozIPlacesAutoComplete.MATCH_BOUNDARY;
 const MATCH_BEGINNING = Ci.mozIPlacesAutoComplete.MATCH_BEGINNING;
 const MATCH_BEGINNING_CASE_SENSITIVE = Ci.mozIPlacesAutoComplete.MATCH_BEGINNING_CASE_SENSITIVE;
 
 // AutoComplete query type constants.
 // Describes the various types of queries that we can process rows for.
-const QUERYTYPE_KEYWORD       = 0;
-const QUERYTYPE_FILTERED      = 1;
-const QUERYTYPE_AUTOFILL_HOST = 2;
-const QUERYTYPE_AUTOFILL_URL  = 3;
-const QUERYTYPE_AUTOFILL_PREDICTURL  = 4;
+const QUERYTYPE_FILTERED            = 0;
+const QUERYTYPE_AUTOFILL_HOST       = 1;
+const QUERYTYPE_AUTOFILL_URL        = 2;
+const QUERYTYPE_AUTOFILL_PREDICTURL = 3;
 
 // This separator is used as an RTL-friendly way to split the title and tags.
 // It can also be used by an nsIAutoCompleteResult consumer to re-split the
 // "comment" back into the title and the tag.
 const TITLE_TAGS_SEPARATOR = " \u2013 ";
 
 // This separator identifies the search engine name in the title.
 const TITLE_SEARCH_ENGINE_SEPARATOR = " \u00B7\u2013\u00B7 ";
 
 // Telemetry probes.
 const TELEMETRY_1ST_RESULT = "PLACES_AUTOCOMPLETE_1ST_RESULT_TIME_MS";
 const TELEMETRY_6_FIRST_RESULTS = "PLACES_AUTOCOMPLETE_6_FIRST_RESULTS_TIME_MS";
 // The default frecency value used when inserting matches with unknown frecency.
-const FRECENCY_SEARCHENGINES_DEFAULT = 1000;
+const FRECENCY_DEFAULT = 1000;
 
 // Sqlite result row index constants.
 const QUERYINDEX_QUERYTYPE     = 0;
 const QUERYINDEX_URL           = 1;
 const QUERYINDEX_TITLE         = 2;
 const QUERYINDEX_ICONURL       = 3;
 const QUERYINDEX_BOOKMARKED    = 4;
 const QUERYINDEX_BOOKMARKTITLE = 5;
@@ -144,33 +143,16 @@ const SQL_ADAPTIVE_QUERY =
    LEFT JOIN moz_openpages_temp t ON t.url = h.url
    WHERE AUTOCOMPLETE_MATCH(NULL, h.url,
                             IFNULL(btitle, h.title), tags,
                             h.visit_count, h.typed, bookmarked,
                             t.open_count,
                             :matchBehavior, :searchBehavior)
    ORDER BY rank DESC, h.frecency DESC`;
 
-const SQL_KEYWORD_QUERY =
-  `/* do not warn (bug 487787) */
-   SELECT :query_type,
-          REPLACE(h.url, '%s', :query_string) AS search_url, h.title,
-     IFNULL(f.url, (SELECT f.url
-                    FROM moz_places
-                    JOIN moz_favicons f ON f.id = favicon_id
-                    WHERE rev_host = h.rev_host
-                    ORDER BY frecency DESC
-                    LIMIT 1)
-           ),
-     1, NULL, NULL, h.visit_count, h.typed, h.id, t.open_count, h.frecency
-   FROM moz_keywords k
-   JOIN moz_places h ON k.place_id = h.id
-   LEFT JOIN moz_favicons f ON f.id = h.favicon_id
-   LEFT JOIN moz_openpages_temp t ON t.url = search_url
-   WHERE k.keyword = LOWER(:keyword)`;
 
 function hostQuery(conditions = "") {
   let query =
     `/* do not warn (bug NA): not worth to index on (typed, frecency) */
      SELECT :query_type, host || '/', IFNULL(prefix, '') || host || '/',
             NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, frecency
      FROM moz_hosts
      WHERE host BETWEEN :searchString AND :searchString || X'FFFF'
@@ -726,24 +708,26 @@ Search.prototype = {
 
     TelemetryStopwatch.start(TELEMETRY_1ST_RESULT);
     if (this._searchString)
       TelemetryStopwatch.start(TELEMETRY_6_FIRST_RESULTS);
 
     // Since we call the synchronous parseSubmissionURL function later, we must
     // wait for the initialization of PlacesSearchAutocompleteProvider first.
     yield PlacesSearchAutocompleteProvider.ensureInitialized();
+    if (!this.pending)
+      return;
 
     // For any given search, we run many queries/heuristics:
     // 1) by alias (as defined in SearchService)
     // 2) inline completion from search engine resultDomains
     // 3) inline completion for hosts (this._hostQuery) or urls (this._urlQuery)
     // 4) directly typed in url (ie, can be navigated to as-is)
     // 5) submission for the current search engine
-    // 6) keywords (this._keywordQuery)
+    // 6) Places keywords
     // 7) adaptive learning (this._adaptiveQuery)
     // 8) open pages not supported by history (this._switchToTabQuery)
     // 9) query based on match behavior
     //
     // (6) only gets ran if we get any filtered tokens, since if there are no
     // tokens, there is nothing to match. This is the *first* query we check if
     // we want to run, but it gets queued to be run later.
     //
@@ -767,25 +751,23 @@ Search.prototype = {
 
     // When actions are enabled, we run a series of heuristics to determine what
     // the first result should be - which is always a special result.
     // |hasFirstResult| is used to keep track of whether we've obtained such a
     // result yet, so we can skip further heuristics and not add any additional
     // special results.
     let hasFirstResult = false;
 
-    if (this._searchTokens.length > 0 &&
-        PlacesUtils.bookmarks.getURIForKeyword(this._searchTokens[0])) {
-      // This may be a keyword of a bookmark.
-      queries.unshift(this._keywordQuery);
-      hasFirstResult = true;
+    if (this._searchTokens.length > 0) {
+      // This may be a Places keyword.
+      hasFirstResult = yield this._matchPlacesKeyword();
     }
 
-    if (this._enableActions && !hasFirstResult) {
-      // If it's not a bookmarked keyword, then it may be a search engine
+    if (this.pending && this._enableActions && !hasFirstResult) {
+      // If it's not a Places keyword, then it may be a search engine
       // with an alias - which works like a keyword.
       hasFirstResult = yield this._matchSearchEngineAlias();
     }
 
     let shouldAutofill = this._shouldAutofill;
     if (this.pending && !hasFirstResult && shouldAutofill) {
       // It may also look like a URL we know from the database.
       // Here we can only try to predict whether the URL autofill query is
@@ -870,16 +852,45 @@ Search.prototype = {
     yield conn.executeCached(query, params, row => {
       gotResult = true;
       this._onResultRow(row);
     });
 
     return gotResult;
   },
 
+  _matchPlacesKeyword: function* () {
+    // The first word could be a keyword, so that's what we'll search.
+    let keyword = this._searchTokens[0];
+    let entry = yield PlacesUtils.keywords.fetch(this._searchTokens[0]);
+    if (!entry)
+      return false;
+
+    // Build the url.
+    let searchString = this._trimmedOriginalSearchString;
+    let queryString = "";
+    let queryIndex = searchString.indexOf(" ");
+    if (queryIndex != -1) {
+      queryString = searchString.substring(queryIndex + 1);
+    }
+    // We need to escape the parameters as if they were the query in a URL
+    queryString = encodeURIComponent(queryString).replace(/%20/g, "+");
+    let escapedURL = entry.url.href.replace("%s", queryString);
+
+    let style = (this._enableActions ? "action " : "") + "keyword";
+    let actionURL = makeActionURL("keyword", { url: escapedURL,
+                                               input: this._originalSearchString });
+    let value = this._enableActions ? actionURL : escapedURL;
+    // The title will end up being "host: queryString"
+    let comment = entry.url.host;
+
+    this._addMatch({ value, comment, style, frecency: FRECENCY_DEFAULT });
+    return true;
+  },
+
   _matchSearchEngineUrl: function* () {
     if (!Prefs.autofillSearchEngines)
       return false;
 
     let match = yield PlacesSearchAutocompleteProvider.findMatchByToken(
                                                            this._searchString);
     if (!match)
       return false;
@@ -917,17 +928,17 @@ Search.prototype = {
 
     this._result.setDefaultIndex(0);
     this._addMatch({
       value: value,
       comment: match.engineName,
       icon: match.iconUrl,
       style: "priority-search",
       finalCompleteValue: match.url,
-      frecency: FRECENCY_SEARCHENGINES_DEFAULT
+      frecency: FRECENCY_DEFAULT
     });
     return true;
   },
 
   _matchSearchEngineAlias: function* () {
     if (this._searchTokens.length < 2)
       return false;
 
@@ -964,17 +975,17 @@ Search.prototype = {
     }
     let value = makeActionURL("searchengine", actionURLParams);
 
     this._addMatch({
       value: value,
       comment: match.engineName,
       icon: match.iconUrl,
       style: "action searchengine",
-      frecency: FRECENCY_SEARCHENGINES_DEFAULT,
+      frecency: FRECENCY_DEFAULT,
     });
   },
 
   // These are separated out so we can run them in two distinct cases:
   // (1) We didn't match on anything that we know about
   // (2) Our predictive query for URL autofill thought we may get a result,
   //     but we didn't.
   _matchHeuristicFallback: function* () {
@@ -1047,17 +1058,16 @@ Search.prototype = {
       case QUERYTYPE_AUTOFILL_PREDICTURL:
         match = this._processHostRow(row);
         break;
       case QUERYTYPE_AUTOFILL_URL:
         this._result.setDefaultIndex(0);
         match = this._processUrlRow(row);
         break;
       case QUERYTYPE_FILTERED:
-      case QUERYTYPE_KEYWORD:
         match = this._processRow(row);
         break;
     }
     this._addMatch(match);
     // If the search has been canceled by the user or by _addMatch reaching the
     // maximum number of results, we can stop the underlying Sqlite query.
     if (!this.pending)
       throw StopIteration;
@@ -1231,27 +1241,16 @@ Search.prototype = {
     if (this._enableActions && openPageCount > 0 && this.hasBehavior("openpage")) {
       url = makeActionURL("switchtab", {url: escapedURL});
       action = "switchtab";
     }
 
     // Always prefer the bookmark title unless it is empty
     let title = bookmarkTitle || historyTitle;
 
-    if (queryType == QUERYTYPE_KEYWORD) {
-      match.style = "keyword";
-      if (this._enableActions) {
-        url = makeActionURL("keyword", {
-          url: escapedURL,
-          input: this._originalSearchString,
-        });
-        action = "keyword";
-      }
-    }
-
     // We will always prefer to show tags if we have them.
     let showTags = !!tags;
 
     // However, we'll act as if a page is not bookmarked if the user wants
     // only history and not bookmarks and there are no tags.
     if (this.hasBehavior("history") && !this.hasBehavior("bookmark") &&
         !showTags) {
       showTags = false;
@@ -1348,47 +1347,16 @@ Search.prototype = {
         // Limit the query to the the maximum number of desired results.
         // This way we can avoid doing more work than needed.
         maxResults: Prefs.maxRichResults
       }
     ];
   },
 
   /**
-   * Obtains the query to search for keywords.
-   *
-   * @return an array consisting of the correctly optimized query to search the
-   *         database with and an object containing the params to bound.
-   */
-  get _keywordQuery() {
-    // The keyword is the first word in the search string, with the parameters
-    // following it.
-    let searchString = this._trimmedOriginalSearchString;
-    let queryString = "";
-    let queryIndex = searchString.indexOf(" ");
-    if (queryIndex != -1) {
-      queryString = searchString.substring(queryIndex + 1);
-    }
-    // We need to escape the parameters as if they were the query in a URL
-    queryString = encodeURIComponent(queryString).replace(/%20/g, "+");
-
-    // The first word could be a keyword, so that's what we'll search.
-    let keyword = this._searchTokens[0];
-
-    return [
-      SQL_KEYWORD_QUERY,
-      {
-        keyword: keyword,
-        query_string: queryString,
-        query_type: QUERYTYPE_KEYWORD
-      }
-    ];
-  },
-
-  /**
    * Obtains the query to search for switch-to-tab entries.
    *
    * @return an array consisting of the correctly optimized query to search the
    *         database with and an object containing the params to bound.
    */
   get _switchToTabQuery() [
     SQL_SWITCHTAB_QUERY,
     {
--- a/toolkit/components/places/nsPlacesAutoComplete.js
+++ b/toolkit/components/places/nsPlacesAutoComplete.js
@@ -7,16 +7,18 @@
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
                                   "resource://gre/modules/PlacesUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "TelemetryStopwatch",
                                   "resource://gre/modules/TelemetryStopwatch.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
                                   "resource://gre/modules/NetUtil.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Task",
+                                  "resource://gre/modules/Task.jsm");
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Constants
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 
@@ -1163,26 +1165,18 @@ nsPlacesAutoComplete.prototype = {
       aRow.getResultByIndex(kQueryIndexBookmarkTitle) : null;
     let entryTags = aRow.getResultByIndex(kQueryIndexTags) || "";
 
     // Always prefer the bookmark title unless it is empty
     let title = entryBookmarkTitle || entryTitle;
 
     let style;
     if (aRow.getResultByIndex(kQueryIndexQueryType) == kQueryTypeKeyword) {
-      // If we do not have a title, then we must have a keyword, so let the UI
-      // know it is a keyword.  Otherwise, we found an exact page match, so just
-      // show the page like a regular result.  Because the page title is likely
-      // going to be more specific than the bookmark title (keyword title).
-      if (!entryTitle) {
-        style = "keyword";
-      }
-      else {
-        title = entryTitle;
-      }
+      style = "keyword";
+      title = NetUtil.newURI(escapedEntryURL).host;
     }
 
     // We will always prefer to show tags if we have them.
     let showTags = !!entryTags;
 
     // However, we'll act as if a page is not bookmarked if the user wants
     // only history and not bookmarks and there are no tags.
     if (this._hasBehavior("history") && !this._hasBehavior("bookmark") &&
@@ -1427,16 +1421,18 @@ urlInlineComplete.prototype = {
   startSearch: function UIC_startSearch(aSearchString, aSearchParam,
                                         aPreviousResult, aListener)
   {
     // Stop the search in case the controller has not taken care of it.
     if (this._pendingQuery) {
       this.stopSearch();
     }
 
+    let pendingSearch = this._pendingSearch = {};
+
     // We want to store the original string with no leading or trailing
     // whitespace for case sensitive searches.
     this._originalSearchString = aSearchString;
     this._currentSearchString =
       fixupSearchText(this._originalSearchString.toLowerCase());
     // The protocol and the host are lowercased by nsIURI, so it's fine to
     // lowercase the typed prefix to add it back to the results later.
     this._strippedPrefix = this._originalSearchString.slice(
@@ -1445,84 +1441,92 @@ urlInlineComplete.prototype = {
 
     this._result = Cc["@mozilla.org/autocomplete/simple-result;1"].
                    createInstance(Ci.nsIAutoCompleteSimpleResult);
     this._result.setSearchString(aSearchString);
     this._result.setTypeAheadResult(true);
 
     this._listener = aListener;
 
-    // Don't autoFill if the search term is recognized as a keyword, otherwise
-    // it will override default keywords behavior.  Note that keywords are
-    // hashed on first use, so while the first query may delay a little bit,
-    // next ones will just hit the memory hash.
-    if (this._currentSearchString.length == 0 || !this._db ||
-        PlacesUtils.bookmarks.getURIForKeyword(this._currentSearchString)) {
-      this._finishSearch();
-      return;
-    }
+    Task.spawn(function* () {
+      // Don't autoFill if the search term is recognized as a keyword, otherwise
+      // it will override default keywords behavior.  Note that keywords are
+      // hashed on first use, so while the first query may delay a little bit,
+      // next ones will just hit the memory hash.
+      let dontAutoFill = this._currentSearchString.length == 0 || !this._db ||
+                         (yield PlacesUtils.keywords.fetch(this._currentSearchString));
+      if (this._pendingSearch != pendingSearch)
+        return;
+      if (dontAutoFill) {
+        this._finishSearch();
+        return;
+      }
 
-    // Don't try to autofill if the search term includes any whitespace.
-    // This may confuse completeDefaultIndex cause the AUTOCOMPLETE_MATCH
-    // tokenizer ends up trimming the search string and returning a value
-    // that doesn't match it, or is even shorter.
-    if (/\s/.test(this._currentSearchString)) {
-      this._finishSearch();
-      return;
-    }
+      // Don't try to autofill if the search term includes any whitespace.
+      // This may confuse completeDefaultIndex cause the AUTOCOMPLETE_MATCH
+      // tokenizer ends up trimming the search string and returning a value
+      // that doesn't match it, or is even shorter.
+      if (/\s/.test(this._currentSearchString)) {
+        this._finishSearch();
+        return;
+      }
 
-    // Hosts have no "/" in them.
-    let lastSlashIndex = this._currentSearchString.lastIndexOf("/");
+      // Hosts have no "/" in them.
+      let lastSlashIndex = this._currentSearchString.lastIndexOf("/");
 
-    // Search only URLs if there's a slash in the search string...
-    if (lastSlashIndex != -1) {
-      // ...but not if it's exactly at the end of the search string.
-      if (lastSlashIndex < this._currentSearchString.length - 1)
-        this._queryURL();
-      else
-        this._finishSearch();
-      return;
-    }
+      // Search only URLs if there's a slash in the search string...
+      if (lastSlashIndex != -1) {
+        // ...but not if it's exactly at the end of the search string.
+        if (lastSlashIndex < this._currentSearchString.length - 1)
+          this._queryURL();
+        else
+          this._finishSearch();
+        return;
+      }
 
-    // Do a synchronous search on the table of hosts.
-    let query = this._hostQuery;
-    query.params.search_string = this._currentSearchString.toLowerCase();
-    // This is just to measure the delay to reach the UI, not the query time.
-    TelemetryStopwatch.start(DOMAIN_QUERY_TELEMETRY);
-    let ac = this;
-    let wrapper = new AutoCompleteStatementCallbackWrapper(this, {
-      handleResult: function (aResultSet) {
-        let row = aResultSet.getNextRow();
-        let trimmedHost = row.getResultByIndex(0);
-        let untrimmedHost = row.getResultByIndex(1);
-        // If the untrimmed value doesn't preserve the user's input just
-        // ignore it and complete to the found host.
-        if (untrimmedHost &&
-            !untrimmedHost.toLowerCase().contains(ac._originalSearchString.toLowerCase())) {
-          untrimmedHost = null;
-        }
+      // Do a synchronous search on the table of hosts.
+      let query = this._hostQuery;
+      query.params.search_string = this._currentSearchString.toLowerCase();
+      // This is just to measure the delay to reach the UI, not the query time.
+      TelemetryStopwatch.start(DOMAIN_QUERY_TELEMETRY);
+      let wrapper = new AutoCompleteStatementCallbackWrapper(this, {
+        handleResult: aResultSet => {
+          if (this._pendingSearch != pendingSearch)
+            return;
+          let row = aResultSet.getNextRow();
+          let trimmedHost = row.getResultByIndex(0);
+          let untrimmedHost = row.getResultByIndex(1);
+          // If the untrimmed value doesn't preserve the user's input just
+          // ignore it and complete to the found host.
+          if (untrimmedHost &&
+              !untrimmedHost.toLowerCase().contains(this._originalSearchString.toLowerCase())) {
+            untrimmedHost = null;
+          }
 
-        ac._result.appendMatch(ac._strippedPrefix + trimmedHost, "", "", "", untrimmedHost);
+          this._result.appendMatch(this._strippedPrefix + trimmedHost, "", "", "", untrimmedHost);
 
-        // handleCompletion() will cause the result listener to be called, and
-        // will display the result in the UI.
-      },
+          // handleCompletion() will cause the result listener to be called, and
+          // will display the result in the UI.
+        },
 
-      handleError: function (aError) {
-        Components.utils.reportError(
-          "URL Inline Complete: An async statement encountered an " +
-          "error: " + aError.result + ", '" + aError.message + "'");
-      },
+        handleError: aError => {
+          Components.utils.reportError(
+            "URL Inline Complete: An async statement encountered an " +
+            "error: " + aError.result + ", '" + aError.message + "'");
+        },
 
-      handleCompletion: function (aReason) {
-        TelemetryStopwatch.finish(DOMAIN_QUERY_TELEMETRY);
-        ac._finishSearch();
-      }
-    }, this._db);
-    this._pendingQuery = wrapper.executeAsync([query]);
+        handleCompletion: aReason => {
+          if (this._pendingSearch != pendingSearch)
+            return;
+          TelemetryStopwatch.finish(DOMAIN_QUERY_TELEMETRY);
+          this._finishSearch();
+        }
+      }, this._db);
+      this._pendingQuery = wrapper.executeAsync([query]);
+    }.bind(this));
   },
 
   /**
    * Execute an asynchronous search through places, and complete
    * up to the next URL separator.
    */
   _queryURL: function UIC__queryURL()
   {
@@ -1541,70 +1545,70 @@ urlInlineComplete.prototype = {
     let params = query.params;
     params.matchBehavior = MATCH_BEGINNING_CASE_SENSITIVE;
     params.searchBehavior |= Ci.mozIPlacesAutoComplete.BEHAVIOR_HISTORY |
                              Ci.mozIPlacesAutoComplete.BEHAVIOR_TYPED |
                              Ci.mozIPlacesAutoComplete.BEHAVIOR_URL;
     params.searchString = this._currentSearchString;
 
     // Execute the query.
-    let ac = this;
     let wrapper = new AutoCompleteStatementCallbackWrapper(this, {
-      handleResult: function(aResultSet) {
+      handleResult: aResultSet => {
         let row = aResultSet.getNextRow();
         let value = row.getResultByIndex(0);
         let url = fixupSearchText(value);
 
         let prefix = value.slice(0, value.length - stripPrefix(value).length);
 
         // We must complete the URL up to the next separator (which is /, ? or #).
-        let separatorIndex = url.slice(ac._currentSearchString.length)
+        let separatorIndex = url.slice(this._currentSearchString.length)
                                 .search(/[\/\?\#]/);
         if (separatorIndex != -1) {
-          separatorIndex += ac._currentSearchString.length;
+          separatorIndex += this._currentSearchString.length;
           if (url[separatorIndex] == "/") {
             separatorIndex++; // Include the "/" separator
           }
           url = url.slice(0, separatorIndex);
         }
 
         // Add the result.
         // If the untrimmed value doesn't preserve the user's input just
         // ignore it and complete to the found url.
         let untrimmedURL = prefix + url;
         if (untrimmedURL &&
-            !untrimmedURL.toLowerCase().contains(ac._originalSearchString.toLowerCase())) {
+            !untrimmedURL.toLowerCase().contains(this._originalSearchString.toLowerCase())) {
           untrimmedURL = null;
          }
 
-        ac._result.appendMatch(ac._strippedPrefix + url, "", "", "", untrimmedURL);
+        this._result.appendMatch(this._strippedPrefix + url, "", "", "", untrimmedURL);
 
         // handleCompletion() will cause the result listener to be called, and
         // will display the result in the UI.
       },
 
-      handleError: function(aError) {
+      handleError: aError => {
         Components.utils.reportError(
           "URL Inline Complete: An async statement encountered an " +
           "error: " + aError.result + ", '" + aError.message + "'");
       },
 
-      handleCompletion: function(aReason) {
-        ac._finishSearch();
+      handleCompletion: aReason => {
+        this._finishSearch();
       }
     }, this._db);
     this._pendingQuery = wrapper.executeAsync([query]);
   },
 
   stopSearch: function UIC_stopSearch()
   {
     delete this._originalSearchString;
     delete this._currentSearchString;
     delete this._result;
     delete this._listener;
+    delete this._pendingSearch;
 
     if (this._pendingQuery) {
       this._pendingQuery.cancel();
       delete this._pendingQuery;
     }
   },
 
   /**
--- a/toolkit/components/places/tests/autocomplete/test_keyword_search.js
+++ b/toolkit/components/places/tests/autocomplete/test_keyword_search.js
@@ -33,28 +33,30 @@ let kURIs = [
   keyBase,
   otherBase + "%s",
   keyBase + "twoKey",
   otherBase + "twoKey"
 ];
 let kTitles = [
   "Generic page title",
   "Keyword title",
+  "abc",
+  "xyz"
 ];
 
 // Add the keyword bookmark
 addPageBook(0, 0, 1, [], keyKey);
 // Add in the "fake pages" for keyword searches
-gPages[1] = [1,0];
-gPages[2] = [2,0];
-gPages[3] = [3,0];
-gPages[4] = [4,0];
+gPages[1] = [1,2];
+gPages[2] = [2,2];
+gPages[3] = [3,2];
+gPages[4] = [4,2];
 // Add a page into history
-addPageBook(5, 0);
-gPages[6] = [6,0];
+addPageBook(5, 2);
+gPages[6] = [6,2];
 
 // Provide for each test: description; search terms; array of gPages indices of
 // pages that should match; optional function to be run before the test
 let gTests = [
   ["0: Plain keyword query",
    keyKey + " term", [1]],
   ["1: Multi-word keyword query",
    keyKey + " multi word", [2]],
--- a/toolkit/components/places/tests/inline/head_autocomplete.js
+++ b/toolkit/components/places/tests/inline/head_autocomplete.js
@@ -117,84 +117,83 @@ function ensure_results(aSearchString, a
   controller.input = input;
 
   let numSearchesStarted = 0;
   input.onSearchBegin = function() {
     numSearchesStarted++;
     do_check_eq(numSearchesStarted, 1);
   };
 
-  input.onSearchComplete = function() {
-    // We should be running only one query.
-    do_check_eq(numSearchesStarted, 1);
 
-    // Check the autoFilled result.
-    do_check_eq(input.textValue, autoFilledValue);
+  let promise = new Promise(resolve => {
+    input.onSearchComplete = function() {
+      // We should be running only one query.
+      do_check_eq(numSearchesStarted, 1);
+
+      // Check the autoFilled result.
+      do_check_eq(input.textValue, autoFilledValue);
 
-    if (completedValue) {
-      // Now force completion and check correct casing of the result.
-      // This ensures the controller is able to do its magic case-preserving
-      // stuff and correct replacement of the user's casing with result's one.
-      controller.handleEnter(false);
-      do_check_eq(input.textValue, completedValue);
-    }
+      if (completedValue) {
+        // Now force completion and check correct casing of the result.
+        // This ensures the controller is able to do its magic case-preserving
+        // stuff and correct replacement of the user's casing with result's one.
+        controller.handleEnter(false);
+        do_check_eq(input.textValue, completedValue);
+      }
 
-    waitForCleanup(run_next_test);
-  };
+      // Cleanup.
+      remove_all_bookmarks();
+      PlacesTestUtils.clearHistory().then(resolve);
+    };
+  });
 
   do_print("Searching for: '" + aSearchString + "'");
   controller.startSearch(aSearchString);
+
+  return promise;
 }
 
 function run_test() {
   do_register_cleanup(function () {
     Services.prefs.clearUserPref("browser.urlbar.autocomplete.enabled");
     Services.prefs.clearUserPref("browser.urlbar.autoFill");
     Services.prefs.clearUserPref("browser.urlbar.autoFill.typed");
   });
 
   gAutoCompleteTests.forEach(function (testData) {
     let [description, searchString, expectedValue, setupFunc] = testData;
-    add_test(function () {
+    add_task(function* () {
       do_print(description);
       Services.prefs.setBoolPref("browser.urlbar.autocomplete.enabled", true);
       Services.prefs.setBoolPref("browser.urlbar.autoFill", true);
       Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
 
       if (setupFunc) {
-        setupFunc();
+        yield setupFunc();
       }
 
       // At this point frecency could still be updating due to latest pages
       // updates.
       // This is not a problem in real life, but autocomplete tests should
       // return reliable resultsets, thus we have to wait.
-      PlacesTestUtils.promiseAsyncUpdates()
-                     .then(() => ensure_results(searchString, expectedValue));
+      yield PlacesTestUtils.promiseAsyncUpdates();
+      yield ensure_results(searchString, expectedValue);
     })
   }, this);
 
   run_next_test();
 }
 
 let gAutoCompleteTests = [];
 function add_autocomplete_test(aTestData) {
   gAutoCompleteTests.push(aTestData);
 }
 
-function waitForCleanup(aCallback) {
-  remove_all_bookmarks();
-  PlacesTestUtils.clearHistory().then(aCallback);
-}
-
-function addBookmark(aBookmarkObj) {
+function* addBookmark(aBookmarkObj) {
   do_check_true(!!aBookmarkObj.url);
-  let parentId = aBookmarkObj.parentId ? aBookmarkObj.parentId
-                                       : PlacesUtils.unfiledBookmarksFolderId;
-  let itemId = PlacesUtils.bookmarks
-                          .insertBookmark(parentId,
-                                          NetUtil.newURI(aBookmarkObj.url),
-                                          PlacesUtils.bookmarks.DEFAULT_INDEX,
-                                          "A bookmark");
+  yield PlacesUtils.bookmarks
+                   .insert({ parentGuid: PlacesUtils.bookmarks.unfiledGuid,
+                             url: aBookmarkObj.url });
   if (aBookmarkObj.keyword) {
-    PlacesUtils.bookmarks.setKeywordForBookmark(itemId, aBookmarkObj.keyword);
+    yield PlacesUtils.keywords.insert({ keyword: aBookmarkObj.keyword,
+                                        url: aBookmarkObj.url });
   }
 }
--- a/toolkit/components/places/tests/inline/test_autocomplete_functional.js
+++ b/toolkit/components/places/tests/inline/test_autocomplete_functional.js
@@ -3,131 +3,118 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Functional tests for inline autocomplete
 
 add_autocomplete_test([
   "Check disabling autocomplete disables autofill",
   "vis",
   "vis",
-  function ()
-  {
+  function* () {
     Services.prefs.setBoolPref("browser.urlbar.autocomplete.enabled", false);
-    PlacesTestUtils.addVisits({
+    yield PlacesTestUtils.addVisits({
       uri: NetUtil.newURI("http://visit.mozilla.org"),
       transition: TRANSITION_TYPED
     });
   }
 ]);
 
 add_autocomplete_test([
   "Check disabling autofill disables autofill",
   "vis",
   "vis",
-  function ()
-  {
+  function* () {
     Services.prefs.setBoolPref("browser.urlbar.autoFill", false);
-    PlacesTestUtils.addVisits({
+    yield PlacesTestUtils.addVisits({
       uri: NetUtil.newURI("http://visit.mozilla.org"),
       transition: TRANSITION_TYPED
     });
   }
 ]);
 
 add_autocomplete_test([
   "Add urls, check for correct order",
   "vis",
   "visit2.mozilla.org/",
-  function ()
-  {
+  function* () {
     let places = [{ uri: NetUtil.newURI("http://visit1.mozilla.org") },
                   { uri: NetUtil.newURI("http://visit2.mozilla.org"),
                     transition: TRANSITION_TYPED }];
-    PlacesTestUtils.addVisits(places);
+    yield PlacesTestUtils.addVisits(places);
   }
 ]);
 
 add_autocomplete_test([
   "Add urls, make sure www and http are ignored",
   "visit1",
   "visit1.mozilla.org/",
-  function ()
-  {
-    PlacesTestUtils.addVisits(NetUtil.newURI("http://www.visit1.mozilla.org"));
+  function* () {
+    yield PlacesTestUtils.addVisits(NetUtil.newURI("http://www.visit1.mozilla.org"));
   }
 ]);
 
 add_autocomplete_test([
   "Autocompleting after an existing host completes to the url",
   "visit3.mozilla.org/",
   "visit3.mozilla.org/",
-  function ()
-  {
-    PlacesTestUtils.addVisits(NetUtil.newURI("http://www.visit3.mozilla.org"));
+  function* () {
+    yield PlacesTestUtils.addVisits(NetUtil.newURI("http://www.visit3.mozilla.org"));
   }
 ]);
 
 add_autocomplete_test([
   "Searching for www.me should yield www.me.mozilla.org/",
   "www.me",
   "www.me.mozilla.org/",
-  function ()
-  {
-    PlacesTestUtils.addVisits(NetUtil.newURI("http://www.me.mozilla.org"));
+  function* () {
+    yield PlacesTestUtils.addVisits(NetUtil.newURI("http://www.me.mozilla.org"));
   }
 ]);
 
 add_autocomplete_test([
   "With a bookmark and history, the query result should be the bookmark",
   "bookmark",
   "bookmark1.mozilla.org/",
-  function ()
-  {
-    addBookmark({ url: "http://bookmark1.mozilla.org/", });
-    PlacesTestUtils.addVisits(NetUtil.newURI("http://bookmark1.mozilla.org/foo"));
+  function* () {
+    yield addBookmark({ url: "http://bookmark1.mozilla.org/", });
+    yield PlacesTestUtils.addVisits(NetUtil.newURI("http://bookmark1.mozilla.org/foo"));
   }
 ]);
 
 add_autocomplete_test([
   "Check to make sure we get the proper results with full paths",
   "smokey",
   "smokey.mozilla.org/",
-  function ()
-  {
-
+  function* () {
     let places = [{ uri: NetUtil.newURI("http://smokey.mozilla.org/foo/bar/baz?bacon=delicious") },
                   { uri: NetUtil.newURI("http://smokey.mozilla.org/foo/bar/baz?bacon=smokey") }];
-    PlacesTestUtils.addVisits(places);
+    yield PlacesTestUtils.addVisits(places);
   }
 ]);
 
 add_autocomplete_test([
   "Check to make sure we autocomplete to the following '/'",
   "smokey.mozilla.org/fo",
   "smokey.mozilla.org/foo/",
-  function ()
-  {
-
+  function* () {
     let places = [{ uri: NetUtil.newURI("http://smokey.mozilla.org/foo/bar/baz?bacon=delicious") },
                   { uri: NetUtil.newURI("http://smokey.mozilla.org/foo/bar/baz?bacon=smokey") }];
-    PlacesTestUtils.addVisits(places);
+    yield PlacesTestUtils.addVisits(places);
   }
 ]);
 
 add_autocomplete_test([
   "Check to make sure we autocomplete after ?",
   "smokey.mozilla.org/foo?",
   "smokey.mozilla.org/foo?bacon=delicious",
-  function ()
-  {
-    PlacesTestUtils.addVisits(NetUtil.newURI("http://smokey.mozilla.org/foo?bacon=delicious"));
+  function* () {
+    yield PlacesTestUtils.addVisits(NetUtil.newURI("http://smokey.mozilla.org/foo?bacon=delicious"));
   }
 ]);
 
 add_autocomplete_test([
   "Check to make sure we autocomplete after #",
   "smokey.mozilla.org/foo?bacon=delicious#bar",
   "smokey.mozilla.org/foo?bacon=delicious#bar",
-  function ()
-  {
-    PlacesTestUtils.addVisits(NetUtil.newURI("http://smokey.mozilla.org/foo?bacon=delicious#bar"));
+  function* () {
+    yield PlacesTestUtils.addVisits(NetUtil.newURI("http://smokey.mozilla.org/foo?bacon=delicious#bar"));
   }
 ]);
--- a/toolkit/components/places/tests/inline/test_casing.js
+++ b/toolkit/components/places/tests/inline/test_casing.js
@@ -1,102 +1,102 @@
 /* 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_autocomplete_test([
   "Searching for cased entry 1",
   "MOZ",
   { autoFilled: "MOZilla.org/", completed: "mozilla.org/" },
-  function () {
-    PlacesTestUtils.addVisits({ uri: NetUtil.newURI("http://mozilla.org/test/") });
+  function* () {
+    yield PlacesTestUtils.addVisits({ uri: NetUtil.newURI("http://mozilla.org/test/") });
   }
 ]);
 
 add_autocomplete_test([
   "Searching for cased entry 2",
   "mozilla.org/T",
   { autoFilled: "mozilla.org/T", completed: "mozilla.org/T" },
-  function () {
-    PlacesTestUtils.addVisits({ uri: NetUtil.newURI("http://mozilla.org/test/") });
+  function* () {
+    yield PlacesTestUtils.addVisits({ uri: NetUtil.newURI("http://mozilla.org/test/") });
   }
 ]);
 
 add_autocomplete_test([
   "Searching for cased entry 3",
   "mozilla.org/T",
   { autoFilled: "mozilla.org/Test/", completed: "http://mozilla.org/Test/" },
-  function () {
-    PlacesTestUtils.addVisits({ uri: NetUtil.newURI("http://mozilla.org/Test/") });
+  function* () {
+    yield PlacesTestUtils.addVisits({ uri: NetUtil.newURI("http://mozilla.org/Test/") });
   }
 ]);
 
 add_autocomplete_test([
   "Searching for cased entry 4",
   "mOzilla.org/t",
   { autoFilled: "mOzilla.org/t", completed: "mOzilla.org/t" },
-  function () {
-    PlacesTestUtils.addVisits({ uri: NetUtil.newURI("http://mozilla.org/Test/") });
+  function* () {
+    yield PlacesTestUtils.addVisits({ uri: NetUtil.newURI("http://mozilla.org/Test/") });
   },
 ]);
 
 add_autocomplete_test([
   "Searching for cased entry 5",
   "mOzilla.org/T",
   { autoFilled: "mOzilla.org/Test/", completed: "http://mozilla.org/Test/" },
-  function () {
-    PlacesTestUtils.addVisits({ uri: NetUtil.newURI("http://mozilla.org/Test/") });
+  function* () {
+    yield PlacesTestUtils.addVisits({ uri: NetUtil.newURI("http://mozilla.org/Test/") });
   },
 ]);
 
 add_autocomplete_test([
   "Searching for untrimmed cased entry",
   "http://mOz",
   { autoFilled: "http://mOzilla.org/", completed: "http://mozilla.org/" },
-  function () {
-    PlacesTestUtils.addVisits({ uri: NetUtil.newURI("http://mozilla.org/Test/") });
+  function* () {
+    yield PlacesTestUtils.addVisits({ uri: NetUtil.newURI("http://mozilla.org/Test/") });
   },
 ]);
 
 add_autocomplete_test([
   "Searching for untrimmed cased entry with www",
   "http://www.mOz",
   { autoFilled: "http://www.mOzilla.org/", completed: "http://www.mozilla.org/" },
-  function () {
-    PlacesTestUtils.addVisits({ uri: NetUtil.newURI("http://www.mozilla.org/Test/") });
+  function* () {
+    yield PlacesTestUtils.addVisits({ uri: NetUtil.newURI("http://www.mozilla.org/Test/") });
   },
 ]);
 
 add_autocomplete_test([
   "Searching for untrimmed cased entry with path",
   "http://mOzilla.org/t",
   { autoFilled: "http://mOzilla.org/t", completed: "http://mOzilla.org/t" },
-  function () {
-    PlacesTestUtils.addVisits({ uri: NetUtil.newURI("http://mozilla.org/Test/") });
+  function* () {
+    yield PlacesTestUtils.addVisits({ uri: NetUtil.newURI("http://mozilla.org/Test/") });
   },
 ]);
 
 add_autocomplete_test([
   "Searching for untrimmed cased entry with path 2",
   "http://mOzilla.org/T",
   { autoFilled: "http://mOzilla.org/Test/", completed: "http://mozilla.org/Test/" },
-  function () {
-    PlacesTestUtils.addVisits({ uri: NetUtil.newURI("http://mozilla.org/Test/") });
+  function* () {
+    yield PlacesTestUtils.addVisits({ uri: NetUtil.newURI("http://mozilla.org/Test/") });
   },
 ]);
 
 add_autocomplete_test([
   "Searching for untrimmed cased entry with www and path",
   "http://www.mOzilla.org/t",
   { autoFilled: "http://www.mOzilla.org/t", completed: "http://www.mOzilla.org/t" },
-  function () {
-    PlacesTestUtils.addVisits({ uri: NetUtil.newURI("http://www.mozilla.org/Test/") });
+  function* () {
+    yield PlacesTestUtils.addVisits({ uri: NetUtil.newURI("http://www.mozilla.org/Test/") });
   },
 ]);
 
 add_autocomplete_test([
   "Searching for untrimmed cased entry with www and path 2",
   "http://www.mOzilla.org/T",
   { autoFilled: "http://www.mOzilla.org/Test/", completed: "http://www.mozilla.org/Test/" },
-  function () {
-    PlacesTestUtils.addVisits({ uri: NetUtil.newURI("http://www.mozilla.org/Test/") });
+  function* () {
+    yield PlacesTestUtils.addVisits({ uri: NetUtil.newURI("http://www.mozilla.org/Test/") });
   },
 ]);
--- a/toolkit/components/places/tests/inline/test_do_not_trim.js
+++ b/toolkit/components/places/tests/inline/test_do_not_trim.js
@@ -4,76 +4,76 @@
 
 // Inline should never return matches shorter than the search string, since
 // that largely confuses completeDefaultIndex
 
 add_autocomplete_test([
   "Do not autofill whitespaced entry 1",
   "mozilla.org ",
   "mozilla.org ",
-  function () {
-    PlacesTestUtils.addVisits({
+  function* () {
+    yield PlacesTestUtils.addVisits({
       uri: NetUtil.newURI("http://mozilla.org/link/"),
       transition: TRANSITION_TYPED
     });
   }
 ]);
 
 add_autocomplete_test([
   "Do not autofill whitespaced entry 2",
   "mozilla.org/ ",
   "mozilla.org/ ",
-  function () {
-    PlacesTestUtils.addVisits({
+  function* () {
+    yield PlacesTestUtils.addVisits({
       uri: NetUtil.newURI("http://mozilla.org/link/"),
       transition: TRANSITION_TYPED
     });
   }
 ]);
 
 add_autocomplete_test([
   "Do not autofill whitespaced entry 3",
   "mozilla.org/link ",
   "mozilla.org/link ",
-  function () {
-    PlacesTestUtils.addVisits({
+  function* () {
+    yield PlacesTestUtils.addVisits({
       uri: NetUtil.newURI("http://mozilla.org/link/"),
       transition: TRANSITION_TYPED
     });
   }
 ]);
 
 add_autocomplete_test([
   "Do not autofill whitespaced entry 4",
   "mozilla.org/link/ ",
   "mozilla.org/link/ ",
-  function () {
-    PlacesTestUtils.addVisits({
+  function* () {
+    yield PlacesTestUtils.addVisits({
       uri: NetUtil.newURI("http://mozilla.org/link/"),
       transition: TRANSITION_TYPED
     });
   }
 ]);
 
 
 add_autocomplete_test([
   "Do not autofill whitespaced entry 5",
   "moz illa ",
   "moz illa ",
-  function () {
-    PlacesTestUtils.addVisits({
+  function* () {
+    yield PlacesTestUtils.addVisits({
       uri: NetUtil.newURI("http://mozilla.org/link/"),
       transition: TRANSITION_TYPED
     });
   }
 ]);
 
 add_autocomplete_test([
   "Do not autofill whitespaced entry 6",
   " mozilla",
   " mozilla",
-  function () {
-    PlacesTestUtils.addVisits({
+  function* () {
+    yield PlacesTestUtils.addVisits({
       uri: NetUtil.newURI("http://mozilla.org/link/"),
       transition: TRANSITION_TYPED
     });
   }
 ]);
--- a/toolkit/components/places/tests/inline/test_keywords.js
+++ b/toolkit/components/places/tests/inline/test_keywords.js
@@ -1,48 +1,48 @@
 /* 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_autocomplete_test([
   "Searching for non-keyworded entry should autoFill it",
   "moz",
   "mozilla.org/",
-  function () {
-    addBookmark({ url: "http://mozilla.org/test/" });
+  function* () {
+    yield addBookmark({ url: "http://mozilla.org/test/" });
   }
 ]);
 
 add_autocomplete_test([
   "Searching for keyworded entry should not autoFill it",
   "moz",
   "moz",
-  function () {
-    addBookmark({ url: "http://mozilla.org/test/", keyword: "moz" });
+  function* () {
+    yield addBookmark({ url: "http://mozilla.org/test/", keyword: "moz" });
   }
 ]);
 
 add_autocomplete_test([
   "Searching for more than keyworded entry should autoFill it",
   "mozi",
   "mozilla.org/",
-  function () {
-    addBookmark({ url: "http://mozilla.org/test/", keyword: "moz" });
+  function* () {
+    yield addBookmark({ url: "http://mozilla.org/test/", keyword: "moz" });
   }
 ]);
 
 add_autocomplete_test([
   "Searching for less than keyworded entry should autoFill it",
   "mo",
   "mozilla.org/",
-  function () {
-    addBookmark({ url: "http://mozilla.org/test/", keyword: "moz" });
+  function* () {
+    yield addBookmark({ url: "http://mozilla.org/test/", keyword: "moz" });
   }
 ]);
 
 add_autocomplete_test([
   "Searching for keyworded entry is case-insensitive",
   "MoZ",
   "MoZ",
-  function () {
-    addBookmark({ url: "http://mozilla.org/test/", keyword: "moz" });
+  function* () {
+    yield addBookmark({ url: "http://mozilla.org/test/", keyword: "moz" });
   }
 ]);
--- a/toolkit/components/places/tests/inline/test_queryurl.js
+++ b/toolkit/components/places/tests/inline/test_queryurl.js
@@ -1,60 +1,60 @@
 /* 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_autocomplete_test([
   "Searching for host match without slash should match host",
   "file",
   "file.org/",
-  function () {
-    PlacesTestUtils.addVisits({
+  function* () {
+    yield PlacesTestUtils.addVisits({
       uri: NetUtil.newURI("http://file.org/test/"),
       transition: TRANSITION_TYPED
     }, {
       uri: NetUtil.newURI("file:///c:/test.html"),
       transition: TRANSITION_TYPED
     });
   },
 ]);
 
 add_autocomplete_test([
   "Searching match with slash at the end should do nothing",
   "file.org/",
   "file.org/",
-  function () {
-    PlacesTestUtils.addVisits({
+  function* () {
+    yield PlacesTestUtils.addVisits({
       uri: NetUtil.newURI("http://file.org/test/"),
       transition: TRANSITION_TYPED
     }, {
       uri: NetUtil.newURI("file:///c:/test.html"),
       transition: TRANSITION_TYPED
     });
   },
 ]);
 
 add_autocomplete_test([
   "Searching match with slash in the middle should match url",
   "file.org/t",
   "file.org/test/",
-  function () {
-    PlacesTestUtils.addVisits({
+  function* () {
+    yield PlacesTestUtils.addVisits({
       uri: NetUtil.newURI("http://file.org/test/"),
       transition: TRANSITION_TYPED
     }, {
       uri: NetUtil.newURI("file:///c:/test.html"),
       transition: TRANSITION_TYPED
     });
   },
 ]);
 
 add_autocomplete_test([
   "Searching for non-host match without slash should not match url",
   "file",
   "file",
-  function () {
-    PlacesTestUtils.addVisits({
+  function* () {
+    yield PlacesTestUtils.addVisits({
       uri: NetUtil.newURI("file:///c:/test.html"),
       transition: TRANSITION_TYPED
     });
   },
 ]);
--- a/toolkit/components/places/tests/inline/test_trimming.js
+++ b/toolkit/components/places/tests/inline/test_trimming.js
@@ -1,313 +1,306 @@
 /* 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_autocomplete_test([
   "Searching for untrimmed https://www entry",
   "mo",
   { autoFilled: "mozilla.org/", completed: "https://www.mozilla.org/" },
-  function () {
-    PlacesTestUtils.addVisits({
+  function* () {
+    yield PlacesTestUtils.addVisits({
       uri: NetUtil.newURI("https://www.mozilla.org/test/"),
       transition: TRANSITION_TYPED
     });
   },
 ]);
 
 add_autocomplete_test([
   "Searching for untrimmed https://www entry with path",
   "mozilla.org/t",
   { autoFilled: "mozilla.org/test/", completed: "https://www.mozilla.org/test/" },
-  function () {
-    PlacesTestUtils.addVisits({
+  function* () {
+    yield PlacesTestUtils.addVisits({
       uri: NetUtil.newURI("https://www.mozilla.org/test/"),
       transition: TRANSITION_TYPED
     });
   },
 ]);
 
 add_autocomplete_test([
   "Searching for untrimmed https:// entry",
   "mo",
   { autoFilled: "mozilla.org/", completed: "https://mozilla.org/" },
-  function () {
-    PlacesTestUtils.addVisits({
+  function* () {
+    yield PlacesTestUtils.addVisits({
       uri: NetUtil.newURI("https://mozilla.org/test/"),
       transition: TRANSITION_TYPED
     });
   },
 ]);
 
 add_autocomplete_test([
   "Searching for untrimmed https:// entry with path",
   "mozilla.org/t",
   { autoFilled: "mozilla.org/test/", completed: "https://mozilla.org/test/" },
-  function () {
-    PlacesTestUtils.addVisits({
+  function* () {
+    yield PlacesTestUtils.addVisits({
       uri: NetUtil.newURI("https://mozilla.org/test/"),
       transition: TRANSITION_TYPED
     });
   },
 ]);
 
 add_autocomplete_test([
   "Searching for untrimmed http://www entry",
   "mo",
   { autoFilled: "mozilla.org/", completed: "www.mozilla.org/" },
-  function () {
-    PlacesTestUtils.addVisits({
+  function* () {
+    yield PlacesTestUtils.addVisits({
       uri: NetUtil.newURI("http://www.mozilla.org/test/"),
       transition: TRANSITION_TYPED
     });
   },
 ]);
 
 add_autocomplete_test([
   "Searching for untrimmed http://www entry with path",
   "mozilla.org/t",
   { autoFilled: "mozilla.org/test/", completed: "http://www.mozilla.org/test/" },
-  function () {
-    PlacesTestUtils.addVisits({
+  function* () {
+    yield PlacesTestUtils.addVisits({
       uri: NetUtil.newURI("http://www.mozilla.org/test/"),
       transition: TRANSITION_TYPED
     });
   },
 ]);
 
 add_autocomplete_test([
   "Searching for untrimmed ftp:// entry",
   "mo",
   { autoFilled: "mozilla.org/", completed: "ftp://mozilla.org/" },
-  function () {
-    PlacesTestUtils.addVisits({
+  function* () {
+    yield PlacesTestUtils.addVisits({
       uri: NetUtil.newURI("ftp://mozilla.org/test/"),
       transition: TRANSITION_TYPED
     });
   },
 ]);
 
 add_autocomplete_test([
   "Searching for untrimmed ftp:// entry with path",
   "mozilla.org/t",
   { autoFilled: "mozilla.org/test/", completed: "ftp://mozilla.org/test/" },
-  function () {
-    PlacesTestUtils.addVisits({
+  function* () {
+    yield PlacesTestUtils.addVisits({
       uri: NetUtil.newURI("ftp://mozilla.org/test/"),
       transition: TRANSITION_TYPED
     });
   },
 ]);
 
 add_autocomplete_test([
   "Ensuring correct priority 1",
   "mo",
   { autoFilled: "mozilla.org/", completed: "mozilla.org/" },
-  function () {
-    PlacesTestUtils.addVisits({
-      uri: NetUtil.newURI("https://www.mozilla.org/test/"),
-      transition: TRANSITION_TYPED
-    });
-    PlacesTestUtils.addVisits({
-      uri: NetUtil.newURI("https://mozilla.org/test/"),
-      transition: TRANSITION_TYPED
-    });
-    PlacesTestUtils.addVisits({
-      uri: NetUtil.newURI("ftp://mozilla.org/test/"),
-      transition: TRANSITION_TYPED
-    });
-    PlacesTestUtils.addVisits({
-      uri: NetUtil.newURI("http://www.mozilla.org/test/"),
-      transition: TRANSITION_TYPED
-    });
-    PlacesTestUtils.addVisits({
-      uri: NetUtil.newURI("http://mozilla.org/test/"),
-      transition: TRANSITION_TYPED
-    });
+  function* () {
+    yield PlacesTestUtils.addVisits([
+      { uri: NetUtil.newURI("https://www.mozilla.org/test/"),
+        transition: TRANSITION_TYPED
+      },
+      { uri: NetUtil.newURI("https://mozilla.org/test/"),
+        transition: TRANSITION_TYPED
+      },
+      { uri: NetUtil.newURI("ftp://mozilla.org/test/"),
+        transition: TRANSITION_TYPED
+      },
+      { uri: NetUtil.newURI("http://www.mozilla.org/test/"),
+        transition: TRANSITION_TYPED
+      },
+      { uri: NetUtil.newURI("http://mozilla.org/test/"),
+        transition: TRANSITION_TYPED
+      }
+    ]);
   },
 ]);
 
 add_autocomplete_test([
   "Ensuring correct priority 2",
   "mo",
   { autoFilled: "mozilla.org/", completed: "mozilla.org/" },
-  function () {
-    PlacesTestUtils.addVisits({
-      uri: NetUtil.newURI("https://mozilla.org/test/"),
-      transition: TRANSITION_TYPED
-    });
-    PlacesTestUtils.addVisits({
-      uri: NetUtil.newURI("ftp://mozilla.org/test/"),
-      transition: TRANSITION_TYPED
-    });
-    PlacesTestUtils.addVisits({
-      uri: NetUtil.newURI("http://www.mozilla.org/test/"),
-      transition: TRANSITION_TYPED
-    });
-    PlacesTestUtils.addVisits({
-      uri: NetUtil.newURI("http://mozilla.org/test/"),
-      transition: TRANSITION_TYPED
-    });
+  function* () {
+    yield PlacesTestUtils.addVisits([
+      { uri: NetUtil.newURI("https://mozilla.org/test/"),
+        transition: TRANSITION_TYPED
+      },
+      { uri: NetUtil.newURI("ftp://mozilla.org/test/"),
+        transition: TRANSITION_TYPED
+      },
+      { uri: NetUtil.newURI("http://www.mozilla.org/test/"),
+        transition: TRANSITION_TYPED
+      },
+      { uri: NetUtil.newURI("http://mozilla.org/test/"),
+        transition: TRANSITION_TYPED
+      }
+    ]);
   },
 ]);
 
 add_autocomplete_test([
   "Ensuring correct priority 3",
   "mo",
   { autoFilled: "mozilla.org/", completed: "mozilla.org/" },
-  function () {
-    PlacesTestUtils.addVisits({
-      uri: NetUtil.newURI("ftp://mozilla.org/test/"),
-      transition: TRANSITION_TYPED
-    });
-    PlacesTestUtils.addVisits({
-      uri: NetUtil.newURI("http://www.mozilla.org/test/"),
-      transition: TRANSITION_TYPED
-    });
-    PlacesTestUtils.addVisits({
-      uri: NetUtil.newURI("http://mozilla.org/test/"),
-      transition: TRANSITION_TYPED
-    });
+  function* () {
+    yield PlacesTestUtils.addVisits([
+      { uri: NetUtil.newURI("ftp://mozilla.org/test/"),
+        transition: TRANSITION_TYPED
+      },
+      { uri: NetUtil.newURI("http://www.mozilla.org/test/"),
+        transition: TRANSITION_TYPED
+      },
+      { uri: NetUtil.newURI("http://mozilla.org/test/"),
+        transition: TRANSITION_TYPED
+      }
+    ]);
   },
 ]);
 
 add_autocomplete_test([
   "Ensuring correct priority 4",
   "mo",
   { autoFilled: "mozilla.org/", completed: "mozilla.org/" },
-  function () {
-    PlacesTestUtils.addVisits({
-      uri: NetUtil.newURI("http://www.mozilla.org/test/"),
-      transition: TRANSITION_TYPED
-    });
-    PlacesTestUtils.addVisits({
-      uri: NetUtil.newURI("http://mozilla.org/test/"),
-      transition: TRANSITION_TYPED
-    });
+  function* () {
+    yield PlacesTestUtils.addVisits([
+      { uri: NetUtil.newURI("http://www.mozilla.org/test/"),
+        transition: TRANSITION_TYPED
+      },
+      { uri: NetUtil.newURI("http://mozilla.org/test/"),
+        transition: TRANSITION_TYPED
+      }
+    ]);
   },
 ]);
 
 add_autocomplete_test([
   "Ensuring correct priority 5",
   "mo",
   { autoFilled: "mozilla.org/", completed: "ftp://mozilla.org/" },
-  function () {
-    PlacesTestUtils.addVisits({
-      uri: NetUtil.newURI("ftp://mozilla.org/test/"),
-      transition: TRANSITION_TYPED
-    });
-    PlacesTestUtils.addVisits({
-      uri: NetUtil.newURI("ftp://www.mozilla.org/test/"),
-      transition: TRANSITION_TYPED
-    });
+  function* () {
+    yield PlacesTestUtils.addVisits([
+      { uri: NetUtil.newURI("ftp://mozilla.org/test/"),
+        transition: TRANSITION_TYPED
+      },
+      { uri: NetUtil.newURI("ftp://www.mozilla.org/test/"),
+        transition: TRANSITION_TYPED
+      }
+    ]);
   },
 ]);
 
 add_autocomplete_test([
   "Ensuring correct priority 6",
   "mo",
   { autoFilled: "mozilla.org/", completed: "www.mozilla.org/" },
-  function () {
-    PlacesTestUtils.addVisits({
-      uri: NetUtil.newURI("http://www.mozilla.org/test1/"),
-      transition: TRANSITION_TYPED
-    });
-    PlacesTestUtils.addVisits({
-      uri: NetUtil.newURI("http://www.mozilla.org/test2/"),
-      transition: TRANSITION_TYPED
-    });
+  function* () {
+    yield PlacesTestUtils.addVisits([
+      { uri: NetUtil.newURI("http://www.mozilla.org/test1/"),
+        transition: TRANSITION_TYPED
+      },
+      { uri: NetUtil.newURI("http://www.mozilla.org/test2/"),
+        transition: TRANSITION_TYPED
+      }
+    ]);
   },
 ]);
 
 add_autocomplete_test([
   "Ensuring longer domain can't match",
   "mo",
   { autoFilled: "mozilla.co/", completed: "mozilla.co/" },
-  function () {
+  function* () {
     // The .co should be preferred, but should not get the https from the .com.
     // The .co domain must be added later to activate the trigger bug.
-    PlacesTestUtils.addVisits({
-      uri: NetUtil.newURI("https://mozilla.com/"),
-      transition: TRANSITION_TYPED
-    });
-    PlacesTestUtils.addVisits({
-      uri: NetUtil.newURI("http://mozilla.co/"),
-      transition: TRANSITION_TYPED
-    });
-    PlacesTestUtils.addVisits({
-      uri: NetUtil.newURI("http://mozilla.co/"),
-      transition: TRANSITION_TYPED
-    });
+    yield PlacesTestUtils.addVisits([
+      { uri: NetUtil.newURI("https://mozilla.com/"),
+        transition: TRANSITION_TYPED
+      },
+      { uri: NetUtil.newURI("http://mozilla.co/"),
+        transition: TRANSITION_TYPED
+      },
+      { uri: NetUtil.newURI("http://mozilla.co/"),
+        transition: TRANSITION_TYPED
+      }
+    ]);
   },
 ]);
 
 add_autocomplete_test([
   "Searching for URL with characters that are normally escaped",
   "https://www.mozilla.org/啊-test",
   { autoFilled: "https://www.mozilla.org/啊-test", completed: "https://www.mozilla.org/啊-test" },
-  function () {
-    PlacesTestUtils.addVisits({
+  function* () {
+    yield PlacesTestUtils.addVisits({
       uri: NetUtil.newURI("https://www.mozilla.org/啊-test"),
       transition: TRANSITION_TYPED
     });
   },
 ]);
 
 add_autocomplete_test([
   "Don't return unsecure URL when searching for secure ones",
   "https://test.moz.org/t",
   { autoFilled: "https://test.moz.org/test/", completed: "https://test.moz.org/test/" },
-  function () {
-    PlacesTestUtils.addVisits({
+  function* () {
+    yield PlacesTestUtils.addVisits({
       uri: NetUtil.newURI("http://test.moz.org/test/"),
       transition: TRANSITION_TYPED
     });
   },
 ]);
 
 add_autocomplete_test([
   "Don't return unsecure domain when searching for secure ones",
   "https://test.moz",
   { autoFilled: "https://test.moz.org/", completed: "https://test.moz.org/" },
-  function () {
-    PlacesTestUtils.addVisits({
+  function* () {
+    yield PlacesTestUtils.addVisits({
       uri: NetUtil.newURI("http://test.moz.org/test/"),
       transition: TRANSITION_TYPED
     });
   },
 ]);
 
 add_autocomplete_test([
   "Untyped is not accounted for www",
   "mo",
   { autoFilled: "moz.org/", completed: "moz.org/" },
-  function () {
-    PlacesTestUtils.addVisits({ uri: NetUtil.newURI("http://www.moz.org/test/") });
+  function* () {
+    yield PlacesTestUtils.addVisits({ uri: NetUtil.newURI("http://www.moz.org/test/") });
   },
 ]);
 
 add_autocomplete_test([
   "Untyped is not accounted for ftp",
   "mo",
   { autoFilled: "moz.org/", completed: "moz.org/" },
-  function () {
-    PlacesTestUtils.addVisits({ uri: NetUtil.newURI("ftp://moz.org/test/") });
+  function* () {
+    yield PlacesTestUtils.addVisits({ uri: NetUtil.newURI("ftp://moz.org/test/") });
   },
 ]);
 
 add_autocomplete_test([
   "Untyped is not accounted for https",
   "mo",
   { autoFilled: "moz.org/", completed: "moz.org/" },
-  function () {
-    PlacesTestUtils.addVisits({ uri: NetUtil.newURI("https://moz.org/test/") });
+  function* () {
+    yield PlacesTestUtils.addVisits({ uri: NetUtil.newURI("https://moz.org/test/") });
   },
 ]);
 
 add_autocomplete_test([
   "Untyped is not accounted for https://www",
   "mo",
   { autoFilled: "moz.org/", completed: "moz.org/" },
-  function () {
-    PlacesTestUtils.addVisits({ uri: NetUtil.newURI("https://www.moz.org/test/") });
+  function* () {
+    yield PlacesTestUtils.addVisits({ uri: NetUtil.newURI("https://www.moz.org/test/") });
   },
 ]);
--- a/toolkit/components/places/tests/inline/test_typed.js
+++ b/toolkit/components/places/tests/inline/test_typed.js
@@ -4,67 +4,67 @@
 
 // First do searches with typed behavior forced to false, so later tests will
 // ensure autocomplete is able to dinamically switch behavior.
 
 add_autocomplete_test([
   "Searching for domain should autoFill it",
   "moz",
   "mozilla.org/",
-  function () {
+  function* () {
     Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
-    PlacesTestUtils.addVisits(NetUtil.newURI("http://mozilla.org/link/"));
+    yield PlacesTestUtils.addVisits(NetUtil.newURI("http://mozilla.org/link/"));
   }
 ]);
 
 add_autocomplete_test([
   "Searching for url should autoFill it",
   "mozilla.org/li",
   "mozilla.org/link/",
-  function () {
+  function* () {
     Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
-    PlacesTestUtils.addVisits(NetUtil.newURI("http://mozilla.org/link/"));
+    yield PlacesTestUtils.addVisits(NetUtil.newURI("http://mozilla.org/link/"));
   }
 ]);
 
 // Now do searches with typed behavior forced to true.
 
 add_autocomplete_test([
   "Searching for non-typed domain should not autoFill it",
   "moz",
   "moz",
-  function () {
+  function* () {
     Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", true);
-    PlacesTestUtils.addVisits(NetUtil.newURI("http://mozilla.org/link/"));
+    yield PlacesTestUtils.addVisits(NetUtil.newURI("http://mozilla.org/link/"));
   }
 ]);
 
 add_autocomplete_test([
   "Searching for typed domain should autoFill it",
   "moz",
   "mozilla.org/",
-  function () {
+  function* () {
     Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", true);
-    PlacesTestUtils.addVisits({ uri: NetUtil.newURI("http://mozilla.org/typed/"),
-                       transition: TRANSITION_TYPED });
+    yield PlacesTestUtils.addVisits({ uri: NetUtil.newURI("http://mozilla.org/typed/"),
+                                      transition: TRANSITION_TYPED });
   }
 ]);
 
 add_autocomplete_test([
   "Searching for non-typed url should not autoFill it",
   "mozilla.org/li",
   "mozilla.org/li",
-  function () {
+  function* () {
     Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", true);
-    PlacesTestUtils.addVisits(NetUtil.newURI("http://mozilla.org/link/"));
+    yield PlacesTestUtils.addVisits(NetUtil.newURI("http://mozilla.org/link/"));
   }
 ]);
 
 add_autocomplete_test([
   "Searching for typed url should autoFill it",
   "mozilla.org/li",
   "mozilla.org/link/",
-  function () {
+  function* () {
     Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", true);
-    PlacesTestUtils.addVisits({ uri: NetUtil.newURI("http://mozilla.org/link/"),
-                       transition: TRANSITION_TYPED });
+    yield PlacesTestUtils.addVisits({ uri: NetUtil.newURI("http://mozilla.org/link/"),
+                                      transition: TRANSITION_TYPED });
   }
 ]);
--- a/toolkit/components/places/tests/inline/test_zero_frecency.js
+++ b/toolkit/components/places/tests/inline/test_zero_frecency.js
@@ -3,29 +3,29 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Ensure inline autocomplete doesn't return zero frecency pages.
 
 add_autocomplete_test([
   "Searching for zero frecency domain should not autoFill it",
   "moz",
   "moz",
-  function () {
+  function* () {
     Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
-    PlacesTestUtils.addVisits({
+    yield PlacesTestUtils.addVisits({
       uri: NetUtil.newURI("http://mozilla.org/framed_link/"),
       transition: TRANSITION_FRAMED_LINK
     });
   }
 ]);
 
 add_autocomplete_test([
   "Searching for zero frecency url should not autoFill it",
   "mozilla.org/f",
   "mozilla.org/f",
-  function () {
+  function* () {
     Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
-    PlacesTestUtils.addVisits({
+    yield PlacesTestUtils.addVisits({
       uri: NetUtil.newURI("http://mozilla.org/framed_link/"),
       transition: TRANSITION_FRAMED_LINK
     });
   }
 ]);
--- a/toolkit/components/places/tests/unifiedcomplete/head_autocomplete.js
+++ b/toolkit/components/places/tests/unifiedcomplete/head_autocomplete.js
@@ -221,17 +221,18 @@ let addBookmark = Task.async(function* (
   let bm = yield PlacesUtils.bookmarks.insert({
     parentGuid: (yield PlacesUtils.promiseItemGuid(parentId)),
     title: aBookmarkObj.title || "A bookmark",
     url: aBookmarkObj.uri
   });
   let itemId = yield PlacesUtils.promiseItemId(bm.guid);
 
   if (aBookmarkObj.keyword) {
-    PlacesUtils.bookmarks.setKeywordForBookmark(itemId, aBookmarkObj.keyword);
+    yield PlacesUtils.keywords.insert({ keyword: aBookmarkObj.keyword,
+                                        url: aBookmarkObj.uri.spec });
   }
 
   if (aBookmarkObj.tags) {
     PlacesUtils.tagging.tagURI(aBookmarkObj.uri, aBookmarkObj.tags);
   }
 });
 
 function addOpenPages(aUri, aCount=1) {
--- a/toolkit/components/places/tests/unifiedcomplete/test_keyword_search.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_keyword_search.js
@@ -19,49 +19,49 @@ add_task(function* test_keyword_searc() 
     { uri: uri1, title: "Generic page title" },
     { uri: uri2, title: "Generic page title" }
   ]);
   yield addBookmark({ uri: uri1, title: "Bookmark title", keyword: "key"});
 
   do_print("Plain keyword query");
   yield check_autocomplete({
     search: "key term",
-    matches: [ { uri: NetUtil.newURI("http://abc/?search=term"), title: "Generic page title", style: ["keyword"] } ]
+    matches: [ { uri: NetUtil.newURI("http://abc/?search=term"), title: "abc", style: ["keyword"] } ]
   });
 
   do_print("Multi-word keyword query");
   yield check_autocomplete({
     search: "key multi word",
-    matches: [ { uri: NetUtil.newURI("http://abc/?search=multi+word"), title: "Generic page title", style: ["keyword"] } ]
+    matches: [ { uri: NetUtil.newURI("http://abc/?search=multi+word"), title: "abc", style: ["keyword"] } ]
   });
 
   do_print("Keyword query with +");
   yield check_autocomplete({
     search: "key blocking+",
-    matches: [ { uri: NetUtil.newURI("http://abc/?search=blocking%2B"), title: "Generic page title", style: ["keyword"] } ]
+    matches: [ { uri: NetUtil.newURI("http://abc/?search=blocking%2B"), title: "abc", style: ["keyword"] } ]
   });
 
   do_print("Unescaped term in query");
   yield check_autocomplete({
     search: "key ユニコード",
-    matches: [ { uri: NetUtil.newURI("http://abc/?search=ユニコード"), title: "Generic page title", style: ["keyword"] } ]
+    matches: [ { uri: NetUtil.newURI("http://abc/?search=ユニコード"), title: "abc", style: ["keyword"] } ]
   });
 
   do_print("Keyword that happens to match a page");
   yield check_autocomplete({
     search: "key ThisPageIsInHistory",
-    matches: [ { uri: NetUtil.newURI("http://abc/?search=ThisPageIsInHistory"), title: "Generic page title", style: ["keyword"] } ]
+    matches: [ { uri: NetUtil.newURI("http://abc/?search=ThisPageIsInHistory"), title: "abc", style: ["keyword"] } ]
   });
 
   do_print("Keyword without query (without space)");
   yield check_autocomplete({
     search: "key",
-    matches: [ { uri: NetUtil.newURI("http://abc/?search="), title: "Generic page title", style: ["keyword"] } ]
+    matches: [ { uri: NetUtil.newURI("http://abc/?search="), title: "abc", style: ["keyword"] } ]
   });
 
   do_print("Keyword without query (with space)");
   yield check_autocomplete({
     search: "key ",
-    matches: [ { uri: NetUtil.newURI("http://abc/?search="), title: "Generic page title", style: ["keyword"] } ]
+    matches: [ { uri: NetUtil.newURI("http://abc/?search="), title: "abc", style: ["keyword"] } ]
   });
 
   yield cleanup();
 });
--- a/toolkit/components/places/tests/unifiedcomplete/test_keyword_search_actions.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_keyword_search_actions.js
@@ -20,55 +20,55 @@ add_task(function* test_keyword_search()
     { uri: uri2, title: "Generic page title" }
   ]);
   yield addBookmark({ uri: uri1, title: "Bookmark title", keyword: "key"});
 
   do_print("Plain keyword query");
   yield check_autocomplete({
     search: "key term",
     searchParam: "enable-actions",
-    matches: [ { uri: makeActionURI("keyword", {url: "http://abc/?search=term", input: "key term"}), title: "Generic page title", style: [ "action", "keyword" ] } ]
+    matches: [ { uri: makeActionURI("keyword", {url: "http://abc/?search=term", input: "key term"}), title: "abc", style: [ "action", "keyword" ] } ]
   });
 
   do_print("Multi-word keyword query");
   yield check_autocomplete({
     search: "key multi word",
     searchParam: "enable-actions",
-    matches: [ { uri: makeActionURI("keyword", {url: "http://abc/?search=multi+word", input: "key multi word"}), title: "Generic page title", style: [ "action", "keyword" ] } ]
+    matches: [ { uri: makeActionURI("keyword", {url: "http://abc/?search=multi+word", input: "key multi word"}), title: "abc", style: [ "action", "keyword" ] } ]
   });
 
   do_print("Keyword query with +");
   yield check_autocomplete({
     search: "key blocking+",
     searchParam: "enable-actions",
-    matches: [ { uri: makeActionURI("keyword", {url: "http://abc/?search=blocking%2B", input: "key blocking+"}), title: "Generic page title", style: [ "action", "keyword" ] } ]
+    matches: [ { uri: makeActionURI("keyword", {url: "http://abc/?search=blocking%2B", input: "key blocking+"}), title: "abc", style: [ "action", "keyword" ] } ]
   });
 
   do_print("Unescaped term in query");
   yield check_autocomplete({
     search: "key ユニコード",
     searchParam: "enable-actions",
-    matches: [ { uri: makeActionURI("keyword", {url: "http://abc/?search=ユニコード", input: "key ユニコード"}), title: "Generic page title", style: [ "action", "keyword" ] } ]
+    matches: [ { uri: makeActionURI("keyword", {url: "http://abc/?search=ユニコード", input: "key ユニコード"}), title: "abc", style: [ "action", "keyword" ] } ]
   });
 
   do_print("Keyword that happens to match a page");
   yield check_autocomplete({
     search: "key ThisPageIsInHistory",
     searchParam: "enable-actions",
-    matches: [ { uri: makeActionURI("keyword", {url: "http://abc/?search=ThisPageIsInHistory", input: "key ThisPageIsInHistory"}), title: "Generic page title", style: [ "action", "keyword" ] } ]
+    matches: [ { uri: makeActionURI("keyword", {url: "http://abc/?search=ThisPageIsInHistory", input: "key ThisPageIsInHistory"}), title: "abc", style: [ "action", "keyword" ] } ]
   });
 
   do_print("Keyword without query (without space)");
   yield check_autocomplete({
     search: "key",
     searchParam: "enable-actions",
-    matches: [ { uri: makeActionURI("keyword", {url: "http://abc/?search=", input: "key"}), title: "Generic page title", style: [ "action", "keyword" ] } ]
+    matches: [ { uri: makeActionURI("keyword", {url: "http://abc/?search=", input: "key"}), title: "abc", style: [ "action", "keyword" ] } ]
   });
 
   do_print("Keyword without query (with space)");
   yield check_autocomplete({
     search: "key ",
     searchParam: "enable-actions",
-    matches: [ { uri: makeActionURI("keyword", {url: "http://abc/?search=", input: "key "}), title: "Generic page title", style: [ "action", "keyword" ] } ]
+    matches: [ { uri: makeActionURI("keyword", {url: "http://abc/?search=", input: "key "}), title: "abc", style: [ "action", "keyword" ] } ]
   });
 
   yield cleanup();
 });