634 lines
19 KiB
JavaScript
634 lines
19 KiB
JavaScript
/* Any copyright is dedicated to the Public Domain.
|
|
https://creativecommons.org/publicdomain/zero/1.0/ */
|
|
|
|
"use strict";
|
|
|
|
const { setTimeout } = ChromeUtils.importESModule(
|
|
"resource://gre/modules/Timer.sys.mjs"
|
|
);
|
|
const { NetUtil } = ChromeUtils.importESModule(
|
|
"resource://gre/modules/NetUtil.sys.mjs"
|
|
);
|
|
const { PlacesTestUtils } = ChromeUtils.importESModule(
|
|
"resource://testing-common/PlacesTestUtils.sys.mjs"
|
|
);
|
|
const { PlacesUtils } = ChromeUtils.importESModule(
|
|
"resource://gre/modules/PlacesUtils.sys.mjs"
|
|
);
|
|
const { TestUtils } = ChromeUtils.importESModule(
|
|
"resource://testing-common/TestUtils.sys.mjs"
|
|
);
|
|
const { DownloadHistory } = ChromeUtils.importESModule(
|
|
"resource://gre/modules/DownloadHistory.sys.mjs"
|
|
);
|
|
const { AddonTestUtils } = ChromeUtils.importESModule(
|
|
"resource://testing-common/AddonTestUtils.sys.mjs"
|
|
);
|
|
const { ExtensionTestUtils } = ChromeUtils.importESModule(
|
|
"resource://testing-common/ExtensionXPCShellUtils.sys.mjs"
|
|
);
|
|
const { formAutofillStorage } = ChromeUtils.importESModule(
|
|
"resource://autofill/FormAutofillStorage.sys.mjs"
|
|
);
|
|
const { Sanitizer } = ChromeUtils.importESModule(
|
|
"resource:///modules/Sanitizer.sys.mjs"
|
|
);
|
|
const { NewTabUtils } = ChromeUtils.importESModule(
|
|
"resource://gre/modules/NewTabUtils.sys.mjs"
|
|
);
|
|
const { CookieXPCShellUtils } = ChromeUtils.importESModule(
|
|
"resource://testing-common/CookieXPCShellUtils.sys.mjs"
|
|
);
|
|
|
|
ExtensionTestUtils.init(this);
|
|
AddonTestUtils.init(this);
|
|
AddonTestUtils.createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1");
|
|
|
|
const nsLoginInfo = new Components.Constructor(
|
|
"@mozilla.org/login-manager/loginInfo;1",
|
|
Ci.nsILoginInfo,
|
|
"init"
|
|
);
|
|
|
|
/**
|
|
* This suite of tests ensures that the current backup will be deleted, and
|
|
* a new one generated when certain user actions occur.
|
|
*/
|
|
|
|
/**
|
|
* Adds a history visit to the Places database.
|
|
*
|
|
* @param {string} uriString
|
|
* A string representation of the URI to add a visit for.
|
|
* @param {number} [timestamp=Date.now()]
|
|
* The timestamp for the visit to be used. By default, this is the current
|
|
* date and time.
|
|
* @returns {Promise<undefined>}
|
|
*/
|
|
async function addTestHistory(uriString, timestamp = Date.now()) {
|
|
let uri = NetUtil.newURI(uriString);
|
|
await PlacesTestUtils.addVisits({
|
|
uri,
|
|
transition: Ci.nsINavHistoryService.TRANSITION_TYPED,
|
|
visitDate: timestamp * 1000,
|
|
});
|
|
}
|
|
|
|
let gCookieCounter = 0;
|
|
|
|
const COOKIE_HOST = "example.com";
|
|
const COOKIE_PATH = "/";
|
|
const COOKIE_ORIGIN_ATTRIBUTES = Object.freeze({});
|
|
|
|
/**
|
|
* Adds a new non-session cookie to the cookie database with the host set
|
|
* as COOKIE_HOST, the path as COOKIE_PATH, with the origin attributes of
|
|
* COOKIE_ORIGIN_ATTRIBUTES and a generated name and value.
|
|
*
|
|
* @param {boolean} isSessionCookie
|
|
* True if the cookie should be a session cookie.
|
|
* @returns {string}
|
|
* The name of the cookie that was generated.
|
|
*/
|
|
function addTestCookie(isSessionCookie) {
|
|
gCookieCounter++;
|
|
let name = `Cookie name: ${gCookieCounter}`;
|
|
|
|
Services.cookies.add(
|
|
COOKIE_HOST,
|
|
COOKIE_PATH,
|
|
name,
|
|
`Cookie value: ${gCookieCounter}`,
|
|
false,
|
|
false,
|
|
isSessionCookie,
|
|
Date.now() / 1000 + 1,
|
|
COOKIE_ORIGIN_ATTRIBUTES,
|
|
Ci.nsICookie.SAMESITE_NONE,
|
|
Ci.nsICookie.SCHEME_HTTP
|
|
);
|
|
|
|
return name;
|
|
}
|
|
|
|
/**
|
|
* A helper function that sets up a BackupService to be instrumented to detect
|
|
* a backup regeneration, and then runs an async taskFn to ensure that the
|
|
* regeneration occurs.
|
|
*
|
|
* @param {Function} taskFn
|
|
* The async function to run after the BackupService has been set up. It is
|
|
* not passed any arguments.
|
|
* @param {string} msg
|
|
* The message to write in the assertion when the regeneration occurs.
|
|
*/
|
|
async function expectRegeneration(taskFn, msg) {
|
|
let sandbox = sinon.createSandbox();
|
|
// Override the default REGENERATION_DEBOUNCE_RATE_MS to 0 so that we don't
|
|
// have to wait long for the debouncer to fire. We need to do this before
|
|
// we construct the BackupService that we'll use for the test.
|
|
sandbox.stub(BackupService, "REGENERATION_DEBOUNCE_RATE_MS").get(() => 0);
|
|
|
|
let bs = new BackupService();
|
|
|
|
// Now we set up some stubs on the BackupService to detect calls to
|
|
// deleteLastBackup and createbackupOnIdleDispatch, which are both called
|
|
// on regeneration.
|
|
let deleteDeferred = Promise.withResolvers();
|
|
sandbox.stub(bs, "deleteLastBackup").callsFake(() => {
|
|
Assert.ok(true, "Saw deleteLastBackup call");
|
|
deleteDeferred.resolve();
|
|
return Promise.resolve();
|
|
});
|
|
|
|
let createBackupDeferred = Promise.withResolvers();
|
|
sandbox.stub(bs, "createBackupOnIdleDispatch").callsFake(() => {
|
|
Assert.ok(true, "Saw createBackupOnIdleDispatch call");
|
|
createBackupDeferred.resolve();
|
|
return Promise.resolve();
|
|
});
|
|
|
|
// Creating a new backup will only occur if scheduled backups are enabled,
|
|
// so let's set the pref...
|
|
Services.prefs.setBoolPref("browser.backup.scheduled.enabled", true);
|
|
// But also stub out `onIdle` so that we don't get any interference during
|
|
// our test by the idle service.
|
|
sandbox.stub(bs, "onIdle").returns();
|
|
|
|
bs.initBackupScheduler();
|
|
|
|
await taskFn();
|
|
|
|
let regenerationPromises = [
|
|
deleteDeferred.promise,
|
|
createBackupDeferred.promise,
|
|
];
|
|
|
|
// We'll wait for 1 second before considering the regeneration a bust.
|
|
let timeoutPromise = new Promise((resolve, reject) =>
|
|
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
|
|
setTimeout(() => {
|
|
reject();
|
|
}, 1000)
|
|
);
|
|
|
|
try {
|
|
await Promise.race([Promise.all(regenerationPromises), timeoutPromise]);
|
|
Assert.ok(true, msg);
|
|
} catch (e) {
|
|
Assert.ok(false, "Timed out waiting for regeneration.");
|
|
}
|
|
|
|
bs.uninitBackupScheduler();
|
|
sandbox.restore();
|
|
}
|
|
|
|
/**
|
|
* A helper function that sets up a BackupService to be instrumented to detect
|
|
* a backup regeneration, and then runs an async taskFn to ensure that the
|
|
* regeneration DOES NOT occur.
|
|
*
|
|
* @param {Function} taskFn
|
|
* The async function to run after the BackupService has been set up. It is
|
|
* not passed any arguments.
|
|
* @param {string} msg
|
|
* The message to write in the assertion when the regeneration does not occur
|
|
* within the timeout.
|
|
*/
|
|
async function expectNoRegeneration(taskFn, msg) {
|
|
let sandbox = sinon.createSandbox();
|
|
// Override the default REGENERATION_DEBOUNCE_RATE_MS to 0 so that we don't
|
|
// have to wait long for the debouncer to fire. We need to do this before
|
|
// we construct the BackupService that we'll use for the test.
|
|
sandbox.stub(BackupService, "REGENERATION_DEBOUNCE_RATE_MS").get(() => 0);
|
|
|
|
let bs = new BackupService();
|
|
|
|
// Now we set up some stubs on the BackupService to detect calls to
|
|
// deleteLastBackup and createbackupOnIdleDispatch, which are both called
|
|
// on regeneration. We share the same Promise here because in either of these
|
|
// being called, this test is a failure.
|
|
let regenerationPromise = Promise.withResolvers();
|
|
sandbox.stub(bs, "deleteLastBackup").callsFake(() => {
|
|
Assert.ok(false, "Unexpectedly saw deleteLastBackup call");
|
|
regenerationPromise.reject();
|
|
return Promise.resolve();
|
|
});
|
|
|
|
sandbox.stub(bs, "createBackupOnIdleDispatch").callsFake(() => {
|
|
Assert.ok(false, "Unexpectedly saw createBackupOnIdleDispatch call");
|
|
regenerationPromise.reject();
|
|
return Promise.resolve();
|
|
});
|
|
|
|
// Creating a new backup will only occur if scheduled backups are enabled,
|
|
// so let's set the pref...
|
|
Services.prefs.setBoolPref("browser.backup.scheduled.enabled", true);
|
|
// But also stub out `onIdle` so that we don't get any interference during
|
|
// our test by the idle service.
|
|
sandbox.stub(bs, "onIdle").returns();
|
|
|
|
bs.initBackupScheduler();
|
|
|
|
await taskFn();
|
|
|
|
// We'll wait for 1 second, and if we don't see the regeneration attempt,
|
|
// we'll assume it's not coming.
|
|
let timeoutPromise = new Promise(resolve =>
|
|
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
|
|
setTimeout(() => {
|
|
Assert.ok(true, "Saw no regeneration within 1 second.");
|
|
resolve();
|
|
}, 1000)
|
|
);
|
|
|
|
try {
|
|
await Promise.race([regenerationPromise.promise, timeoutPromise]);
|
|
Assert.ok(true, msg);
|
|
} catch (e) {
|
|
Assert.ok(false, "Saw an unexpected regeneration.");
|
|
}
|
|
|
|
bs.uninitBackupScheduler();
|
|
sandbox.restore();
|
|
}
|
|
|
|
add_setup(() => {
|
|
CookieXPCShellUtils.createServer({ hosts: ["example.com"] });
|
|
Services.prefs.setBoolPref("dom.security.https_first", false);
|
|
|
|
// Allow all cookies.
|
|
Services.prefs.setIntPref("network.cookie.cookieBehavior", 0);
|
|
Services.prefs.setBoolPref(
|
|
"network.cookieJarSettings.unblocked_for_testing",
|
|
true
|
|
);
|
|
});
|
|
|
|
/**
|
|
* Tests that backup regeneration occurs on the page-removed PlacesObserver
|
|
* event that indicates manual user deletion of a page from history.
|
|
*/
|
|
add_task(async function test_page_removed_reason_deleted() {
|
|
const PAGE_URI = "https://test.com";
|
|
await addTestHistory(PAGE_URI);
|
|
await expectRegeneration(async () => {
|
|
await PlacesUtils.history.remove(PAGE_URI);
|
|
}, "Saw regeneration on page-removed via user deletion.");
|
|
});
|
|
|
|
/**
|
|
* Tests that backup regeneration does not occur on the page-removed
|
|
* PlacesObserver event that indicates automatic deletion of a page from
|
|
* history.
|
|
*/
|
|
add_task(async function test_page_removed_reason_expired() {
|
|
const PAGE_URI = "https://test.com";
|
|
await addTestHistory(
|
|
PAGE_URI,
|
|
0 /* Timestamp at 0 is wayyyyy in the past, in the 1960's - it's the UNIX epoch start date */
|
|
);
|
|
await expectNoRegeneration(async () => {
|
|
// This is how the Places tests force expiration, so we'll do it the same
|
|
// way.
|
|
let promise = TestUtils.topicObserved(
|
|
PlacesUtils.TOPIC_EXPIRATION_FINISHED
|
|
);
|
|
let expire = Cc["@mozilla.org/places/expiration;1"].getService(
|
|
Ci.nsIObserver
|
|
);
|
|
expire.observe(null, "places-debug-start-expiration", -1);
|
|
await promise;
|
|
}, "Saw no regeneration on page-removed via expiration.");
|
|
});
|
|
|
|
/**
|
|
* Tests that backup regeneration occurs on the history-cleared PlacesObserver
|
|
* event that indicates clearing of all user history.
|
|
*/
|
|
add_task(async function test_history_cleared() {
|
|
const PAGE_URI = "https://test.com";
|
|
await addTestHistory(PAGE_URI);
|
|
await expectRegeneration(async () => {
|
|
await PlacesUtils.history.clear();
|
|
}, "Saw regeneration on history-cleared.");
|
|
});
|
|
|
|
/**
|
|
* Tests that backup regeneration occurs when removing a download from history.
|
|
*/
|
|
add_task(async function test_download_removed() {
|
|
const FAKE_FILE_PATH = PathUtils.join(PathUtils.tempDir, "somefile.zip");
|
|
let download = {
|
|
source: {
|
|
url: "https://test.com/somefile",
|
|
isPrivate: false,
|
|
},
|
|
target: { path: FAKE_FILE_PATH },
|
|
};
|
|
await DownloadHistory.addDownloadToHistory(download);
|
|
|
|
await expectRegeneration(async () => {
|
|
await PlacesUtils.history.remove(download.source.url);
|
|
}, "Saw regeneration on download removal.");
|
|
});
|
|
|
|
/**
|
|
* Tests that backup regeneration occurs when clearing all downloads.
|
|
*/
|
|
add_task(async function test_all_downloads_removed() {
|
|
const FAKE_FILE_PATH = PathUtils.join(PathUtils.tempDir, "somefile.zip");
|
|
let download1 = {
|
|
source: {
|
|
url: "https://test.com/somefile",
|
|
isPrivate: false,
|
|
},
|
|
target: { path: FAKE_FILE_PATH },
|
|
};
|
|
let download2 = {
|
|
source: {
|
|
url: "https://test.com/somefile2",
|
|
isPrivate: false,
|
|
},
|
|
target: { path: FAKE_FILE_PATH },
|
|
};
|
|
await DownloadHistory.addDownloadToHistory(download1);
|
|
await DownloadHistory.addDownloadToHistory(download2);
|
|
|
|
await expectRegeneration(async () => {
|
|
await PlacesUtils.history.removeVisitsByFilter({
|
|
transition: PlacesUtils.history.TRANSITIONS.DOWNLOAD,
|
|
});
|
|
}, "Saw regeneration on all downloads removed.");
|
|
});
|
|
|
|
/**
|
|
* Tests that backup regeneration occurs when removing a password.
|
|
*/
|
|
add_task(async function test_password_removed() {
|
|
let login = new nsLoginInfo(
|
|
"https://example.com",
|
|
"https://example.com",
|
|
null,
|
|
"notifyu1",
|
|
"notifyp1",
|
|
"user",
|
|
"pass"
|
|
);
|
|
await Services.logins.addLoginAsync(login);
|
|
|
|
await expectRegeneration(async () => {
|
|
Services.logins.removeLogin(login);
|
|
}, "Saw regeneration on password removed.");
|
|
});
|
|
|
|
/**
|
|
* Tests that backup regeneration occurs when all passwords are removed.
|
|
*/
|
|
add_task(async function test_all_passwords_removed() {
|
|
let login1 = new nsLoginInfo(
|
|
"https://example.com",
|
|
"https://example.com",
|
|
null,
|
|
"notifyu1",
|
|
"notifyp1",
|
|
"user",
|
|
"pass"
|
|
);
|
|
let login2 = new nsLoginInfo(
|
|
"https://example.com",
|
|
"https://example.com",
|
|
null,
|
|
"",
|
|
"notifyp1",
|
|
"",
|
|
"pass"
|
|
);
|
|
|
|
await Services.logins.addLoginAsync(login1);
|
|
await Services.logins.addLoginAsync(login2);
|
|
|
|
await expectRegeneration(async () => {
|
|
Services.logins.removeAllLogins();
|
|
}, "Saw regeneration on all passwords removed.");
|
|
});
|
|
|
|
/**
|
|
* Tests that backup regeneration occurs when removing a bookmark.
|
|
*/
|
|
add_task(async function test_bookmark_removed() {
|
|
let bookmark = await PlacesUtils.bookmarks.insert({
|
|
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
|
url: "data:text/plain,Content",
|
|
title: "Regeneration Test Bookmark",
|
|
});
|
|
|
|
await expectRegeneration(async () => {
|
|
await PlacesUtils.bookmarks.remove(bookmark);
|
|
}, "Saw regeneration on bookmark removed.");
|
|
});
|
|
|
|
/**
|
|
* Tests that backup regeneration occurs when all bookmarks are removed.
|
|
*/
|
|
add_task(async function test_all_bookmarks_removed() {
|
|
await PlacesUtils.bookmarks.insert({
|
|
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
|
url: "data:text/plain,Content",
|
|
title: "Regeneration Test Bookmark 1",
|
|
});
|
|
await PlacesUtils.bookmarks.insert({
|
|
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
|
url: "data:text/plain,Content2",
|
|
title: "Regeneration Test Bookmark 2",
|
|
});
|
|
|
|
await expectRegeneration(async () => {
|
|
await PlacesUtils.bookmarks.eraseEverything();
|
|
}, "Saw regeneration on all bookmarks removed.");
|
|
});
|
|
|
|
/**
|
|
* Tests that backup regeneration occurs when an addon is uninstalled.
|
|
*/
|
|
add_task(async function test_addon_uninstalled() {
|
|
await AddonTestUtils.promiseStartupManager();
|
|
|
|
let testExtension = ExtensionTestUtils.loadExtension({
|
|
manifest: {
|
|
name: "Some test extension",
|
|
browser_specific_settings: {
|
|
gecko: { id: "test-backup-regeneration@ext-0" },
|
|
},
|
|
},
|
|
useAddonManager: "temporary",
|
|
});
|
|
|
|
await testExtension.startup();
|
|
|
|
await expectRegeneration(async () => {
|
|
await testExtension.unload();
|
|
}, "Saw regeneration on test extension uninstall.");
|
|
});
|
|
|
|
/**
|
|
* Tests that backup regeneration occurs when removing a payment method.
|
|
*/
|
|
add_task(async function test_payment_method_removed() {
|
|
await formAutofillStorage.initialize();
|
|
let guid = await formAutofillStorage.creditCards.add({
|
|
"cc-name": "Foxy the Firefox",
|
|
"cc-number": "5555555555554444",
|
|
"cc-exp-month": 5,
|
|
"cc-exp-year": 2099,
|
|
});
|
|
|
|
await expectRegeneration(async () => {
|
|
await formAutofillStorage.creditCards.remove(guid);
|
|
}, "Saw regeneration on payment method removal.");
|
|
});
|
|
|
|
/**
|
|
* Tests that backup regeneration occurs when removing an address.
|
|
*/
|
|
add_task(async function test_address_removed() {
|
|
await formAutofillStorage.initialize();
|
|
let guid = await formAutofillStorage.addresses.add({
|
|
"given-name": "John",
|
|
"additional-name": "R.",
|
|
"family-name": "Smith",
|
|
organization: "World Wide Web Consortium",
|
|
"street-address": "32 Vassar Street\\\nMIT Room 32-G524",
|
|
"address-level2": "Cambridge",
|
|
"address-level1": "MA",
|
|
"postal-code": "02139",
|
|
country: "US",
|
|
tel: "+15195555555",
|
|
email: "user@example.com",
|
|
});
|
|
|
|
await expectRegeneration(async () => {
|
|
await formAutofillStorage.addresses.remove(guid);
|
|
}, "Saw regeneration on address removal.");
|
|
});
|
|
|
|
/**
|
|
* Tests that backup regeneration occurs after any kind of data sanitization.
|
|
*/
|
|
add_task(async function test_sanitization() {
|
|
await expectRegeneration(async () => {
|
|
await Sanitizer.sanitize(["cookiesAndStorage"]);
|
|
}, "Saw regeneration on sanitization of cookies and storage.");
|
|
|
|
await expectRegeneration(async () => {
|
|
await Sanitizer.sanitize(["siteSettings"]);
|
|
}, "Saw regeneration on sanitization of site settings.");
|
|
});
|
|
|
|
/**
|
|
* Tests that backup regeneration occurs after a permission is removed.
|
|
*/
|
|
add_task(async function test_permission_removed() {
|
|
let principal =
|
|
Services.scriptSecurityManager.createContentPrincipalFromOrigin(
|
|
"https://test-permission-site.com"
|
|
);
|
|
const PERMISSION_TYPE = "desktop-notification";
|
|
Services.perms.addFromPrincipal(
|
|
principal,
|
|
PERMISSION_TYPE,
|
|
Services.perms.ALLOW_ACTION
|
|
);
|
|
|
|
await expectRegeneration(async () => {
|
|
Services.perms.removeFromPrincipal(principal, PERMISSION_TYPE);
|
|
}, "Saw regeneration on permission removal.");
|
|
});
|
|
|
|
/**
|
|
* Tests that backup regeneration occurs when persistent and session cookies are
|
|
* removed.
|
|
*/
|
|
add_task(async function test_cookies_removed() {
|
|
for (let isSessionCookie of [false, true]) {
|
|
Services.cookies.removeAll();
|
|
|
|
// First, let's remove a single cookie by host, path, name and origin
|
|
// attrbutes.
|
|
let name = addTestCookie(isSessionCookie);
|
|
|
|
if (isSessionCookie) {
|
|
Assert.equal(
|
|
Services.cookies.sessionCookies.length,
|
|
1,
|
|
"Make sure we actually added a session cookie."
|
|
);
|
|
} else {
|
|
Assert.equal(
|
|
Services.cookies.sessionCookies.length,
|
|
0,
|
|
"Make sure we actually added a persistent cookie."
|
|
);
|
|
}
|
|
|
|
await expectRegeneration(async () => {
|
|
Services.cookies.remove(
|
|
COOKIE_HOST,
|
|
name,
|
|
COOKIE_PATH,
|
|
COOKIE_ORIGIN_ATTRIBUTES
|
|
);
|
|
}, "Saw regeneration on single cookie removal.");
|
|
|
|
// Now remove all cookies for a particular host.
|
|
addTestCookie(isSessionCookie);
|
|
addTestCookie(isSessionCookie);
|
|
|
|
await expectRegeneration(async () => {
|
|
Services.cookies.removeCookiesFromExactHost(COOKIE_HOST, "{}");
|
|
}, "Saw regeneration on cookie removal by host.");
|
|
|
|
// Now remove all cookies.
|
|
const COOKIES_TO_ADD = 10;
|
|
for (let i = 0; i < COOKIES_TO_ADD; ++i) {
|
|
addTestCookie(isSessionCookie);
|
|
}
|
|
|
|
await expectRegeneration(async () => {
|
|
Services.cookies.removeAll();
|
|
}, "Saw regeneration on all cookie removal.");
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Tests that backup regeneration does not occur if a cookie is removed due
|
|
* to expiry.
|
|
*/
|
|
add_task(async function test_cookies_not_removed_expiry() {
|
|
await expectNoRegeneration(async () => {
|
|
const COOKIE = "test=test";
|
|
await CookieXPCShellUtils.setCookieToDocument(
|
|
"http://example.com/",
|
|
COOKIE
|
|
);
|
|
|
|
// Now expire that cookie by using the same value, but setting the expires
|
|
// directive to sometime wayyyyy in the past.
|
|
const EXPIRE = `${COOKIE}; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`;
|
|
await CookieXPCShellUtils.setCookieToDocument(
|
|
"http://example.com/",
|
|
EXPIRE
|
|
);
|
|
}, "Saw no regeneration on cookie expiry.");
|
|
});
|
|
|
|
/**
|
|
* Tests that backup regeneration occurs when newtab links are blocked.
|
|
*/
|
|
add_task(async function test_newtab_link_blocked() {
|
|
NewTabUtils.init();
|
|
|
|
await expectRegeneration(async () => {
|
|
NewTabUtils.activityStreamLinks.blockURL("https://example.com");
|
|
}, "Saw regeneration on the blocking of a newtab link");
|
|
});
|