import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

View file

@ -0,0 +1,7 @@
"use strict";
module.exports = {
"extends": [
"../../../../../testing/mochitest/browser.eslintrc.js"
]
};

View file

@ -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]

View file

@ -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");
});

View file

@ -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);
});

View file

@ -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;
});

View file

@ -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;
});

View file

@ -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;
});

View file

@ -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");
});

View file

@ -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.");
});

View file

@ -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");
});
});

View file

@ -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();
}

View file

@ -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;
});

View file

@ -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");
});
});

View file

@ -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");
});

View file

@ -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");
});

View file

@ -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");
});

View file

@ -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);
});

View file

@ -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");
});

View file

@ -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");
});

View file

@ -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");
});

View file

@ -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);
});

View file

@ -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");
});

View file

@ -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");
});

View file

@ -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);
});
}

View file

@ -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");
});

View file

@ -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);
});

View file

@ -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> &gt;angles&lt; &amp; \"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 &amp;&lt;&gt;\"'") > -1, "Junk test");
});

View file

@ -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.");
}

View file

@ -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();
});
});

View file

@ -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.");
});

View file

@ -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;
});

View file

@ -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);
});
}

View file

@ -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");
});
});

View file

@ -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;
}

View file

@ -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");
});

View file

@ -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 };
}

View file

@ -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])
});
})();

View file

@ -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;
});
}

View file

@ -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>

View file

@ -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>

View file

@ -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>

File diff suppressed because one or more lines are too long

View file

@ -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>