1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/browser/metro/base/tests/mochitest/browser_topsites.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,522 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 et sw=2 tw=80: */ 1.6 +/* Any copyright is dedicated to the Public Domain. 1.7 + http://creativecommons.org/publicdomain/zero/1.0/ */ 1.8 + 1.9 +"use strict"; 1.10 + 1.11 +////////////////////////////////////////////////////////////////////////// 1.12 +// Test helpers 1.13 + 1.14 +let TopSitesTestHelper = { 1.15 + get grid() { 1.16 + return Browser.selectedBrowser.contentDocument.getElementById("start-topsites-grid"); 1.17 + }, 1.18 + get document() { 1.19 + return Browser.selectedBrowser.contentDocument; 1.20 + }, 1.21 + setup: function() { 1.22 + return Task.spawn(function(){ 1.23 + if (BrowserUI.isStartTabVisible) 1.24 + return; 1.25 + 1.26 + yield addTab("about:start"); 1.27 + 1.28 + yield waitForCondition(() => BrowserUI.isStartTabVisible); 1.29 + }); 1.30 + }, 1.31 + mockLinks: function th_mockLinks(aLinks) { 1.32 + // create link objects where index. corresponds to grid position 1.33 + // falsy values are set to null 1.34 + let links = (typeof aLinks == "string") ? 1.35 + aLinks.split(/\s*,\s*/) : aLinks; 1.36 + 1.37 + links = links.map(function (id) { 1.38 + return (id) ? {url: "http://example.com/#" + id, title: id} : null; 1.39 + }); 1.40 + return links; 1.41 + }, 1.42 + siteFromNode: function th_siteFromNode(aNode) { 1.43 + return { 1.44 + url: aNode.getAttribute("value"), 1.45 + title: aNode.getAttribute("label") 1.46 + } 1.47 + }, 1.48 + clearHistory: function th_clearHistory() { 1.49 + PlacesUtils.history.removeAllPages(); 1.50 + }, 1.51 + fillHistory: function th_fillHistory(aLinks) { 1.52 + return Task.spawn(function(){ 1.53 + let numLinks = aLinks.length; 1.54 + let transitionLink = Ci.nsINavHistoryService.TRANSITION_LINK; 1.55 + 1.56 + let updateDeferred = Promise.defer(); 1.57 + 1.58 + for (let link of aLinks.reverse()) { 1.59 + let place = { 1.60 + uri: Util.makeURI(link.url), 1.61 + title: link.title, 1.62 + visits: [{visitDate: Date.now() * 1000, transitionType: transitionLink}] 1.63 + }; 1.64 + try { 1.65 + PlacesUtils.asyncHistory.updatePlaces(place, { 1.66 + handleError: function (aError) { 1.67 + ok(false, "couldn't add visit to history"); 1.68 + throw new Task.Result(aError); 1.69 + }, 1.70 + handleResult: function () {}, 1.71 + handleCompletion: function () { 1.72 + if(--numLinks <= 0) { 1.73 + updateDeferred.resolve(true); 1.74 + } 1.75 + } 1.76 + }); 1.77 + } catch(e) { 1.78 + ok(false, "because: " + e); 1.79 + } 1.80 + } 1.81 + return updateDeferred.promise; 1.82 + }); 1.83 + }, 1.84 + 1.85 + /** 1.86 + * Allows to specify the list of pinned links (that have a fixed position in 1.87 + * the grid. 1.88 + * @param aLinksPattern the pattern (see below) 1.89 + * 1.90 + * Example: setPinnedLinks("foo,,bar") 1.91 + * Result: 'http://example.com/#foo' is pinned in the first cell. 'http://example.com/#bar' is 1.92 + * pinned in the third cell. 1.93 + */ 1.94 + setPinnedLinks: function th_setPinnedLinks(aLinks) { 1.95 + let links = TopSitesTestHelper.mockLinks(aLinks); 1.96 + 1.97 + // (we trust that NewTabUtils works, and test our consumption of it) 1.98 + // clear all existing pins 1.99 + Array.forEach(NewTabUtils.pinnedLinks.links, function(aLink){ 1.100 + if(aLink) 1.101 + NewTabUtils.pinnedLinks.unpin(aLink); 1.102 + }); 1.103 + 1.104 + links.forEach(function(aLink, aIndex){ 1.105 + if(aLink) { 1.106 + NewTabUtils.pinnedLinks.pin(aLink, aIndex); 1.107 + } 1.108 + }); 1.109 + NewTabUtils.pinnedLinks.save(); 1.110 + }, 1.111 + 1.112 + /** 1.113 + * Allows to provide a list of links that is used to construct the grid. 1.114 + * @param aLinksPattern the pattern (see below) 1.115 + * @param aPinnedLinksPattern the pattern (see below) 1.116 + * 1.117 + * Example: setLinks("dougal,florence,zebedee") 1.118 + * Result: [{url: "http://example.com/#dougal", title: "dougal"}, 1.119 + * {url: "http://example.com/#florence", title: "florence"} 1.120 + * {url: "http://example.com/#zebedee", title: "zebedee"}] 1.121 + * Example: setLinks("dougal,florence,zebedee","dougal,,zebedee") 1.122 + * Result: http://example.com/#dougal is pinned at index 0, http://example.com/#florence at index 2 1.123 + */ 1.124 + 1.125 + setLinks: function th_setLinks(aLinks, aPinnedLinks) { 1.126 + let links = TopSitesTestHelper.mockLinks(aLinks); 1.127 + if (links.filter(function(aLink){ 1.128 + return !aLink; 1.129 + }).length) { 1.130 + throw new Error("null link objects in setLinks"); 1.131 + } 1.132 + 1.133 + return Task.spawn(function() { 1.134 + TopSitesTestHelper.clearHistory(); 1.135 + 1.136 + yield Task.spawn(TopSitesTestHelper.fillHistory(links)); 1.137 + 1.138 + if(aPinnedLinks) { 1.139 + TopSitesTestHelper.setPinnedLinks(aPinnedLinks); 1.140 + } 1.141 + 1.142 + // reset the TopSites state, have it update its cache with the new data fillHistory put there 1.143 + yield TopSites.prepareCache(true); 1.144 + }); 1.145 + }, 1.146 + 1.147 + updatePagesAndWait: function th_updatePagesAndWait() { 1.148 + let deferredUpdate = Promise.defer(); 1.149 + let updater = { 1.150 + update: function() { 1.151 + NewTabUtils.allPages.unregister(updater); 1.152 + deferredUpdate.resolve(true); 1.153 + } 1.154 + }; 1.155 + NewTabUtils.allPages.register(updater); 1.156 + setTimeout(function() { 1.157 + NewTabUtils.allPages.update(); 1.158 + }, 0); 1.159 + return deferredUpdate.promise; 1.160 + }, 1.161 + 1.162 + tearDown: function th_tearDown() { 1.163 + TopSitesTestHelper.clearHistory(); 1.164 + } 1.165 +}; 1.166 + 1.167 + 1.168 +////////////////////////////////////////////////////////////////////////// 1.169 + 1.170 + 1.171 +function test() { 1.172 + registerCleanupFunction(TopSitesTestHelper.tearDown); 1.173 + runTests(); 1.174 +} 1.175 + 1.176 +gTests.push({ 1.177 + desc: "TopSites dependencies", 1.178 + run: function() { 1.179 + ok(NewTabUtils, "NewTabUtils is truthy"); 1.180 + ok(TopSites, "TopSites is truthy"); 1.181 + } 1.182 +}); 1.183 + 1.184 +gTests.push({ 1.185 + desc: "load and display top sites", 1.186 + setUp: function() { 1.187 + yield TopSitesTestHelper.setup(); 1.188 + let grid = TopSitesTestHelper.grid; 1.189 + 1.190 + // setup - set history to known state 1.191 + yield TopSitesTestHelper.setLinks("brian,dougal,dylan,ermintrude,florence,moose,sgtsam,train,zebedee,zeebad"); 1.192 + 1.193 + let arrangedPromise = waitForEvent(grid, "arranged"); 1.194 + yield TopSitesTestHelper.updatePagesAndWait(); 1.195 + // pause until the update has fired and the view is finishd updating 1.196 + yield arrangedPromise; 1.197 + }, 1.198 + run: function() { 1.199 + let grid = TopSitesTestHelper.grid; 1.200 + let items = grid.items; 1.201 + is(items.length, 8, "should be 8 topsites"); // i.e. not 10 1.202 + if(items.length) { 1.203 + let firstitem = items[0]; 1.204 + is( 1.205 + firstitem.getAttribute("label"), 1.206 + "brian", 1.207 + "first item label should be 'brian': " + firstitem.getAttribute("label") 1.208 + ); 1.209 + is( 1.210 + firstitem.getAttribute("value"), 1.211 + "http://example.com/#brian", 1.212 + "first item url should be 'http://example.com/#brian': " + firstitem.getAttribute("url") 1.213 + ); 1.214 + } 1.215 + } 1.216 +}); 1.217 + 1.218 +gTests.push({ 1.219 + desc: "pinned sites", 1.220 + pins: "dangermouse,zebedee,,,dougal", 1.221 + setUp: function() { 1.222 + yield TopSitesTestHelper.setup(); 1.223 + // setup - set history to known state 1.224 + yield TopSitesTestHelper.setLinks( 1.225 + "brian,dougal,dylan,ermintrude,florence,moose,sgtsam,train,zebedee,zeebad", 1.226 + this.pins 1.227 + ); 1.228 + // pause until the update has fired and the view is finishd updating 1.229 + let arrangedPromise = waitForEvent(TopSitesTestHelper.grid, "arranged"); 1.230 + yield TopSitesTestHelper.updatePagesAndWait(); 1.231 + yield arrangedPromise; 1.232 + }, 1.233 + run: function() { 1.234 + // test that pinned state of each site as rendered matches our expectations 1.235 + let pins = this.pins.split(","); 1.236 + let items = TopSitesTestHelper.grid.items; 1.237 + is(items.length, 8, "should be 8 topsites in the grid"); 1.238 + 1.239 + is(TopSitesTestHelper.document.querySelectorAll("#start-topsites-grid > [pinned]").length, 3, "should be 3 children with 'pinned' attribute"); 1.240 + try { 1.241 + Array.forEach(items, function(aItem, aIndex){ 1.242 + // pinned state should agree with the pins array 1.243 + is( 1.244 + aItem.hasAttribute("pinned"), !!pins[aIndex], 1.245 + "site at index " + aIndex + " was " +aItem.hasAttribute("pinned") 1.246 + +", should agree with " + !!pins[aIndex] 1.247 + ); 1.248 + if (pins[aIndex]) { 1.249 + is( 1.250 + aItem.getAttribute("label"), 1.251 + pins[aIndex], 1.252 + "pinned site has correct label: " + pins[aIndex] +"=="+ aItem.getAttribute("label") 1.253 + ); 1.254 + } 1.255 + }, this); 1.256 + } catch(e) { 1.257 + ok(false, this.desc + ": Test of pinned state on items failed"); 1.258 + info("because: " + e.message + "\n" + e.stack); 1.259 + } 1.260 + } 1.261 +}); 1.262 + 1.263 +gTests.push({ 1.264 + desc: "pin site", 1.265 + setUp: function() { 1.266 + yield TopSitesTestHelper.setup(); 1.267 + // setup - set history to known state 1.268 + yield TopSitesTestHelper.setLinks("sgtsam,train,zebedee,zeebad", []); // nothing initially pinned 1.269 + // pause until the update has fired and the view is finishd updating 1.270 + let arrangedPromise = waitForEvent(TopSitesTestHelper.grid, "arranged"); 1.271 + yield TopSitesTestHelper.updatePagesAndWait(); 1.272 + yield arrangedPromise; 1.273 + }, 1.274 + run: function() { 1.275 + // pin a site 1.276 + // test that site is pinned as expected 1.277 + // and that sites fill positions around it 1.278 + let grid = TopSitesTestHelper.grid, 1.279 + items = grid.items; 1.280 + is(items.length, 4, this.desc + ": should be 4 topsites"); 1.281 + 1.282 + let tile = grid.items[2], 1.283 + url = tile.getAttribute("value"), 1.284 + title = tile.getAttribute("label"); 1.285 + 1.286 + info(this.desc + ": pinning site at index 2"); 1.287 + TopSites.pinSites([{ 1.288 + url: url, 1.289 + title: title 1.290 + }], [2]); 1.291 + 1.292 + // pinning shouldn't require re-arranging - just wait for isUpdating flag to flip 1.293 + yield waitForCondition(function(){ 1.294 + return !grid.controller.isUpdating; 1.295 + }); 1.296 + 1.297 + let thirdTile = grid.items[2]; 1.298 + ok( thirdTile.hasAttribute("pinned"), thirdTile.getAttribute("value")+ " should look pinned" ); 1.299 + 1.300 + // visit some more sites 1.301 + yield TopSitesTestHelper.fillHistory( TopSitesTestHelper.mockLinks("brian,dougal,dylan,ermintrude,florence,moose") ); 1.302 + 1.303 + // force flush and repopulation of links cache 1.304 + yield TopSites.prepareCache(true); 1.305 + // pause until the update has fired and the view is finishd updating 1.306 + let arrangedPromise = waitForEvent(grid, "arranged"); 1.307 + yield TopSitesTestHelper.updatePagesAndWait(); 1.308 + yield arrangedPromise; 1.309 + 1.310 + // check zebedee is still pinned at index 2 1.311 + is( items[2].getAttribute("label"), "zebedee", "Pinned site remained at its index" ); 1.312 + ok( items[2].hasAttribute("pinned"), "3rd site should still look pinned" ); 1.313 + } 1.314 +}); 1.315 + 1.316 +gTests.push({ 1.317 + desc: "unpin site", 1.318 + pins: ",zebedee", 1.319 + setUp: function() { 1.320 + yield TopSitesTestHelper.setup(); 1.321 + // setup - set history to known state 1.322 + yield TopSitesTestHelper.setLinks( 1.323 + "brian,dougal,dylan,ermintrude,florence,moose,sgtsam,train,zebedee,zeebad", 1.324 + this.pins 1.325 + ); 1.326 + // pause until the update has fired and the view is finishd updating 1.327 + let arrangedPromise = waitForEvent(TopSitesTestHelper.grid, "arranged"); 1.328 + yield TopSitesTestHelper.updatePagesAndWait(); 1.329 + yield arrangedPromise; 1.330 + }, 1.331 + run: function() { 1.332 + // unpin a pinned site 1.333 + // test that sites are unpinned as expected 1.334 + let grid = TopSitesTestHelper.grid, 1.335 + items = grid.items; 1.336 + is(items.length, 8, this.desc + ": should be 8 topsites"); 1.337 + let site = { 1.338 + url: items[1].getAttribute("value"), 1.339 + title: items[1].getAttribute("label") 1.340 + }; 1.341 + // verify assumptions before unpinning this site 1.342 + ok( NewTabUtils.pinnedLinks.isPinned(site), "2nd item is pinned" ); 1.343 + ok( items[1].hasAttribute("pinned"), "2nd item has pinned attribute" ); 1.344 + 1.345 + // unpinning shouldn't require re-arranging - just wait for isUpdating flag to flip 1.346 + TopSites.unpinSites([site]); 1.347 + 1.348 + yield waitForCondition(function(){ 1.349 + return !grid.controller.isUpdating; 1.350 + }); 1.351 + 1.352 + let secondTile = grid.items[1]; 1.353 + ok( !secondTile.hasAttribute("pinned"), "2nd item should no longer be marked as pinned" ); 1.354 + ok( !NewTabUtils.pinnedLinks.isPinned(site), "2nd item should no longer be pinned" ); 1.355 + } 1.356 +}); 1.357 + 1.358 +gTests.push({ 1.359 + desc: "block/unblock sites", 1.360 + setUp: function() { 1.361 + yield TopSitesTestHelper.setup(); 1.362 + // setup - set topsites to known state 1.363 + yield TopSitesTestHelper.setLinks( 1.364 + "brian,dougal,dylan,ermintrude,florence,moose,sgtsam,train,zebedee,zeebad,basic,coral", 1.365 + ",dougal" 1.366 + ); 1.367 + // pause until the update has fired and the view is finishd updating 1.368 + let arrangedPromise = waitForEvent(TopSitesTestHelper.grid, "arranged"); 1.369 + yield TopSitesTestHelper.updatePagesAndWait(); 1.370 + yield arrangedPromise; 1.371 + }, 1.372 + run: function() { 1.373 + try { 1.374 + // block a site 1.375 + // test that sites are removed from the grid as expected 1.376 + let grid = TopSitesTestHelper.grid, 1.377 + items = grid.items; 1.378 + is(items.length, 8, this.desc + ": should be 8 topsites"); 1.379 + 1.380 + let brianSite = TopSitesTestHelper.siteFromNode(items[0]); 1.381 + let dougalSite = TopSitesTestHelper.siteFromNode(items[1]); 1.382 + let dylanSite = TopSitesTestHelper.siteFromNode(items[2]); 1.383 + 1.384 + let arrangedPromise = waitForEvent(grid, "arranged"); 1.385 + // we'll block brian (he's not pinned) 1.386 + TopSites.hideSites([brianSite]); 1.387 + // pause until the update has fired and the view is finished updating 1.388 + yield arrangedPromise; 1.389 + 1.390 + // verify brian is blocked and removed from the grid 1.391 + ok( (new Site(brianSite)).blocked, "Site has truthy blocked property" ); 1.392 + ok( NewTabUtils.blockedLinks.isBlocked(brianSite), "Site was blocked" ); 1.393 + is( grid.querySelectorAll("[value='"+brianSite.url+"']").length, 0, "Blocked site was removed from grid"); 1.394 + 1.395 + // make sure the empty slot was backfilled 1.396 + is(items.length, 8, this.desc + ": should be 8 topsites"); 1.397 + 1.398 + arrangedPromise = waitForEvent(grid, "arranged"); 1.399 + // block dougal,dylan. dougal is currently pinned at index 1 1.400 + TopSites.hideSites([dougalSite, dylanSite]); 1.401 + // pause until the update has fired and the view is finished updating 1.402 + yield arrangedPromise; 1.403 + 1.404 + // verify dougal is blocked and removed from the grid 1.405 + ok( (new Site(dougalSite)).blocked, "Site has truthy blocked property" ); 1.406 + ok( NewTabUtils.blockedLinks.isBlocked(dougalSite), "Site was blocked" ); 1.407 + ok( !NewTabUtils.pinnedLinks.isPinned(dougalSite), "Blocked Site is no longer pinned" ); 1.408 + is( grid.querySelectorAll("[value='"+dougalSite.url+"']").length, 0, "Blocked site was removed from grid"); 1.409 + 1.410 + // verify dylan is blocked and removed from the grid 1.411 + ok( (new Site(dylanSite)).blocked, "Site has truthy blocked property" ); 1.412 + ok( NewTabUtils.blockedLinks.isBlocked(dylanSite), "Site was blocked" ); 1.413 + ok( !NewTabUtils.pinnedLinks.isPinned(dylanSite), "Blocked Site is no longer pinned" ); 1.414 + is( grid.querySelectorAll("[value='"+dylanSite.url+"']").length, 0, "Blocked site was removed from grid"); 1.415 + 1.416 + // make sure the empty slots were backfilled 1.417 + is(items.length, 8, this.desc + ": should be 8 topsites"); 1.418 + 1.419 + arrangedPromise = waitForEvent(grid, "arranged"); 1.420 + TopSites.restoreSites([brianSite, dougalSite, dylanSite]); 1.421 + // pause until the update has fired and the view is finished updating 1.422 + yield arrangedPromise; 1.423 + 1.424 + // verify brian, dougal and dyland are unblocked and back in the grid 1.425 + ok( !NewTabUtils.blockedLinks.isBlocked(brianSite), "site was unblocked" ); 1.426 + is( grid.querySelectorAll("[value='"+brianSite.url+"']").length, 1, "Unblocked site is back in the grid"); 1.427 + 1.428 + ok( !NewTabUtils.blockedLinks.isBlocked(dougalSite), "site was unblocked" ); 1.429 + is( grid.querySelectorAll("[value='"+dougalSite.url+"']").length, 1, "Unblocked site is back in the grid"); 1.430 + // ..and that a previously pinned site is re-pinned after being blocked, then restored 1.431 + ok( NewTabUtils.pinnedLinks.isPinned(dougalSite), "Restoring previously pinned site makes it pinned again" ); 1.432 + is( grid.items[1].getAttribute("value"), dougalSite.url, "Blocked Site restored to pinned index" ); 1.433 + 1.434 + ok( !NewTabUtils.blockedLinks.isBlocked(dylanSite), "site was unblocked" ); 1.435 + is( grid.querySelectorAll("[value='"+dylanSite.url+"']").length, 1, "Unblocked site is back in the grid"); 1.436 + 1.437 + } catch(ex) { 1.438 + 1.439 + ok(false, this.desc+": Caught exception in test: " + ex); 1.440 + info("trace: " + ex.stack); 1.441 + } 1.442 + } 1.443 +}); 1.444 + 1.445 +gTests.push({ 1.446 + desc: "delete and restore site tiles", 1.447 + pins: "brian", 1.448 + setUp: function() { 1.449 + yield TopSitesTestHelper.setup(); 1.450 + // setup - set history to known state 1.451 + yield TopSitesTestHelper.setLinks( 1.452 + "brian,dougal,dylan,ermintrude", 1.453 + this.pins 1.454 + ); 1.455 + // pause until the update has fired and the view is finishd updating 1.456 + let arrangedPromise = waitForEvent(TopSitesTestHelper.grid, "arranged"); 1.457 + yield TopSitesTestHelper.updatePagesAndWait(); 1.458 + yield arrangedPromise; 1.459 + }, 1.460 + run: function() { 1.461 + // delete a both pinned and unpinned sites 1.462 + // test that sites are removed from the grid 1.463 + let grid = TopSitesTestHelper.grid, 1.464 + items = grid.items; 1.465 + is(items.length, 4, this.desc + ": should be 4 topsites"); 1.466 + 1.467 + let brianTile = grid.querySelector('richgriditem[value$="brian"]'); 1.468 + let dougalTile = grid.querySelector('richgriditem[value$="dougal"]') 1.469 + 1.470 + // verify assumptions before deleting sites 1.471 + ok( brianTile, "Tile for Brian was created"); 1.472 + ok( dougalTile, "Tile for Dougal was created"); 1.473 + 1.474 + let brianSite = TopSitesTestHelper.siteFromNode(brianTile); 1.475 + let dougalSite = TopSitesTestHelper.siteFromNode(dougalTile); 1.476 + ok( NewTabUtils.pinnedLinks.isPinned( brianSite ), "Brian tile is pinned" ); 1.477 + 1.478 + // select the 2 tiles 1.479 + grid.toggleItemSelection(brianTile); 1.480 + grid.toggleItemSelection(dougalTile); 1.481 + is(grid.selectedItems.length, 2, "2 tiles were selected"); 1.482 + 1.483 + // pause until the update has fired and the view is finishd updating 1.484 + let arrangedPromise = waitForEvent(grid, "arranged"); 1.485 + 1.486 + // raise a mock context-action event to trigger deletion of the selection 1.487 + let event = document.createEvent("Events"); 1.488 + event.action = "delete"; 1.489 + event.initEvent("context-action", true, true); // is cancelable 1.490 + grid.dispatchEvent(event); 1.491 + 1.492 + yield arrangedPromise; 1.493 + 1.494 + // those sites are blocked and their tiles have been removed from the grid? 1.495 + ok( !grid.querySelector('richgriditem[value="'+brianSite.value+'"]')); 1.496 + ok( !grid.querySelector('richgriditem[value="'+dougalSite.value+'"]')); 1.497 + ok( NewTabUtils.blockedLinks.isBlocked(brianSite), "Brian site was blocked" ); 1.498 + ok( NewTabUtils.blockedLinks.isBlocked(dougalSite), "Dougal site was blocked" ); 1.499 + // with the tiles deleted, selection should be empty 1.500 + is( grid.selectedItems.length, 0, "Gris selection is empty after deletion" ); 1.501 + 1.502 + // raise a mock context-action event to trigger restore 1.503 + arrangedPromise = waitForEvent(grid, "arranged"); 1.504 + event = document.createEvent("Events"); 1.505 + event.action = "restore"; 1.506 + event.initEvent("context-action", true, true); // is cancelable 1.507 + grid.dispatchEvent(event); 1.508 + 1.509 + yield arrangedPromise; 1.510 + brianTile = grid.querySelector('richgriditem[value$="brian"]'); 1.511 + dougalTile = grid.querySelector('richgriditem[value$="dougal"]'); 1.512 + 1.513 + // those tiles have been restored to the grid? 1.514 + ok( brianTile, "First tile was restored to the grid" ); 1.515 + ok( dougalTile, "2nd tile was restored to the grid" ); 1.516 + 1.517 + is(grid.selectedItems.length, 2, "2 tiles are still selected"); 1.518 + is( grid.selectedItems[0], brianTile, "Brian is still selected" ); 1.519 + is( grid.selectedItems[1], dougalTile, "Dougal is still selected" ); 1.520 + ok( NewTabUtils.pinnedLinks.isPinned( brianSite ), "Brian tile is still pinned" ); 1.521 + ok( !NewTabUtils.blockedLinks.isBlocked(brianSite), "Brian site was unblocked" ); 1.522 + ok( !NewTabUtils.blockedLinks.isBlocked(dougalSite), "Dougal site was unblocked" ); 1.523 + 1.524 + } 1.525 +});