Bug 455553 - Part 5 - New Tab Page tests and test suite; r=dietrich
☠☠ backed out by 84c998ef1689 ☠ ☠
authorTim Taubert <tim.taubert@gmx.de>
Fri, 20 Jan 2012 02:43:20 +0100
changeset 86169 c389d719d4ec42911c0ae0ddaf4f770053dcb6ab
parent 86168 34e078df2ed6616b203661efcaff990990e2e5a9
child 86170 84c998ef1689174fa1b1d26b4b95066963b90ac8
push id805
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 18:17:35 +0000
treeherdermozilla-aurora@6fb3bf232436 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdietrich
bugs455553
milestone12.0a1
Bug 455553 - Part 5 - New Tab Page tests and test suite; r=dietrich
browser/base/content/test/Makefile.in
browser/base/content/test/newtab/Makefile.in
browser/base/content/test/newtab/browser_newtab_block.js
browser/base/content/test/newtab/browser_newtab_disable.js
browser/base/content/test/newtab/browser_newtab_drag_drop.js
browser/base/content/test/newtab/browser_newtab_drop_preview.js
browser/base/content/test/newtab/browser_newtab_private_browsing.js
browser/base/content/test/newtab/browser_newtab_reset.js
browser/base/content/test/newtab/browser_newtab_tabsync.js
browser/base/content/test/newtab/browser_newtab_unpin.js
browser/base/content/test/newtab/head.js
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -35,16 +35,20 @@
 # ***** END LICENSE BLOCK *****
 
 DEPTH		= ../../../..
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = browser/base/content/test
 
+DIRS += \
+		newtab \
+		$(NULL)
+
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES = \
 		test_feed_discovery.html \
 		feed_discovery.html \
 		test_bug395533.html \
 		bug395533-data.txt \
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/newtab/Makefile.in
@@ -0,0 +1,27 @@
+# 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/.
+
+DEPTH		= ../../../../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+relativesrcdir  = browser/base/content/test/newtab
+
+include $(DEPTH)/config/autoconf.mk
+include $(topsrcdir)/config/rules.mk
+
+_BROWSER_FILES = \
+	browser_newtab_block.js \
+	browser_newtab_disable.js \
+	browser_newtab_drag_drop.js \
+	browser_newtab_drop_preview.js \
+	browser_newtab_private_browsing.js \
+	browser_newtab_reset.js \
+	browser_newtab_tabsync.js \
+	browser_newtab_unpin.js \
+	head.js \
+	$(NULL)
+
+libs::	$(_BROWSER_FILES)
+	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/newtab/browser_newtab_block.js
@@ -0,0 +1,61 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/*
+ * These tests make sure that blocking/removing sites from the grid works
+ * as expected. Pinned tabs should not be moved. Gaps will be re-filled
+ * if more sites are available.
+ */
+function runTests() {
+  // we remove sites and expect the gaps to be filled as long as there still
+  // are some sites available
+  setLinks("0,1,2,3,4,5,6,7,8,9");
+  setPinnedLinks("");
+
+  yield addNewTabPageTab();
+  checkGrid("0,1,2,3,4,5,6,7,8");
+
+  yield blockCell(cells[4]);
+  checkGrid("0,1,2,3,5,6,7,8,9");
+
+  yield blockCell(cells[4]);
+  checkGrid("0,1,2,3,6,7,8,9,");
+
+  yield blockCell(cells[4]);
+  checkGrid("0,1,2,3,7,8,9,,");
+
+  // we removed a pinned site
+  reset();
+  setLinks("0,1,2,3,4,5,6,7,8");
+  setPinnedLinks(",1");
+
+  yield addNewTabPageTab();
+  checkGrid("0,1p,2,3,4,5,6,7,8");
+
+  yield blockCell(cells[1]);
+  checkGrid("0,2,3,4,5,6,7,8,");
+
+  // we remove the last site on the grid (which is pinned) and expect the gap
+  // to be re-filled and the new site to be unpinned
+  reset();
+  setLinks("0,1,2,3,4,5,6,7,8,9");
+  setPinnedLinks(",,,,,,,,8");
+
+  yield addNewTabPageTab();
+  checkGrid("0,1,2,3,4,5,6,7,8p");
+
+  yield blockCell(cells[8]);
+  checkGrid("0,1,2,3,4,5,6,7,9");
+
+  // we remove the first site on the grid with the last one pinned. all cells
+  // but the last one should shift to the left and a new site fades in
+  reset();
+  setLinks("0,1,2,3,4,5,6,7,8,9");
+  setPinnedLinks(",,,,,,,,8");
+
+  yield addNewTabPageTab();
+  checkGrid("0,1,2,3,4,5,6,7,8p");
+
+  yield blockCell(cells[0]);
+  checkGrid("1,2,3,4,5,6,7,9,8p");
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/newtab/browser_newtab_disable.js
@@ -0,0 +1,34 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/*
+ * These tests make sure that the 'New Tab Page' feature can be disabled if the
+ * decides not to use it.
+ */
+function runTests() {
+  // create a new tab page and hide it.
+  setLinks("0,1,2,3,4,5,6,7,8");
+  setPinnedLinks("");
+
+  yield addNewTabPageTab();
+  let gridNode = cw.gGrid.node;
+
+  ok(!gridNode.hasAttribute("page-disabled"), "page is not disabled");
+
+  cw.gToolbar.hide();
+  ok(gridNode.hasAttribute("page-disabled"), "page is disabled");
+
+  let oldGridNode = cw.gGrid.node;
+
+  // create a second new tage page and make sure it's disabled. enable it
+  // again and check if the former page gets enabled as well.
+  yield addNewTabPageTab();
+  ok(gridNode.hasAttribute("page-disabled"), "page is disabled");
+
+  // check that no sites have been rendered
+  is(0, cw.document.querySelectorAll(".site").length, "no sites have been rendered");
+
+  cw.gToolbar.show();
+  ok(!gridNode.hasAttribute("page-disabled"), "page is not disabled");
+  ok(!oldGridNode.hasAttribute("page-disabled"), "old page is not disabled");
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/newtab/browser_newtab_drag_drop.js
@@ -0,0 +1,115 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/*
+ * These tests make sure that dragging and dropping sites works as expected.
+ * Sites contained in the grid need to shift around to indicate the result
+ * of the drag-and-drop operation. If the grid is full and we're dragging
+ * a new site into it another one gets pushed out.
+ */
+function runTests() {
+  // test a simple drag-and-drop scenario
+  setLinks("0,1,2,3,4,5,6,7,8");
+  setPinnedLinks("");
+
+  yield addNewTabPageTab();
+  checkGrid("0,1,2,3,4,5,6,7,8");
+
+  yield simulateDrop(cells[1], cells[0]);
+  checkGrid("1,0p,2,3,4,5,6,7,8");
+
+  // drag a cell to its current cell and make sure it's not pinned afterwards
+  setLinks("0,1,2,3,4,5,6,7,8");
+  setPinnedLinks("");
+
+  yield addNewTabPageTab();
+  checkGrid("0,1,2,3,4,5,6,7,8");
+
+  yield simulateDrop(cells[0], cells[0]);
+  checkGrid("0,1,2,3,4,5,6,7,8");
+
+  // ensure that pinned pages aren't moved if that's not necessary
+  setLinks("0,1,2,3,4,5,6,7,8");
+  setPinnedLinks(",1,2");
+
+  yield addNewTabPageTab();
+  checkGrid("0,1p,2p,3,4,5,6,7,8");
+
+  yield simulateDrop(cells[3], cells[0]);
+  checkGrid("3,1p,2p,0p,4,5,6,7,8");
+
+  // pinned sites should always be moved around as blocks. if a pinned site is
+  // moved around, neighboring pinned are affected as well
+  setLinks("0,1,2,3,4,5,6,7,8");
+  setPinnedLinks("0,1");
+
+  yield addNewTabPageTab();
+  checkGrid("0p,1p,2,3,4,5,6,7,8");
+
+  yield simulateDrop(cells[0], cells[2]);
+  checkGrid("2p,0p,1p,3,4,5,6,7,8");
+
+  // pinned sites should not be pushed out of the grid (unless there are only
+  // pinned ones left on the grid)
+  setLinks("0,1,2,3,4,5,6,7,8");
+  setPinnedLinks(",,,,,,,7,8");
+
+  yield addNewTabPageTab();
+  checkGrid("0,1,2,3,4,5,6,7p,8p");
+
+  yield simulateDrop(cells[8], cells[2]);
+  checkGrid("0,1,3,4,5,6,7p,8p,2p");
+
+  // make sure that pinned sites are re-positioned correctly
+  setLinks("0,1,2,3,4,5,6,7,8");
+  setPinnedLinks("0,1,2,,,5");
+
+  yield addNewTabPageTab();
+  checkGrid("0p,1p,2p,3,4,5p,6,7,8");
+
+  yield simulateDrop(cells[4], cells[0]);
+  checkGrid("3,1p,2p,4,0p,5p,6,7,8");
+
+  // drag a new site onto the very first cell
+  setLinks("0,1,2,3,4,5,6,7,8");
+  setPinnedLinks(",,,,,,,7,8");
+
+  yield addNewTabPageTab();
+  checkGrid("0,1,2,3,4,5,6,7p,8p");
+
+  yield simulateDrop(cells[0]);
+  checkGrid("99p,0,1,2,3,4,5,7p,8p");
+
+  // drag a new site onto the grid and make sure that pinned cells don't get
+  // pushed out
+  setLinks("0,1,2,3,4,5,6,7,8");
+  setPinnedLinks(",,,,,,,7,8");
+
+  yield addNewTabPageTab();
+  checkGrid("0,1,2,3,4,5,6,7p,8p");
+
+  yield simulateDrop(cells[7]);
+  checkGrid("0,1,2,3,4,5,7p,99p,8p");
+
+  // drag a new site beneath a pinned cell and make sure the pinned cell is
+  // not moved
+  setLinks("0,1,2,3,4,5,6,7,8");
+  setPinnedLinks(",,,,,,,,8");
+
+  yield addNewTabPageTab();
+  checkGrid("0,1,2,3,4,5,6,7,8p");
+
+  yield simulateDrop(cells[7]);
+  checkGrid("0,1,2,3,4,5,6,99p,8p");
+
+  // drag a new site onto a block of pinned sites and make sure they're shifted
+  // around accordingly
+  setLinks("0,1,2,3,4,5,6,7,8");
+  setPinnedLinks("0,1,2,,,,,,");
+
+  yield addNewTabPageTab();
+  checkGrid("0p,1p,2p");
+
+  yield simulateDrop(cells[1]);
+  checkGrid("0p,99p,1p,2p,3,4,5,6,7");
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/newtab/browser_newtab_drop_preview.js
@@ -0,0 +1,21 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/*
+ * These tests ensure that the drop preview correctly arranges sites when
+ * dragging them around.
+ */
+function runTests() {
+  // the first three sites are pinned - make sure they're re-arranged correctly
+  setLinks("0,1,2,3,4,5,6,7,8");
+  setPinnedLinks("0,1,2,,,5");
+
+  yield addNewTabPageTab();
+  checkGrid("0p,1p,2p,3,4,5p,6,7,8");
+
+  cw.gDrag._draggedSite = cells[0].site;
+  let sites = cw.gDropPreview.rearrange(cells[4]);
+  cw.gDrag._draggedSite = null;
+
+  checkGrid("3,1p,2p,4,0p,5p,6,7,8", sites);
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/newtab/browser_newtab_private_browsing.js
@@ -0,0 +1,54 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/*
+ * These tests ensure that all changes made to the new tab page in private
+ * browsing mode are discarded after switching back to normal mode again.
+ * The private browsing mode should start with the current grid shown in normal
+ * mode.
+ */
+let pb = Cc["@mozilla.org/privatebrowsing;1"]
+         .getService(Ci.nsIPrivateBrowsingService);
+
+function runTests() {
+  // prepare the grid
+  setLinks("0,1,2,3,4,5,6,7,8,9");
+  ok(!pb.privateBrowsingEnabled, "private browsing is disabled");
+
+  yield addNewTabPageTab();
+  pinCell(cells[0]);
+  checkGrid("0p,1,2,3,4,5,6,7,8");
+
+  // enter private browsing mode
+  yield togglePrivateBrowsing();
+  ok(pb.privateBrowsingEnabled, "private browsing is enabled");
+
+  yield addNewTabPageTab();
+  checkGrid("0p,1,2,3,4,5,6,7,8");
+
+  // modify the grid while we're in pb mode
+  yield blockCell(cells[1]);
+  checkGrid("0p,2,3,4,5,6,7,8");
+
+  yield unpinCell(cells[0]);
+  checkGrid("0,2,3,4,5,6,7,8");
+
+  // exit private browsing mode
+  yield togglePrivateBrowsing();
+  ok(!pb.privateBrowsingEnabled, "private browsing is disabled");
+
+  // check that the grid is the same as before entering pb mode
+  yield addNewTabPageTab();
+  checkGrid("0p,1,2,3,4,5,6,7,8");
+}
+
+function togglePrivateBrowsing() {
+  let topic = "private-browsing-transition-complete";
+
+  Services.obs.addObserver(function observe() {
+    Services.obs.removeObserver(observe, topic);
+    executeSoon(TestRunner.next);
+  }, topic, false);
+
+  pb.privateBrowsingEnabled = !pb.privateBrowsingEnabled;
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/newtab/browser_newtab_reset.js
@@ -0,0 +1,25 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/*
+ * These tests make sure that resetting the 'New Tage Page' works as expected.
+ */
+function runTests() {
+  // create a new tab page and check its modified state after blocking a site
+  setLinks("0,1,2,3,4,5,6,7,8");
+  setPinnedLinks("");
+
+  yield addNewTabPageTab();
+  let resetButton = cw.document.getElementById("toolbar-button-reset");
+
+  checkGrid("0,1,2,3,4,5,6,7,8");
+  ok(!resetButton.hasAttribute("modified"), "page is not modified");
+
+  yield blockCell(cells[4]);
+  checkGrid("0,1,2,3,5,6,7,8,");
+  ok(resetButton.hasAttribute("modified"), "page is modified");
+
+  yield cw.gToolbar.reset(TestRunner.next);
+  checkGrid("0,1,2,3,4,5,6,7,8");
+  ok(!resetButton.hasAttribute("modified"), "page is not modified");
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/newtab/browser_newtab_tabsync.js
@@ -0,0 +1,58 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/*
+ * These tests make sure that all changes that are made to a specific
+ * 'New Tab Page' are synchronized with all other open 'New Tab Pages'
+ * automatically. All about:newtab pages should always be in the same
+ * state.
+ */
+function runTests() {
+  setLinks("0,1,2,3,4,5,6,7,8,9");
+  setPinnedLinks(",1");
+
+  yield addNewTabPageTab();
+  checkGrid("0,1p,2,3,4,5,6,7,8");
+
+  let resetButton = cw.document.getElementById("toolbar-button-reset");
+  ok(!resetButton.hasAttribute("modified"), "page is not modified");
+
+  let oldCw = cw;
+  let oldResetButton = resetButton;
+
+  // create the new tab page
+  yield addNewTabPageTab();
+  checkGrid("0,1p,2,3,4,5,6,7,8");
+
+  resetButton = cw.document.getElementById("toolbar-button-reset");
+  ok(!resetButton.hasAttribute("modified"), "page is not modified");
+
+  // unpin a cell
+  yield unpinCell(cells[1]);
+  checkGrid("0,1,2,3,4,5,6,7,8");
+  checkGrid("0,1,2,3,4,5,6,7,8", oldCw.gGrid.sites);
+
+  // remove a cell
+  yield blockCell(cells[1]);
+  checkGrid("0,2,3,4,5,6,7,8,9");
+  checkGrid("0,2,3,4,5,6,7,8,9", oldCw.gGrid.sites);
+  ok(resetButton.hasAttribute("modified"), "page is modified");
+  ok(oldResetButton.hasAttribute("modified"), "page is modified");
+
+  // insert a new cell by dragging
+  yield simulateDrop(cells[1]);
+  checkGrid("0,99p,2,3,4,5,6,7,8");
+  checkGrid("0,99p,2,3,4,5,6,7,8", oldCw.gGrid.sites);
+
+  // drag a cell around
+  yield simulateDrop(cells[1], cells[2]);
+  checkGrid("0,2p,99p,3,4,5,6,7,8");
+  checkGrid("0,2p,99p,3,4,5,6,7,8", oldCw.gGrid.sites);
+
+  // reset the new tab page
+  yield cw.gToolbar.reset(TestRunner.next);
+  checkGrid("0,1,2,3,4,5,6,7,8");
+  checkGrid("0,1,2,3,4,5,6,7,8", oldCw.gGrid.sites);
+  ok(!resetButton.hasAttribute("modified"), "page is not modified");
+  ok(!oldResetButton.hasAttribute("modified"), "page is not modified");
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/newtab/browser_newtab_unpin.js
@@ -0,0 +1,56 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/*
+ * These tests make sure that when a site gets unpinned it is either moved to
+ * its actual place in the grid or removed in case it's not on the grid anymore.
+ */
+function runTests() {
+  // we have a pinned link that didn't change its position since it was pinned.
+  // nothing should happend when we unpin it.
+  setLinks("0,1,2,3,4,5,6,7,8");
+  setPinnedLinks(",1");
+
+  yield addNewTabPageTab();
+  checkGrid("0,1p,2,3,4,5,6,7,8");
+
+  yield unpinCell(cells[1]);
+  checkGrid("0,1,2,3,4,5,6,7,8");
+
+  // we have a pinned link that is not anymore in the list of the most-visited
+  // links. this should disappear, the remaining links adjust their positions
+  // and a new link will appear at the end of the grid.
+  setLinks("0,1,2,3,4,5,6,7,8");
+  setPinnedLinks(",99");
+
+  yield addNewTabPageTab();
+  checkGrid("0,99p,1,2,3,4,5,6,7");
+
+  yield unpinCell(cells[1]);
+  checkGrid("0,1,2,3,4,5,6,7,8");
+
+  // we have a pinned link that changed its position since it was pinned. it
+  // should be moved to its new position after being unpinned.
+  setLinks("0,1,2,3,4,5,6,7");
+  setPinnedLinks(",1,,,,,,,0");
+
+  yield addNewTabPageTab();
+  checkGrid("2,1p,3,4,5,6,7,,0p");
+
+  yield unpinCell(cells[1]);
+  checkGrid("1,2,3,4,5,6,7,,0p");
+
+  yield unpinCell(cells[8]);
+  checkGrid("0,1,2,3,4,5,6,7,");
+
+  // we have pinned link that changed its position since it was pinned. the
+  // link will disappear from the grid because it's now a much lower priority
+  setLinks("0,1,2,3,4,5,6,7,8,9");
+  setPinnedLinks("9");
+
+  yield addNewTabPageTab();
+  checkGrid("9p,0,1,2,3,4,5,6,7");
+
+  yield unpinCell(cells[0]);
+  checkGrid("0,1,2,3,4,5,6,7,8");
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/newtab/head.js
@@ -0,0 +1,251 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+Cu.import("resource:///modules/NewTabUtils.jsm");
+
+registerCleanupFunction(function () {
+  reset();
+
+  while (gBrowser.tabs.length > 1)
+    gBrowser.removeTab(gBrowser.tabs[1]);
+});
+
+/**
+ * Global variables that are accessed by tests.
+ */
+let cw;
+let cells;
+
+/**
+ * We'll want to restore the original links provider later.
+ */
+let originalProvider = NewTabUtils.links._provider;
+
+/**
+ * Provide the default test function to start our test runner.
+ */
+function test() {
+  TestRunner.run();
+}
+
+/**
+ * The test runner that controls the execution flow of our tests.
+ */
+let TestRunner = {
+  /**
+   * Starts the test runner.
+   */
+  run: function () {
+    waitForExplicitFinish();
+
+    this._iter = runTests();
+    this.next();
+  },
+
+  /**
+   * Runs the next available test or finishes if there's no test left.
+   */
+  next: function () {
+    try {
+      TestRunner._iter.next();
+    } catch (e if e instanceof StopIteration) {
+      finish();
+    }
+  }
+};
+
+/**
+ * Allows to provide a list of links that is used to construct the grid.
+ * @param aLinksPattern the pattern (see below)
+ *
+ * Example: setLinks("1,2,3")
+ * Result: [{url: "about:blank#1", title: "site#1"},
+ *          {url: "about:blank#2", title: "site#2"}
+ *          {url: "about:blank#3", title: "site#3"}]
+ */
+function setLinks(aLinksPattern) {
+  let links = aLinksPattern.split(/\s*,\s*/).map(function (id) {
+    return {url: "about:blank#" + id, title: "site#" + id};
+  });
+
+  NewTabUtils.links._provider = {getLinks: function (c) c(links)};
+  NewTabUtils.links._links = links;
+}
+
+/**
+ * Allows to specify the list of pinned links (that have a fixed position in
+ * the grid.
+ * @param aLinksPattern the pattern (see below)
+ *
+ * Example: setPinnedLinks("3,,1")
+ * Result: 'about:blank#3' is pinned in the first cell. 'about:blank#1' is
+ *         pinned in the third cell.
+ */
+function setPinnedLinks(aLinksPattern) {
+  let pinnedLinks = [];
+
+  aLinksPattern.split(/\s*,\s*/).forEach(function (id, index) {
+    let link;
+
+    if (id)
+      link = {url: "about:blank#" + id, title: "site#" + id};
+
+    pinnedLinks[index] = link;
+  });
+
+  // Inject the list of pinned links to work with.
+  NewTabUtils.pinnedLinks._links = pinnedLinks;
+}
+
+/**
+ * Resets the lists of blocked and pinned links and clears the storage.
+ */
+function reset() {
+  NewTabUtils.reset();
+
+  // Restore the old provider to prevent memory leaks.
+  NewTabUtils.links._provider = originalProvider;
+}
+
+/**
+ * Creates a new tab containing 'about:newtab'.
+ */
+function addNewTabPageTab() {
+  let tab = gBrowser.selectedTab = gBrowser.addTab("about:newtab");
+  let browser = tab.linkedBrowser;
+
+  // Wait for the new tab page to be loaded.
+  browser.addEventListener("load", function onLoad() {
+    browser.removeEventListener("load", onLoad, true);
+
+    cw = browser.contentWindow;
+
+    if (NewTabUtils.allPages.enabled)
+      cells = cw.gGrid.cells;
+
+    TestRunner.next();
+  }, true);
+}
+
+/**
+ * Compares the current grid arrangement with the given pattern.
+ * @param the pattern (see below)
+ * @param the array of sites to compare with (optional)
+ *
+ * Example: checkGrid("3p,2,,1p")
+ * Result: We expect the first cell to contain the pinned site 'about:blank#3'.
+ *         The second cell contains 'about:blank#2'. The third cell is empty.
+ *         The fourth cell contains the pinned site 'about:blank#4'.
+ */
+function checkGrid(aSitesPattern, aSites) {
+  let valid = true;
+
+  aSites = aSites || cw.gGrid.sites;
+
+  aSitesPattern.split(/\s*,\s*/).forEach(function (id, index) {
+    let site = aSites[index];
+    let match = id.match(/^\d+/);
+
+    // We expect the cell to be empty.
+    if (!match) {
+      if (site) {
+        valid = false;
+        ok(false, "expected cell#" + index + " to be empty");
+      }
+
+      return;
+    }
+
+    // We expect the cell to contain a site.
+    if (!site) {
+      valid = false;
+      ok(false, "didn't expect cell#" + index + " to be empty");
+
+      return;
+    }
+
+    let num = match[0];
+
+    // Check the site's url.
+    if (site.url != "about:blank#" + num) {
+      valid = false;
+      is(site.url, "about:blank#" + num, "cell#" + index + " has the wrong url");
+    }
+
+    let shouldBePinned = /p$/.test(id);
+    let cellContainsPinned = site.isPinned();
+    let cssClassPinned = site.node && site.node.hasAttribute("pinned");
+
+    // Check if the site should be and is pinned.
+    if (shouldBePinned) {
+      if (!cellContainsPinned) {
+        valid = false;
+        ok(false, "expected cell#" + index + " to be pinned");
+      } else if (!cssClassPinned) {
+        valid = false;
+        ok(false, "expected cell#" + index + " to have css class 'pinned'");
+      }
+    } else {
+      if (cellContainsPinned) {
+        valid = false;
+        ok(false, "didn't expect cell#" + index + " to be pinned");
+      } else if (cssClassPinned) {
+        valid = false;
+        ok(false, "didn't expect cell#" + index + " to have css class 'pinned'");
+      }
+    }
+  });
+
+  // If every test passed, say so.
+  if (valid)
+    ok(true, "grid status = " + aSitesPattern);
+}
+
+/**
+ * Blocks the given cell's site from the grid.
+ * @param aCell the cell that contains the site to block
+ */
+function blockCell(aCell) {
+  aCell.site.block(function () executeSoon(TestRunner.next));
+}
+
+/**
+ * Pins a given cell's site on a given position.
+ * @param aCell the cell that contains the site to pin
+ * @param aIndex the index the defines where the site should be pinned
+ */
+function pinCell(aCell, aIndex) {
+  aCell.site.pin(aIndex);
+}
+
+/**
+ * Unpins the given cell's site.
+ * @param aCell the cell that contains the site to unpin
+ */
+function unpinCell(aCell) {
+  aCell.site.unpin(function () executeSoon(TestRunner.next));
+}
+
+/**
+ * Simulates a drop and drop operation.
+ * @param aDropTarget the cell that is the drop target
+ * @param aDragSource the cell that contains the dragged site (optional)
+ */
+function simulateDrop(aDropTarget, aDragSource) {
+  let event = {
+    dataTransfer: {
+      mozUserCancelled: false,
+      setData: function () null,
+      setDragImage: function () null,
+      getData: function () "about:blank#99\nblank"
+    }
+  };
+
+  if (aDragSource)
+    cw.gDrag.start(aDragSource.site, event);
+
+  cw.gDrop.drop(aDropTarget, event, function () executeSoon(TestRunner.next));
+
+  if (aDragSource)
+    cw.gDrag.end(aDragSource.site);
+}