зеркало из https://github.com/mozilla/gecko-dev.git
merge fx-team to mozilla-central
This commit is contained in:
Коммит
46de95bc78
|
@ -1467,7 +1467,7 @@ pref("browser.newtabpage.rows", 3);
|
|||
// number of columns of newtab grid
|
||||
pref("browser.newtabpage.columns", 3);
|
||||
|
||||
pref("browser.newtabpage.directorySource", "chrome://global/content/directoryLinks.json");
|
||||
pref("browser.newtabpage.directory.source", "chrome://global/content/directoryLinks.json");
|
||||
|
||||
// Enable the DOM fullscreen API.
|
||||
pref("full-screen-api.enabled", true);
|
||||
|
|
|
@ -217,6 +217,7 @@ let gPage = {
|
|||
}
|
||||
}
|
||||
|
||||
DirectoryLinksProvider.reportShownCount(directoryCount);
|
||||
// Record how many directory sites were shown, but place counts over the
|
||||
// default 9 in the same bucket
|
||||
for (let type of Object.keys(directoryCount)) {
|
||||
|
|
|
@ -56,7 +56,7 @@ const EXPECTED_REFLOWS = [
|
|||
];
|
||||
|
||||
const PREF_PRELOAD = "browser.newtab.preload";
|
||||
const PREF_NEWTAB_DIRECTORYSOURCE = "browser.newtabpage.directorySource";
|
||||
const PREF_NEWTAB_DIRECTORYSOURCE = "browser.newtabpage.directory.source";
|
||||
|
||||
/*
|
||||
* This test ensures that there are no unexpected
|
||||
|
@ -64,26 +64,51 @@ const PREF_NEWTAB_DIRECTORYSOURCE = "browser.newtabpage.directorySource";
|
|||
*/
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
let DirectoryLinksProvider = Cu.import("resource://gre/modules/DirectoryLinksProvider.jsm", {}).DirectoryLinksProvider;
|
||||
let NewTabUtils = Cu.import("resource://gre/modules/NewTabUtils.jsm", {}).NewTabUtils;
|
||||
let Promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
|
||||
|
||||
// resolves promise when directory links are downloaded and written to disk
|
||||
function watchLinksChangeOnce() {
|
||||
let deferred = Promise.defer();
|
||||
let observer = {
|
||||
onManyLinksChanged: () => {
|
||||
DirectoryLinksProvider.removeObserver(observer);
|
||||
NewTabUtils.links.populateCache(() => {
|
||||
NewTabUtils.allPages.update();
|
||||
deferred.resolve();
|
||||
}, true);
|
||||
}
|
||||
};
|
||||
observer.onDownloadFail = observer.onManyLinksChanged;
|
||||
DirectoryLinksProvider.addObserver(observer);
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
Services.prefs.setBoolPref(PREF_PRELOAD, false);
|
||||
Services.prefs.setCharPref(PREF_NEWTAB_DIRECTORYSOURCE, "data:application/json,{}");
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref(PREF_PRELOAD);
|
||||
Services.prefs.clearUserPref(PREF_NEWTAB_DIRECTORYSOURCE);
|
||||
return watchLinksChangeOnce();
|
||||
});
|
||||
|
||||
// Add a reflow observer and open a new tab.
|
||||
docShell.addWeakReflowObserver(observer);
|
||||
BrowserOpenTab();
|
||||
// run tests when directory source change completes
|
||||
watchLinksChangeOnce().then(() => {
|
||||
// Add a reflow observer and open a new tab.
|
||||
docShell.addWeakReflowObserver(observer);
|
||||
BrowserOpenTab();
|
||||
|
||||
// Wait until the tabopen animation has finished.
|
||||
waitForTransitionEnd(function () {
|
||||
// Remove reflow observer and clean up.
|
||||
docShell.removeWeakReflowObserver(observer);
|
||||
gBrowser.removeCurrentTab();
|
||||
|
||||
finish();
|
||||
// Wait until the tabopen animation has finished.
|
||||
waitForTransitionEnd(function () {
|
||||
// Remove reflow observer and clean up.
|
||||
docShell.removeWeakReflowObserver(observer);
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
});
|
||||
});
|
||||
|
||||
Services.prefs.setBoolPref(PREF_PRELOAD, false);
|
||||
// set directory source to empty links
|
||||
Services.prefs.setCharPref(PREF_NEWTAB_DIRECTORYSOURCE, "data:application/json,{}");
|
||||
}
|
||||
|
||||
let observer = {
|
||||
|
|
|
@ -2,20 +2,19 @@
|
|||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const PREF_NEWTAB_ENABLED = "browser.newtabpage.enabled";
|
||||
const PREF_NEWTAB_DIRECTORYSOURCE = "browser.newtabpage.directorySource";
|
||||
const PREF_NEWTAB_DIRECTORYSOURCE = "browser.newtabpage.directory.source";
|
||||
|
||||
Services.prefs.setBoolPref(PREF_NEWTAB_ENABLED, true);
|
||||
// start with no directory links by default
|
||||
Services.prefs.setCharPref(PREF_NEWTAB_DIRECTORYSOURCE, "data:application/json,{}");
|
||||
|
||||
let tmp = {};
|
||||
Cu.import("resource://gre/modules/Promise.jsm", tmp);
|
||||
Cu.import("resource://gre/modules/NewTabUtils.jsm", tmp);
|
||||
Cu.import("resource://gre/modules/DirectoryLinksProvider.jsm", tmp);
|
||||
Cc["@mozilla.org/moz/jssubscript-loader;1"]
|
||||
.getService(Ci.mozIJSSubScriptLoader)
|
||||
.loadSubScript("chrome://browser/content/sanitize.js", tmp);
|
||||
Cu.import("resource://gre/modules/Timer.jsm", tmp);
|
||||
let {Promise, NewTabUtils, Sanitizer, clearTimeout} = tmp;
|
||||
let {Promise, NewTabUtils, Sanitizer, clearTimeout, DirectoryLinksProvider} = tmp;
|
||||
|
||||
let uri = Services.io.newURI("about:newtab", null, null);
|
||||
let principal = Services.scriptSecurityManager.getNoAppCodebasePrincipal(uri);
|
||||
|
@ -60,22 +59,45 @@ registerCleanupFunction(function () {
|
|||
if (oldInnerHeight)
|
||||
gBrowser.contentWindow.innerHeight = oldInnerHeight;
|
||||
|
||||
Services.prefs.clearUserPref(PREF_NEWTAB_ENABLED);
|
||||
Services.prefs.clearUserPref(PREF_NEWTAB_DIRECTORYSOURCE);
|
||||
|
||||
// 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.clearUserPref(PREF_NEWTAB_DIRECTORYSOURCE);
|
||||
|
||||
return watchLinksChangeOnce();
|
||||
});
|
||||
|
||||
/**
|
||||
* Resolves promise when directory links are downloaded and written to disk
|
||||
*/
|
||||
function watchLinksChangeOnce() {
|
||||
let deferred = Promise.defer();
|
||||
let observer = {
|
||||
onManyLinksChanged: () => {
|
||||
DirectoryLinksProvider.removeObserver(observer);
|
||||
deferred.resolve();
|
||||
}
|
||||
};
|
||||
observer.onDownloadFail = observer.onManyLinksChanged;
|
||||
DirectoryLinksProvider.addObserver(observer);
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
/**
|
||||
* Provide the default test function to start our test runner.
|
||||
*/
|
||||
function test() {
|
||||
TestRunner.run();
|
||||
waitForExplicitFinish();
|
||||
// start TestRunner.run() after directory links is downloaded and written to disk
|
||||
watchLinksChangeOnce().then(() => {
|
||||
TestRunner.run();
|
||||
});
|
||||
Services.prefs.setCharPref(PREF_NEWTAB_DIRECTORYSOURCE, "data:application/json,{}");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -86,8 +108,6 @@ let TestRunner = {
|
|||
* Starts the test runner.
|
||||
*/
|
||||
run: function () {
|
||||
waitForExplicitFinish();
|
||||
|
||||
this._iter = runTests();
|
||||
this.next();
|
||||
},
|
||||
|
|
|
@ -10,6 +10,7 @@ skip-if = e10s # Bug ?????? - intermittent crash of child process reported when
|
|||
[browser_bug982298.js]
|
||||
[browser_default_image_filename.js]
|
||||
skip-if = e10s # Bug 933103 - mochitest's EventUtils.synthesizeMouse functions not e10s friendly
|
||||
[browser_f7_caret_browsing.js]
|
||||
[browser_findbar.js]
|
||||
skip-if = e10s # Disabled for e10s: Bug ?????? - seems to be a timing issue with RemoteFinder.jsm messages coming later than the tests expect.
|
||||
[browser_input_file_tooltips.js]
|
||||
|
|
|
@ -0,0 +1,242 @@
|
|||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
"resource://gre/modules/Promise.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
"resource://gre/modules/Task.jsm");
|
||||
|
||||
let gTab = null;
|
||||
let gListener = null;
|
||||
const kURL = "data:text/html;charset=utf-8,Caret browsing is fun.<input id='in'>";
|
||||
|
||||
const kPrefShortcutEnabled = "accessibility.browsewithcaret_shortcut.enabled";
|
||||
const kPrefWarnOnEnable = "accessibility.warn_on_browsewithcaret";
|
||||
const kPrefCaretBrowsingOn = "accessibility.browsewithcaret";
|
||||
|
||||
let oldPrefs = {};
|
||||
for (let pref of [kPrefShortcutEnabled, kPrefWarnOnEnable, kPrefCaretBrowsingOn]) {
|
||||
oldPrefs[pref] = Services.prefs.getBoolPref(pref);
|
||||
}
|
||||
|
||||
Services.prefs.setBoolPref(kPrefShortcutEnabled, true);
|
||||
Services.prefs.setBoolPref(kPrefWarnOnEnable, true);
|
||||
Services.prefs.setBoolPref(kPrefCaretBrowsingOn, false);
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
if (gTab)
|
||||
gBrowser.removeTab(gTab);
|
||||
if (gListener)
|
||||
Services.wm.removeListener(gListener);
|
||||
|
||||
for (let pref of [kPrefShortcutEnabled, kPrefWarnOnEnable, kPrefCaretBrowsingOn]) {
|
||||
Services.prefs.setBoolPref(pref, oldPrefs[pref]);
|
||||
}
|
||||
});
|
||||
|
||||
function promiseWaitForFocusEvent(el) {
|
||||
let deferred = Promise.defer();
|
||||
el.addEventListener("focus", function listener() {
|
||||
el.removeEventListener("focus", listener, false);
|
||||
deferred.resolve();
|
||||
}, false);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function promiseTestPageLoad() {
|
||||
let deferred = Promise.defer();
|
||||
info("Waiting for test page to load.");
|
||||
|
||||
gTab = gBrowser.selectedTab = gBrowser.addTab(kURL);
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
browser.addEventListener("load", function listener() {
|
||||
if (browser.currentURI.spec == "about:blank")
|
||||
return;
|
||||
info("Page loaded: " + browser.currentURI.spec);
|
||||
browser.removeEventListener("load", listener, true);
|
||||
|
||||
deferred.resolve();
|
||||
}, true);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function promiseCaretPromptOpened() {
|
||||
let deferred = Promise.defer();
|
||||
if (gListener) {
|
||||
console.trace();
|
||||
ok(false, "Should not be waiting for another prompt right now.");
|
||||
return false;
|
||||
}
|
||||
info("Waiting for caret prompt to open");
|
||||
gListener = {
|
||||
onOpenWindow: function(win) {
|
||||
let window = win.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindow);
|
||||
window.addEventListener("load", function listener() {
|
||||
window.removeEventListener("load", listener);
|
||||
if (window.location.href == "chrome://global/content/commonDialog.xul") {
|
||||
info("Caret prompt opened, removing listener and focusing");
|
||||
Services.wm.removeListener(gListener);
|
||||
gListener = null;
|
||||
deferred.resolve(window);
|
||||
}
|
||||
});
|
||||
},
|
||||
onCloseWindow: function() {},
|
||||
};
|
||||
Services.wm.addListener(gListener);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function hitF7(async = true) {
|
||||
let f7 = () => EventUtils.sendKey("F7", window.content);
|
||||
// Need to not stop execution inside this task:
|
||||
if (async) {
|
||||
executeSoon(f7);
|
||||
} else {
|
||||
f7();
|
||||
}
|
||||
}
|
||||
|
||||
function syncToggleCaretNoDialog(expected) {
|
||||
let openedDialog = false;
|
||||
promiseCaretPromptOpened().then(function(win) {
|
||||
openedDialog = true;
|
||||
win.close(); // This will eventually return focus here and allow the test to continue...
|
||||
});
|
||||
// Cause the dialog to appear sync, if it still does.
|
||||
hitF7(false);
|
||||
if (gListener) {
|
||||
Services.wm.removeListener(gListener);
|
||||
gListener = null;
|
||||
}
|
||||
let expectedStr = expected ? "on." : "off.";
|
||||
ok(!openedDialog, "Shouldn't open a dialog to turn caret browsing " + expectedStr);
|
||||
let prefVal = Services.prefs.getBoolPref(kPrefCaretBrowsingOn);
|
||||
is(prefVal, expected, "Caret browsing should now be " + expectedStr);
|
||||
}
|
||||
|
||||
add_task(function* checkTogglingCaretBrowsing() {
|
||||
yield promiseTestPageLoad();
|
||||
let textEl = window.content.document.getElementById("in");
|
||||
textEl.focus();
|
||||
|
||||
let promiseGotKey = promiseCaretPromptOpened();
|
||||
hitF7();
|
||||
let prompt = yield promiseGotKey;
|
||||
let doc = prompt.document;
|
||||
is(doc.documentElement.defaultButton, "cancel", "'No' button should be the default");
|
||||
ok(!doc.getElementById("checkbox").checked, "Checkbox shouldn't be checked by default.");
|
||||
let promiseInputFocused = promiseWaitForFocusEvent(textEl);
|
||||
doc.documentElement.cancelDialog();
|
||||
yield promiseInputFocused;
|
||||
ok(!Services.prefs.getBoolPref(kPrefCaretBrowsingOn), "Caret browsing should still be off after cancelling the dialog.");
|
||||
|
||||
promiseGotKey = promiseCaretPromptOpened();
|
||||
hitF7();
|
||||
prompt = yield promiseGotKey;
|
||||
|
||||
doc = prompt.document;
|
||||
is(doc.documentElement.defaultButton, "cancel", "'No' button should be the default");
|
||||
ok(!doc.getElementById("checkbox").checked, "Checkbox shouldn't be checked by default.");
|
||||
promiseInputFocused = promiseWaitForFocusEvent(textEl);
|
||||
doc.documentElement.acceptDialog();
|
||||
yield promiseInputFocused;
|
||||
ok(Services.prefs.getBoolPref(kPrefCaretBrowsingOn), "Caret browsing should be on after accepting the dialog.");
|
||||
|
||||
syncToggleCaretNoDialog(false);
|
||||
|
||||
promiseGotKey = promiseCaretPromptOpened();
|
||||
hitF7();
|
||||
prompt = yield promiseGotKey;
|
||||
doc = prompt.document;
|
||||
|
||||
is(doc.documentElement.defaultButton, "cancel", "'No' button should be the default");
|
||||
ok(!doc.getElementById("checkbox").checked, "Checkbox shouldn't be checked by default.");
|
||||
|
||||
promiseInputFocused = promiseWaitForFocusEvent(textEl);
|
||||
doc.documentElement.cancelDialog();
|
||||
yield promiseInputFocused;
|
||||
|
||||
ok(!Services.prefs.getBoolPref(kPrefCaretBrowsingOn), "Caret browsing should still be off after cancelling the dialog.");
|
||||
|
||||
Services.prefs.setBoolPref(kPrefShortcutEnabled, true);
|
||||
Services.prefs.setBoolPref(kPrefWarnOnEnable, true);
|
||||
Services.prefs.setBoolPref(kPrefCaretBrowsingOn, false);
|
||||
|
||||
gBrowser.removeTab(gTab);
|
||||
gTab = null;
|
||||
});
|
||||
|
||||
add_task(function* toggleCheckboxNoCaretBrowsing() {
|
||||
yield promiseTestPageLoad();
|
||||
let textEl = window.content.document.getElementById("in");
|
||||
textEl.focus();
|
||||
|
||||
let promiseGotKey = promiseCaretPromptOpened();
|
||||
hitF7();
|
||||
let prompt = yield promiseGotKey;
|
||||
let doc = prompt.document;
|
||||
is(doc.documentElement.defaultButton, "cancel", "'No' button should be the default");
|
||||
let checkbox = doc.getElementById("checkbox");
|
||||
ok(!checkbox.checked, "Checkbox shouldn't be checked by default.");
|
||||
|
||||
// Check the box:
|
||||
checkbox.click();
|
||||
let promiseInputFocused = promiseWaitForFocusEvent(textEl);
|
||||
// Say no:
|
||||
doc.documentElement.getButton("cancel").click();
|
||||
yield promiseInputFocused;
|
||||
ok(!Services.prefs.getBoolPref(kPrefCaretBrowsingOn), "Caret browsing should still be off.");
|
||||
|
||||
ok(!Services.prefs.getBoolPref(kPrefShortcutEnabled), "Shortcut should now be disabled.");
|
||||
|
||||
syncToggleCaretNoDialog(false);
|
||||
ok(!Services.prefs.getBoolPref(kPrefShortcutEnabled), "Shortcut should still be disabled.");
|
||||
|
||||
Services.prefs.setBoolPref(kPrefShortcutEnabled, true);
|
||||
Services.prefs.setBoolPref(kPrefWarnOnEnable, true);
|
||||
Services.prefs.setBoolPref(kPrefCaretBrowsingOn, false);
|
||||
|
||||
gBrowser.removeTab(gTab);
|
||||
gTab = null;
|
||||
});
|
||||
|
||||
|
||||
add_task(function* toggleCheckboxNoCaretBrowsing() {
|
||||
yield promiseTestPageLoad();
|
||||
let textEl = window.content.document.getElementById("in");
|
||||
textEl.focus();
|
||||
|
||||
let promiseGotKey = promiseCaretPromptOpened();
|
||||
hitF7();
|
||||
let prompt = yield promiseGotKey;
|
||||
let doc = prompt.document;
|
||||
is(doc.documentElement.defaultButton, "cancel", "'No' button should be the default");
|
||||
let checkbox = doc.getElementById("checkbox");
|
||||
ok(!checkbox.checked, "Checkbox shouldn't be checked by default.");
|
||||
|
||||
// Check the box:
|
||||
checkbox.click();
|
||||
let promiseInputFocused = promiseWaitForFocusEvent(textEl);
|
||||
// Say yes:
|
||||
doc.documentElement.acceptDialog();
|
||||
yield promiseInputFocused;
|
||||
ok(Services.prefs.getBoolPref(kPrefCaretBrowsingOn), "Caret browsing should now be on.");
|
||||
ok(Services.prefs.getBoolPref(kPrefShortcutEnabled), "Shortcut should still be enabled.");
|
||||
ok(!Services.prefs.getBoolPref(kPrefWarnOnEnable), "Should no longer warn when enabling.");
|
||||
|
||||
|
||||
syncToggleCaretNoDialog(false);
|
||||
syncToggleCaretNoDialog(true);
|
||||
syncToggleCaretNoDialog(false);
|
||||
|
||||
Services.prefs.setBoolPref(kPrefShortcutEnabled, true);
|
||||
Services.prefs.setBoolPref(kPrefWarnOnEnable, true);
|
||||
Services.prefs.setBoolPref(kPrefCaretBrowsingOn, false);
|
||||
|
||||
gBrowser.removeTab(gTab);
|
||||
gTab = null;
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
|
@ -1100,7 +1100,11 @@
|
|||
if (event.defaultPrevented || !event.isTrusted)
|
||||
return;
|
||||
|
||||
var isEnabled = this.mPrefs.getBoolPref("accessibility.browsewithcaret_shortcut.enabled");
|
||||
const kPrefShortcutEnabled = "accessibility.browsewithcaret_shortcut.enabled";
|
||||
const kPrefWarnOnEnable = "accessibility.warn_on_browsewithcaret";
|
||||
const kPrefCaretBrowsingOn = "accessibility.browsewithcaret";
|
||||
|
||||
var isEnabled = this.mPrefs.getBoolPref(kPrefShortcutEnabled);
|
||||
if (!isEnabled)
|
||||
return;
|
||||
|
||||
|
@ -1109,12 +1113,12 @@
|
|||
var warn = true;
|
||||
|
||||
try {
|
||||
warn = this.mPrefs.getBoolPref("accessibility.warn_on_browsewithcaret");
|
||||
warn = this.mPrefs.getBoolPref(kPrefWarnOnEnable);
|
||||
} catch (ex) {
|
||||
}
|
||||
|
||||
try {
|
||||
browseWithCaretOn = this.mPrefs.getBoolPref("accessibility.browsewithcaret");
|
||||
browseWithCaretOn = this.mPrefs.getBoolPref(kPrefCaretBrowsingOn);
|
||||
} catch (ex) {
|
||||
}
|
||||
if (warn && !browseWithCaretOn) {
|
||||
|
@ -1125,14 +1129,22 @@
|
|||
var buttonPressed = promptService.confirmEx(window,
|
||||
this.mStrBundle.GetStringFromName('browsewithcaret.checkWindowTitle'),
|
||||
this.mStrBundle.GetStringFromName('browsewithcaret.checkLabel'),
|
||||
promptService.STD_YES_NO_BUTTONS,
|
||||
// Make "No" the default:
|
||||
promptService.STD_YES_NO_BUTTONS | promptService.BUTTON_POS_1_DEFAULT,
|
||||
null, null, null, this.mStrBundle.GetStringFromName('browsewithcaret.checkMsg'),
|
||||
checkValue);
|
||||
if (buttonPressed != 0)
|
||||
if (buttonPressed != 0) {
|
||||
if (checkValue.value) {
|
||||
try {
|
||||
this.mPrefs.setBoolPref(kPrefShortcutEnabled, false);
|
||||
} catch (ex) {
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (checkValue.value) {
|
||||
try {
|
||||
this.mPrefs.setBoolPref("accessibility.warn_on_browsewithcaret", false);
|
||||
this.mPrefs.setBoolPref(kPrefWarnOnEnable, false);
|
||||
}
|
||||
catch (ex) {
|
||||
}
|
||||
|
@ -1141,7 +1153,7 @@
|
|||
|
||||
// Toggle the pref
|
||||
try {
|
||||
this.mPrefs.setBoolPref("accessibility.browsewithcaret",!browseWithCaretOn);
|
||||
this.mPrefs.setBoolPref(kPrefCaretBrowsingOn, !browseWithCaretOn);
|
||||
} catch (ex) {
|
||||
}
|
||||
]]>
|
||||
|
|
|
@ -14,6 +14,7 @@ const XMLHttpRequest =
|
|||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||
"resource://gre/modules/NetUtil.jsm");
|
||||
|
@ -21,6 +22,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
|||
"resource://gre/modules/osfile.jsm")
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
"resource://gre/modules/Promise.jsm");
|
||||
XPCOMUtils.defineLazyGetter(this, "gTextDecoder", () => {
|
||||
return new TextDecoder();
|
||||
});
|
||||
|
||||
// The filename where directory links are stored locally
|
||||
const DIRECTORY_LINKS_FILE = "directoryLinks.json";
|
||||
|
@ -32,7 +36,7 @@ const PREF_MATCH_OS_LOCALE = "intl.locale.matchOS";
|
|||
const PREF_SELECTED_LOCALE = "general.useragent.locale";
|
||||
|
||||
// The preference that tells where to obtain directory links
|
||||
const PREF_DIRECTORY_SOURCE = "browser.newtabpage.directorySource";
|
||||
const PREF_DIRECTORY_SOURCE = "browser.newtabpage.directory.source";
|
||||
|
||||
// The frecency of a directory link
|
||||
const DIRECTORY_FRECENCY = 1000;
|
||||
|
@ -52,7 +56,13 @@ let DirectoryLinksProvider = {
|
|||
|
||||
__linksURL: null,
|
||||
|
||||
_observers: [],
|
||||
_observers: new Set(),
|
||||
|
||||
// links download deferred, resolved upon download completion
|
||||
_downloadDeferred: null,
|
||||
|
||||
// download default interval is 24 hours in milliseconds
|
||||
_downloadIntervalMS: 86400000,
|
||||
|
||||
get _observedPrefs() Object.freeze({
|
||||
linksURL: PREF_DIRECTORY_SOURCE,
|
||||
|
@ -111,8 +121,9 @@ let DirectoryLinksProvider = {
|
|||
if (aData == this._observedPrefs["linksURL"]) {
|
||||
delete this.__linksURL;
|
||||
}
|
||||
this._callObservers("onManyLinksChanged");
|
||||
}
|
||||
// force directory download on changes to any of the observed prefs
|
||||
this._fetchAndCacheLinksIfNecessary(true);
|
||||
},
|
||||
|
||||
_addPrefsObserver: function DirectoryLinksProvider_addObserver() {
|
||||
|
@ -129,38 +140,6 @@ let DirectoryLinksProvider = {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Fetches the current set of directory links.
|
||||
* @param aCallback a callback that is provided a set of links.
|
||||
*/
|
||||
_fetchLinks: function DirectoryLinksProvider_fetchLinks(aCallback) {
|
||||
try {
|
||||
NetUtil.asyncFetch(this._linksURL, (aInputStream, aResult, aRequest) => {
|
||||
let output;
|
||||
if (Components.isSuccessCode(aResult)) {
|
||||
try {
|
||||
let json = NetUtil.readInputStreamToString(aInputStream,
|
||||
aInputStream.available(),
|
||||
{charset: "UTF-8"});
|
||||
let locale = this.locale;
|
||||
output = JSON.parse(json)[locale];
|
||||
}
|
||||
catch (e) {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Cu.reportError(new Error("the fetch of " + this._linksURL + "was unsuccessful"));
|
||||
}
|
||||
aCallback(output || []);
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
Cu.reportError(e);
|
||||
aCallback([]);
|
||||
}
|
||||
},
|
||||
|
||||
_fetchAndCacheLinks: function DirectoryLinksProvider_fetchAndCacheLinks(uri) {
|
||||
let deferred = Promise.defer();
|
||||
let xmlHttp = new XMLHttpRequest();
|
||||
|
@ -172,11 +151,9 @@ let DirectoryLinksProvider = {
|
|||
if (this.status && this.status != 200) {
|
||||
json = "{}";
|
||||
}
|
||||
let directoryLinksFilePath = OS.Path.join(OS.Constants.Path.localProfileDir, DIRECTORY_LINKS_FILE);
|
||||
OS.File.writeAtomic(directoryLinksFilePath, json, {tmpPath: directoryLinksFilePath + ".tmp"})
|
||||
OS.File.writeAtomic(self._directoryFilePath, json, {tmpPath: self._directoryFilePath + ".tmp"})
|
||||
.then(() => {
|
||||
deferred.resolve();
|
||||
self._callObservers("onManyLinksChanged");
|
||||
},
|
||||
() => {
|
||||
deferred.reject("Error writing uri data in profD.");
|
||||
|
@ -197,12 +174,93 @@ let DirectoryLinksProvider = {
|
|||
return deferred.promise;
|
||||
},
|
||||
|
||||
/**
|
||||
* Downloads directory links if needed
|
||||
* @return promise resolved immediately if no download needed, or upon completion
|
||||
*/
|
||||
_fetchAndCacheLinksIfNecessary: function DirectoryLinksProvider_fetchAndCacheLinksIfNecessary(forceDownload=false) {
|
||||
if (this._downloadDeferred) {
|
||||
// fetching links already - just return the promise
|
||||
return this._downloadDeferred.promise;
|
||||
}
|
||||
|
||||
if (forceDownload || this._needsDownload) {
|
||||
this._downloadDeferred = Promise.defer();
|
||||
this._fetchAndCacheLinks(this._linksURL).then(() => {
|
||||
// the new file was successfully downloaded and cached, so update a timestamp
|
||||
this._lastDownloadMS = Date.now();
|
||||
this._downloadDeferred.resolve();
|
||||
this._downloadDeferred = null;
|
||||
this._callObservers("onManyLinksChanged")
|
||||
},
|
||||
error => {
|
||||
this._downloadDeferred.resolve();
|
||||
this._downloadDeferred = null;
|
||||
this._callObservers("onDownloadFail");
|
||||
});
|
||||
return this._downloadDeferred.promise;
|
||||
}
|
||||
|
||||
// download is not needed
|
||||
return Promise.resolve();
|
||||
},
|
||||
|
||||
/**
|
||||
* @return true if download is needed, false otherwise
|
||||
*/
|
||||
get _needsDownload () {
|
||||
// fail if last download occured less then 24 hours ago
|
||||
if ((Date.now() - this._lastDownloadMS) > this._downloadIntervalMS) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Reads directory links file and parses its content
|
||||
* @return a promise resolved to valid list of links or [] if read or parse fails
|
||||
*/
|
||||
_readDirectoryLinksFile: function DirectoryLinksProvider_readDirectoryLinksFile() {
|
||||
return OS.File.read(this._directoryFilePath).then(binaryData => {
|
||||
let output;
|
||||
try {
|
||||
let locale = this.locale;
|
||||
let json = gTextDecoder.decode(binaryData);
|
||||
output = JSON.parse(json)[locale];
|
||||
}
|
||||
catch (e) {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
return output || [];
|
||||
},
|
||||
error => {
|
||||
Cu.reportError(error);
|
||||
return [];
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Submits counts of shown directory links for each type and
|
||||
* triggers directory download if sponsored link was shown
|
||||
*
|
||||
* @param object keyed on types containing counts
|
||||
* @return download promise
|
||||
*/
|
||||
reportShownCount: function DirectoryLinksProvider_reportShownCount(directoryCount) {
|
||||
if (directoryCount.sponsored > 0
|
||||
|| directoryCount.affiliate > 0
|
||||
|| directoryCount.organic > 0) {
|
||||
return this._fetchAndCacheLinksIfNecessary();
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the current set of directory links.
|
||||
* @param aCallback The function that the array of links is passed to.
|
||||
*/
|
||||
getLinks: function DirectoryLinksProvider_getLinks(aCallback) {
|
||||
this._fetchLinks(rawLinks => {
|
||||
this._readDirectoryLinksFile().then(rawLinks => {
|
||||
// all directory links have a frecency of DIRECTORY_FRECENCY
|
||||
aCallback(rawLinks.map((link, position) => {
|
||||
link.frecency = DIRECTORY_FRECENCY;
|
||||
|
@ -214,6 +272,19 @@ let DirectoryLinksProvider = {
|
|||
|
||||
init: function DirectoryLinksProvider_init() {
|
||||
this._addPrefsObserver();
|
||||
// setup directory file path and last download timestamp
|
||||
this._directoryFilePath = OS.Path.join(OS.Constants.Path.localProfileDir, DIRECTORY_LINKS_FILE);
|
||||
this._lastDownloadMS = 0;
|
||||
return Task.spawn(function() {
|
||||
// get the last modified time of the links file if it exists
|
||||
let doesFileExists = yield OS.File.exists(this._directoryFilePath);
|
||||
if (doesFileExists) {
|
||||
let fileInfo = yield OS.File.stat(this._directoryFilePath);
|
||||
this._lastDownloadMS = Date.parse(fileInfo.lastModificationDate);
|
||||
}
|
||||
// fetch directory on startup without force
|
||||
yield this._fetchAndCacheLinksIfNecessary();
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -226,7 +297,11 @@ let DirectoryLinksProvider = {
|
|||
},
|
||||
|
||||
addObserver: function DirectoryLinksProvider_addObserver(aObserver) {
|
||||
this._observers.push(aObserver);
|
||||
this._observers.add(aObserver);
|
||||
},
|
||||
|
||||
removeObserver: function DirectoryLinksProvider_removeObserver(aObserver) {
|
||||
this._observers.delete(aObserver);
|
||||
},
|
||||
|
||||
_callObservers: function DirectoryLinksProvider__callObservers(aMethodName, aArg) {
|
||||
|
@ -242,8 +317,6 @@ let DirectoryLinksProvider = {
|
|||
},
|
||||
|
||||
_removeObservers: function() {
|
||||
while (this._observers.length) {
|
||||
this._observers.pop();
|
||||
}
|
||||
this._observers.clear();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -14,7 +14,9 @@ Cu.import("resource://gre/modules/Promise.jsm");
|
|||
Cu.import("resource://gre/modules/Http.jsm");
|
||||
Cu.import("resource://testing-common/httpd.js");
|
||||
Cu.import("resource://gre/modules/osfile.jsm")
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||
"resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
|
@ -29,6 +31,10 @@ const kTestURL = 'data:application/json,' + JSON.stringify(kURLData);
|
|||
const kLocalePref = DirectoryLinksProvider._observedPrefs.prefSelectedLocale;
|
||||
const kSourceUrlPref = DirectoryLinksProvider._observedPrefs.linksURL;
|
||||
|
||||
// app/profile/firefox.js are not avaialble in xpcshell: hence, preset them
|
||||
Services.prefs.setCharPref(kLocalePref, "en-US");
|
||||
Services.prefs.setCharPref(kSourceUrlPref, kTestURL);
|
||||
|
||||
// httpd settings
|
||||
var server;
|
||||
const kDefaultServerPort = 9000;
|
||||
|
@ -103,19 +109,44 @@ function cleanJsonFile(jsonFile = DIRECTORY_LINKS_FILE) {
|
|||
return OS.File.remove(directoryLinksFilePath);
|
||||
}
|
||||
|
||||
// All tests that call setupDirectoryLinksProvider() must also call cleanDirectoryLinksProvider().
|
||||
function setupDirectoryLinksProvider(options = {}) {
|
||||
let linksURL = options.linksURL || kTestURL;
|
||||
DirectoryLinksProvider.init();
|
||||
Services.prefs.setCharPref(kLocalePref, options.locale || "en-US");
|
||||
Services.prefs.setCharPref(kSourceUrlPref, linksURL);
|
||||
do_check_eq(DirectoryLinksProvider._linksURL, linksURL);
|
||||
function LinksChangeObserver() {
|
||||
this.deferred = Promise.defer();
|
||||
this.onManyLinksChanged = () => this.deferred.resolve();
|
||||
this.onDownloadFail = this.onManyLinksChanged;
|
||||
}
|
||||
|
||||
function cleanDirectoryLinksProvider() {
|
||||
DirectoryLinksProvider.reset();
|
||||
Services.prefs.clearUserPref(kLocalePref);
|
||||
Services.prefs.clearUserPref(kSourceUrlPref);
|
||||
function promiseDirectoryDownloadOnPrefChange(pref, newValue) {
|
||||
let oldValue = Services.prefs.getCharPref(pref);
|
||||
if (oldValue != newValue) {
|
||||
// if the preference value is already equal to newValue
|
||||
// the pref service will not call our observer and we
|
||||
// deadlock. Hence only setup observer if values differ
|
||||
let observer = new LinksChangeObserver();
|
||||
DirectoryLinksProvider.addObserver(observer);
|
||||
Services.prefs.setCharPref(pref, newValue);
|
||||
return observer.deferred.promise;
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function promiseSetupDirectoryLinksProvider(options = {}) {
|
||||
return Task.spawn(function() {
|
||||
let linksURL = options.linksURL || kTestURL;
|
||||
yield DirectoryLinksProvider.init();
|
||||
yield promiseDirectoryDownloadOnPrefChange(kLocalePref, options.locale || "en-US");
|
||||
yield promiseDirectoryDownloadOnPrefChange(kSourceUrlPref, linksURL);
|
||||
do_check_eq(DirectoryLinksProvider._linksURL, linksURL);
|
||||
DirectoryLinksProvider._lastDownloadMS = options.lastDownloadMS || 0;
|
||||
});
|
||||
}
|
||||
|
||||
function promiseCleanDirectoryLinksProvider() {
|
||||
return Task.spawn(function() {
|
||||
yield promiseDirectoryDownloadOnPrefChange(kLocalePref, "en-US");
|
||||
yield promiseDirectoryDownloadOnPrefChange(kSourceUrlPref, kTestURL);
|
||||
DirectoryLinksProvider._lastDownloadMS = 0;
|
||||
DirectoryLinksProvider.reset();
|
||||
});
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
|
@ -130,10 +161,14 @@ function run_test() {
|
|||
// Teardown.
|
||||
do_register_cleanup(function() {
|
||||
server.stop(function() { });
|
||||
DirectoryLinksProvider.reset();
|
||||
Services.prefs.clearUserPref(kLocalePref);
|
||||
Services.prefs.clearUserPref(kSourceUrlPref);
|
||||
});
|
||||
}
|
||||
|
||||
add_task(function test_fetchAndCacheLinks_local() {
|
||||
yield DirectoryLinksProvider.init();
|
||||
yield cleanJsonFile();
|
||||
// Trigger cache of data or chrome uri files in profD
|
||||
yield DirectoryLinksProvider._fetchAndCacheLinks(kTestURL);
|
||||
|
@ -142,6 +177,7 @@ add_task(function test_fetchAndCacheLinks_local() {
|
|||
});
|
||||
|
||||
add_task(function test_fetchAndCacheLinks_remote() {
|
||||
yield DirectoryLinksProvider.init();
|
||||
yield cleanJsonFile();
|
||||
// this must trigger directory links json download and save it to cache file
|
||||
yield DirectoryLinksProvider._fetchAndCacheLinks(kExampleURL);
|
||||
|
@ -150,6 +186,7 @@ add_task(function test_fetchAndCacheLinks_remote() {
|
|||
});
|
||||
|
||||
add_task(function test_fetchAndCacheLinks_malformedURI() {
|
||||
yield DirectoryLinksProvider.init();
|
||||
yield cleanJsonFile();
|
||||
let someJunk = "some junk";
|
||||
try {
|
||||
|
@ -165,6 +202,7 @@ add_task(function test_fetchAndCacheLinks_malformedURI() {
|
|||
});
|
||||
|
||||
add_task(function test_fetchAndCacheLinks_unknownHost() {
|
||||
yield DirectoryLinksProvider.init();
|
||||
yield cleanJsonFile();
|
||||
let nonExistentServer = "http://nosuchhost";
|
||||
try {
|
||||
|
@ -180,6 +218,7 @@ add_task(function test_fetchAndCacheLinks_unknownHost() {
|
|||
});
|
||||
|
||||
add_task(function test_fetchAndCacheLinks_non200Status() {
|
||||
yield DirectoryLinksProvider.init();
|
||||
yield cleanJsonFile();
|
||||
yield DirectoryLinksProvider._fetchAndCacheLinks(kFailURL);
|
||||
let data = yield readJsonFile();
|
||||
|
@ -187,24 +226,19 @@ add_task(function test_fetchAndCacheLinks_non200Status() {
|
|||
});
|
||||
|
||||
// To test onManyLinksChanged observer, trigger a fetch
|
||||
add_task(function test_linkObservers() {
|
||||
let deferred = Promise.defer();
|
||||
let testObserver = {
|
||||
onManyLinksChanged: function() {
|
||||
deferred.resolve();
|
||||
}
|
||||
}
|
||||
add_task(function test_DirectoryLinksProvider__linkObservers() {
|
||||
yield DirectoryLinksProvider.init();
|
||||
|
||||
DirectoryLinksProvider.init();
|
||||
let testObserver = new LinksChangeObserver();
|
||||
DirectoryLinksProvider.addObserver(testObserver);
|
||||
do_check_eq(DirectoryLinksProvider._observers.length, 1);
|
||||
DirectoryLinksProvider._fetchAndCacheLinks(kTestURL);
|
||||
do_check_eq(DirectoryLinksProvider._observers.size, 1);
|
||||
DirectoryLinksProvider._fetchAndCacheLinksIfNecessary(true);
|
||||
|
||||
yield deferred.promise;
|
||||
yield testObserver.deferred.promise;
|
||||
DirectoryLinksProvider._removeObservers();
|
||||
do_check_eq(DirectoryLinksProvider._observers.length, 0);
|
||||
do_check_eq(DirectoryLinksProvider._observers.size, 0);
|
||||
|
||||
cleanDirectoryLinksProvider();
|
||||
yield promiseCleanDirectoryLinksProvider();
|
||||
});
|
||||
|
||||
add_task(function test_linksURL_locale() {
|
||||
|
@ -217,7 +251,7 @@ add_task(function test_linksURL_locale() {
|
|||
};
|
||||
let dataURI = 'data:application/json,' + JSON.stringify(data);
|
||||
|
||||
setupDirectoryLinksProvider({linksURL: dataURI});
|
||||
yield promiseSetupDirectoryLinksProvider({linksURL: dataURI});
|
||||
|
||||
let links;
|
||||
let expected_data;
|
||||
|
@ -227,7 +261,7 @@ add_task(function test_linksURL_locale() {
|
|||
expected_data = [{url: "http://example.com", title: "US", frecency: DIRECTORY_FRECENCY, lastVisitDate: 1}];
|
||||
isIdentical(links, expected_data);
|
||||
|
||||
Services.prefs.setCharPref('general.useragent.locale', 'zh-CN');
|
||||
yield promiseDirectoryDownloadOnPrefChange("general.useragent.locale", "zh-CN");
|
||||
|
||||
links = yield fetchData();
|
||||
do_check_eq(links.length, 2)
|
||||
|
@ -237,11 +271,11 @@ add_task(function test_linksURL_locale() {
|
|||
];
|
||||
isIdentical(links, expected_data);
|
||||
|
||||
cleanDirectoryLinksProvider();
|
||||
yield promiseCleanDirectoryLinksProvider();
|
||||
});
|
||||
|
||||
add_task(function test_prefObserver_url() {
|
||||
setupDirectoryLinksProvider({linksURL: kTestURL});
|
||||
add_task(function test_DirectoryLinksProvider__prefObserver_url() {
|
||||
yield promiseSetupDirectoryLinksProvider({linksURL: kTestURL});
|
||||
|
||||
let links = yield fetchData();
|
||||
do_check_eq(links.length, 1);
|
||||
|
@ -252,18 +286,146 @@ add_task(function test_prefObserver_url() {
|
|||
// 1. _linksURL is properly set after the pref change
|
||||
// 2. invalid source url is correctly handled
|
||||
let exampleUrl = 'http://nosuchhost/bad';
|
||||
Services.prefs.setCharPref(kSourceUrlPref, exampleUrl);
|
||||
yield promiseDirectoryDownloadOnPrefChange(kSourceUrlPref, exampleUrl);
|
||||
do_check_eq(DirectoryLinksProvider._linksURL, exampleUrl);
|
||||
|
||||
// since the download fail, the directory file must remain the same
|
||||
let newLinks = yield fetchData();
|
||||
isIdentical(newLinks, expectedData);
|
||||
|
||||
// now remove the file, and re-download
|
||||
yield cleanJsonFile();
|
||||
yield promiseDirectoryDownloadOnPrefChange(kSourceUrlPref, exampleUrl + " ");
|
||||
// we now should see empty links
|
||||
newLinks = yield fetchData();
|
||||
isIdentical(newLinks, []);
|
||||
|
||||
cleanDirectoryLinksProvider();
|
||||
yield promiseCleanDirectoryLinksProvider();
|
||||
});
|
||||
|
||||
add_task(function test_getLinks_noLocaleData() {
|
||||
setupDirectoryLinksProvider({locale: 'zh-CN'});
|
||||
add_task(function test_DirectoryLinksProvider_getLinks_noLocaleData() {
|
||||
yield promiseSetupDirectoryLinksProvider({locale: 'zh-CN'});
|
||||
let links = yield fetchData();
|
||||
do_check_eq(links.length, 0);
|
||||
cleanDirectoryLinksProvider();
|
||||
yield promiseCleanDirectoryLinksProvider();
|
||||
});
|
||||
|
||||
add_task(function test_DirectoryLinksProvider_needsDownload() {
|
||||
// test timestamping
|
||||
DirectoryLinksProvider._lastDownloadMS = 0;
|
||||
do_check_true(DirectoryLinksProvider._needsDownload);
|
||||
DirectoryLinksProvider._lastDownloadMS = Date.now();
|
||||
do_check_false(DirectoryLinksProvider._needsDownload);
|
||||
DirectoryLinksProvider._lastDownloadMS = Date.now() - (60*60*24 + 1)*1000;
|
||||
do_check_true(DirectoryLinksProvider._needsDownload);
|
||||
DirectoryLinksProvider._lastDownloadMS = 0;
|
||||
});
|
||||
|
||||
add_task(function test_DirectoryLinksProvider_fetchAndCacheLinksIfNecessary() {
|
||||
yield DirectoryLinksProvider.init();
|
||||
yield cleanJsonFile();
|
||||
// explicitly change source url to cause the download during setup
|
||||
yield promiseSetupDirectoryLinksProvider({linksURL: kTestURL+" "});
|
||||
yield DirectoryLinksProvider._fetchAndCacheLinksIfNecessary();
|
||||
|
||||
// inspect lastDownloadMS timestamp which should be 5 seconds less then now()
|
||||
let lastDownloadMS = DirectoryLinksProvider._lastDownloadMS;
|
||||
do_check_true((Date.now() - lastDownloadMS) < 5000);
|
||||
|
||||
// we should have fetched a new file during setup
|
||||
let data = yield readJsonFile();
|
||||
isIdentical(data, kURLData);
|
||||
|
||||
// attempt to download again - the timestamp should not change
|
||||
yield DirectoryLinksProvider._fetchAndCacheLinksIfNecessary();
|
||||
do_check_eq(DirectoryLinksProvider._lastDownloadMS, lastDownloadMS);
|
||||
|
||||
// clean the file and force the download
|
||||
yield cleanJsonFile();
|
||||
yield DirectoryLinksProvider._fetchAndCacheLinksIfNecessary(true);
|
||||
data = yield readJsonFile();
|
||||
isIdentical(data, kURLData);
|
||||
|
||||
// make sure that failed download does not corrupt the file, nor changes lastDownloadMS
|
||||
lastDownloadMS = DirectoryLinksProvider._lastDownloadMS;
|
||||
yield promiseDirectoryDownloadOnPrefChange(kSourceUrlPref, "http://");
|
||||
yield DirectoryLinksProvider._fetchAndCacheLinksIfNecessary(true);
|
||||
data = yield readJsonFile();
|
||||
isIdentical(data, kURLData);
|
||||
do_check_eq(DirectoryLinksProvider._lastDownloadMS, lastDownloadMS);
|
||||
|
||||
// _fetchAndCacheLinksIfNecessary must return same promise if download is in progress
|
||||
let downloadPromise = DirectoryLinksProvider._fetchAndCacheLinksIfNecessary(true);
|
||||
let anotherPromise = DirectoryLinksProvider._fetchAndCacheLinksIfNecessary(true);
|
||||
do_check_true(downloadPromise === anotherPromise);
|
||||
yield downloadPromise;
|
||||
|
||||
yield promiseCleanDirectoryLinksProvider();
|
||||
});
|
||||
|
||||
add_task(function test_DirectoryLinksProvider_fetchDirectoryOnPrefChange() {
|
||||
yield DirectoryLinksProvider.init();
|
||||
|
||||
let testObserver = new LinksChangeObserver();
|
||||
DirectoryLinksProvider.addObserver(testObserver);
|
||||
|
||||
yield cleanJsonFile();
|
||||
// ensure that provider does not think it needs to download
|
||||
do_check_false(DirectoryLinksProvider._needsDownload);
|
||||
|
||||
// change the source URL, which should force directory download
|
||||
yield promiseDirectoryDownloadOnPrefChange(kSourceUrlPref, kExampleURL);
|
||||
// then wait for testObserver to fire and test that json is downloaded
|
||||
yield testObserver.deferred.promise;
|
||||
let data = yield readJsonFile();
|
||||
isIdentical(data, kHttpHandlerData[kExamplePath]);
|
||||
|
||||
yield promiseCleanDirectoryLinksProvider();
|
||||
});
|
||||
|
||||
add_task(function test_DirectoryLinksProvider_fetchDirectoryOnShowCount() {
|
||||
yield promiseSetupDirectoryLinksProvider();
|
||||
|
||||
// set lastdownload to 0 to make DirectoryLinksProvider want to download
|
||||
DirectoryLinksProvider._lastDownloadMS = 0;
|
||||
do_check_true(DirectoryLinksProvider._needsDownload);
|
||||
|
||||
// Tell DirectoryLinksProvider that newtab has no room for sponsored links
|
||||
let directoryCount = {sponsored: 0};
|
||||
yield DirectoryLinksProvider.reportShownCount(directoryCount);
|
||||
// the provider must skip download, hence that lastdownload is still 0
|
||||
do_check_eq(DirectoryLinksProvider._lastDownloadMS, 0);
|
||||
|
||||
// make room for sponsored links and repeat, download should happen
|
||||
directoryCount.sponsored = 1;
|
||||
yield DirectoryLinksProvider.reportShownCount(directoryCount);
|
||||
do_check_true(DirectoryLinksProvider._lastDownloadMS != 0);
|
||||
|
||||
yield promiseCleanDirectoryLinksProvider();
|
||||
});
|
||||
|
||||
add_task(function test_DirectoryLinksProvider_fetchDirectoryOnInit() {
|
||||
// ensure preferences are set to defaults
|
||||
yield promiseSetupDirectoryLinksProvider();
|
||||
// now clean to provider, so we can init it again
|
||||
yield promiseCleanDirectoryLinksProvider();
|
||||
|
||||
yield cleanJsonFile();
|
||||
yield DirectoryLinksProvider.init();
|
||||
let data = yield readJsonFile();
|
||||
isIdentical(data, kURLData);
|
||||
|
||||
yield promiseCleanDirectoryLinksProvider();
|
||||
});
|
||||
|
||||
add_task(function test_DirectoryLinksProvider_getLinksFromCorruptedFile() {
|
||||
yield promiseSetupDirectoryLinksProvider();
|
||||
|
||||
// write bogus json to a file and attempt to fetch from it
|
||||
let directoryLinksFilePath = OS.Path.join(OS.Constants.Path.profileDir, DIRECTORY_LINKS_FILE);
|
||||
yield OS.File.writeAtomic(directoryLinksFilePath, '{"en-US":');
|
||||
let data = yield fetchData();
|
||||
isIdentical(data, []);
|
||||
|
||||
yield promiseCleanDirectoryLinksProvider();
|
||||
});
|
||||
|
|
Загрузка…
Ссылка в новой задаче