diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index b00a9ece6c3f4..2cedc48abfb42 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -3139,6 +3139,8 @@ pref("startup.homepage_override_url_nimbus", ""); // These prefs are referring to the Fx update version pref("startup.homepage_override_nimbus_maxVersion", ""); pref("startup.homepage_override_nimbus_minVersion", ""); +// Pref to disable all What's New pages +pref("startup.homepage_override_nimbus_disable_wnp", false); // Pref to enable the content relevancy feature. pref("toolkit.contentRelevancy.enabled", false); diff --git a/browser/components/BrowserContentHandler.sys.mjs b/browser/components/BrowserContentHandler.sys.mjs index 4d97c94b21181..16bfb8954bb33 100644 --- a/browser/components/BrowserContentHandler.sys.mjs +++ b/browser/components/BrowserContentHandler.sys.mjs @@ -189,13 +189,20 @@ function needHomepageOverride(updateMilestones = true) { * The default override page * @param nimbusOverridePage * Nimbus provided URL + * @param disableWnp + * Boolean, disables all WNPs if true * @return The override page. */ function getPostUpdateOverridePage( update, defaultOverridePage, - nimbusOverridePage + nimbusOverridePage, + disableWnp ) { + if (disableWnp) { + return ""; + } + update = update.QueryInterface(Ci.nsIWritablePropertyBag); let actions = update.getProperty("actions"); // When the update doesn't specify actions fallback to the original behavior @@ -784,15 +791,22 @@ nsBrowserContentHandler.prototype = { "startup.homepage_override_nimbus_minVersion", "" ); + // Pref used to disable all WNPs + const disableWNP = Services.prefs.getBoolPref( + "startup.homepage_override_nimbus_disable_wnp", + false + ); let nimbusWNP; + // minVersion and maxVersion optional variables + const versionMatch = + (!maxVersion || + Services.vc.compare(update.appVersion, maxVersion) <= 0) && + (!minVersion || + Services.vc.compare(update.appVersion, minVersion) >= 0); // The update version should be less than or equal to maxVersion and // greater or equal to minVersion set by the experiment. - if ( - nimbusOverrideUrl && - Services.vc.compare(update.appVersion, maxVersion) <= 0 && - Services.vc.compare(update.appVersion, minVersion) >= 0 - ) { + if (nimbusOverrideUrl && versionMatch) { try { let uri = Services.io.newURI(nimbusOverrideUrl); // Only allow https://www.mozilla.org and https://www.mozilla.com @@ -816,19 +830,21 @@ nsBrowserContentHandler.prototype = { overridePage = getPostUpdateOverridePage( update, overridePage, - nimbusWNP + nimbusWNP, + disableWNP ); // Record a Nimbus exposure event for the whatsNewPage feature. - // The override page could be set in 3 ways: 1. set by Nimbus 2. - // set by the update file(openURL) 3. The default evergreen page(Set by the - // startup.homepage_override_url pref, could be different - // depending on the Fx channel). This is done to record that the - // control cohort could have seen the experimental What's New Page - // (and will instead see the default What's New Page). - // recordExposureEvent only records an event if the user is - // enrolled in an experiment or rollout on the whatsNewPage - // feature, so it's safe to call it unconditionally. - if (overridePage) { + // The override page could be set in 3 ways: 1. set by Nimbus; 2. + // set by the update file (openURL); 3. defaulting to the + // evergreen page (set by the startup.homepage_override_url pref, + // value depends on the Fx channel). This is done to record that + // the control cohort could have seen the experimental What's New + // Page (and will instead see the default What's New Page, or + // won't see a WNP if the experiment disabled it by setting + // disable_wnp). `recordExposureEvent` only records an event if + // the user is enrolled in an experiment or rollout on the + // whatsNewPage feature, so it's safe to call it unconditionally. + if (overridePage || (versionMatch && disableWNP)) { let nimbusWNPFeature = lazy.NimbusFeatures.whatsNewPage; nimbusWNPFeature .ready() diff --git a/browser/components/tests/browser/whats_new_page/browser.toml b/browser/components/tests/browser/whats_new_page/browser.toml index 51426ea851c86..c4f4aefe1a7e3 100644 --- a/browser/components/tests/browser/whats_new_page/browser.toml +++ b/browser/components/tests/browser/whats_new_page/browser.toml @@ -21,3 +21,4 @@ prefs = [ ["browser_whats_new_page.js"] ["include:./browser_whats_new_page_nimbus.toml"] +["include:./browser_whats_new_page_nimbus_disable.toml"] diff --git a/browser/components/tests/browser/whats_new_page/browser_whats_new_page_nimbus_disable.js b/browser/components/tests/browser/whats_new_page/browser_whats_new_page_nimbus_disable.js new file mode 100644 index 0000000000000..37e275cbc9c29 --- /dev/null +++ b/browser/components/tests/browser/whats_new_page/browser_whats_new_page_nimbus_disable.js @@ -0,0 +1,99 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function nimbus_whats_new_page_disable() { + // The test harness will use the current tab and remove the tab's history. + gBrowser.selectedTab = gBrowser.tabs[0]; + await TestUtils.waitForCondition( + () => + gBrowser.selectedBrowser && + gBrowser.selectedBrowser.currentURI && + gBrowser.selectedBrowser.currentURI.spec == "about:blank", + `Expected about:blank but got ${gBrowser.selectedBrowser.currentURI.spec}` + ); + is( + gBrowser.selectedBrowser.currentURI.spec, + "about:blank", + "What's New pages should be disabled" + ); + + let um = Cc["@mozilla.org/updates/update-manager;1"].getService( + Ci.nsIUpdateManager + ); + await TestUtils.waitForCondition( + async () => !(await um.getReadyUpdate()), + "Waiting for the ready update to be removed" + ); + ok(!(await um.getReadyUpdate()), "There should not be a ready update"); + let history; + await TestUtils.waitForCondition(async () => { + history = await um.getHistory(); + return !!history[0]; + }, "Waiting for the ready update to be moved to the update history"); + ok(!!history[0], "There should be an update in the update history"); + + // Leave no trace. Since this test modifies its support files put them back in + // their original state. + let alternatePath = Services.prefs.getCharPref("app.update.altUpdateDirPath"); + let testRoot = Services.prefs.getCharPref("mochitest.testRoot"); + let relativePath = alternatePath.substring("".length); + if (AppConstants.platform == "win") { + relativePath = relativePath.replace(/\//g, "\\"); + } + alternatePath = testRoot + relativePath; + let updateDir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); + updateDir.initWithPath(alternatePath); + + let activeUpdateFile = updateDir.clone(); + activeUpdateFile.append("active-update.xml"); + await TestUtils.waitForCondition( + () => !activeUpdateFile.exists(), + "Waiting until the active-update.xml file does not exist" + ); + + let updatesFile = updateDir.clone(); + updatesFile.append("updates.xml"); + await TestUtils.waitForCondition( + () => updatesFile.exists(), + "Waiting until the updates.xml file exists" + ); + + let fos = Cc["@mozilla.org/network/file-output-stream;1"].createInstance( + Ci.nsIFileOutputStream + ); + let flags = + FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE | FileUtils.MODE_TRUNCATE; + + let stateSucceeded = "succeeded\n"; + let updateStatusFile = updateDir.clone(); + updateStatusFile.append("updates"); + updateStatusFile.append("0"); + updateStatusFile.append("update.status"); + updateStatusFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE); + fos.init(updateStatusFile, flags, FileUtils.PERMS_FILE, 0); + fos.write(stateSucceeded, stateSucceeded.length); + fos.close(); + + let xmlContents = + '\n'; + activeUpdateFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE); + fos.init(activeUpdateFile, flags, FileUtils.PERMS_FILE, 0); + fos.write(xmlContents, xmlContents.length); + fos.close(); + + updatesFile.remove(false); + Cc["@mozilla.org/updates/update-manager;1"] + .getService(Ci.nsIUpdateManager) + .internal.reload(false); +}); diff --git a/browser/components/tests/browser/whats_new_page/browser_whats_new_page_nimbus_disable.toml b/browser/components/tests/browser/whats_new_page/browser_whats_new_page_nimbus_disable.toml new file mode 100644 index 0000000000000..5d6709fcadebf --- /dev/null +++ b/browser/components/tests/browser/whats_new_page/browser_whats_new_page_nimbus_disable.toml @@ -0,0 +1,6 @@ +[DEFAULT] + +["browser_whats_new_page_nimbus_disable.js"] +# These are prefs set by nimbus to be used for What's new pages +prefs = ["startup.homepage_override_url_nimbus='https://www.mozilla.org/en-US/projects/firefox/whatsnew/|https://www.mozilla.org/en-US/projects/firefox/whatsnew/'", +"startup.homepage_override_nimbus_maxVersion='99999999.0'", "startup.homepage_override_nimbus_disable_wnp=true"] diff --git a/toolkit/components/nimbus/FeatureManifest.yaml b/toolkit/components/nimbus/FeatureManifest.yaml index b36c81a76932b..6555bab0b8dd9 100644 --- a/toolkit/components/nimbus/FeatureManifest.yaml +++ b/toolkit/components/nimbus/FeatureManifest.yaml @@ -1414,6 +1414,14 @@ whatsNewPage: setPref: branch: user pref: startup.homepage_override_nimbus_minVersion + disableWNP: + description: >- + Block all What's New Pages. Used to compare no-WNP control branches to + WNP treatment branches. + type: boolean + setPref: + branch: user + pref: startup.homepage_override_nimbus_disable_wnp pbNewtab: description: "A Firefox Messaging System message for the pbNewtab message channel"