diff options
Diffstat (limited to 'browser/base/content/test/newtab')
43 files changed, 2846 insertions, 0 deletions
diff --git a/browser/base/content/test/newtab/.eslintrc.js b/browser/base/content/test/newtab/.eslintrc.js new file mode 100644 index 000000000..7c8021192 --- /dev/null +++ b/browser/base/content/test/newtab/.eslintrc.js @@ -0,0 +1,7 @@ +"use strict"; + +module.exports = { + "extends": [ + "../../../../../testing/mochitest/browser.eslintrc.js" + ] +}; diff --git a/browser/base/content/test/newtab/browser.ini b/browser/base/content/test/newtab/browser.ini new file mode 100644 index 000000000..2d14d208d --- /dev/null +++ b/browser/base/content/test/newtab/browser.ini @@ -0,0 +1,55 @@ +[DEFAULT] +skip-if = (os == 'linux') # Bug 1243103, Bug 1243398, etc. +support-files = + head.js + +[browser_newtab_1188015.js] +[browser_newtab_background_captures.js] +[browser_newtab_block.js] +[browser_newtab_bug721442.js] +[browser_newtab_bug722273.js] +skip-if = (os == "mac" && debug) # temporary skip-if due to increase in intermittent failures on Mac debug - bug 1119906 +[browser_newtab_bug723102.js] +[browser_newtab_bug723121.js] +[browser_newtab_bug725996.js] +[browser_newtab_bug734043.js] +[browser_newtab_bug735987.js] +[browser_newtab_bug752841.js] +[browser_newtab_bug765628.js] +[browser_newtab_bug876313.js] +[browser_newtab_bug991111.js] +[browser_newtab_bug991210.js] +[browser_newtab_bug998387.js] +[browser_newtab_bug1145428.js] +[browser_newtab_bug1178586.js] +[browser_newtab_bug1194895.js] +[browser_newtab_bug1271075.js] +[browser_newtab_disable.js] +[browser_newtab_drag_drop.js] +[browser_newtab_drag_drop_ext.js] +# temporary until determine why more intermittent on VM +subsuite = clipboard +[browser_newtab_drop_preview.js] +[browser_newtab_enhanced.js] +[browser_newtab_focus.js] +[browser_newtab_perwindow_private_browsing.js] +[browser_newtab_reportLinkAction.js] +[browser_newtab_reflow_load.js] +support-files = + content-reflows.js +[browser_newtab_search.js] +support-files = + searchEngineNoLogo.xml + searchEngineFavicon.xml + searchEngine1xLogo.xml + searchEngine2xLogo.xml + searchEngine1x2xLogo.xml + ../general/searchSuggestionEngine.xml + ../general/searchSuggestionEngine.sjs +[browser_newtab_sponsored_icon_click.js] +skip-if = true # Bug 1314619 +[browser_newtab_undo.js] +# temporary until determine why more intermittent on VM +subsuite = clipboard +[browser_newtab_unpin.js] +[browser_newtab_update.js] diff --git a/browser/base/content/test/newtab/browser_newtab_1188015.js b/browser/base/content/test/newtab/browser_newtab_1188015.js new file mode 100644 index 000000000..f19aae1b9 --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_1188015.js @@ -0,0 +1,26 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +gDirectorySource = "data:application/json," + JSON.stringify({ + "directory": [{ + url: "http://example1.com/", + enhancedImageURI: "data:image/png;base64,helloWORLD2", + title: "title1", + type: "affiliate", + titleBgColor: "green" + }] +}); + +add_task(function* () { + yield pushPrefs(["browser.newtab.preload", false]); + + // Make the page have a directory link + yield setLinks([]); + yield* addNewTabPageTab(); + + let color = yield performOnCell(0, cell => { + return cell.node.querySelector(".newtab-title").style.backgroundColor; + }); + + is(color, "green", "title bg color is green"); +}); diff --git a/browser/base/content/test/newtab/browser_newtab_background_captures.js b/browser/base/content/test/newtab/browser_newtab_background_captures.js new file mode 100644 index 000000000..5e838196e --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_background_captures.js @@ -0,0 +1,64 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Verifies that hidden, pre-loaded newtabs don't allow background captures, and + * when unhidden, do allow background captures. + */ + +const CAPTURE_PREF = "browser.pagethumbnails.capturing_disabled"; + +add_task(function* () { + let imports = {}; + Cu.import("resource://gre/modules/PageThumbs.jsm", imports); + + // Disable captures. + yield pushPrefs([CAPTURE_PREF, false]); + + // Make sure the thumbnail doesn't exist yet. + let url = "http://example.com/"; + let path = imports.PageThumbsStorage.getFilePathForURL(url); + let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); + file.initWithPath(path); + try { + file.remove(false); + } + catch (err) {} + + // Add a top site. + yield setLinks("-1"); + + // We need a handle to a hidden, pre-loaded newtab so we can verify that it + // doesn't allow background captures. Ensure we have a preloaded browser. + gBrowser._createPreloadBrowser(); + + // Wait for the preloaded browser to load. + if (gBrowser._preloadedBrowser.contentDocument.readyState != "complete") { + yield BrowserTestUtils.waitForEvent(gBrowser._preloadedBrowser, "load", true); + } + + // We're now ready to use the preloaded browser. + BrowserOpenTab(); + let tab = gBrowser.selectedTab; + + let thumbnailCreatedPromise = new Promise(resolve => { + // Showing the preloaded tab should trigger thumbnail capture. + Services.obs.addObserver(function onCreate(subj, topic, data) { + if (data != url) + return; + Services.obs.removeObserver(onCreate, "page-thumbnail:create"); + ok(true, "thumbnail created after preloaded tab was shown"); + + resolve(); + }, "page-thumbnail:create", false); + }); + + // Enable captures. + yield pushPrefs([CAPTURE_PREF, false]); + + yield thumbnailCreatedPromise; + + // Test finished! + gBrowser.removeTab(tab); + file.remove(false); +}); diff --git a/browser/base/content/test/newtab/browser_newtab_block.js b/browser/base/content/test/newtab/browser_newtab_block.js new file mode 100644 index 000000000..70656462a --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_block.js @@ -0,0 +1,95 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +requestLongerTimeout(2); + +/* + * 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. + */ + +gDirectorySource = "data:application/json," + JSON.stringify({ + "suggested": [{ + url: "http://suggested.com/", + imageURI: "data:image/png;base64,helloWORLD3", + title: "title", + type: "affiliate", + adgroup_name: "test", + frecent_sites: ["example0.com"] + }] +}); + +add_task(function* () { + let origGetFrecentSitesName = DirectoryLinksProvider.getFrecentSitesName; + DirectoryLinksProvider.getFrecentSitesName = () => ""; + let origIsTopPlacesSite = NewTabUtils.isTopPlacesSite; + NewTabUtils.isTopPlacesSite = (site) => false; + + // we remove sites and expect the gaps to be filled as long as there still + // are some sites available + yield setLinks("0,1,2,3,4,5,6,7,8,9"); + setPinnedLinks(""); + + yield* addNewTabPageTab(); + yield customizeNewTabPage("enhanced"); // Toggle enhanced off + yield* checkGrid("0,1,2,3,4,5,6,7,8"); + + yield blockCell(4); + yield* checkGrid("0,1,2,3,5,6,7,8,9"); + + yield blockCell(4); + yield* checkGrid("0,1,2,3,6,7,8,9,"); + + yield blockCell(4); + yield* checkGrid("0,1,2,3,7,8,9,,"); + + // we removed a pinned site + yield restore(); + yield setLinks("0,1,2,3,4,5,6,7,8"); + setPinnedLinks(",1"); + + yield* addNewTabPageTab(); + yield* checkGrid("0,1p,2,3,4,5,6,7,8"); + + yield blockCell(1); + yield* 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 + yield restore(); + yield setLinks("0,1,2,3,4,5,6,7,8,9"); + setPinnedLinks(",,,,,,,,8"); + + yield* addNewTabPageTab(); + yield* checkGrid("0,1,2,3,4,5,6,7,8p"); + + yield blockCell(8); + yield* 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 + yield restore(); + yield setLinks("0,1,2,3,4,5,6,7,8,9"); + setPinnedLinks(",,,,,,,,8"); + + yield* addNewTabPageTab(); + yield* checkGrid("0,1,2,3,4,5,6,7,8p"); + + yield blockCell(0); + yield* checkGrid("1,2,3,4,5,6,7,9,8p"); + + // Test that blocking the targeted site also removes its associated suggested tile + NewTabUtils.isTopPlacesSite = origIsTopPlacesSite; + yield restore(); + yield setLinks("0,1,2,3,4,5,6,7,8,9"); + yield customizeNewTabPage("enhanced"); // Toggle enhanced on + yield* addNewTabPageTab(); + + yield* checkGrid("http://suggested.com/,0,1,2,3,4,5,6,7,8,9"); + + yield blockCell(1); + yield* addNewTabPageTab(); + yield* checkGrid("1,2,3,4,5,6,7,8,9"); + DirectoryLinksProvider.getFrecentSitesName = origGetFrecentSitesName; +}); diff --git a/browser/base/content/test/newtab/browser_newtab_bug1145428.js b/browser/base/content/test/newtab/browser_newtab_bug1145428.js new file mode 100644 index 000000000..72fe70212 --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_bug1145428.js @@ -0,0 +1,87 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/* + * These tests make sure that pinning suggested tile results in: + * - making suggested tile a history tile and replacing enhancedImageURI with imageURI + * - upond end of campaign, replaces landing url with baseDomain and switches + * background image to thumbnail + */ + +gDirectorySource = "data:application/json," + JSON.stringify({ + "suggested": [{ + url: "http://example.com/landing/page.html", + imageURI: "data:image/png;base64,helloWORLD3", + enhancedImageURI: "data:image/png;base64,helloWORLD2", + title: "title", + type: "affiliate", + adgroup_name: "example", + frecent_sites: ["example0.com"], + }] +}); + +add_task(function* () { + let origGetFrecentSitesName = DirectoryLinksProvider.getFrecentSitesName; + DirectoryLinksProvider.getFrecentSitesName = () => ""; + + function getData(cellNum) { + return performOnCell(cellNum, cell => { + if (!cell.site) + return null; + let siteNode = cell.site.node; + return { + type: siteNode.getAttribute("type"), + thumbnail: siteNode.querySelector(".newtab-thumbnail.thumbnail").style.backgroundImage, + enhanced: siteNode.querySelector(".enhanced-content").style.backgroundImage, + title: siteNode.querySelector(".newtab-title").textContent, + suggested: siteNode.getAttribute("suggested"), + url: siteNode.querySelector(".newtab-link").getAttribute("href"), + }; + }); + } + + yield setLinks("0,1,2,3,4,5,6,7,8,9"); + setPinnedLinks(""); + + yield* addNewTabPageTab(); + // load another newtab since the first may not get suggested tile + yield* addNewTabPageTab(); + yield* checkGrid("http://example.com/landing/page.html,0,1,2,3,4,5,6,7,8,9"); + // evaluate suggested tile + let tileData = yield getData(0); + is(tileData.type, "affiliate", "unpinned type"); + is(tileData.thumbnail, "url(\"data:image/png;base64,helloWORLD3\")", "unpinned thumbnail"); + is(tileData.enhanced, "url(\"data:image/png;base64,helloWORLD2\")", "unpinned enhanced"); + is(tileData.suggested, "true", "has suggested set", "unpinned suggested exists"); + is(tileData.url, "http://example.com/landing/page.html", "unpinned landing page"); + + // suggested tile should not be pinned + is(NewTabUtils.pinnedLinks.isPinned({url: "http://example.com/landing/page.html"}), false, "suggested tile is not pinned"); + + // pin suggested tile + let updatedPromise = whenPagesUpdated(); + yield BrowserTestUtils.synthesizeMouseAtCenter(".newtab-site > .newtab-control-pin", {}, gBrowser.selectedBrowser); + yield updatedPromise; + + // tile should be pinned and turned into history tile + is(NewTabUtils.pinnedLinks.isPinned({url: "http://example.com/landing/page.html"}), true, "suggested tile is pinned"); + tileData = yield getData(0); + is(tileData.type, "history", "pinned type"); + is(tileData.suggested, null, "no suggested attribute"); + is(tileData.url, "http://example.com/landing/page.html", "original landing page"); + + // set pinned tile endTime into past and reload the page + NewTabUtils.pinnedLinks._links[0].endTime = Date.now() - 1000; + yield* addNewTabPageTab(); + + // check that url is reset to base domain and thumbnail points to moz-page-thumb service + is(NewTabUtils.pinnedLinks.isPinned({url: "http://example.com/"}), true, "baseDomain url is pinned"); + tileData = yield getData(0); + is(tileData.type, "history", "type is history"); + is(tileData.title, "example.com", "title changed to baseDomain"); + is(tileData.thumbnail.indexOf("moz-page-thumb") != -1, true, "thumbnail contains moz-page-thumb"); + is(tileData.enhanced, "", "no enhanced image"); + is(tileData.url, "http://example.com/", "url points to baseDomian"); + + DirectoryLinksProvider.getFrecentSitesName = origGetFrecentSitesName; +}); diff --git a/browser/base/content/test/newtab/browser_newtab_bug1178586.js b/browser/base/content/test/newtab/browser_newtab_bug1178586.js new file mode 100644 index 000000000..84d5cb577 --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_bug1178586.js @@ -0,0 +1,83 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/* + * These tests make sure that pinned suggested tile turns into history tile + * and remains a history tile after a user clicks on it + */ + +gDirectorySource = "data:application/json," + JSON.stringify({ + "suggested": [{ + url: "http://example.com/hardlanding/page.html", + imageURI: "data:image/png;base64,helloWORLD3", + enhancedImageURI: "data:image/png;base64,helloWORLD2", + title: "title", + type: "affiliate", + adgroup_name: "example", + frecent_sites: ["example0.com"], + }] +}); + +add_task(function* () { + let origGetFrecentSitesName = DirectoryLinksProvider.getFrecentSitesName; + DirectoryLinksProvider.getFrecentSitesName = () => ""; + + function getData(cellNum) { + return performOnCell(cellNum, cell => { + if (!cell.site) + return null; + let siteNode = cell.site.node; + return { + type: siteNode.getAttribute("type"), + thumbnail: siteNode.querySelector(".newtab-thumbnail.thumbnail").style.backgroundImage, + enhanced: siteNode.querySelector(".enhanced-content").style.backgroundImage, + title: siteNode.querySelector(".newtab-title").textContent, + suggested: siteNode.getAttribute("suggested"), + url: siteNode.querySelector(".newtab-link").getAttribute("href"), + }; + }); + } + + yield setLinks("0,1,2,3,4,5,6,7,8,9"); + setPinnedLinks(""); + + yield* addNewTabPageTab(); + // load another newtab since the first may not get suggested tile + yield* addNewTabPageTab(); + yield* checkGrid("http://example.com/hardlanding/page.html,0,1,2,3,4,5,6,7,8,9"); + // evaluate suggested tile + let tileData = yield getData(0); + is(tileData.type, "affiliate", "unpinned type"); + is(tileData.thumbnail, "url(\"data:image/png;base64,helloWORLD3\")", "unpinned thumbnail"); + is(tileData.enhanced, "url(\"data:image/png;base64,helloWORLD2\")", "unpinned enhanced"); + is(tileData.suggested, "true", "has suggested set", "unpinned suggested exists"); + is(tileData.url, "http://example.com/hardlanding/page.html", "unpinned landing page"); + + // suggested tile should not be pinned + is(NewTabUtils.pinnedLinks.isPinned({url: "http://example.com/hardlanding/page.html"}), false, "suggested tile is not pinned"); + + // pin suggested tile + let updatedPromise = whenPagesUpdated(); + yield BrowserTestUtils.synthesizeMouseAtCenter(".newtab-site > .newtab-control-pin", {}, gBrowser.selectedBrowser); + yield updatedPromise; + + // tile should be pinned and turned into history tile + is(NewTabUtils.pinnedLinks.isPinned({url: "http://example.com/hardlanding/page.html"}), true, "suggested tile is pinned"); + tileData = yield getData(0); + is(tileData.type, "history", "pinned type"); + is(tileData.suggested, null, "no suggested attribute"); + is(tileData.url, "http://example.com/hardlanding/page.html", "original landing page"); + + // click the pinned tile + yield BrowserTestUtils.synthesizeMouseAtCenter(".newtab-site", {}, gBrowser.selectedBrowser); + // add new page twice to avoid using cached version + yield* addNewTabPageTab(); + yield* addNewTabPageTab(); + + // check that type and suggested did not change + tileData = yield getData(0); + is(tileData.type, "history", "pinned type"); + is(tileData.suggested, null, "no suggested attribute"); + + DirectoryLinksProvider.getFrecentSitesName = origGetFrecentSitesName; +}); diff --git a/browser/base/content/test/newtab/browser_newtab_bug1194895.js b/browser/base/content/test/newtab/browser_newtab_bug1194895.js new file mode 100644 index 000000000..c08b23185 --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_bug1194895.js @@ -0,0 +1,146 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +const PRELOAD_PREF = "browser.newtab.preload"; +const PREF_NEWTAB_COLUMNS = "browser.newtabpage.columns"; +const PREF_NEWTAB_ROWS = "browser.newtabpage.rows"; + +function populateDirectoryTiles() { + let directoryTiles = []; + let i = 0; + while (i++ < 14) { + directoryTiles.push({ + directoryId: i, + url: "http://example" + i + ".com/", + enhancedImageURI: "data:image/png;base64,helloWORLD", + title: "dirtitle" + i, + type: "affiliate" + }); + } + return directoryTiles; +} + +gDirectorySource = "data:application/json," + JSON.stringify({ + "directory": populateDirectoryTiles() +}); + + +add_task(function* () { + requestLongerTimeout(4); + let origEnhanced = NewTabUtils.allPages.enhanced; + let origCompareLinks = NewTabUtils.links.compareLinks; + registerCleanupFunction(() => { + NewTabUtils.allPages.enhanced = origEnhanced; + NewTabUtils.links.compareLinks = origCompareLinks; + }); + + // turn off preload to ensure grid updates on every setLinks + yield pushPrefs([PRELOAD_PREF, false]); + // set newtab to have three columns only + yield pushPrefs([PREF_NEWTAB_COLUMNS, 3]); + yield pushPrefs([PREF_NEWTAB_ROWS, 5]); + + yield* addNewTabPageTab(); + yield customizeNewTabPage("enhanced"); // Toggle enhanced off + + // Testing history tiles + + // two rows of tiles should always fit on any screen + yield setLinks("0,1,2,3,4,5"); + yield* addNewTabPageTab(); + + // should do not see scrollbar since tiles fit into visible space + yield* checkGrid("0,1,2,3,4,5"); + let scrolling = yield hasScrollbar(); + ok(!scrolling, "no scrollbar"); + + // add enough tiles to cause extra two rows and observe scrollbar + yield setLinks("0,1,2,3,4,5,6,7,8,9"); + yield* addNewTabPageTab(); + yield* checkGrid("0,1,2,3,4,5,6,7,8,9"); + scrolling = yield hasScrollbar(); + ok(scrolling, "document has scrollbar"); + + // pin the last tile to make it stay at the bottom of the newtab + yield pinCell(9); + // block first 6 tiles, which should not remove the scroll bar + // since the last tile is pinned in the nineth position + for (let i = 0; i < 6; i++) { + yield blockCell(0); + } + yield* addNewTabPageTab(); + yield* checkGrid("6,7,8,,,,,,,9p"); + scrolling = yield hasScrollbar(); + ok(scrolling, "document has scrollbar when tile is pinned to the last row"); + + // unpin the site: this will move tile up and make scrollbar disappear + yield unpinCell(9); + yield* addNewTabPageTab(); + yield* checkGrid("6,7,8,9"); + scrolling = yield hasScrollbar(); + ok(!scrolling, "no scrollbar when bottom row tile is unpinned"); + + // reset everything to clean slate + NewTabUtils.restore(); + + // Testing directory tiles + yield customizeNewTabPage("enhanced"); // Toggle enhanced on + + // setup page with no history tiles to test directory only display + yield setLinks([]); + yield* addNewTabPageTab(); + ok(!scrolling, "no scrollbar for directory tiles"); + + // introduce one history tile - it should occupy the last + // available slot at the bottom of newtab and cause scrollbar + yield setLinks("41"); + yield* addNewTabPageTab(); + scrolling = yield hasScrollbar(); + ok(scrolling, "adding low frecency history site causes scrollbar"); + + // set PREF_NEWTAB_ROWS to 4, that should clip off the history tile + // and remove scroll bar + yield pushPrefs([PREF_NEWTAB_ROWS, 4]); + yield* addNewTabPageTab(); + + scrolling = yield hasScrollbar(); + ok(!scrolling, "no scrollbar if history tiles falls past max rows"); + + // restore max rows and watch scrollbar re-appear + yield pushPrefs([PREF_NEWTAB_ROWS, 5]); + yield* addNewTabPageTab(); + scrolling = yield hasScrollbar(); + ok(scrolling, "scrollbar is back when max rows allow for bottom history tile"); + + // block that history tile, and watch scrollbar disappear + yield blockCell(14); + yield* addNewTabPageTab(); + scrolling = yield hasScrollbar(); + ok(!scrolling, "no scrollbar after bottom history tiles is blocked"); + + // Test well-populated user history - newtab has highly-frecent history sites + // redefine compareLinks to always choose history tiles first + NewTabUtils.links.compareLinks = function (aLink1, aLink2) { + if (aLink1.type == aLink2.type) { + return aLink2.frecency - aLink1.frecency || + aLink2.lastVisitDate - aLink1.lastVisitDate; + } + if (aLink2.type == "history") { + return 1; + } + return -1; + }; + + // add a row of history tiles, directory tiles will be clipped off, hence no scrollbar + yield setLinks("31,32,33"); + yield* addNewTabPageTab(); + scrolling = yield hasScrollbar(); + ok(!scrolling, "no scrollbar when directory tiles follow history tiles"); + + // fill first four rows with history tiles and observer scrollbar + yield setLinks("30,31,32,33,34,35,36,37,38,39"); + yield* addNewTabPageTab(); + scrolling = yield hasScrollbar(); + ok(scrolling, "scrollbar appears when history tiles need extra row"); +}); + diff --git a/browser/base/content/test/newtab/browser_newtab_bug1271075.js b/browser/base/content/test/newtab/browser_newtab_bug1271075.js new file mode 100644 index 000000000..723b48fc6 --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_bug1271075.js @@ -0,0 +1,32 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +add_task(function* () { + is(gBrowser.tabs.length, 1, "one tab is open initially"); + + // Add a few tabs. + let tabs = []; + function addTab(aURL, aReferrer) { + let tab = gBrowser.addTab(aURL, {referrerURI: aReferrer}); + tabs.push(tab); + return BrowserTestUtils.browserLoaded(tab.linkedBrowser); + } + + yield addTab("http://mochi.test:8888/#0"); + yield addTab("http://mochi.test:8888/#1"); + yield addTab("http://mochi.test:8888/#2"); + yield addTab("http://mochi.test:8888/#3"); + + // Create a new tab page with a "www.example.com" tile and move it to the 2nd tab position. + yield setLinks("-1"); + yield* addNewTabPageTab(); + gBrowser.moveTabTo(gBrowser.selectedTab, 1); + + // Send a middle-click and confirm that the clicked site opens immediately next to the new tab page. + yield BrowserTestUtils.synthesizeMouseAtCenter(".newtab-cell", + {button: 1}, gBrowser.selectedBrowser); + + yield BrowserTestUtils.browserLoaded(gBrowser.getBrowserAtIndex(2)); + is(gBrowser.getBrowserAtIndex(2).currentURI.spec, "http://example.com/", + "Middle click opens site in a new tab immediately to the right."); +}); diff --git a/browser/base/content/test/newtab/browser_newtab_bug721442.js b/browser/base/content/test/newtab/browser_newtab_bug721442.js new file mode 100644 index 000000000..99bd8d930 --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_bug721442.js @@ -0,0 +1,28 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +add_task(function* () { + yield setLinks("0,1,2,3,4,5,6,7,8"); + setPinnedLinks([ + {url: "http://example7.com/", title: ""}, + {url: "http://example8.com/", title: "title"}, + {url: "http://example9.com/", title: "http://example9.com/"} + ]); + + yield* addNewTabPageTab(); + yield* checkGrid("7p,8p,9p,0,1,2,3,4,5"); + + yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () { + function checkTooltip(aIndex, aExpected, aMessage) { + let cell = content.gGrid.cells[aIndex]; + + let link = cell.node.querySelector(".newtab-link"); + Assert.equal(link.getAttribute("title"), aExpected, aMessage); + } + + checkTooltip(0, "http://example7.com/", "1st tooltip is correct"); + checkTooltip(1, "title\nhttp://example8.com/", "2nd tooltip is correct"); + checkTooltip(2, "http://example9.com/", "3rd tooltip is correct"); + }); +}); + diff --git a/browser/base/content/test/newtab/browser_newtab_bug722273.js b/browser/base/content/test/newtab/browser_newtab_bug722273.js new file mode 100644 index 000000000..5cbfcd3ff --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_bug722273.js @@ -0,0 +1,73 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +const NOW = Date.now() * 1000; +const URL = "http://fake-site.com/"; + +var tmp = {}; +Cc["@mozilla.org/moz/jssubscript-loader;1"] + .getService(Ci.mozIJSSubScriptLoader) + .loadSubScript("chrome://browser/content/sanitize.js", tmp); + +var {Sanitizer} = tmp; + +add_task(function* () { + yield promiseSanitizeHistory(); + yield promiseAddFakeVisits(); + yield* addNewTabPageTab(); + + let cellUrl = yield performOnCell(0, cell => { return cell.site.url; }); + is(cellUrl, URL, "first site is our fake site"); + + let updatedPromise = whenPagesUpdated(); + yield promiseSanitizeHistory(); + yield updatedPromise; + + let isGone = yield performOnCell(0, cell => { return cell.site == null; }); + ok(isGone, "fake site is gone"); +}); + +function promiseAddFakeVisits() { + let visits = []; + for (let i = 59; i > 0; i--) { + visits.push({ + visitDate: NOW - i * 60 * 1000000, + transitionType: Ci.nsINavHistoryService.TRANSITION_LINK + }); + } + let place = { + uri: makeURI(URL), + title: "fake site", + visits: visits + }; + return new Promise((resolve, reject) => { + PlacesUtils.asyncHistory.updatePlaces(place, { + handleError: () => reject(new Error("Couldn't add visit")), + handleResult: function () {}, + handleCompletion: function () { + NewTabUtils.links.populateCache(function () { + NewTabUtils.allPages.update(); + resolve(); + }, true); + } + }); + }); +} + +function promiseSanitizeHistory() { + let s = new Sanitizer(); + s.prefDomain = "privacy.cpd."; + + let prefs = gPrefService.getBranch(s.prefDomain); + prefs.setBoolPref("history", true); + prefs.setBoolPref("downloads", false); + prefs.setBoolPref("cache", false); + prefs.setBoolPref("cookies", false); + prefs.setBoolPref("formdata", false); + prefs.setBoolPref("offlineApps", false); + prefs.setBoolPref("passwords", false); + prefs.setBoolPref("sessions", false); + prefs.setBoolPref("siteSettings", false); + + return s.sanitize(); +} diff --git a/browser/base/content/test/newtab/browser_newtab_bug723102.js b/browser/base/content/test/newtab/browser_newtab_bug723102.js new file mode 100644 index 000000000..02282dc97 --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_bug723102.js @@ -0,0 +1,24 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +add_task(function* () { + // create a new tab page and hide it. + yield setLinks("0,1,2,3,4,5,6,7,8"); + setPinnedLinks(""); + + yield* addNewTabPageTab(); + let firstTab = gBrowser.selectedTab; + + yield* addNewTabPageTab(); + yield BrowserTestUtils.removeTab(firstTab); + + ok(NewTabUtils.allPages.enabled, "page is enabled"); + NewTabUtils.allPages.enabled = false; + + yield ContentTask.spawn(gBrowser.selectedBrowser, null, function* () { + Assert.ok(content.gGrid.node.hasAttribute("page-disabled"), "page is disabled"); + }); + + NewTabUtils.allPages.enabled = true; +}); + diff --git a/browser/base/content/test/newtab/browser_newtab_bug723121.js b/browser/base/content/test/newtab/browser_newtab_bug723121.js new file mode 100644 index 000000000..82f45ebd5 --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_bug723121.js @@ -0,0 +1,42 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +add_task(function* () { + yield setLinks("0,1,2,3,4,5,6,7,8"); + setPinnedLinks(""); + + yield* addNewTabPageTab(); + + yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function*() { + let grid = content.gGrid; + let cell = grid.cells[0]; + let site = cell.site.node; + let link = site.querySelector(".newtab-link"); + + function checkGridLocked(aLocked, aMessage) { + Assert.equal(grid.node.hasAttribute("locked"), aLocked, aMessage); + } + + function sendDragEvent(aEventType, aTarget) { + let dataTransfer = new content.DataTransfer(aEventType, false); + let event = content.document.createEvent("DragEvent"); + event.initDragEvent(aEventType, true, true, content, 0, 0, 0, 0, 0, + false, false, false, false, 0, null, dataTransfer); + aTarget.dispatchEvent(event); + } + + checkGridLocked(false, "grid is unlocked"); + + sendDragEvent("dragstart", link); + checkGridLocked(true, "grid is now locked"); + + sendDragEvent("dragend", link); + checkGridLocked(false, "grid isn't locked anymore"); + + sendDragEvent("dragstart", cell.node); + checkGridLocked(false, "grid isn't locked - dragstart was ignored"); + + sendDragEvent("dragstart", site); + checkGridLocked(false, "grid isn't locked - dragstart was ignored"); + }); +}); diff --git a/browser/base/content/test/newtab/browser_newtab_bug725996.js b/browser/base/content/test/newtab/browser_newtab_bug725996.js new file mode 100644 index 000000000..e0de809c8 --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_bug725996.js @@ -0,0 +1,35 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +add_task(function* () { + yield setLinks("0,1,2,3,4,5,6,7,8"); + setPinnedLinks(""); + + yield* addNewTabPageTab(); + yield* checkGrid("0,1,2,3,4,5,6,7,8"); + + function doDrop(data) { + return ContentTask.spawn(gBrowser.selectedBrowser, { data: data }, function*(args) { + let dataTransfer = new content.DataTransfer("dragstart", false); + dataTransfer.mozSetDataAt("text/x-moz-url", args.data, 0); + let event = content.document.createEvent("DragEvent"); + event.initDragEvent("drop", true, true, content, 0, 0, 0, 0, 0, + false, false, false, false, 0, null, dataTransfer); + + let target = content.gGrid.cells[0].node; + target.dispatchEvent(event); + }); + } + + yield doDrop("http://example99.com/\nblank"); + is(NewTabUtils.pinnedLinks.links[0].url, "http://example99.com/", + "first cell is pinned and contains the dropped site"); + + yield whenPagesUpdated(); + yield* checkGrid("99p,0,1,2,3,4,5,6,7"); + + yield doDrop(""); + is(NewTabUtils.pinnedLinks.links[0].url, "http://example99.com/", + "first cell is still pinned with the site we dropped before"); +}); + diff --git a/browser/base/content/test/newtab/browser_newtab_bug734043.js b/browser/base/content/test/newtab/browser_newtab_bug734043.js new file mode 100644 index 000000000..02f765274 --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_bug734043.js @@ -0,0 +1,34 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +add_task(function* () { + yield setLinks("0,1,2,3,4,5,6,7,8"); + setPinnedLinks(""); + + yield* addNewTabPageTab(); + yield* checkGrid("0,1,2,3,4,5,6,7,8"); + + yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () { + content.addEventListener("error", function () { + sendAsyncMessage("test:newtab-error", {}); + }); + }); + + let receivedError = false; + let mm = gBrowser.selectedBrowser.messageManager; + mm.addMessageListener("test:newtab-error", function onResponse(message) { + mm.removeMessageListener("test:newtab-error", onResponse); + ok(false, "Error event happened"); + receivedError = true; + }); + + let pagesUpdatedPromise = whenPagesUpdated(); + + for (let i = 0; i < 3; i++) { + yield BrowserTestUtils.synthesizeMouseAtCenter(".newtab-control-block", {}, gBrowser.selectedBrowser); + } + + yield pagesUpdatedPromise; + + ok(!receivedError, "we got here without any errors"); +}); diff --git a/browser/base/content/test/newtab/browser_newtab_bug735987.js b/browser/base/content/test/newtab/browser_newtab_bug735987.js new file mode 100644 index 000000000..2ae541c70 --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_bug735987.js @@ -0,0 +1,32 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +add_task(function* () { + yield setLinks("0,1,2,3,4,5,6,7,8"); + setPinnedLinks(""); + + yield* addNewTabPageTab(); + yield* checkGrid("0,1,2,3,4,5,6,7,8"); + + yield* simulateExternalDrop(1); + yield* checkGrid("0,99p,1,2,3,4,5,6,7"); + + yield blockCell(1); + yield* checkGrid("0,1,2,3,4,5,6,7,8"); + + yield* simulateExternalDrop(1); + yield* checkGrid("0,99p,1,2,3,4,5,6,7"); + + // Simulate a restart and force the next about:newtab + // instance to read its data from the storage again. + NewTabUtils.blockedLinks.resetCache(); + + // Update all open pages, e.g. preloaded ones. + NewTabUtils.allPages.update(); + + yield* addNewTabPageTab(); + yield* checkGrid("0,99p,1,2,3,4,5,6,7"); + + yield blockCell(1); + yield* checkGrid("0,1,2,3,4,5,6,7,8"); +}); diff --git a/browser/base/content/test/newtab/browser_newtab_bug752841.js b/browser/base/content/test/newtab/browser_newtab_bug752841.js new file mode 100644 index 000000000..e3faad13f --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_bug752841.js @@ -0,0 +1,56 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +const PREF_NEWTAB_ROWS = "browser.newtabpage.rows"; +const PREF_NEWTAB_COLUMNS = "browser.newtabpage.columns"; + +function getCellsCount() +{ + return ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () { + return content.gGrid.cells.length; + }); +} + +add_task(function* () { + let testValues = [ + {row: 0, column: 0}, + {row: -1, column: -1}, + {row: -1, column: 0}, + {row: 0, column: -1}, + {row: 2, column: 4}, + {row: 2, column: 5}, + ]; + + // Expected length of grid + let expectedValues = [1, 1, 1, 1, 8, 10]; + + // Values before setting new pref values (15 is the default value -> 5 x 3) + let previousValues = [15, 1, 1, 1, 1, 8]; + + yield* addNewTabPageTab(); + let existingTab = gBrowser.selectedTab; + + for (let i = 0; i < expectedValues.length; i++) { + let existingTabGridLength = yield getCellsCount(); + is(existingTabGridLength, previousValues[i], + "Grid length of existing page before update is correctly."); + + yield pushPrefs([PREF_NEWTAB_ROWS, testValues[i].row]); + yield pushPrefs([PREF_NEWTAB_COLUMNS, testValues[i].column]); + + existingTabGridLength = yield getCellsCount(); + is(existingTabGridLength, expectedValues[i], + "Existing page grid is updated correctly."); + + yield* addNewTabPageTab(); + let newTab = gBrowser.selectedTab; + let newTabGridLength = yield getCellsCount(); + is(newTabGridLength, expectedValues[i], + "New page grid is updated correctly."); + + yield BrowserTestUtils.removeTab(newTab); + } + + gBrowser.removeTab(existingTab); +}); + diff --git a/browser/base/content/test/newtab/browser_newtab_bug765628.js b/browser/base/content/test/newtab/browser_newtab_bug765628.js new file mode 100644 index 000000000..25afd32a9 --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_bug765628.js @@ -0,0 +1,32 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +add_task(function* () { + yield setLinks("0,1,2,3,4,5,6,7,8"); + setPinnedLinks(""); + + yield* addNewTabPageTab(); + yield checkGrid("0,1,2,3,4,5,6,7,8"); + + yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function*() { + const BAD_DRAG_DATA = "javascript:alert('h4ck0rz');\nbad stuff"; + const GOOD_DRAG_DATA = "http://example99.com/\nsite 99"; + + function sendDropEvent(aCellIndex, aDragData) { + let dataTransfer = new content.DataTransfer("dragstart", false); + dataTransfer.mozSetDataAt("text/x-moz-url", aDragData, 0); + let event = content.document.createEvent("DragEvent"); + event.initDragEvent("drop", true, true, content, 0, 0, 0, 0, 0, + false, false, false, false, 0, null, dataTransfer); + + let target = content.gGrid.cells[aCellIndex].node; + target.dispatchEvent(event); + } + + sendDropEvent(0, BAD_DRAG_DATA); + sendDropEvent(1, GOOD_DRAG_DATA); + }); + + yield whenPagesUpdated(); + yield* checkGrid("0,99p,1,2,3,4,5,6,7"); +}); diff --git a/browser/base/content/test/newtab/browser_newtab_bug876313.js b/browser/base/content/test/newtab/browser_newtab_bug876313.js new file mode 100644 index 000000000..1c0b0f501 --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_bug876313.js @@ -0,0 +1,24 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/* + * This test makes sure that the changes made by unpinning + * a site are actually written to NewTabUtils' storage. + */ +add_task(function* () { + // Second cell is pinned with page #99. + yield setLinks("0,1,2,3,4,5,6,7,8"); + setPinnedLinks(",99"); + + yield* addNewTabPageTab(); + yield* checkGrid("0,99p,1,2,3,4,5,6,7"); + + // Unpin the second cell's site. + yield unpinCell(1); + yield* checkGrid("0,1,2,3,4,5,6,7,8"); + + // Clear the pinned cache to force NewTabUtils to read the pref again. + NewTabUtils.pinnedLinks.resetCache(); + NewTabUtils.allPages.update(); + yield* checkGrid("0,1,2,3,4,5,6,7,8"); +}); diff --git a/browser/base/content/test/newtab/browser_newtab_bug991111.js b/browser/base/content/test/newtab/browser_newtab_bug991111.js new file mode 100644 index 000000000..37aa8213b --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_bug991111.js @@ -0,0 +1,35 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +add_task(function* () { + // set max rows to 1, to avoid scroll events by clicking middle button + yield pushPrefs(["browser.newtabpage.rows", 1]); + yield setLinks("-1"); + yield* addNewTabPageTab(); + // we need a second newtab to honor max rows + yield* addNewTabPageTab(); + + yield ContentTask.spawn(gBrowser.selectedBrowser, {index: 0}, function* (args) { + let {site} = content.wrappedJSObject.gGrid.cells[args.index]; + + let origOnClick = site.onClick; + site.onClick = e => { + origOnClick.call(site, e); + sendAsyncMessage("test:clicked-on-cell", {}); + }; + }); + + let mm = gBrowser.selectedBrowser.messageManager; + let messagePromise = new Promise(resolve => { + mm.addMessageListener("test:clicked-on-cell", function onResponse(message) { + mm.removeMessageListener("test:clicked-on-cell", onResponse); + resolve(); + }); + }); + + // Send a middle-click and make sure it happened + yield BrowserTestUtils.synthesizeMouseAtCenter(".newtab-cell", + {button: 1}, gBrowser.selectedBrowser); + yield messagePromise; + ok(true, "middle click triggered click listener"); +}); diff --git a/browser/base/content/test/newtab/browser_newtab_bug991210.js b/browser/base/content/test/newtab/browser_newtab_bug991210.js new file mode 100644 index 000000000..367c49f5c --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_bug991210.js @@ -0,0 +1,34 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +add_task(function* () { + // turn off preload to ensure that a newtab page loads + yield pushPrefs(["browser.newtab.preload", false]); + + // add a test provider that waits for load + let afterLoadProvider = { + getLinks: function(callback) { + this.callback = callback; + }, + addObserver: function() {}, + }; + NewTabUtils.links.addProvider(afterLoadProvider); + + // wait until about:newtab loads before calling provider callback + yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:newtab"); + + afterLoadProvider.callback([]); + + yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () { + let {_cellHeight, _cellWidth, node} = content.gGrid; + Assert.notEqual(_cellHeight, null, "grid has a computed cell height"); + Assert.notEqual(_cellWidth, null, "grid has a computed cell width"); + let {height, maxHeight, maxWidth} = node.style; + Assert.notEqual(height, "", "grid has a computed grid height"); + Assert.notEqual(maxHeight, "", "grid has a computed grid max-height"); + Assert.notEqual(maxWidth, "", "grid has a computed grid max-width"); + }); + + // restore original state + NewTabUtils.links.removeProvider(afterLoadProvider); +}); diff --git a/browser/base/content/test/newtab/browser_newtab_bug998387.js b/browser/base/content/test/newtab/browser_newtab_bug998387.js new file mode 100644 index 000000000..30424c2e5 --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_bug998387.js @@ -0,0 +1,39 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +add_task(function* () { + // set max rows to 1, to avoid scroll events by clicking middle button + yield pushPrefs(["browser.newtabpage.rows", 1]); + yield setLinks("0"); + yield* addNewTabPageTab(); + // we need a second newtab to honor max rows + yield* addNewTabPageTab(); + + yield ContentTask.spawn(gBrowser.selectedBrowser, {index: 0}, function* (args) { + let {site} = content.wrappedJSObject.gGrid.cells[args.index]; + + let origOnClick = site.onClick; + site.onClick = e => { + origOnClick.call(site, e); + sendAsyncMessage("test:clicked-on-cell", {}); + }; + }); + + let mm = gBrowser.selectedBrowser.messageManager; + let messagePromise = new Promise(resolve => { + mm.addMessageListener("test:clicked-on-cell", function onResponse(message) { + mm.removeMessageListener("test:clicked-on-cell", onResponse); + resolve(); + }); + }); + + // Send a middle-click and make sure it happened + yield BrowserTestUtils.synthesizeMouseAtCenter(".newtab-control-block", + {button: 1}, gBrowser.selectedBrowser); + + yield messagePromise; + ok(true, "middle click triggered click listener"); + + // Make sure the cell didn't actually get blocked + yield* checkGrid("0"); +}); diff --git a/browser/base/content/test/newtab/browser_newtab_disable.js b/browser/base/content/test/newtab/browser_newtab_disable.js new file mode 100644 index 000000000..58b9a18af --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_disable.js @@ -0,0 +1,49 @@ +/* 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. + */ +add_task(function* () { + // create a new tab page and hide it. + yield setLinks("0,1,2,3,4,5,6,7,8"); + setPinnedLinks(""); + + let firstTab = yield* addNewTabPageTab(); + + function isGridDisabled(browser = gBrowser.selectedBrowser) + { + return ContentTask.spawn(browser, {}, function*() { + return content.gGrid.node.hasAttribute("page-disabled"); + }); + } + + let isDisabled = yield isGridDisabled(); + ok(!isDisabled, "page is not disabled"); + + NewTabUtils.allPages.enabled = false; + + isDisabled = yield isGridDisabled(); + ok(isDisabled, "page is disabled"); + + // create a second new tab page and make sure it's disabled. enable it + // again and check if the former page gets enabled as well. + yield* addNewTabPageTab(); + isDisabled = yield isGridDisabled(firstTab.linkedBrowser); + ok(isDisabled, "page is disabled"); + + // check that no sites have been rendered + yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function*() { + Assert.equal(content.document.querySelectorAll(".site").length, 0, + "no sites have been rendered"); + }); + + NewTabUtils.allPages.enabled = true; + + isDisabled = yield isGridDisabled(); + ok(!isDisabled, "page is not disabled"); + + isDisabled = yield isGridDisabled(firstTab.linkedBrowser); + ok(!isDisabled, "old page is not disabled"); +}); diff --git a/browser/base/content/test/newtab/browser_newtab_drag_drop.js b/browser/base/content/test/newtab/browser_newtab_drag_drop.js new file mode 100644 index 000000000..da9d89de7 --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_drag_drop.js @@ -0,0 +1,95 @@ +/* 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. + */ +add_task(function* () { + requestLongerTimeout(2); + yield* addNewTabPageTab(); + + // test a simple drag-and-drop scenario + yield setLinks("0,1,2,3,4,5,6,7,8"); + setPinnedLinks(""); + + yield* addNewTabPageTab(); + yield* checkGrid("0,1,2,3,4,5,6,7,8"); + + yield doDragEvent(0, 1); + yield* 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 + yield setLinks("0,1,2,3,4,5,6,7,8"); + setPinnedLinks(""); + + yield* addNewTabPageTab(); + yield* checkGrid("0,1,2,3,4,5,6,7,8"); + + yield doDragEvent(0, 0); + yield* checkGrid("0,1,2,3,4,5,6,7,8"); + + // ensure that pinned pages aren't moved if that's not necessary + yield setLinks("0,1,2,3,4,5,6,7,8"); + setPinnedLinks(",1,2"); + + yield* addNewTabPageTab(); + yield* checkGrid("0,1p,2p,3,4,5,6,7,8"); + + yield doDragEvent(0, 3); + yield* 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 + yield setLinks("0,1,2,3,4,5,6,7,8"); + setPinnedLinks("0,1"); + + yield* addNewTabPageTab(); + yield* checkGrid("0p,1p,2,3,4,5,6,7,8"); + + yield doDragEvent(2, 0); + yield* 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) + yield setLinks("0,1,2,3,4,5,6,7,8"); + setPinnedLinks(",,,,,,,7,8"); + + yield* addNewTabPageTab(); + yield* checkGrid("0,1,2,3,4,5,6,7p,8p"); + + yield doDragEvent(2, 5); + yield* checkGrid("0,1,3,4,5,2p,6,7p,8p"); + + // make sure that pinned sites are re-positioned correctly + yield setLinks("0,1,2,3,4,5,6,7,8"); + setPinnedLinks("0,1,2,,,5"); + + yield* addNewTabPageTab(); + yield* checkGrid("0p,1p,2p,3,4,5p,6,7,8"); + + yield doDragEvent(0, 4); + yield* checkGrid("3,1p,2p,4,0p,5p,6,7,8"); +}); + +function doDragEvent(sourceIndex, dropIndex) { + return ContentTask.spawn(gBrowser.selectedBrowser, + { sourceIndex: sourceIndex, dropIndex: dropIndex }, function*(args) { + let dataTransfer = new content.DataTransfer("dragstart", false); + let event = content.document.createEvent("DragEvent"); + event.initDragEvent("dragstart", true, true, content, 0, 0, 0, 0, 0, + false, false, false, false, 0, null, dataTransfer); + + let target = content.gGrid.cells[args.sourceIndex].site.node; + target.dispatchEvent(event); + + event = content.document.createEvent("DragEvent"); + event.initDragEvent("drop", true, true, content, 0, 0, 0, 0, 0, + false, false, false, false, 0, null, dataTransfer); + + target = content.gGrid.cells[args.dropIndex].node; + target.dispatchEvent(event); + }); +} diff --git a/browser/base/content/test/newtab/browser_newtab_drag_drop_ext.js b/browser/base/content/test/newtab/browser_newtab_drag_drop_ext.js new file mode 100644 index 000000000..4e7b062cb --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_drag_drop_ext.js @@ -0,0 +1,63 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +requestLongerTimeout(2); + +const PREF_NEWTAB_COLUMNS = "browser.newtabpage.columns"; + +/* + * 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. + * This is a continuation of browser_newtab_drag_drop.js + * to decrease test run time, focusing on external sites. + */ + add_task(function* () { + yield* addNewTabPageTab(); + + // drag a new site onto the very first cell + yield setLinks("0,1,2,3,4,5,6,7,8"); + setPinnedLinks(",,,,,,,7,8"); + + yield* addNewTabPageTab(); + yield* checkGrid("0,1,2,3,4,5,6,7p,8p"); + + yield* simulateExternalDrop(0); + yield* 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 + yield setLinks("0,1,2,3,4,5,6,7,8"); + setPinnedLinks(",,,,,,,7,8"); + + yield* addNewTabPageTab(); + yield* checkGrid("0,1,2,3,4,5,6,7p,8p"); + + // force the grid to be small enough that a pinned cell could be pushed out + yield pushPrefs([PREF_NEWTAB_COLUMNS, 3]); + yield* simulateExternalDrop(5); + yield* checkGrid("0,1,2,3,4,99p,5,7p,8p"); + + // drag a new site beneath a pinned cell and make sure the pinned cell is + // not moved + yield setLinks("0,1,2,3,4,5,6,7,8"); + setPinnedLinks(",,,,,,,,8"); + + yield* addNewTabPageTab(); + yield* checkGrid("0,1,2,3,4,5,6,7,8p"); + + yield* simulateExternalDrop(5); + yield* checkGrid("0,1,2,3,4,99p,5,6,8p"); + + // drag a new site onto a block of pinned sites and make sure they're shifted + // around accordingly + yield setLinks("0,1,2,3,4,5,6,7,8"); + setPinnedLinks("0,1,2,,,,,,"); + + yield* addNewTabPageTab(); + yield* checkGrid("0p,1p,2p"); + + yield* simulateExternalDrop(1); + yield* checkGrid("0p,99p,1p,2p,3,4,5,6,7"); +}); diff --git a/browser/base/content/test/newtab/browser_newtab_drop_preview.js b/browser/base/content/test/newtab/browser_newtab_drop_preview.js new file mode 100644 index 000000000..f9e37f629 --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_drop_preview.js @@ -0,0 +1,41 @@ +/* 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. + */ +add_task(function* () { + yield* addNewTabPageTab(); + + // the first three sites are pinned - make sure they're re-arranged correctly + yield setLinks("0,1,2,3,4,5,6,7,8"); + setPinnedLinks("0,1,2,,,5"); + + yield* addNewTabPageTab(); + yield* checkGrid("0p,1p,2p,3,4,5p,6,7,8"); + + let foundSites = yield ContentTask.spawn(gWindow.gBrowser.selectedBrowser, {}, function*() { + let cells = content.gGrid.cells; + content.gDrag._draggedSite = cells[0].site; + let sites = content.gDropPreview.rearrange(cells[4]); + content.gDrag._draggedSite = null; + + sites = sites.slice(0, 9); + return sites.map(function (aSite) { + if (!aSite) + return ""; + + let pinned = aSite.isPinned(); + if (pinned != aSite.node.hasAttribute("pinned")) { + Assert.ok(false, "invalid state (site.isPinned() != site[pinned])"); + } + + return aSite.url.replace(/^http:\/\/example(\d+)\.com\/$/, "$1") + (pinned ? "p" : ""); + }); + }); + + let expectedSites = "3,1p,2p,4,0p,5p,6,7,8" + is(foundSites, expectedSites, "grid status = " + expectedSites); +}); + diff --git a/browser/base/content/test/newtab/browser_newtab_enhanced.js b/browser/base/content/test/newtab/browser_newtab_enhanced.js new file mode 100644 index 000000000..5ac07ce55 --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_enhanced.js @@ -0,0 +1,228 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +requestLongerTimeout(2); + +const PRELOAD_PREF = "browser.newtab.preload"; + +var suggestedLink = { + url: "http://example1.com/2", + imageURI: "data:image/png;base64,helloWORLD3", + title: "title2", + type: "affiliate", + adgroup_name: "Technology", + frecent_sites: ["classroom.google.com", "codeacademy.org", "codecademy.com", "codeschool.com", "codeyear.com", "elearning.ut.ac.id", "how-to-build-websites.com", "htmlcodetutorial.com", "htmldog.com", "htmlplayground.com", "learn.jquery.com", "quackit.com", "roseindia.net", "teamtreehouse.com", "tizag.com", "tutorialspoint.com", "udacity.com", "w3schools.com", "webdevelopersnotes.com"] +}; + +gDirectorySource = "data:application/json," + JSON.stringify({ + "enhanced": [{ + url: "http://example.com/", + enhancedImageURI: "data:image/png;base64,helloWORLD", + title: "title", + type: "organic", + }], + "directory": [{ + url: "http://example1.com/", + enhancedImageURI: "data:image/png;base64,helloWORLD2", + title: "title1", + type: "organic" + }], + "suggested": [suggestedLink] +}); + +add_task(function* () { + let origEnhanced = NewTabUtils.allPages.enhanced; + registerCleanupFunction(() => { + NewTabUtils.allPages.enhanced = origEnhanced; + }); + + yield pushPrefs([PRELOAD_PREF, false]); + + function getData(cellNum) { + return performOnCell(cellNum, cell => { + if (!cell.site) + return null; + let siteNode = cell.site.node; + return { + type: siteNode.getAttribute("type"), + enhanced: siteNode.querySelector(".enhanced-content").style.backgroundImage, + title: siteNode.querySelector(".newtab-title").textContent, + suggested: siteNode.querySelector(".newtab-suggested").innerHTML + }; + }); + } + + // Make the page have a directory link, enhanced link, and history link + yield setLinks("-1"); + + // Test with enhanced = false + yield* addNewTabPageTab(); + yield customizeNewTabPage("classic"); + yield customizeNewTabPage("enhanced"); // Toggle enhanced off + let {type, enhanced, title, suggested} = yield getData(0); + isnot(type, "enhanced", "history link is not enhanced"); + is(enhanced, "", "history link has no enhanced image"); + is(title, "example.com"); + is(suggested, "", "There is no suggested explanation"); + + let data = yield getData(1); + is(data, null, "there is only one link and it's a history link"); + + // Test with enhanced = true + yield* addNewTabPageTab(); + yield customizeNewTabPage("enhanced"); // Toggle enhanced on + ({type, enhanced, title, suggested} = yield getData(0)); + is(type, "organic", "directory link is organic"); + isnot(enhanced, "", "directory link has enhanced image"); + is(title, "title1"); + is(suggested, "", "There is no suggested explanation"); + + ({type, enhanced, title, suggested} = yield getData(1)); + is(type, "enhanced", "history link is enhanced"); + isnot(enhanced, "", "history link has enhanced image"); + is(title, "title"); + is(suggested, "", "There is no suggested explanation"); + + data = yield getData(2); + is(data, null, "there are only 2 links, directory and enhanced history"); + + // Test with a pinned link + setPinnedLinks("-1"); + yield* addNewTabPageTab(); + ({type, enhanced, title, suggested} = yield getData(0)); + is(type, "enhanced", "pinned history link is enhanced"); + isnot(enhanced, "", "pinned history link has enhanced image"); + is(title, "title"); + is(suggested, "", "There is no suggested explanation"); + + ({type, enhanced, title, suggested} = yield getData(1)); + is(type, "organic", "directory link is organic"); + isnot(enhanced, "", "directory link has enhanced image"); + is(title, "title1"); + is(suggested, "", "There is no suggested explanation"); + + data = yield getData(2); + is(data, null, "directory link pushed out by pinned history link"); + + // Test pinned link with enhanced = false + yield* addNewTabPageTab(); + yield customizeNewTabPage("enhanced"); // Toggle enhanced off + ({type, enhanced, title, suggested} = yield getData(0)); + isnot(type, "enhanced", "history link is not enhanced"); + is(enhanced, "", "history link has no enhanced image"); + is(title, "example.com"); + is(suggested, "", "There is no suggested explanation"); + + data = yield getData(1); + is(data, null, "directory link still pushed out by pinned history link"); + + yield unpinCell(0); + + + + // Test that a suggested tile is not enhanced by a directory tile + NewTabUtils.isTopPlacesSite = () => true; + yield setLinks("-1,2,3,4,5,6,7,8"); + + // Test with enhanced = false + yield* addNewTabPageTab(); + ({type, enhanced, title, suggested} = yield getData(0)); + isnot(type, "enhanced", "history link is not enhanced"); + is(enhanced, "", "history link has no enhanced image"); + is(title, "example.com"); + is(suggested, "", "There is no suggested explanation"); + + data = yield getData(7); + isnot(data, null, "there are 8 history links"); + data = yield getData(8); + is(data, null, "there are 8 history links"); + + + // Test with enhanced = true + yield* addNewTabPageTab(); + yield customizeNewTabPage("enhanced"); + + // Suggested link was not enhanced by directory link with same domain + ({type, enhanced, title, suggested} = yield getData(0)); + is(type, "affiliate", "suggested link is affiliate"); + is(enhanced, "", "suggested link has no enhanced image"); + is(title, "title2"); + ok(suggested.indexOf("Suggested for <strong> Technology </strong> visitors") > -1, "Suggested for 'Technology'"); + + // Enhanced history link shows up second + ({type, enhanced, title, suggested} = yield getData(1)); + is(type, "enhanced", "pinned history link is enhanced"); + isnot(enhanced, "", "pinned history link has enhanced image"); + is(title, "title"); + is(suggested, "", "There is no suggested explanation"); + + data = yield getData(9); + is(data, null, "there is a suggested link followed by an enhanced history link and the remaining history links"); + + + + // Test no override category/adgroup name. + let linksChangedPromise = watchLinksChangeOnce(); + yield pushPrefs([PREF_NEWTAB_DIRECTORYSOURCE, + "data:application/json," + JSON.stringify({"suggested": [suggestedLink]})]); + yield linksChangedPromise; + + yield* addNewTabPageTab(); + ({type, enhanced, title, suggested} = yield getData(0)); + Cu.reportError("SUGGEST " + suggested); + ok(suggested.indexOf("Suggested for <strong> Technology </strong> visitors") > -1, "Suggested for 'Technology'"); + + + // Test server provided explanation string. + suggestedLink.explanation = "Suggested for %1$S enthusiasts who visit sites like %2$S"; + linksChangedPromise = watchLinksChangeOnce(); + yield pushPrefs([PREF_NEWTAB_DIRECTORYSOURCE, + "data:application/json," + encodeURIComponent(JSON.stringify({"suggested": [suggestedLink]}))]); + yield linksChangedPromise; + + yield* addNewTabPageTab(); + ({type, enhanced, title, suggested} = yield getData(0)); + Cu.reportError("SUGGEST " + suggested); + ok(suggested.indexOf("Suggested for <strong> Technology </strong> enthusiasts who visit sites like <strong> classroom.google.com </strong>") > -1, "Suggested for 'Technology' enthusiasts"); + + + // Test server provided explanation string with category override. + suggestedLink.adgroup_name = "webdev education"; + linksChangedPromise = watchLinksChangeOnce(); + yield pushPrefs([PREF_NEWTAB_DIRECTORYSOURCE, + "data:application/json," + encodeURIComponent(JSON.stringify({"suggested": [suggestedLink]}))]); + yield linksChangedPromise; + + yield* addNewTabPageTab(); + ({type, enhanced, title, suggested} = yield getData(0)); + Cu.reportError("SUGGEST " + suggested); + ok(suggested.indexOf("Suggested for <strong> webdev education </strong> enthusiasts who visit sites like <strong> classroom.google.com </strong>") > -1, "Suggested for 'webdev education' enthusiasts"); + + + + // Test with xml entities in category name + suggestedLink.url = "http://example1.com/3"; + suggestedLink.adgroup_name = ">angles< & \"quotes\'"; + linksChangedPromise = watchLinksChangeOnce(); + yield pushPrefs([PREF_NEWTAB_DIRECTORYSOURCE, + "data:application/json," + encodeURIComponent(JSON.stringify({"suggested": [suggestedLink]}))]); + yield linksChangedPromise; + + yield* addNewTabPageTab(); + ({type, enhanced, title, suggested} = yield getData(0)); + Cu.reportError("SUGGEST " + suggested); + ok(suggested.indexOf("Suggested for <strong> >angles< & \"quotes\' </strong> enthusiasts who visit sites like <strong> classroom.google.com </strong>") > -1, "Suggested for 'xml entities' enthusiasts"); + + + // Test with xml entities in explanation. + suggestedLink.explanation = "Testing junk explanation &<>\"'"; + linksChangedPromise = watchLinksChangeOnce(); + yield pushPrefs([PREF_NEWTAB_DIRECTORYSOURCE, + "data:application/json," + encodeURIComponent(JSON.stringify({"suggested": [suggestedLink]}))]); + yield linksChangedPromise; + + yield* addNewTabPageTab(); + ({type, enhanced, title, suggested} = yield getData(0)); + Cu.reportError("SUGGEST " + suggested); + ok(suggested.indexOf("Testing junk explanation &<>\"'") > -1, "Junk test"); +}); diff --git a/browser/base/content/test/newtab/browser_newtab_focus.js b/browser/base/content/test/newtab/browser_newtab_focus.js new file mode 100644 index 000000000..ae0dd8d29 --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_focus.js @@ -0,0 +1,48 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/* + * These tests make sure that focusing the 'New Tab Page' works as expected. + */ +add_task(function* () { + yield pushPrefs(["accessibility.tabfocus", 7]); + + // Focus count in new tab page. + // 30 = 9 * 3 + 3 = 9 sites, each with link, pin and remove buttons; search + // bar; search button; and toggle button. Additionaly there may or may not be + // a scroll bar caused by fix to 1180387, which will eat an extra focus + let FOCUS_COUNT = 30; + + // Create a new tab page. + yield setLinks("0,1,2,3,4,5,6,7,8"); + setPinnedLinks(""); + + yield* addNewTabPageTab(); + gURLBar.focus(); + + // Count the focus with the enabled page. + countFocus(FOCUS_COUNT); + + // Disable page and count the focus with the disabled page. + NewTabUtils.allPages.enabled = false; + + countFocus(4); + + NewTabUtils.allPages.enabled = true; +}); + +/** + * Focus the urlbar and count how many focus stops to return again to the urlbar. + */ +function countFocus(aExpectedCount) { + let focusCount = 0; + do { + EventUtils.synthesizeKey("VK_TAB", {}); + if (document.activeElement == gBrowser.selectedBrowser) { + focusCount++; + } + } while (document.activeElement != gURLBar.inputField); + + ok(focusCount == aExpectedCount || focusCount == (aExpectedCount + 1), + "Validate focus count in the new tab page."); +} diff --git a/browser/base/content/test/newtab/browser_newtab_perwindow_private_browsing.js b/browser/base/content/test/newtab/browser_newtab_perwindow_private_browsing.js new file mode 100644 index 000000000..b330bec13 --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_perwindow_private_browsing.js @@ -0,0 +1,56 @@ +/* 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. + */ + +add_task(function* () { + // prepare the grid + yield testOnWindow(undefined); + yield setLinks("0,1,2,3,4,5,6,7,8,9"); + + yield* addNewTabPageTab(); + yield pinCell(0); + yield* checkGrid("0p,1,2,3,4,5,6,7,8"); + + // open private window + yield testOnWindow({private: true}); + + yield* addNewTabPageTab(); + yield* checkGrid("0p,1,2,3,4,5,6,7,8"); + + // modify the grid while we're in pb mode + yield blockCell(1); + yield* checkGrid("0p,2,3,4,5,6,7,8"); + + yield unpinCell(0); + yield* checkGrid("0,2,3,4,5,6,7,8"); + + // open normal window + yield testOnWindow(undefined); + + // check that the grid is the same as before entering pb mode + yield* addNewTabPageTab(); + yield* checkGrid("0,2,3,4,5,6,7,8") +}); + +var windowsToClose = []; +function* testOnWindow(options) { + let newWindowPromise = BrowserTestUtils.waitForNewWindow(); + var win = OpenBrowserWindow(options); + windowsToClose.push(win); + gWindow = win; + yield newWindowPromise; +} + +registerCleanupFunction(function () { + gWindow = window; + windowsToClose.forEach(function(win) { + win.close(); + }); +}); + diff --git a/browser/base/content/test/newtab/browser_newtab_reflow_load.js b/browser/base/content/test/newtab/browser_newtab_reflow_load.js new file mode 100644 index 000000000..b8a24595e --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_reflow_load.js @@ -0,0 +1,37 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const FRAME_SCRIPT = getRootDirectory(gTestPath) + "content-reflows.js"; +const ADDITIONAL_WAIT_MS = 2000; + +/* + * Ensure that loading about:newtab doesn't cause uninterruptible reflows. + */ +add_task(function* () { + yield BrowserTestUtils.openNewForegroundTab(gBrowser, () => { + return gBrowser.selectedTab = gBrowser.addTab("about:blank", {animate: false}); + }, false); + + let browser = gBrowser.selectedBrowser; + let mm = browser.messageManager; + mm.loadFrameScript(FRAME_SCRIPT, true); + mm.addMessageListener("newtab-reflow", ({data: stack}) => { + ok(false, `unexpected uninterruptible reflow ${stack}`); + }); + + let browserLoadedPromise = BrowserTestUtils.waitForEvent(browser, "load", true); + browser.loadURI("about:newtab"); + yield browserLoadedPromise; + + // Wait some more to catch sync reflows after the page has loaded. + yield new Promise(resolve => { + setTimeout(resolve, ADDITIONAL_WAIT_MS); + }); + + // Clean up. + gBrowser.removeCurrentTab({animate: false}); + + ok(true, "Each test requires at least one pass, fail or todo so here is a pass."); +}); diff --git a/browser/base/content/test/newtab/browser_newtab_reportLinkAction.js b/browser/base/content/test/newtab/browser_newtab_reportLinkAction.js new file mode 100644 index 000000000..24e1be369 --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_reportLinkAction.js @@ -0,0 +1,83 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +const PRELOAD_PREF = "browser.newtab.preload"; + +gDirectorySource = "data:application/json," + JSON.stringify({ + "directory": [{ + url: "http://example.com/organic", + type: "organic" + }, { + url: "http://localhost/sponsored", + type: "sponsored" + }] +}); + +add_task(function* () { + yield pushPrefs([PRELOAD_PREF, false]); + + let originalReportSitesAction = DirectoryLinksProvider.reportSitesAction; + registerCleanupFunction(() => { + DirectoryLinksProvider.reportSitesAction = originalReportSitesAction; + }); + + let expected = {}; + + function expectReportSitesAction() { + return new Promise(resolve => { + DirectoryLinksProvider.reportSitesAction = function(sites, action, siteIndex) { + let {link} = sites[siteIndex]; + is(link.type, expected.type, "got expected type"); + is(action, expected.action, "got expected action"); + is(NewTabUtils.pinnedLinks.isPinned(link), expected.pinned, "got expected pinned"); + resolve(); + } + }); + } + + // Test that the last visible site (index 1) is reported + let reportSitesPromise = expectReportSitesAction(); + expected.type = "sponsored"; + expected.action = "view"; + expected.pinned = false; + yield* addNewTabPageTab(); + yield reportSitesPromise; + + // Click the pin button on the link in the 1th tile spot + expected.action = "pin"; + // tiles become "history" when pinned + expected.type = "history"; + expected.pinned = true; + let pagesUpdatedPromise = whenPagesUpdated(); + reportSitesPromise = expectReportSitesAction(); + + yield BrowserTestUtils.synthesizeMouseAtCenter(".newtab-cell + .newtab-cell .newtab-control-pin", {}, gBrowser.selectedBrowser); + yield pagesUpdatedPromise; + yield reportSitesPromise; + + // Unpin that link + expected.action = "unpin"; + expected.pinned = false; + pagesUpdatedPromise = whenPagesUpdated(); + reportSitesPromise = expectReportSitesAction(); + yield BrowserTestUtils.synthesizeMouseAtCenter(".newtab-cell + .newtab-cell .newtab-control-pin", {}, gBrowser.selectedBrowser); + yield pagesUpdatedPromise; + yield reportSitesPromise; + + // Block the site in the 0th tile spot + expected.type = "organic"; + expected.action = "block"; + expected.pinned = false; + pagesUpdatedPromise = whenPagesUpdated(); + reportSitesPromise = expectReportSitesAction(); + yield BrowserTestUtils.synthesizeMouseAtCenter(".newtab-site .newtab-control-block", {}, gBrowser.selectedBrowser); + yield pagesUpdatedPromise; + yield reportSitesPromise; + + // Click the 1th link now in the 0th tile spot + expected.type = "history"; + expected.action = "click"; + reportSitesPromise = expectReportSitesAction(); + yield BrowserTestUtils.synthesizeMouseAtCenter(".newtab-site", {}, gBrowser.selectedBrowser); + yield reportSitesPromise; +}); diff --git a/browser/base/content/test/newtab/browser_newtab_search.js b/browser/base/content/test/newtab/browser_newtab_search.js new file mode 100644 index 000000000..19ed4ba74 --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_search.js @@ -0,0 +1,247 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// See browser/components/search/test/browser_*_behavior.js for tests of actual +// searches. + +Cu.import("resource://gre/modules/Task.jsm"); + +const ENGINE_NO_LOGO = { + name: "searchEngineNoLogo.xml", + numLogos: 0, +}; + +const ENGINE_FAVICON = { + name: "searchEngineFavicon.xml", + logoPrefix1x: "data:image/png;base64,AAABAAIAICAAAAEAIACoEAAAJgAAABAQAAABACAAaAQAAM4QAAAoAAAAIAAAAEAAAAABACAAAAAAAAAQAAATCwAAEwsA", + numLogos: 1, +}; +ENGINE_FAVICON.logoPrefix2x = ENGINE_FAVICON.logoPrefix1x; + +const ENGINE_1X_LOGO = { + name: "searchEngine1xLogo.xml", + logoPrefix1x: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEEAAAAaCAIAAABn3KYmAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gkTADEw", + numLogos: 1, +}; +ENGINE_1X_LOGO.logoPrefix2x = ENGINE_1X_LOGO.logoPrefix1x; + +const ENGINE_2X_LOGO = { + name: "searchEngine2xLogo.xml", + logoPrefix2x: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIIAAAA0CAIAAADJ8nfCAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gkTADMU", + numLogos: 1, +}; +ENGINE_2X_LOGO.logoPrefix1x = ENGINE_2X_LOGO.logoPrefix2x; + +const ENGINE_1X_2X_LOGO = { + name: "searchEngine1x2xLogo.xml", + logoPrefix1x: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEEAAAAaCAIAAABn3KYmAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gkTADIG", + logoPrefix2x: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIIAAAA0CAIAAADJ8nfCAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gkTADMo", + numLogos: 2, +}; + +const ENGINE_SUGGESTIONS = { + name: "searchSuggestionEngine.xml", + numLogos: 0, +}; + +// The test has an expected search event queue and a search event listener. +// Search events that are expected to happen are added to the queue, and the +// listener consumes the queue and ensures that each event it receives is at +// the head of the queue. +let gExpectedSearchEventQueue = []; +let gExpectedSearchEventResolver = null; + +let gNewEngines = []; + +add_task(function* () { + let oldCurrentEngine = Services.search.currentEngine; + + yield* addNewTabPageTab(); + + // The tab is removed at the end of the test, so there's no need to remove + // this listener at the end of the test. + info("Adding search event listener"); + yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () { + const SERVICE_EVENT_NAME = "ContentSearchService"; + content.addEventListener(SERVICE_EVENT_NAME, function (event) { + sendAsyncMessage("test:search-event", { eventType: event.detail.type }); + }); + }); + + let mm = gBrowser.selectedBrowser.messageManager; + mm.addMessageListener("test:search-event", function (message) { + let eventType = message.data.eventType; + if (!gExpectedSearchEventResolver) { + ok(false, "Got search event " + eventType + " with no promise assigned"); + } + + let expectedEventType = gExpectedSearchEventQueue.shift(); + is(eventType, expectedEventType, "Got expected search event " + expectedEventType); + if (!gExpectedSearchEventQueue.length) { + gExpectedSearchEventResolver(); + gExpectedSearchEventResolver = null; + } + }); + + // Add the engine without any logos and switch to it. + let noLogoEngine = yield promiseNewSearchEngine(ENGINE_NO_LOGO); + let searchEventsPromise = promiseSearchEvents(["CurrentEngine"]); + Services.search.currentEngine = noLogoEngine; + yield searchEventsPromise; + yield* checkCurrentEngine(ENGINE_NO_LOGO); + + // Add the engine with favicon and switch to it. + let faviconEngine = yield promiseNewSearchEngine(ENGINE_FAVICON); + searchEventsPromise = promiseSearchEvents(["CurrentEngine"]); + Services.search.currentEngine = faviconEngine; + yield searchEventsPromise; + yield* checkCurrentEngine(ENGINE_FAVICON); + + // Add the engine with a 1x-DPI logo and switch to it. + let logo1xEngine = yield promiseNewSearchEngine(ENGINE_1X_LOGO); + searchEventsPromise = promiseSearchEvents(["CurrentEngine"]); + Services.search.currentEngine = logo1xEngine; + yield searchEventsPromise; + yield* checkCurrentEngine(ENGINE_1X_LOGO); + + // Add the engine with a 2x-DPI logo and switch to it. + let logo2xEngine = yield promiseNewSearchEngine(ENGINE_2X_LOGO); + searchEventsPromise = promiseSearchEvents(["CurrentEngine"]); + Services.search.currentEngine = logo2xEngine; + yield searchEventsPromise; + yield* checkCurrentEngine(ENGINE_2X_LOGO); + + // Add the engine with 1x- and 2x-DPI logos and switch to it. + let logo1x2xEngine = yield promiseNewSearchEngine(ENGINE_1X_2X_LOGO); + searchEventsPromise = promiseSearchEvents(["CurrentEngine"]); + Services.search.currentEngine = logo1x2xEngine; + yield searchEventsPromise; + yield* checkCurrentEngine(ENGINE_1X_2X_LOGO); + + // Add the engine that provides search suggestions and switch to it. + let suggestionEngine = yield promiseNewSearchEngine(ENGINE_SUGGESTIONS); + searchEventsPromise = promiseSearchEvents(["CurrentEngine"]); + Services.search.currentEngine = suggestionEngine; + yield searchEventsPromise; + yield* checkCurrentEngine(ENGINE_SUGGESTIONS); + + // Avoid intermittent failures. + yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () { + content.gSearch._contentSearchController.remoteTimeout = 5000; + }); + + // Type an X in the search input. This is only a smoke test. See + // browser_searchSuggestionUI.js for comprehensive content search suggestion + // UI tests. + let suggestionsOpenPromise = new Promise(resolve => { + mm.addMessageListener("test:newtab-suggestions-open", function onResponse(message) { + mm.removeMessageListener("test:newtab-suggestions-open", onResponse); + resolve(); + }); + }); + + yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () { + let table = content.document.getElementById("searchSuggestionTable"); + + let input = content.document.getElementById("newtab-search-text"); + input.focus(); + + info("Waiting for suggestions table to open"); + let observer = new content.MutationObserver(() => { + if (input.getAttribute("aria-expanded") == "true") { + observer.disconnect(); + Assert.ok(!table.hidden, "Search suggestion table unhidden"); + sendAsyncMessage("test:newtab-suggestions-open", {}); + } + }); + observer.observe(input, { + attributes: true, + attributeFilter: ["aria-expanded"], + }); + }); + + let suggestionsPromise = promiseSearchEvents(["Suggestions"]); + + EventUtils.synthesizeKey("x", {}); + + // Wait for the search suggestions to become visible and for the Suggestions + // message. + yield suggestionsOpenPromise; + yield suggestionsPromise; + + // Empty the search input, causing the suggestions to be hidden. + EventUtils.synthesizeKey("a", { accelKey: true }); + EventUtils.synthesizeKey("VK_DELETE", {}); + + yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () { + Assert.ok(content.document.getElementById("searchSuggestionTable").hidden, + "Search suggestion table hidden"); + }); + + // Done. Revert the current engine and remove the new engines. + searchEventsPromise = promiseSearchEvents(["CurrentEngine"]); + Services.search.currentEngine = oldCurrentEngine; + yield searchEventsPromise; + + let events = Array(gNewEngines.length).fill("CurrentState", 0, gNewEngines.length); + searchEventsPromise = promiseSearchEvents(events); + + for (let engine of gNewEngines) { + Services.search.removeEngine(engine); + } + yield searchEventsPromise; +}); + +function promiseSearchEvents(events) { + info("Expecting search events: " + events); + return new Promise(resolve => { + gExpectedSearchEventQueue.push(...events); + gExpectedSearchEventResolver = resolve; + }); +} + +function promiseNewSearchEngine({name: basename, numLogos}) { + info("Waiting for engine to be added: " + basename); + + // Wait for the search events triggered by adding the new engine. + // engine-added engine-loaded + let expectedSearchEvents = ["CurrentState", "CurrentState"]; + // engine-changed for each of the logos + for (let i = 0; i < numLogos; i++) { + expectedSearchEvents.push("CurrentState"); + } + let eventPromise = promiseSearchEvents(expectedSearchEvents); + + // Wait for addEngine(). + let addEnginePromise = new Promise((resolve, reject) => { + let url = getRootDirectory(gTestPath) + basename; + Services.search.addEngine(url, null, "", false, { + onSuccess: function (engine) { + info("Search engine added: " + basename); + gNewEngines.push(engine); + resolve(engine); + }, + onError: function (errCode) { + ok(false, "addEngine failed with error code " + errCode); + reject(); + }, + }); + }); + + return Promise.all([addEnginePromise, eventPromise]).then(([newEngine, _]) => { + return newEngine; + }); +} + +function* checkCurrentEngine(engineInfo) +{ + let engine = Services.search.currentEngine; + ok(engine.name.includes(engineInfo.name), + "Sanity check: current engine: engine.name=" + engine.name + + " basename=" + engineInfo.name); + + yield ContentTask.spawn(gBrowser.selectedBrowser, { name: engine.name }, function* (args) { + Assert.equal(content.gSearch._contentSearchController.defaultEngine.name, + args.name, "currentEngineName: " + args.name); + }); +} diff --git a/browser/base/content/test/newtab/browser_newtab_sponsored_icon_click.js b/browser/base/content/test/newtab/browser_newtab_sponsored_icon_click.js new file mode 100644 index 000000000..f6bb85d47 --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_sponsored_icon_click.js @@ -0,0 +1,53 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +add_task(function* () { + yield setLinks("0"); + yield* addNewTabPageTab(); + + yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () { + var EventUtils = {}; + EventUtils.window = {}; + EventUtils.parent = EventUtils.window; + EventUtils._EU_Ci = Components.interfaces; + + Services.scriptloader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/EventUtils.js", EventUtils); + + let cell = content.gGrid.cells[0]; + + let site = cell.node.querySelector(".newtab-site"); + site.setAttribute("type", "sponsored"); + + // test explain text appearing upon a click + let sponsoredButton = site.querySelector(".newtab-sponsored"); + EventUtils.synthesizeMouseAtCenter(sponsoredButton, {}, content); + let explain = site.querySelector(".sponsored-explain"); + Assert.notEqual(explain, null, "Sponsored explanation shown"); + Assert.ok(explain.querySelector("input").classList.contains("newtab-control-block"), + "sponsored tiles show blocked image"); + Assert.ok(sponsoredButton.hasAttribute("active"), "Sponsored button has active attribute"); + + // test dismissing sponsored explain + EventUtils.synthesizeMouseAtCenter(sponsoredButton, {}, content); + Assert.equal(site.querySelector(".sponsored-explain"), null, + "Sponsored explanation no longer shown"); + Assert.ok(!sponsoredButton.hasAttribute("active"), + "Sponsored button does not have active attribute"); + + // test with enhanced tile + site.setAttribute("type", "enhanced"); + EventUtils.synthesizeMouseAtCenter(sponsoredButton, {}, content); + explain = site.querySelector(".sponsored-explain"); + Assert.notEqual(explain, null, "Sponsored explanation shown"); + Assert.ok(explain.querySelector("input").classList.contains("newtab-customize"), + "enhanced tiles show customize image"); + Assert.ok(sponsoredButton.hasAttribute("active"), "Sponsored button has active attribute"); + + // test dismissing enhanced explain + EventUtils.synthesizeMouseAtCenter(sponsoredButton, {}, content); + Assert.equal(site.querySelector(".sponsored-explain"), null, + "Sponsored explanation no longer shown"); + Assert.ok(!sponsoredButton.hasAttribute("active"), + "Sponsored button does not have active attribute"); + }); +}); diff --git a/browser/base/content/test/newtab/browser_newtab_undo.js b/browser/base/content/test/newtab/browser_newtab_undo.js new file mode 100644 index 000000000..ba094cb26 --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_undo.js @@ -0,0 +1,47 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/* + * These tests make sure that the undo dialog works as expected. + */ +add_task(function* () { + // remove unpinned sites and undo it + yield setLinks("0,1,2,3,4,5,6,7,8"); + setPinnedLinks("5"); + + yield* addNewTabPageTab(); + yield* checkGrid("5p,0,1,2,3,4,6,7,8"); + + yield blockCell(4); + yield blockCell(4); + yield* checkGrid("5p,0,1,2,6,7,8"); + + yield* undo(); + yield* checkGrid("5p,0,1,2,4,6,7,8"); + + // now remove a pinned site and undo it + yield blockCell(0); + yield* checkGrid("0,1,2,4,6,7,8"); + + yield* undo(); + yield* checkGrid("5p,0,1,2,4,6,7,8"); + + // remove a site and restore all + yield blockCell(1); + yield* checkGrid("5p,1,2,4,6,7,8"); + + yield* undoAll(); + yield* checkGrid("5p,0,1,2,3,4,6,7,8"); +}); + +function* undo() { + let updatedPromise = whenPagesUpdated(); + yield BrowserTestUtils.synthesizeMouseAtCenter("#newtab-undo-button", {}, gBrowser.selectedBrowser); + yield updatedPromise; +} + +function* undoAll() { + let updatedPromise = whenPagesUpdated(); + yield BrowserTestUtils.synthesizeMouseAtCenter("#newtab-undo-restore-button", {}, gBrowser.selectedBrowser); + yield updatedPromise; +} diff --git a/browser/base/content/test/newtab/browser_newtab_unpin.js b/browser/base/content/test/newtab/browser_newtab_unpin.js new file mode 100644 index 000000000..14751465f --- /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. + */ +add_task(function* () { + // we have a pinned link that didn't change its position since it was pinned. + // nothing should happen when we unpin it. + yield setLinks("0,1,2,3,4,5,6,7,8"); + setPinnedLinks(",1"); + + yield* addNewTabPageTab(); + yield* checkGrid("0,1p,2,3,4,5,6,7,8"); + + yield unpinCell(1); + yield* 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. + yield setLinks("0,1,2,3,4,5,6,7,8"); + setPinnedLinks(",99"); + + yield* addNewTabPageTab(); + yield* checkGrid("0,99p,1,2,3,4,5,6,7"); + + yield unpinCell(1); + yield* 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. + yield setLinks("0,1,2,3,4,5,6,7"); + setPinnedLinks(",1,,,,,,,0"); + + yield* addNewTabPageTab(); + yield* checkGrid("2,1p,3,4,5,6,7,,0p"); + + yield unpinCell(1); + yield* checkGrid("1,2,3,4,5,6,7,,0p"); + + yield unpinCell(8); + yield* 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 + yield setLinks("0,1,2,3,4,5,6,7,8,9"); + setPinnedLinks("9"); + + yield* addNewTabPageTab(); + yield* checkGrid("9p,0,1,2,3,4,5,6,7"); + + yield unpinCell(0); + yield* checkGrid("0,1,2,3,4,5,6,7,8"); +}); diff --git a/browser/base/content/test/newtab/browser_newtab_update.js b/browser/base/content/test/newtab/browser_newtab_update.js new file mode 100644 index 000000000..6cf089dfd --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_update.js @@ -0,0 +1,48 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Checks that newtab is updated as its links change. + */ +add_task(function* () { + // First, start with an empty page. setLinks will trigger a hidden page + // update because it calls clearHistory. We need to wait for that update to + // happen so that the next time we wait for a page update below, we catch the + // right update and not the one triggered by setLinks. + let updatedPromise = whenPagesUpdated(); + let setLinksPromise = setLinks([]); + yield Promise.all([updatedPromise, setLinksPromise]); + + // Strategy: Add some visits, open a new page, check the grid, repeat. + yield fillHistoryAndWaitForPageUpdate([1]); + yield* addNewTabPageTab(); + yield* checkGrid("1,,,,,,,,"); + + yield fillHistoryAndWaitForPageUpdate([2]); + yield* addNewTabPageTab(); + yield* checkGrid("2,1,,,,,,,"); + + yield fillHistoryAndWaitForPageUpdate([1]); + yield* addNewTabPageTab(); + yield* checkGrid("1,2,,,,,,,"); + + yield fillHistoryAndWaitForPageUpdate([2, 3, 4]); + yield* addNewTabPageTab(); + yield* checkGrid("2,1,3,4,,,,,"); + + // Make sure these added links have the right type + let type = yield performOnCell(1, cell => { return cell.site.link.type }); + is(type, "history", "added link is history"); +}); + +function fillHistoryAndWaitForPageUpdate(links) { + let updatedPromise = whenPagesUpdated; + let fillHistoryPromise = fillHistory(links.map(link)); + return Promise.all([updatedPromise, fillHistoryPromise]); +} + +function link(id) { + return { url: "http://example" + id + ".com/", title: "site#" + id }; +} diff --git a/browser/base/content/test/newtab/content-reflows.js b/browser/base/content/test/newtab/content-reflows.js new file mode 100644 index 000000000..f1a53782e --- /dev/null +++ b/browser/base/content/test/newtab/content-reflows.js @@ -0,0 +1,26 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +(function () { + "use strict"; + + const Ci = Components.interfaces; + + docShell.addWeakReflowObserver({ + reflow() { + // Gather information about the current code path. + let path = (new Error().stack).split("\n").slice(1).join("\n"); + if (path) { + sendSyncMessage("newtab-reflow", path); + } + }, + + reflowInterruptible() { + // We're not interested in interruptible reflows. + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIReflowObserver, + Ci.nsISupportsWeakReference]) + }); +})(); diff --git a/browser/base/content/test/newtab/head.js b/browser/base/content/test/newtab/head.js new file mode 100644 index 000000000..d702103a0 --- /dev/null +++ b/browser/base/content/test/newtab/head.js @@ -0,0 +1,552 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +const PREF_NEWTAB_ENABLED = "browser.newtabpage.enabled"; +const PREF_NEWTAB_DIRECTORYSOURCE = "browser.newtabpage.directory.source"; + +Services.prefs.setBoolPref(PREF_NEWTAB_ENABLED, true); + +var tmp = {}; +Cu.import("resource://gre/modules/NewTabUtils.jsm", tmp); +Cu.import("resource:///modules/DirectoryLinksProvider.jsm", tmp); +Cu.import("resource://testing-common/PlacesTestUtils.jsm", tmp); +Cc["@mozilla.org/moz/jssubscript-loader;1"] + .getService(Ci.mozIJSSubScriptLoader) + .loadSubScript("chrome://browser/content/sanitize.js", tmp); +var {NewTabUtils, Sanitizer, DirectoryLinksProvider, PlacesTestUtils} = tmp; + +var gWindow = window; + +// Default to dummy/empty directory links +var gDirectorySource = 'data:application/json,{"test":1}'; +var gOrigDirectorySource; + +// The tests assume all 3 rows and all 3 columns of sites are shown, but the +// window may be too small to actually show everything. Resize it if necessary. +var requiredSize = {}; +requiredSize.innerHeight = + 40 + 32 + // undo container + bottom margin + 44 + 32 + // search bar + bottom margin + (3 * (180 + 32)) + // 3 rows * (tile height + title and bottom margin) + 100; // breathing room +requiredSize.innerWidth = + (3 * (290 + 20)) + // 3 cols * (tile width + side margins) + 100; // breathing room + +var oldSize = {}; +Object.keys(requiredSize).forEach(prop => { + info([prop, gBrowser.contentWindow[prop], requiredSize[prop]]); + if (gBrowser.contentWindow[prop] < requiredSize[prop]) { + oldSize[prop] = gBrowser.contentWindow[prop]; + info("Changing browser " + prop + " from " + oldSize[prop] + " to " + + requiredSize[prop]); + gBrowser.contentWindow[prop] = requiredSize[prop]; + } +}); + +var screenHeight = {}; +var screenWidth = {}; +Cc["@mozilla.org/gfx/screenmanager;1"]. + getService(Ci.nsIScreenManager). + primaryScreen. + GetAvailRectDisplayPix({}, {}, screenWidth, screenHeight); +screenHeight = screenHeight.value; +screenWidth = screenWidth.value; + +if (screenHeight < gBrowser.contentWindow.outerHeight) { + info("Warning: Browser outer height is now " + + gBrowser.contentWindow.outerHeight + ", which is larger than the " + + "available screen height, " + screenHeight + + ". That may cause problems."); +} + +if (screenWidth < gBrowser.contentWindow.outerWidth) { + info("Warning: Browser outer width is now " + + gBrowser.contentWindow.outerWidth + ", which is larger than the " + + "available screen width, " + screenWidth + + ". That may cause problems."); +} + +registerCleanupFunction(function () { + while (gWindow.gBrowser.tabs.length > 1) + gWindow.gBrowser.removeTab(gWindow.gBrowser.tabs[1]); + + Object.keys(oldSize).forEach(prop => { + if (oldSize[prop]) { + gBrowser.contentWindow[prop] = oldSize[prop]; + } + }); + + // Stop any update timers to prevent unexpected updates in later tests + let timer = NewTabUtils.allPages._scheduleUpdateTimeout; + if (timer) { + clearTimeout(timer); + delete NewTabUtils.allPages._scheduleUpdateTimeout; + } + + Services.prefs.clearUserPref(PREF_NEWTAB_ENABLED); + Services.prefs.setCharPref(PREF_NEWTAB_DIRECTORYSOURCE, gOrigDirectorySource); + + return watchLinksChangeOnce(); +}); + +function pushPrefs(...aPrefs) { + return new Promise(resolve => + SpecialPowers.pushPrefEnv({"set": aPrefs}, resolve)); +} + +/** + * Resolves promise when directory links are downloaded and written to disk + */ +function watchLinksChangeOnce() { + return new Promise(resolve => { + let observer = { + onManyLinksChanged: () => { + DirectoryLinksProvider.removeObserver(observer); + resolve(); + } + }; + observer.onDownloadFail = observer.onManyLinksChanged; + DirectoryLinksProvider.addObserver(observer); + }); +} + +add_task(function* setup() { + registerCleanupFunction(function() { + return new Promise(resolve => { + function cleanupAndFinish() { + PlacesTestUtils.clearHistory().then(() => { + whenPagesUpdated().then(resolve); + NewTabUtils.restore(); + }); + } + + let callbacks = NewTabUtils.links._populateCallbacks; + let numCallbacks = callbacks.length; + + if (numCallbacks) + callbacks.splice(0, numCallbacks, cleanupAndFinish); + else + cleanupAndFinish(); + }); + }); + + let promiseReady = Task.spawn(function*() { + yield watchLinksChangeOnce(); + yield whenPagesUpdated(); + }); + + // Save the original directory source (which is set globally for tests) + gOrigDirectorySource = Services.prefs.getCharPref(PREF_NEWTAB_DIRECTORYSOURCE); + Services.prefs.setCharPref(PREF_NEWTAB_DIRECTORYSOURCE, gDirectorySource); + yield promiseReady; +}); + +/** Perform an action on a cell within the newtab page. + * @param aIndex index of cell + * @param aFn function to call in child process or tab. + * @returns result of calling the function. + */ +function performOnCell(aIndex, aFn) { + return ContentTask.spawn(gWindow.gBrowser.selectedBrowser, + { index: aIndex, fn: aFn.toString() }, function* (args) { + let cell = content.gGrid.cells[args.index]; + return eval(args.fn)(cell); + }); +} + +/** + * Allows to provide a list of links that is used to construct the grid. + * @param aLinksPattern the pattern (see below) + * + * Example: setLinks("-1,0,1,2,3") + * Result: [{url: "http://example.com/", title: "site#-1"}, + * {url: "http://example0.com/", title: "site#0"}, + * {url: "http://example1.com/", title: "site#1"}, + * {url: "http://example2.com/", title: "site#2"}, + * {url: "http://example3.com/", title: "site#3"}] + */ +function setLinks(aLinks) { + return new Promise(resolve => { + let links = aLinks; + + if (typeof links == "string") { + links = aLinks.split(/\s*,\s*/).map(function (id) { + return {url: "http://example" + (id != "-1" ? id : "") + ".com/", + title: "site#" + id}; + }); + } + + // Call populateCache() once to make sure that all link fetching that is + // currently in progress has ended. We clear the history, fill it with the + // given entries and call populateCache() now again to make sure the cache + // has the desired contents. + NewTabUtils.links.populateCache(function () { + PlacesTestUtils.clearHistory().then(() => { + fillHistory(links).then(() => { + NewTabUtils.links.populateCache(function () { + NewTabUtils.allPages.update(); + resolve(); + }, true); + }); + }); + }); + }); +} + +function fillHistory(aLinks) { + return new Promise(resolve => { + let numLinks = aLinks.length; + if (!numLinks) { + executeSoon(resolve); + return; + } + + let transitionLink = Ci.nsINavHistoryService.TRANSITION_LINK; + + // Important: To avoid test failures due to clock jitter on Windows XP, call + // Date.now() once here, not each time through the loop. + let now = Date.now() * 1000; + + for (let i = 0; i < aLinks.length; i++) { + let link = aLinks[i]; + let place = { + uri: makeURI(link.url), + title: link.title, + // Links are secondarily sorted by visit date descending, so decrease the + // visit date as we progress through the array so that links appear in the + // grid in the order they're present in the array. + visits: [{visitDate: now - i, transitionType: transitionLink}] + }; + + PlacesUtils.asyncHistory.updatePlaces(place, { + handleError: () => ok(false, "couldn't add visit to history"), + handleResult: function () {}, + handleCompletion: function () { + if (--numLinks == 0) { + resolve(); + } + } + }); + } + }); +} + +/** + * 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: 'http://example3.com/' is pinned in the first cell. 'http://example1.com/' is + * pinned in the third cell. + */ +function setPinnedLinks(aLinks) { + let links = aLinks; + + if (typeof links == "string") { + links = aLinks.split(/\s*,\s*/).map(function (id) { + if (id) + return {url: "http://example" + (id != "-1" ? id : "") + ".com/", + title: "site#" + id, + type: "history"}; + return undefined; + }); + } + + let string = Cc["@mozilla.org/supports-string;1"] + .createInstance(Ci.nsISupportsString); + string.data = JSON.stringify(links); + Services.prefs.setComplexValue("browser.newtabpage.pinned", + Ci.nsISupportsString, string); + + NewTabUtils.pinnedLinks.resetCache(); + NewTabUtils.allPages.update(); +} + +/** + * Restore the grid state. + */ +function restore() { + return new Promise(resolve => { + whenPagesUpdated().then(resolve); + NewTabUtils.restore(); + }); +} + +/** + * Wait until a given condition becomes true. + */ +function waitForCondition(aConditionFn, aMaxTries=50, aCheckInterval=100) { + return new Promise((resolve, reject) => { + let tries = 0; + + function tryNow() { + tries++; + + if (aConditionFn()) { + resolve(); + } else if (tries < aMaxTries) { + tryAgain(); + } else { + reject("Condition timed out: " + aConditionFn.toSource()); + } + } + + function tryAgain() { + setTimeout(tryNow, aCheckInterval); + } + + tryAgain(); + }); +} + +/** + * Creates a new tab containing 'about:newtab'. + */ +function* addNewTabPageTab() { + let tab = yield BrowserTestUtils.openNewForegroundTab(gWindow.gBrowser, "about:newtab", false); + let browser = tab.linkedBrowser; + + // Wait for the document to become visible in case it was preloaded. + yield waitForCondition(() => !browser.contentDocument.hidden) + + yield new Promise(resolve => { + if (NewTabUtils.allPages.enabled) { + // Continue when the link cache has been populated. + NewTabUtils.links.populateCache(function () { + whenSearchInitDone().then(resolve); + }); + } else { + resolve(); + } + }); + + return tab; +} + +/** + * Compares the current grid arrangement with the given pattern. + * @param the pattern (see below) + * + * Example: checkGrid("3p,2,,1p") + * Result: We expect the first cell to contain the pinned site 'http://example3.com/'. + * The second cell contains 'http://example2.com/'. The third cell is empty. + * The fourth cell contains the pinned site 'http://example4.com/'. + */ +function* checkGrid(pattern) { + let length = pattern.split(",").length; + + yield ContentTask.spawn(gWindow.gBrowser.selectedBrowser, + { length, pattern }, function* (args) { + let grid = content.wrappedJSObject.gGrid; + + let sites = grid.sites.slice(0, args.length); + let foundPattern = sites.map(function (aSite) { + if (!aSite) + return ""; + + let pinned = aSite.isPinned(); + let hasPinnedAttr = aSite.node.hasAttribute("pinned"); + + if (pinned != hasPinnedAttr) + ok(false, "invalid state (site.isPinned() != site[pinned])"); + + return aSite.url.replace(/^http:\/\/example(\d+)\.com\/$/, "$1") + (pinned ? "p" : ""); + }); + + Assert.equal(foundPattern, args.pattern, "grid status = " + args.pattern); + }); +} + +/** + * Blocks a site from the grid. + * @param aIndex The cell index. + */ +function blockCell(aIndex) { + return new Promise(resolve => { + whenPagesUpdated().then(resolve); + performOnCell(aIndex, cell => { + return cell.site.block(); + }); + }); +} + +/** + * Pins a site on a given position. + * @param aIndex The cell index. + * @param aPinIndex The index the defines where the site should be pinned. + */ +function pinCell(aIndex) { + performOnCell(aIndex, cell => { + cell.site.pin(); + }); +} + +/** + * Unpins the given cell's site. + * @param aIndex The cell index. + */ +function unpinCell(aIndex) { + return new Promise(resolve => { + whenPagesUpdated().then(resolve); + performOnCell(aIndex, cell => { + cell.site.unpin(); + }); + }); +} + +/** + * Simulates a drag and drop operation. Instead of rearranging a site that is + * is already contained in the newtab grid, this is used to simulate dragging + * an external link onto the grid e.g. the text from the URL bar. + * @param aDestIndex The cell index of the drop target. + */ +function* simulateExternalDrop(aDestIndex) { + let pagesUpdatedPromise = whenPagesUpdated(); + + yield ContentTask.spawn(gWindow.gBrowser.selectedBrowser, aDestIndex, function*(dropIndex) { + return new Promise(resolve => { + const url = "data:text/html;charset=utf-8," + + "<a id='link' href='http://example99.com/'>link</a>"; + + let doc = content.document; + let iframe = doc.createElement("iframe"); + + function iframeLoaded() { + let dataTransfer = new iframe.contentWindow.DataTransfer("dragstart", false); + dataTransfer.mozSetDataAt("text/x-moz-url", "http://example99.com/", 0); + + let event = content.document.createEvent("DragEvent"); + event.initDragEvent("drop", true, true, content, 0, 0, 0, 0, 0, + false, false, false, false, 0, null, dataTransfer); + + let target = content.gGrid.cells[dropIndex].node; + target.dispatchEvent(event); + + iframe.remove(); + + resolve(); + } + + iframe.addEventListener("load", function onLoad() { + iframe.removeEventListener("load", onLoad); + content.setTimeout(iframeLoaded, 0); + }); + + iframe.setAttribute("src", url); + iframe.style.width = "50px"; + iframe.style.height = "50px"; + iframe.style.position = "absolute"; + iframe.style.zIndex = 50; + + // the frame has to be attached to a visible element + let margin = doc.getElementById("newtab-search-container"); + margin.appendChild(iframe); + }); + }); + + yield pagesUpdatedPromise; +} + +/** + * Resumes testing when all pages have been updated. + */ +function whenPagesUpdated() { + return new Promise(resolve => { + let page = { + observe: _ => _, + + update() { + NewTabUtils.allPages.unregister(this); + executeSoon(resolve); + } + }; + + NewTabUtils.allPages.register(page); + registerCleanupFunction(function () { + NewTabUtils.allPages.unregister(page); + }); + }); +} + +/** + * Waits for the response to the page's initial search state request. + */ +function whenSearchInitDone() { + return ContentTask.spawn(gWindow.gBrowser.selectedBrowser, {}, function*() { + return new Promise(resolve => { + if (content.gSearch) { + let searchController = content.gSearch._contentSearchController; + if (searchController.defaultEngine) { + resolve(); + return; + } + } + + let eventName = "ContentSearchService"; + content.addEventListener(eventName, function onEvent(event) { + if (event.detail.type == "State") { + content.removeEventListener(eventName, onEvent); + let resolver = function() { + // Wait for the search controller to receive the event, then resolve. + if (content.gSearch._contentSearchController.defaultEngine) { + resolve(); + return; + } + } + content.setTimeout(resolver, 0); + } + }); + }); + }); +} + +/** + * Changes the newtab customization option and waits for the panel to open and close + * + * @param {string} aTheme + * Can be any of("blank"|"classic"|"enhanced") + */ +function customizeNewTabPage(aTheme) { + return ContentTask.spawn(gWindow.gBrowser.selectedBrowser, aTheme, function*(aTheme) { + + let document = content.document; + let panel = document.getElementById("newtab-customize-panel"); + let customizeButton = document.getElementById("newtab-customize-button"); + + function panelOpened(opened) { + return new Promise( (resolve) => { + let options = {attributes: true, oldValue: true}; + let observer = new content.MutationObserver(function(mutations) { + mutations.forEach(function(mutation) { + document.getElementById("newtab-customize-" + aTheme).click(); + observer.disconnect(); + if (opened == panel.hasAttribute("open")) { + resolve(); + } + }); + }); + observer.observe(panel, options); + }); + } + + let opened = panelOpened(true); + customizeButton.click(); + yield opened; + + let closed = panelOpened(false); + customizeButton.click(); + yield closed; + }); +} + +/** + * Reports presence of a scrollbar + */ +function hasScrollbar() { + return ContentTask.spawn(gWindow.gBrowser.selectedBrowser, {}, function* () { + let docElement = content.document.documentElement; + return docElement.scrollHeight > docElement.clientHeight; + }); +} diff --git a/browser/base/content/test/newtab/searchEngine1x2xLogo.xml b/browser/base/content/test/newtab/searchEngine1x2xLogo.xml new file mode 100644 index 000000000..c8b6749b3 --- /dev/null +++ b/browser/base/content/test/newtab/searchEngine1x2xLogo.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> +<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/"> +<ShortName>browser_newtab_search searchEngine1x2xLogo.xml</ShortName> +<Url type="text/html" method="GET" template="http://browser-newtab-search.com/1x2xlogo" rel="searchform"/> +<!-- #00FF00 --> +<Image width="65" height="26">data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEEAAAAaCAIAAABn3KYmAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gkTADIGr0+8uwAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAL0lEQVRYw+3PAREAAAQEsKd/Z3I4W4NVJtd14uDg4ODg4ODg4ODg4ODg4ODg8Pqw7M0BM+n9I0oAAAAASUVORK5CYII=</Image> +<!-- #00FFFF --> +<Image width="130" height="52">data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIIAAAA0CAIAAADJ8nfCAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gkTADMoaoKANQAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAYklEQVR42u3RQQ0AAAjEMMC/58MECZ9OwtqVlL4bCzAIAwZhwCAMGIQBgzBgEAYMwoBBGDAIAwZhwCAMGIQBgzBgEAYMwoBBGIQBgzBgEAYMwoBBGDAIAwZhwCAMGIQBg+5ar7sCZiri9VUAAAAASUVORK5CYII=</Image> +</SearchPlugin> diff --git a/browser/base/content/test/newtab/searchEngine1xLogo.xml b/browser/base/content/test/newtab/searchEngine1xLogo.xml new file mode 100644 index 000000000..19ac03f48 --- /dev/null +++ b/browser/base/content/test/newtab/searchEngine1xLogo.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/"> +<ShortName>browser_newtab_search searchEngine1xLogo.xml</ShortName> +<Url type="text/html" method="GET" template="http://browser-newtab-search.com/1xlogo" rel="searchform"/> +<!-- #FF0000 --> +<Image width="65" height="26">data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEEAAAAaCAIAAABn3KYmAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gkTADEwS9h64QAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAL0lEQVRYw+3PAREAAAQEsKd/Z3I4W4PV5LyOg4ODg4ODg4ODg4ODg4ODg4PD78MC7cwBM02qquMAAAAASUVORK5CYII=</Image> +</SearchPlugin> diff --git a/browser/base/content/test/newtab/searchEngine2xLogo.xml b/browser/base/content/test/newtab/searchEngine2xLogo.xml new file mode 100644 index 000000000..941bf040d --- /dev/null +++ b/browser/base/content/test/newtab/searchEngine2xLogo.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/"> +<ShortName>browser_newtab_search searchEngine2xLogo.xml</ShortName> +<Url type="text/html" method="GET" template="http://browser-newtab-search.com/2xlogo" rel="searchform"/> +<!-- #0000FF --> +<Image width="130" height="52">data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIIAAAA0CAIAAADJ8nfCAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gkTADMURe38sgAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAYklEQVR42u3RQQ0AAAjEsAP/nsEECZ9OwlrJRN+1BRiEAYMwYBAGDMKAQRgwCAMGYcAgDBiEAYMwYBAGDMKAQRgwCAMGYcAgDMKAQRgwCAMGYcAgDBiEAYMwYBAGDMKAQXctkIQBZ/1YP3YAAAAASUVORK5CYII=</Image> +</SearchPlugin> diff --git a/browser/base/content/test/newtab/searchEngineFavicon.xml b/browser/base/content/test/newtab/searchEngineFavicon.xml new file mode 100644 index 000000000..6f2a970f5 --- /dev/null +++ b/browser/base/content/test/newtab/searchEngineFavicon.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/"> +<ShortName>browser_newtab_search searchEngineFavicon.xml</ShortName> +<Url type="text/html" method="GET" template="http://browser-newtab-search.com/1xlogo" rel="searchform"/> +<Image width="16" height="16">data:application/ico;base64,AAABAAIAICAAAAEAIACoEAAAJgAAABAQAAABACAAaAQAAM4QAAAoAAAAIAAAAEAAAAABACAAAAAAAAAQAAATCwAAEwsAAAAAAAAAAAAA/wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD//wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAABAAAAAgAAAAAQAgAAAAAAAABAAAEwsAABMLAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</Image> +</SearchPlugin> diff --git a/browser/base/content/test/newtab/searchEngineNoLogo.xml b/browser/base/content/test/newtab/searchEngineNoLogo.xml new file mode 100644 index 000000000..bbff6cf8f --- /dev/null +++ b/browser/base/content/test/newtab/searchEngineNoLogo.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8"?> +<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/"> +<ShortName>browser_newtab_search searchEngineNoLogo.xml</ShortName> +<Url type="text/html" method="GET" template="http://browser-newtab-search.com/nologo" rel="searchform"/> +</SearchPlugin> |