Bug 1421703 - Fix tests to use onVisits r?mak draft
authorDoug Thayer <dothayer@mozilla.com>
Thu, 14 Dec 2017 16:55:31 -0600
changeset 718600 2fa49be7ce9c997129f286be86bdd4587f5b6958
parent 718599 5ea9b38ff006f4adfbcf8e1832646c826a1b934a
child 745553 9e461d515bef3b2630b90101f394b7fe651370a0
push id94999
push userbmo:dothayer@mozilla.com
push dateWed, 10 Jan 2018 17:15:18 +0000
reviewersmak
bugs1421703
milestone59.0a1
Bug 1421703 - Fix tests to use onVisits r?mak Fairly straightforward. Fixes the tests that were broken due to the changes introduced in part 1. MozReview-Commit-ID: GbZ9ZpmG9nE
browser/components/migration/tests/unit/test_automigration.js
browser/components/places/tests/chrome/test_bug549192.xul
docshell/test/browser/browser_bug420605.js
docshell/test/browser/browser_bug503832.js
docshell/test/browser/browser_bug655270.js
services/sync/tests/unit/head_helpers.js
services/sync/tests/unit/test_history_store.js
toolkit/components/jsdownloads/test/unit/head.js
toolkit/components/places/tests/browser/browser_bug399606.js
toolkit/components/places/tests/browser/browser_bug646422.js
toolkit/components/places/tests/browser/browser_double_redirect.js
toolkit/components/places/tests/browser/browser_multi_redirect_frecency.js
toolkit/components/places/tests/browser/browser_notfound.js
toolkit/components/places/tests/browser/browser_onvisit_title_null_for_navigation.js
toolkit/components/places/tests/browser/browser_redirect.js
toolkit/components/places/tests/browser/browser_settitle.js
toolkit/components/places/tests/browser/browser_visited_notfound.js
toolkit/components/places/tests/browser/head.js
toolkit/components/places/tests/expiration/test_notifications_onDeleteURI.js
toolkit/components/places/tests/expiration/test_notifications_onDeleteVisits.js
toolkit/components/places/tests/head_common.js
toolkit/components/places/tests/history/test_async_history_api.js
toolkit/components/places/tests/history/test_remove.js
toolkit/components/places/tests/history/test_removeByFilter.js
toolkit/components/places/tests/history/test_removeMany.js
toolkit/components/places/tests/history/test_removeVisitsByFilter.js
toolkit/components/places/tests/queries/test_history_queries_titles_liveUpdate.js
toolkit/components/places/tests/unit/nsDummyObserver.js
toolkit/components/places/tests/unit/test_download_history.js
toolkit/components/places/tests/unit/test_history_catobs.js
toolkit/components/places/tests/unit/test_history_observer.js
toolkit/components/places/tests/unit/test_markpageas.js
--- a/browser/components/migration/tests/unit/test_automigration.js
+++ b/browser/components/migration/tests/unit/test_automigration.js
@@ -612,18 +612,18 @@ add_task(async function checkUndoVisitsS
   ]);
   let uriDeletedExpected = new Map([
     ["http://www.mozilla.org/", PromiseUtils.defer()],
   ]);
   let wrongMethodDeferred = PromiseUtils.defer();
   let observer = {
     onBeginUpdateBatch() {},
     onEndUpdateBatch() {},
-    onVisit(uri) {
-      wrongMethodDeferred.reject(new Error("Unexpected call to onVisit " + uri.spec));
+    onVisits(visits) {
+      wrongMethodDeferred.reject(new Error("Unexpected call to onVisits " + visits.length));
     },
     onTitleChanged(uri) {
       wrongMethodDeferred.reject(new Error("Unexpected call to onTitleChanged " + uri.spec));
     },
     onClearHistory() {
       wrongMethodDeferred.reject("Unexpected call to onClearHistory");
     },
     onPageChanged(uri) {
--- a/browser/components/places/tests/chrome/test_bug549192.xul
+++ b/browser/components/places/tests/chrome/test_bug549192.xul
@@ -42,17 +42,17 @@
      */
 
     function promiseURIDeleted() {
      return new Promise(resolve => {
        let historyObserver = {
          onBeginUpdateBatch: function PEX_onBeginUpdateBatch() {},
          onEndUpdateBatch: function PEX_onEndUpdateBatch() {},
          onClearHistory() {},
-         onVisit() {},
+         onVisits() {},
          onTitleChanged() {},
          onDeleteURI(aURI, aGUID, aReason) {
            PlacesUtils.history.removeObserver(historyObserver);
            resolve();
          },
          onPageChanged() {},
          onDeleteVisits(aURI, aTime) { },
        };
--- a/docshell/test/browser/browser_bug420605.js
+++ b/docshell/test/browser/browser_bug420605.js
@@ -50,18 +50,17 @@ function test() {
                                                  gBrowser.selectedBrowser);
       }
     }
 
     /* Global history observer that triggers for the two test URLs above. */
     var historyObserver = {
         onBeginUpdateBatch: function() {},
         onEndUpdateBatch: function() {},
-        onVisit: function(aURI, aVisitID, aTime, aSessionId, aReferringId,
-                          aTransitionType, _added) {},
+        onVisits: function() {},
         onTitleChanged: function(aURI, aPageTitle) {},
         onDeleteURI: function(aURI) {},
         onClearHistory: function() {},
         onPageChanged: function(aURI, aWhat, aValue) {
             if (aWhat != Ci.nsINavHistoryObserver.ATTRIBUTE_FAVICON) {
                 return;
             }
             aURI = aURI.spec;
--- a/docshell/test/browser/browser_bug503832.js
+++ b/docshell/test/browser/browser_bug503832.js
@@ -10,18 +10,17 @@ add_task(async function() {
     var historyService = Cc["@mozilla.org/browser/nav-history-service;1"]
                          .getService(Ci.nsINavHistoryService);
 
     let fragmentPromise = new Promise(resolve => {
         /* Global history observer that triggers for the two test URLs above. */
         var historyObserver = {
             onBeginUpdateBatch: function() {},
             onEndUpdateBatch: function() {},
-            onVisit: function(aURI, aVisitID, aTime, aSessionId, aReferringId,
-                              aTransitionType, _added) {},
+            onVisits: function() {},
             onTitleChanged: function(aURI, aPageTitle) {
                 aURI = aURI.spec;
                 switch (aURI) {
                 case pageurl:
                     is(aPageTitle, pagetitle, "Correct page title for " + aURI);
                     return;
                 case fragmenturl:
                     is(aPageTitle, pagetitle, "Correct page title for " + aURI);
--- a/docshell/test/browser/browser_bug655270.js
+++ b/docshell/test/browser/browser_bug655270.js
@@ -43,17 +43,17 @@ function test() {
         gBrowser.removeTab(tab);
         PlacesUtils.history.removeObserver(this);
         finish();
       }
     },
 
     onBeginUpdateBatch: function() { },
     onEndUpdateBatch: function() { },
-    onVisit: function() { },
+    onVisits: function() { },
     onTitleChanged: function() { },
     onDeleteURI: function() { },
     onClearHistory: function() { },
     onDeleteVisits: function() { },
     QueryInterface: XPCOMUtils.generateQI([Ci.nsINavHistoryObserver])
   };
 
   PlacesUtils.history.addObserver(observer);
--- a/services/sync/tests/unit/head_helpers.js
+++ b/services/sync/tests/unit/head_helpers.js
@@ -577,18 +577,19 @@ async function promiseVisit(expectedType
   return new Promise(resolve => {
     function done(type, uri) {
       if (uri.equals(expectedURI) && type == expectedType) {
         PlacesUtils.history.removeObserver(observer);
         resolve();
       }
     }
     let observer = {
-      onVisit(uri) {
-        done("added", uri);
+      onVisits(visits) {
+        Assert.equal(visits.length, 1);
+        done("added", visits[0].uri);
       },
       onBeginUpdateBatch() {},
       onEndUpdateBatch() {},
       onTitleChanged() {},
       onFrecencyChanged() {},
       onManyFrecenciesChanged() {},
       onDeleteURI(uri) {
         done("removed", uri);
--- a/services/sync/tests/unit/test_history_store.js
+++ b/services/sync/tests/unit/test_history_store.js
@@ -15,17 +15,17 @@ const TIMESTAMP3 = (Date.now() - 123894)
 function promiseOnVisitObserved() {
   return new Promise(res => {
     PlacesUtils.history.addObserver({
       onBeginUpdateBatch: function onBeginUpdateBatch() {},
       onEndUpdateBatch: function onEndUpdateBatch() {},
       onPageChanged: function onPageChanged() {},
       onTitleChanged: function onTitleChanged() {
       },
-      onVisit: function onVisit() {
+      onVisits: function onVisits() {
         PlacesUtils.history.removeObserver(this);
         res();
       },
       onDeleteVisits: function onDeleteVisits() {},
       onPageExpired: function onPageExpired() {},
       onDeleteURI: function onDeleteURI() {},
       onClearHistory: function onClearHistory() {},
       QueryInterface: XPCOMUtils.generateQI([
--- a/toolkit/components/jsdownloads/test/unit/head.js
+++ b/toolkit/components/jsdownloads/test/unit/head.js
@@ -153,21 +153,26 @@ function promiseWaitForVisit(aUrl) {
   return new Promise(resolve => {
 
     let uri = NetUtil.newURI(aUrl);
 
     PlacesUtils.history.addObserver({
       QueryInterface: XPCOMUtils.generateQI([Ci.nsINavHistoryObserver]),
       onBeginUpdateBatch() {},
       onEndUpdateBatch() {},
-      onVisit(aURI, aVisitID, aTime, aSessionID, aReferringID,
-                        aTransitionType, aGUID, aHidden) {
-        if (aURI.equals(uri)) {
+      onVisits(aVisits) {
+        Assert.equal(aVisits.length, 1);
+        let {
+          uri: visitUri,
+          time,
+          transitionType,
+        } = aVisits[0];
+        if (visitUri.equals(uri)) {
           PlacesUtils.history.removeObserver(this);
-          resolve([aTime, aTransitionType]);
+          resolve([time, transitionType]);
         }
       },
       onTitleChanged() {},
       onDeleteURI() {},
       onClearHistory() {},
       onPageChanged() {},
       onDeleteVisits() {},
     });
--- a/toolkit/components/places/tests/browser/browser_bug399606.js
+++ b/toolkit/components/places/tests/browser/browser_bug399606.js
@@ -13,20 +13,22 @@ add_task(async function() {
     "http://example.com/tests/toolkit/components/places/tests/browser/399606-httprefresh.html",
     "http://example.com/tests/toolkit/components/places/tests/browser/399606-window.location.html",
   ];
 
   // Create and add history observer.
   let historyObserver = {
     count: 0,
     expectedURI: null,
-    onVisit(aURI) {
-      info("Received onVisit: " + aURI.spec);
-      if (aURI.equals(this.expectedURI)) {
-        this.count++;
+    onVisits(aVisits) {
+      for (let {uri} of aVisits) {
+        info("Received onVisits: " + uri.spec);
+        if (uri.equals(this.expectedURI)) {
+          this.count++;
+        }
       }
     },
     onBeginUpdateBatch() {},
     onEndUpdateBatch() {},
     onTitleChanged() {},
     onDeleteURI() {},
     onClearHistory() {},
     onPageChanged() {},
--- a/toolkit/components/places/tests/browser/browser_bug646422.js
+++ b/toolkit/components/places/tests/browser/browser_bug646422.js
@@ -18,17 +18,17 @@ add_task(async function() {
         if (/new_page$/.test(uri.spec)) {
           resolve(title);
           PlacesUtils.history.removeObserver(observer);
         }
       },
 
       onBeginUpdateBatch() { },
       onEndUpdateBatch() { },
-      onVisit() { },
+      onVisits() { },
       onDeleteURI() { },
       onClearHistory() { },
       onPageChanged() { },
       onDeleteVisits() { },
       QueryInterface: XPCOMUtils.generateQI([Ci.nsINavHistoryObserver])
     };
 
     PlacesUtils.history.addObserver(observer);
--- a/toolkit/components/places/tests/browser/browser_double_redirect.js
+++ b/toolkit/components/places/tests/browser/browser_double_redirect.js
@@ -9,17 +9,17 @@ add_task(async function() {
   const TEST_URI = NetUtil.newURI(BASE_URL + "begin.html");
   const FIRST_REDIRECTING_URI = NetUtil.newURI(BASE_URL + "redirect_twice.sjs");
   const FINAL_URI = NetUtil.newURI(BASE_URL + "final.html");
 
   let promiseVisits = new Promise(resolve => {
     PlacesUtils.history.addObserver({
       __proto__: NavHistoryObserver.prototype,
       _notified: [],
-      onVisit(uri, id, time, sessionId, referrerId, transition) {
+      onVisit(uri, id, time, referrerId, transition) {
         info("Received onVisit: " + uri.spec);
         this._notified.push(uri);
 
         if (!uri.equals(FINAL_URI)) {
           return;
         }
 
         is(this._notified.length, 4);
@@ -39,16 +39,27 @@ add_task(async function() {
 
           is(rows.length, 1, "Found right number of visits");
           let visitedUrl = rows[0].getResultByName("url");
           // Check that redirect from_visit is not from the original typed one
           is(visitedUrl, FIRST_REDIRECTING_URI.spec, "Check referrer for " + visitedUrl);
 
           resolve();
         })();
+      },
+      onVisits(visits) {
+        is(visits.length, 1, "Right number of visits notified");
+        let {
+          uri,
+          visitId,
+          time,
+          referrerId,
+          transitionType,
+        } = visits[0];
+        this.onVisit(uri, visitId, time, referrerId, transitionType);
       }
     });
   });
 
   PlacesUtils.history.markPageAsTyped(TEST_URI);
   await BrowserTestUtils.withNewTab({
     gBrowser,
     url: TEST_URI.spec,
--- a/toolkit/components/places/tests/browser/browser_multi_redirect_frecency.js
+++ b/toolkit/components/places/tests/browser/browser_multi_redirect_frecency.js
@@ -37,26 +37,28 @@ add_task(async function test_multiple_re
 
   redirectSourceFrecency += REDIRECT_SOURCE_VISIT_BONUS;
   // TODO Bug 487813 - This should be TYPED_VISIT_BONUS, however as we don't
   // currently track redirects across multiple redirects, we fallback to the
   // PERM_REDIRECT_VISIT_BONUS.
   redirectTargetFrecency += PERM_REDIRECT_VISIT_BONUS;
   let redirectNotified = false;
 
-  let visitedPromise = PlacesTestUtils.waitForNotification("onVisit", uri => {
-    info("Received onVisit: " + uri.spec);
+  let visitedPromise = PlacesTestUtils.waitForNotification("onVisits", visits => {
+    is(visits.length, 1, "Was notified for the right number of visits.");
+    let {uri} = visits[0];
+    info("Received onVisits: " + uri.spec);
     if (uri.equals(REDIRECT_URI)) {
       redirectNotified = true;
     }
     return uri.equals(TARGET_URI);
   }, "history");
 
   let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, REDIRECT_URI.spec);
-  info("Waiting for onVisit");
+  info("Waiting for onVisits");
   await visitedPromise;
   ok(redirectNotified, "The redirect should have been notified");
 
   await check_uri(REDIRECT_URI, redirectSourceFrecency, 1);
   await check_uri(INTERMEDIATE_URI_1, redirectSourceFrecency, 1);
   await check_uri(INTERMEDIATE_URI_2, redirectSourceFrecency, 1);
   await check_uri(TARGET_URI, redirectTargetFrecency, 0);
 
@@ -69,26 +71,28 @@ add_task(async function redirect_check_s
 
   redirectSourceFrecency += REDIRECT_SOURCE_VISIT_BONUS;
   // TODO Bug 487813 - This should be TYPED_VISIT_BONUS, however as we don't
   // currently track redirects across multiple redirects, we fallback to the
   // PERM_REDIRECT_VISIT_BONUS.
   redirectTargetFrecency += PERM_REDIRECT_VISIT_BONUS;
   let redirectNotified = false;
 
-  let visitedPromise = PlacesTestUtils.waitForNotification("onVisit", uri => {
-    info("Received onVisit: " + uri.spec);
+  let visitedPromise = PlacesTestUtils.waitForNotification("onVisits", visits => {
+    Assert.equal(visits.length, 1, "Was notified for the right number of visits.");
+    let {uri} = visits[0];
+    info("Received onVisits: " + uri.spec);
     if (uri.equals(REDIRECT_URI)) {
       redirectNotified = true;
     }
     return uri.equals(TARGET_URI);
   }, "history");
 
   let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, REDIRECT_URI.spec);
-  info("Waiting for onVisit");
+  info("Waiting for onVisits");
   await visitedPromise;
   ok(redirectNotified, "The redirect should have been notified");
 
   await check_uri(REDIRECT_URI, redirectSourceFrecency, 1);
   await check_uri(INTERMEDIATE_URI_1, redirectSourceFrecency, 1);
   await check_uri(INTERMEDIATE_URI_2, redirectSourceFrecency, 1);
   await check_uri(TARGET_URI, redirectTargetFrecency, 0);
 
@@ -100,26 +104,28 @@ add_task(async function redirect_check_s
   // Another visit, but this time as a visited url.
   redirectSourceFrecency += REDIRECT_SOURCE_VISIT_BONUS;
   // TODO Bug 487813 - This should be TYPED_VISIT_BONUS, however as we don't
   // currently track redirects across multiple redirects, we fallback to the
   // PERM_REDIRECT_VISIT_BONUS.
   redirectTargetFrecency += PERM_REDIRECT_VISIT_BONUS;
   let redirectNotified = false;
 
-  let visitedPromise = PlacesTestUtils.waitForNotification("onVisit", uri => {
-    info("Received onVisit: " + uri.spec);
+  let visitedPromise = PlacesTestUtils.waitForNotification("onVisits", visits => {
+    Assert.equal(visits.length, 1, "Was notified for the right number of visits.");
+    let {uri} = visits[0];
+    info("Received onVisits: " + uri.spec);
     if (uri.equals(REDIRECT_URI)) {
       redirectNotified = true;
     }
     return uri.equals(TARGET_URI);
   }, "history");
 
   let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, REDIRECT_URI.spec);
-  info("Waiting for onVisit");
+  info("Waiting for onVisits");
   await visitedPromise;
   ok(redirectNotified, "The redirect should have been notified");
 
   await check_uri(REDIRECT_URI, redirectSourceFrecency, 1);
   await check_uri(INTERMEDIATE_URI_1, redirectSourceFrecency, 1);
   await check_uri(INTERMEDIATE_URI_2, redirectSourceFrecency, 1);
   await check_uri(TARGET_URI, redirectTargetFrecency, 0);
 
--- a/toolkit/components/places/tests/browser/browser_notfound.js
+++ b/toolkit/components/places/tests/browser/browser_notfound.js
@@ -6,31 +6,41 @@ add_task(async function() {
   const TEST_URL = "http://mochi.test:8888/notFoundPage.html";
 
   // Used to verify errors are not marked as typed.
   PlacesUtils.history.markPageAsTyped(NetUtil.newURI(TEST_URL));
 
   // Create and add history observer.
   let visitedPromise = new Promise(resolve => {
     let historyObserver = {
-      onVisit(aURI, aVisitID, aTime, aSessionID, aReferringID,
-                        aTransitionType) {
+      onVisit(aURI, aVisitID, aTime, aReferringID, aTransitionType) {
         PlacesUtils.history.removeObserver(historyObserver);
         info("Received onVisit: " + aURI.spec);
         fieldForUrl(aURI, "frecency", function(aFrecency) {
           is(aFrecency, 0, "Frecency should be 0");
           fieldForUrl(aURI, "hidden", function(aHidden) {
             is(aHidden, 0, "Page should not be hidden");
             fieldForUrl(aURI, "typed", function(aTyped) {
               is(aTyped, 0, "page should not be marked as typed");
               resolve();
             });
           });
         });
       },
+      onVisits(aVisits) {
+        is(aVisits.length, 1, "Right number of visits notified");
+        let {
+          uri,
+          visitId,
+          time,
+          referrerId,
+          transitionType,
+        } = aVisits[0];
+        this.onVisit(uri, visitId, time, referrerId, transitionType);
+      },
       onBeginUpdateBatch() {},
       onEndUpdateBatch() {},
       onTitleChanged() {},
       onDeleteURI() {},
       onClearHistory() {},
       onPageChanged() {},
       onDeleteVisits() {},
       QueryInterface: XPCOMUtils.generateQI([Ci.nsINavHistoryObserver])
--- a/toolkit/components/places/tests/browser/browser_onvisit_title_null_for_navigation.js
+++ b/toolkit/components/places/tests/browser/browser_onvisit_title_null_for_navigation.js
@@ -1,19 +1,23 @@
 const TEST_PATH = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "http://example.com");
 
 add_task(async function checkTitleNotificationForNavigation() {
   const EXPECTED_URL = Services.io.newURI(TEST_PATH + "empty_page.html");
   let promiseTitleChanged = new Promise(resolve => {
     let obs = {
-      onVisit(aURI, aVisitId, aTime, aSessionId, aReferrerVisitId, aTransitionType,
-              aGuid, aHidden, aVisitCount, aTyped, aLastKnownTitle) {
-        info("onVisit: " + aURI.spec);
-        if (aURI.equals(EXPECTED_URL)) {
-          Assert.equal(aLastKnownTitle, null, "Should not have a title");
+      onVisits(aVisits) {
+        Assert.equal(aVisits.length, 1, "Right number of visits notified");
+        let {
+          uri,
+          lastKnownTitle,
+        } = aVisits[0];
+        info("onVisits: " + uri.spec);
+        if (uri.equals(EXPECTED_URL)) {
+          Assert.equal(lastKnownTitle, null, "Should not have a title");
         }
       },
 
       onTitleChanged(aURI, aTitle, aGuid) {
         if (aURI.equals(EXPECTED_URL)) {
           is(aTitle, "I am an empty page", "Should have correct title in titlechanged notification");
           PlacesUtils.history.removeObserver(obs);
           resolve();
--- a/toolkit/components/places/tests/browser/browser_redirect.js
+++ b/toolkit/components/places/tests/browser/browser_redirect.js
@@ -34,26 +34,28 @@ async function check_uri(uri, frecency, 
 add_task(async function redirect_check_new_typed_visit() {
   // Used to verify the redirect bonus overrides the typed bonus.
   PlacesUtils.history.markPageAsTyped(REDIRECT_URI);
 
   redirectSourceFrecency += REDIRECT_SOURCE_VISIT_BONUS;
   redirectTargetFrecency += TYPED_VISIT_BONUS;
   let redirectNotified = false;
 
-  let visitedPromise = PlacesTestUtils.waitForNotification("onVisit", uri => {
-    info("Received onVisit for: " + uri.spec);
+  let visitedPromise = PlacesTestUtils.waitForNotification("onVisits", visits => {
+    is(visits.length, 1, "Was notified for the right number of visits.");
+    let {uri} = visits[0];
+    info("Received onVisits for: " + uri.spec);
     if (uri.equals(REDIRECT_URI)) {
       redirectNotified = true;
     }
     return uri.equals(TARGET_URI);
   }, "history");
 
   let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, REDIRECT_URI.spec);
-  info("Waiting for onVisit");
+  info("Waiting for onVisits");
   await visitedPromise;
   ok(redirectNotified, "The redirect should have been notified");
 
   await check_uri(REDIRECT_URI, redirectSourceFrecency, 1);
   await check_uri(TARGET_URI, redirectTargetFrecency, 0);
 
   await BrowserTestUtils.removeTab(tab);
 });
@@ -61,51 +63,55 @@ add_task(async function redirect_check_n
 add_task(async function redirect_check_second_typed_visit() {
   // A second visit with a typed url.
   PlacesUtils.history.markPageAsTyped(REDIRECT_URI);
 
   redirectSourceFrecency += REDIRECT_SOURCE_VISIT_BONUS;
   redirectTargetFrecency += TYPED_VISIT_BONUS;
   let redirectNotified = false;
 
-  let visitedPromise = PlacesTestUtils.waitForNotification("onVisit", uri => {
-    info("Received onVisit: " + uri.spec);
+  let visitedPromise = PlacesTestUtils.waitForNotification("onVisits", visits => {
+    is(visits.length, 1, "Was notified for the right number of visits.");
+    let {uri} = visits[0];
+    info("Received onVisits: " + uri.spec);
     if (uri.equals(REDIRECT_URI)) {
       redirectNotified = true;
     }
     return uri.equals(TARGET_URI);
   }, "history");
 
   let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, REDIRECT_URI.spec);
-  info("Waiting for onVisit");
+  info("Waiting for onVisits");
   await visitedPromise;
   ok(redirectNotified, "The redirect should have been notified");
 
   await check_uri(REDIRECT_URI, redirectSourceFrecency, 1);
   await check_uri(TARGET_URI, redirectTargetFrecency, 0);
 
   await BrowserTestUtils.removeTab(tab);
 });
 
 add_task(async function redirect_check_subsequent_link_visit() {
   // Another visit, but this time as a visited url.
   redirectSourceFrecency += REDIRECT_SOURCE_VISIT_BONUS;
   redirectTargetFrecency += LINK_VISIT_BONUS;
   let redirectNotified = false;
 
-  let visitedPromise = PlacesTestUtils.waitForNotification("onVisit", uri => {
-    info("Received onVisit: " + uri.spec);
+  let visitedPromise = PlacesTestUtils.waitForNotification("onVisits", visits => {
+    is(visits.length, 1, "Was notified for the right number of visits.");
+    let {uri} = visits[0];
+    info("Received onVisits: " + uri.spec);
     if (uri.equals(REDIRECT_URI)) {
       redirectNotified = true;
     }
     return uri.equals(TARGET_URI);
   }, "history");
 
   let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, REDIRECT_URI.spec);
-  info("Waiting for onVisit");
+  info("Waiting for onVisits");
   await visitedPromise;
   ok(redirectNotified, "The redirect should have been notified");
 
   await check_uri(REDIRECT_URI, redirectSourceFrecency, 1);
   await check_uri(TARGET_URI, redirectTargetFrecency, 0);
 
   await BrowserTestUtils.removeTab(tab);
 });
--- a/toolkit/components/places/tests/browser/browser_settitle.js
+++ b/toolkit/components/places/tests/browser/browser_settitle.js
@@ -20,19 +20,17 @@ add_task(async function() {
   // notifications.
 
   // Create and add history observer.
   let titleChangedPromise = new Promise(resolve => {
     var historyObserver = {
       data: [],
       onBeginUpdateBatch() {},
       onEndUpdateBatch() {},
-      onVisit(aURI, aVisitID, aTime, aSessionID, aReferringID,
-                        aTransitionType) {
-      },
+      onVisits() {},
       onTitleChanged(aURI, aPageTitle, aGUID) {
         this.data.push({ uri: aURI, title: aPageTitle, guid: aGUID });
 
         // We only expect one title change.
         //
         // Although we are loading two different pages, the first page does not
         // have a title.  Since the title starts out as empty and then is set
         // to empty, there is no title change notification.
--- a/toolkit/components/places/tests/browser/browser_visited_notfound.js
+++ b/toolkit/components/places/tests/browser/browser_visited_notfound.js
@@ -17,19 +17,20 @@ add_task(async function test() {
   is(frecency, 100, "Check initial frecency");
 
   // Used to verify errors are not marked as typed.
   PlacesUtils.history.markPageAsTyped(NetUtil.newURI(TEST_URL));
 
   let promiseVisit = new Promise(resolve => {
     let historyObserver = {
       __proto__: NavHistoryObserver.prototype,
-      onVisit(uri) {
+      onVisits(visits) {
         PlacesUtils.history.removeObserver(historyObserver);
-        is(uri.spec, TEST_URL, "Check visited url");
+        is(visits.length, 1, "Right number of visits");
+        is(visits[0].uri.spec, TEST_URL, "Check visited url");
         resolve();
       }
     };
     PlacesUtils.history.addObserver(historyObserver);
   });
   gBrowser.selectedBrowser.loadURI(TEST_URL);
   await promiseVisit;
 
--- a/toolkit/components/places/tests/browser/head.js
+++ b/toolkit/components/places/tests/browser/head.js
@@ -73,17 +73,17 @@ function promiseFieldForUrl(aURI, aField
  * Generic nsINavHistoryObserver that doesn't implement anything, but provides
  * dummy methods to prevent errors about an object not having a certain method.
  */
 function NavHistoryObserver() {}
 
 NavHistoryObserver.prototype = {
   onBeginUpdateBatch() {},
   onEndUpdateBatch() {},
-  onVisit() {},
+  onVisits() {},
   onTitleChanged() {},
   onDeleteURI() {},
   onClearHistory() {},
   onPageChanged() {},
   onDeleteVisits() {},
   QueryInterface: XPCOMUtils.generateQI([
     Ci.nsINavHistoryObserver,
   ])
--- a/toolkit/components/places/tests/expiration/test_notifications_onDeleteURI.js
+++ b/toolkit/components/places/tests/expiration/test_notifications_onDeleteURI.js
@@ -72,17 +72,17 @@ add_task(async function test_notificatio
       currentTest.bookmarks.push(page);
     }
 
     // Observe history.
     let historyObserver = {
       onBeginUpdateBatch: function PEX_onBeginUpdateBatch() {},
       onEndUpdateBatch: function PEX_onEndUpdateBatch() {},
       onClearHistory() {},
-      onVisit() {},
+      onVisits() {},
       onTitleChanged() {},
       onDeleteURI(aURI, aGUID, aReason) {
         currentTest.receivedNotifications++;
         // Check this uri was not bookmarked.
         Assert.equal(currentTest.bookmarks.indexOf(aURI.spec), -1);
         do_check_valid_places_guid(aGUID);
         Assert.equal(aReason, Ci.nsINavHistoryObserver.REASON_EXPIRED);
       },
--- a/toolkit/components/places/tests/expiration/test_notifications_onDeleteVisits.js
+++ b/toolkit/components/places/tests/expiration/test_notifications_onDeleteVisits.js
@@ -97,17 +97,17 @@ add_task(async function test_notificatio
       currentTest.bookmarks.push(page);
     }
 
     // Observe history.
     let historyObserver = {
       onBeginUpdateBatch: function PEX_onBeginUpdateBatch() {},
       onEndUpdateBatch: function PEX_onEndUpdateBatch() {},
       onClearHistory() {},
-      onVisit() {},
+      onVisits() {},
       onTitleChanged() {},
       onDeleteURI(aURI, aGUID, aReason) {
         // Check this uri was not bookmarked.
         Assert.equal(currentTest.bookmarks.indexOf(aURI.spec), -1);
         do_check_valid_places_guid(aGUID);
         Assert.equal(aReason, Ci.nsINavHistoryObserver.REASON_EXPIRED);
       },
       onPageChanged() {},
--- a/toolkit/components/places/tests/head_common.js
+++ b/toolkit/components/places/tests/head_common.js
@@ -758,17 +758,17 @@ NavBookmarkObserver.prototype = {
  * Generic nsINavHistoryObserver that doesn't implement anything, but provides
  * dummy methods to prevent errors about an object not having a certain method.
  */
 function NavHistoryObserver() {}
 
 NavHistoryObserver.prototype = {
   onBeginUpdateBatch() {},
   onEndUpdateBatch() {},
-  onVisit() {},
+  onVisits() {},
   onTitleChanged() {},
   onDeleteURI() {},
   onClearHistory() {},
   onPageChanged() {},
   onDeleteVisits() {},
   QueryInterface: XPCOMUtils.generateQI([
     Ci.nsINavHistoryObserver,
   ])
--- a/toolkit/components/places/tests/history/test_async_history_api.js
+++ b/toolkit/components/places/tests/history/test_async_history_api.js
@@ -87,33 +87,40 @@ function VisitObserver(aURI,
                        aGUID,
                        aCallback) {
   this.uri = aURI;
   this.guid = aGUID;
   this.callback = aCallback;
 }
 VisitObserver.prototype = {
   __proto__: NavHistoryObserver.prototype,
-  onVisit(aURI,
-                    aVisitId,
-                    aTime,
-                    aSessionId,
-                    aReferringId,
-                    aTransitionType,
-                    aGUID,
-                    aHidden,
-                    aVisitCount,
-                    aTyped,
-                    aLastKnownTitle) {
-    let args = [...arguments].slice(1);
-    info("onVisit(" + aURI.spec + args.join(", ") + ")");
-    if (!this.uri.equals(aURI) || this.guid != aGUID) {
+  onVisits(aVisits) {
+    info("onVisits()!!!");
+    Assert.equal(aVisits.length, 1, "Right number of visits notified");
+    let {
+      uri,
+      visitId,
+      time,
+      referrerId,
+      transitionType,
+      guid,
+      hidden,
+      visitCount,
+      typed,
+      lastKnownTitle,
+    } = aVisits[0];
+    let args = [
+      visitId, time, referrerId, transitionType, guid,
+      hidden, visitCount, typed, lastKnownTitle,
+    ];
+    info("onVisit(" + uri.spec + args.join(", ") + ")");
+    if (!this.uri.equals(uri) || this.guid != guid) {
       return;
     }
-    this.callback(aTime, aTransitionType, aLastKnownTitle);
+    this.callback(time, transitionType, lastKnownTitle);
   },
 };
 
 /**
  * Tests that a title was set properly in the database.
  *
  * @param aURI
  *        The uri to check.
@@ -970,17 +977,19 @@ add_task(async function test_title_chang
         resolve();
       }
     });
     PlacesUtils.history.addObserver(titleChangeObserver);
   });
 
   let visitPromise = new Promise(resolve => {
     PlacesUtils.history.addObserver({
-      onVisit(uri) {
+      onVisits(visits) {
+        Assert.equal(visits.length, 1, "Should only get notified for one visit.");
+        let {uri} = visits[0];
         Assert.equal(uri.spec, place.uri.spec, "Should get notified for visiting the new URI.");
         PlacesUtils.history.removeObserver(this);
         resolve();
       }
     });
   });
   PlacesUtils.asyncHistory.updatePlaces(place);
   await visitPromise;
--- a/toolkit/components/places/tests/history/test_remove.js
+++ b/toolkit/components/places/tests/history/test_remove.js
@@ -39,18 +39,18 @@ add_task(async function test_remove_sing
     }
 
     let shouldRemove = !options.addBookmark;
     let observer;
     let promiseObserved = new Promise((resolve, reject) => {
       observer = {
         onBeginUpdateBatch() {},
         onEndUpdateBatch() {},
-        onVisit(aUri) {
-          reject(new Error("Unexpected call to onVisit " + aUri.spec));
+        onVisits(aVisits) {
+          reject(new Error("Unexpected call to onVisits " + aVisits.length));
         },
         onTitleChanged(aUri) {
           reject(new Error("Unexpected call to onTitleChanged " + aUri.spec));
         },
         onClearHistory() {
           reject("Unexpected call to onClearHistory");
         },
         onPageChanged(aUri) {
--- a/toolkit/components/places/tests/history/test_removeByFilter.js
+++ b/toolkit/components/places/tests/history/test_removeByFilter.js
@@ -281,18 +281,18 @@ function getObserverPromise(bookmarkedUr
   if (!bookmarkedUri) {
     return { observer: null, promiseObserved: Promise.resolve() };
   }
   let observer;
   let promiseObserved = new Promise((resolve, reject) => {
     observer = {
       onBeginUpdateBatch() {},
       onEndUpdateBatch() {},
-      onVisit(aUri) {
-        reject(new Error("Unexpected call to onVisit"));
+      onVisits() {
+        reject(new Error("Unexpected call to onVisits"));
       },
       onTitleChanged(aUri) {
         reject(new Error("Unexpected call to onTitleChanged"));
       },
       onClearHistory() {
         reject(new Error("Unexpected call to onClearHistory"));
       },
       onPageChanged(aUri) {
--- a/toolkit/components/places/tests/history/test_removeMany.js
+++ b/toolkit/components/places/tests/history/test_removeMany.js
@@ -69,18 +69,18 @@ add_task(async function test_remove_many
       keys.push(pages[i].guid);
       keys.push(("guid_" + i + "_01234567890").substr(0, 12));
     }
   }
 
   let observer = {
     onBeginUpdateBatch() {},
     onEndUpdateBatch() {},
-    onVisit(aURI) {
-      Assert.ok(false, "Unexpected call to onVisit " + aURI.spec);
+    onVisits(aVisits) {
+      Assert.ok(false, "Unexpected call to onVisits " + aVisits.length);
     },
     onTitleChanged(aURI) {
       Assert.ok(false, "Unexpected call to onTitleChanged " + aURI.spec);
     },
     onClearHistory() {
       Assert.ok(false, "Unexpected call to onClearHistory");
     },
     onPageChanged(aURI) {
--- a/toolkit/components/places/tests/history/test_removeVisitsByFilter.js
+++ b/toolkit/components/places/tests/history/test_removeVisitsByFilter.js
@@ -129,18 +129,18 @@ add_task(async function test_removeVisit
         uriDeletePromises.set(removedItems[i].uri.spec, PromiseUtils.defer());
       }
     }
 
     let observer = {
       deferred: PromiseUtils.defer(),
       onBeginUpdateBatch() {},
       onEndUpdateBatch() {},
-      onVisit(uri) {
-        this.deferred.reject(new Error("Unexpected call to onVisit " + uri.spec));
+      onVisits(aVisits) {
+        this.deferred.reject(new Error("Unexpected call to onVisits " + aVisits.length));
       },
       onTitleChanged(uri) {
         this.deferred.reject(new Error("Unexpected call to onTitleChanged " + uri.spec));
       },
       onClearHistory() {
         this.deferred.reject("Unexpected call to onClearHistory");
       },
       onPageChanged(uri) {
--- a/toolkit/components/places/tests/queries/test_history_queries_titles_liveUpdate.js
+++ b/toolkit/components/places/tests/queries/test_history_queries_titles_liveUpdate.js
@@ -179,20 +179,25 @@ add_task(async function visits_searchter
   options.resultType = Ci.nsINavHistoryQueryOptions.RESULTS_AS_VISIT;
   let root = PlacesUtils.history.executeQuery(query, options).root;
   root.containerOpen = true;
   compareArrayToResult([], root);
   for (let data of gTestData) {
     let uri = NetUtil.newURI(data.uri);
     let origTitle = data.title;
     data.title = "match";
+
+    info("Adding " + uri.spec);
     await PlacesTestUtils.addVisits({ uri, title: data.title,
                                       visitDate: data.lastVisit });
+
     compareArrayToResult([data], root);
     data.title = origTitle;
+    info("Clobbering " + uri.spec);
     await PlacesTestUtils.addVisits({ uri, title: data.title,
                                       visitDate: data.lastVisit });
+
     compareArrayToResult([], root);
   }
 
   root.containerOpen = false;
   await PlacesTestUtils.clearHistory();
 });
--- a/toolkit/components/places/tests/unit/nsDummyObserver.js
+++ b/toolkit/components/places/tests/unit/nsDummyObserver.js
@@ -12,17 +12,17 @@ const Ci = Components.interfaces;
 function DummyObserver() {
   Services.obs.notifyObservers(null, "dummy-observer-created");
 }
 
 DummyObserver.prototype = {
   // history observer
   onBeginUpdateBatch() {},
   onEndUpdateBatch() {},
-  onVisit(aURI, aVisitID, aTime, aSessionID, aReferringID, aTransitionType) {
+  onVisits(aVisits) {
     Services.obs.notifyObservers(null, "dummy-observer-visited");
   },
   onTitleChanged() {},
   onDeleteURI() {},
   onClearHistory() {},
   onPageChanged() {},
   onDeleteVisits() {},
 
--- a/toolkit/components/places/tests/unit/test_download_history.js
+++ b/toolkit/components/places/tests/unit/test_download_history.js
@@ -17,19 +17,34 @@ const PRIVATE_URI = NetUtil.newURI("http
  * Waits for the first visit notification to be received.
  *
  * @param aCallback
  *        Callback function to be called with the same arguments of onVisit.
  */
 function waitForOnVisit(aCallback) {
   let historyObserver = {
     __proto__: NavHistoryObserver.prototype,
-    onVisit: function HO_onVisit() {
+    onVisits: function HO_onVisit(aVisits) {
+      Assert.equal(aVisits.length, 1, "Right number of visits notified");
+      let {
+        uri,
+        visitId,
+        time,
+        referrerId,
+        transitionType,
+        guid,
+        hidden,
+        visitCount,
+        typed,
+        lastKnownTitle,
+      } = aVisits[0];
       PlacesUtils.history.removeObserver(this);
-      aCallback.apply(null, arguments);
+      aCallback(uri, visitId, time, 0, referrerId,
+                transitionType, guid, hidden, visitCount,
+                typed, lastKnownTitle);
     }
   };
   PlacesUtils.history.addObserver(historyObserver);
 }
 
 /**
  * Waits for the first onDeleteURI notification to be received.
  *
@@ -154,17 +169,17 @@ add_test(function test_dh_addDownload_re
 
       PlacesTestUtils.clearHistory().then(run_next_test);
     });
 
     gDownloadHistory.addDownload(DOWNLOAD_URI, REFERRER_URI, Date.now() * 1000);
   });
 
   // Note that we don't pass the optional callback argument here because we must
-  // ensure that we receive the onVisit notification before we call addDownload.
+  // ensure that we receive the onVisits notification before we call addDownload.
   PlacesUtils.asyncHistory.updatePlaces({
     uri: REFERRER_URI,
     visits: [{
       transitionType: Ci.nsINavHistoryService.TRANSITION_TYPED,
       visitDate: Date.now() * 1000
     }]
   });
 });
@@ -233,17 +248,17 @@ add_test(function test_dh_details() {
     onItemAnnotationSet() {},
     onPageAnnotationRemoved() {},
     onItemAnnotationRemoved() {}
   };
 
   let historyObserver = {
     onBeginUpdateBatch() {},
     onEndUpdateBatch() {},
-    onVisit() {},
+    onVisits() {},
     onTitleChanged: function HO_onTitleChanged(aURI, aPageTitle) {
       if (aURI.equals(SOURCE_URI)) {
         titleSet = true;
         Assert.equal(aPageTitle, DEST_FILE_NAME);
         checkFinished();
       }
     },
     onDeleteURI() {},
--- a/toolkit/components/places/tests/unit/test_history_catobs.js
+++ b/toolkit/components/places/tests/unit/test_history_catobs.js
@@ -9,17 +9,19 @@ add_task(async function() {
   promises.push(TestUtils.topicObserved("dummy-observer-created", () => ++resolved));
   promises.push(TestUtils.topicObserved("dummy-observer-visited", () => ++resolved));
 
   let initialObservers = PlacesUtils.history.getObservers();
 
   // Add a common observer, it should be invoked after the category observer.
   promises.push(new Promise(resolve => {
     let observer = new NavHistoryObserver();
-    observer.onVisit = uri => {
+    observer.onVisits = visits => {
+      Assert.equal(visits.length, 1, "Got the right number of visits");
+      let uri = visits[0].uri;
       info("Got visit for " + uri.spec);
       let observers = PlacesUtils.history.getObservers();
       let observersCount = observers.length;
       Assert.ok(observersCount > initialObservers.length);
 
       // Check the common observer is the last one.
       for (let i = 0; i < initialObservers.length; ++i) {
         Assert.equal(initialObservers[i], observers[i]);
--- a/toolkit/components/places/tests/unit/test_history_observer.js
+++ b/toolkit/components/places/tests/unit/test_history_observer.js
@@ -5,17 +5,17 @@
  * Generic nsINavHistoryObserver that doesn't implement anything, but provides
  * dummy methods to prevent errors about an object not having a certain method.
  */
 function NavHistoryObserver() {
 }
 NavHistoryObserver.prototype = {
   onBeginUpdateBatch() { },
   onEndUpdateBatch() { },
-  onVisit() { },
+  onVisits() { },
   onTitleChanged() { },
   onDeleteURI() { },
   onClearHistory() { },
   onPageChanged() { },
   onDeleteVisits() { },
   QueryInterface: XPCOMUtils.generateQI([Ci.nsINavHistoryObserver])
 };
 
@@ -45,97 +45,95 @@ async function task_add_visit(uri, times
   await PlacesTestUtils.addVisits({
     uri,
     transition: transition || TRANSITION_TYPED,
     visitDate: timestamp
   });
   return [uri, timestamp];
 }
 
-add_task(async function test_onVisit() {
-  let promiseNotify = onNotify(function onVisit(aURI, aVisitID, aTime,
-                                                aSessionID, aReferringID,
-                                                aTransitionType, aGUID,
-                                                aHidden, aVisitCount, aTyped) {
-    Assert.ok(aURI.equals(testuri));
-    Assert.ok(aVisitID > 0);
-    Assert.equal(aTime, testtime);
-    Assert.equal(aSessionID, 0);
-    Assert.equal(aReferringID, 0);
-    Assert.equal(aTransitionType, TRANSITION_TYPED);
-    do_check_guid_for_uri(aURI, aGUID);
-    Assert.ok(!aHidden);
-    Assert.equal(aVisitCount, 1);
-    Assert.equal(aTyped, 1);
+add_task(async function test_onVisits() {
+  let promiseNotify = onNotify(function onVisits(aVisits) {
+    Assert.equal(aVisits.length, 1, "Right number of visits notified");
+    let visit = aVisits[0];
+    Assert.ok(visit.uri.equals(testuri));
+    Assert.ok(visit.visitId > 0);
+    Assert.equal(visit.time, testtime);
+    Assert.equal(visit.referrerId, 0);
+    Assert.equal(visit.transitionType, TRANSITION_TYPED);
+    do_check_guid_for_uri(visit.uri, visit.guid);
+    Assert.ok(!visit.hidden);
+    Assert.equal(visit.visitCount, 1);
+    Assert.equal(visit.typed, 1);
   });
   let testuri = NetUtil.newURI("http://firefox.com/");
   let testtime = Date.now() * 1000;
   await task_add_visit(testuri, testtime);
   await promiseNotify;
 });
 
-add_task(async function test_onVisit() {
-  let promiseNotify = onNotify(function onVisit(aURI, aVisitID, aTime,
-                                                aSessionID, aReferringID,
-                                                aTransitionType, aGUID,
-                                                aHidden, aVisitCount, aTyped) {
-    Assert.ok(aURI.equals(testuri));
-    Assert.ok(aVisitID > 0);
-    Assert.equal(aTime, testtime);
-    Assert.equal(aSessionID, 0);
-    Assert.equal(aReferringID, 0);
-    Assert.equal(aTransitionType, TRANSITION_FRAMED_LINK);
-    do_check_guid_for_uri(aURI, aGUID);
-    Assert.ok(aHidden);
-    Assert.equal(aVisitCount, 1);
-    Assert.equal(aTyped, 0);
+add_task(async function test_onVisits() {
+  let promiseNotify = onNotify(function onVisits(aVisits) {
+    Assert.equal(aVisits.length, 1, "Right number of visits notified");
+    let visit = aVisits[0];
+    Assert.ok(visit.uri.equals(testuri));
+    Assert.ok(visit.visitId > 0);
+    Assert.equal(visit.time, testtime);
+    Assert.equal(visit.referrerId, 0);
+    Assert.equal(visit.transitionType, TRANSITION_FRAMED_LINK);
+    do_check_guid_for_uri(visit.uri, visit.guid);
+    Assert.ok(visit.hidden);
+    Assert.equal(visit.visitCount, 1);
+    Assert.equal(visit.typed, 0);
   });
   let testuri = NetUtil.newURI("http://hidden.firefox.com/");
   let testtime = Date.now() * 1000;
   await task_add_visit(testuri, testtime, TRANSITION_FRAMED_LINK);
   await promiseNotify;
 });
 
 add_task(async function test_multiple_onVisit() {
   let testuri = NetUtil.newURI("http://self.firefox.com/");
   let promiseNotifications = new Promise(resolve => {
     let observer = {
-      _c: 0,
       __proto__: NavHistoryObserver.prototype,
-      onVisit(uri, id, time, unused, referrerId, transition, guid,
-              hidden, visitCount, typed) {
-        Assert.ok(testuri.equals(uri));
-        Assert.ok(id > 0);
-        Assert.ok(time > 0);
-        Assert.ok(!hidden);
-        do_check_guid_for_uri(uri, guid);
-        switch (++this._c) {
-          case 1:
-            Assert.equal(referrerId, 0);
-            Assert.equal(transition, TRANSITION_LINK);
-            Assert.equal(visitCount, 1);
-            Assert.equal(typed, 0);
-            break;
-          case 2:
-            Assert.ok(referrerId > 0);
-            Assert.equal(transition, TRANSITION_LINK);
-            Assert.equal(visitCount, 2);
-            Assert.equal(typed, 0);
-            break;
-          case 3:
-            Assert.equal(referrerId, 0);
-            Assert.equal(transition, TRANSITION_TYPED);
-            Assert.equal(visitCount, 3);
-            Assert.equal(typed, 1);
+      onVisits(aVisits) {
+        Assert.equal(aVisits.length, 3, "Right number of visits notified");
+        for (let i = 0; i < aVisits.length; i++) {
+          let visit = aVisits[i];
+          Assert.ok(testuri.equals(visit.uri));
+          Assert.ok(visit.visitId > 0);
+          Assert.ok(visit.time > 0);
+          Assert.ok(!visit.hidden);
+          do_check_guid_for_uri(visit.uri, visit.guid);
+          switch (i) {
+            case 0:
+              Assert.equal(visit.referrerId, 0);
+              Assert.equal(visit.transitionType, TRANSITION_LINK);
+              Assert.equal(visit.visitCount, 1);
+              Assert.equal(visit.typed, 0);
+              break;
+            case 1:
+              Assert.ok(visit.referrerId > 0);
+              Assert.equal(visit.transitionType, TRANSITION_LINK);
+              Assert.equal(visit.visitCount, 2);
+              Assert.equal(visit.typed, 0);
+              break;
+            case 2:
+              Assert.equal(visit.referrerId, 0);
+              Assert.equal(visit.transitionType, TRANSITION_TYPED);
+              Assert.equal(visit.visitCount, 3);
+              Assert.equal(visit.typed, 1);
 
-            PlacesUtils.history.removeObserver(observer, false);
-            resolve();
-            break;
+              PlacesUtils.history.removeObserver(observer, false);
+              resolve();
+              break;
+          }
         }
-      }
+      },
     };
     PlacesUtils.history.addObserver(observer);
   });
   await PlacesTestUtils.addVisits([
     { uri: testuri, transition: TRANSITION_LINK },
     { uri: testuri, referrer: testuri, transition: TRANSITION_LINK },
     { uri: testuri, transition: TRANSITION_TYPED },
   ]);
--- a/toolkit/components/places/tests/unit/test_markpageas.js
+++ b/toolkit/components/places/tests/unit/test_markpageas.js
@@ -22,16 +22,34 @@ add_task(async function test_execute() {
         Assert.equal(aURI.spec, gVisits[this._visitCount].url);
         Assert.equal(aTransitionType, gVisits[this._visitCount].transition);
         this._visitCount++;
 
         if (this._visitCount == gVisits.length) {
           resolveCompletionPromise();
         }
       },
+      onVisits(aVisits) {
+        Assert.equal(aVisits.length, 1, "Right number of visits notified");
+        let {
+          uri,
+          visitId,
+          time,
+          referrerId,
+          transitionType,
+          guid,
+          hidden,
+          visitCount,
+          typed,
+          lastKnownTitle,
+        } = aVisits[0];
+        this.onVisit(uri, visitId, time, 0, referrerId,
+                     transitionType, guid, hidden, visitCount,
+                     typed, lastKnownTitle);
+      },
     };
   });
 
   PlacesUtils.history.addObserver(observer);
 
   for (var visit of gVisits) {
     if (visit.transition == TRANSITION_TYPED)
       PlacesUtils.history.markPageAsTyped(uri(visit.url));