forked from mirrors/gecko-dev
825 lines
27 KiB
JavaScript
825 lines
27 KiB
JavaScript
"use strict";
|
|
|
|
const { PreferenceExperiments } = ChromeUtils.importESModule(
|
|
"resource://normandy/lib/PreferenceExperiments.sys.mjs"
|
|
);
|
|
const { RecipeRunner } = ChromeUtils.importESModule(
|
|
"resource://normandy/lib/RecipeRunner.sys.mjs"
|
|
);
|
|
const { ExperimentFakes } = ChromeUtils.importESModule(
|
|
"resource://testing-common/NimbusTestUtils.sys.mjs"
|
|
);
|
|
const { ExperimentManager } = ChromeUtils.importESModule(
|
|
"resource://nimbus/lib/ExperimentManager.sys.mjs"
|
|
);
|
|
const { RemoteSettingsExperimentLoader } = ChromeUtils.importESModule(
|
|
"resource://nimbus/lib/RemoteSettingsExperimentLoader.sys.mjs"
|
|
);
|
|
|
|
const { NormandyTestUtils } = ChromeUtils.importESModule(
|
|
"resource://testing-common/NormandyTestUtils.sys.mjs"
|
|
);
|
|
const { addonStudyFactory, preferenceStudyFactory } =
|
|
NormandyTestUtils.factories;
|
|
|
|
function withAboutStudies() {
|
|
return function (testFunc) {
|
|
return async args =>
|
|
BrowserTestUtils.withNewTab("about:studies", async browser =>
|
|
testFunc({ ...args, browser })
|
|
);
|
|
};
|
|
}
|
|
|
|
// Test that the code renders at all
|
|
decorate_task(
|
|
withAboutStudies(),
|
|
async function testAboutStudiesWorks({ browser }) {
|
|
const appFound = await SpecialPowers.spawn(
|
|
browser,
|
|
[],
|
|
() => !!content.document.getElementById("app")
|
|
);
|
|
ok(appFound, "App element was found");
|
|
}
|
|
);
|
|
|
|
// Test that the learn more element is displayed correctly
|
|
decorate_task(
|
|
withPrefEnv({
|
|
set: [["app.normandy.shieldLearnMoreUrl", "http://test/%OS%/"]],
|
|
}),
|
|
withAboutStudies(),
|
|
async function testLearnMore({ browser }) {
|
|
SpecialPowers.spawn(browser, [], async () => {
|
|
const doc = content.document;
|
|
await ContentTaskUtils.waitForCondition(() =>
|
|
doc.getElementById("shield-studies-learn-more")
|
|
);
|
|
doc.getElementById("shield-studies-learn-more").click();
|
|
});
|
|
await BrowserTestUtils.waitForLocationChange(gBrowser);
|
|
|
|
const location = browser.currentURI.spec;
|
|
is(
|
|
location,
|
|
AboutPages.aboutStudies.getShieldLearnMoreHref(),
|
|
"Clicking Learn More opens the correct page on SUMO."
|
|
);
|
|
ok(!location.includes("%OS%"), "The Learn More URL is formatted.");
|
|
}
|
|
);
|
|
|
|
// Test that jumping to preferences worked as expected
|
|
decorate_task(
|
|
withAboutStudies(),
|
|
async function testUpdatePreferences({ browser }) {
|
|
let loadPromise = BrowserTestUtils.firstBrowserLoaded(window);
|
|
|
|
// We have to use gBrowser instead of browser in most spots since we're
|
|
// dealing with a new tab outside of the about:studies tab.
|
|
const tab = await BrowserTestUtils.switchTab(gBrowser, () => {
|
|
SpecialPowers.spawn(browser, [], async () => {
|
|
const doc = content.document;
|
|
await ContentTaskUtils.waitForCondition(() =>
|
|
doc.getElementById("shield-studies-update-preferences")
|
|
);
|
|
content.document
|
|
.getElementById("shield-studies-update-preferences")
|
|
.click();
|
|
});
|
|
});
|
|
|
|
await loadPromise;
|
|
|
|
const location = gBrowser.currentURI.spec;
|
|
is(
|
|
location,
|
|
"about:preferences#privacy",
|
|
"Clicking Update Preferences opens the privacy section of the new about:preferences."
|
|
);
|
|
|
|
BrowserTestUtils.removeTab(tab);
|
|
}
|
|
);
|
|
|
|
// Test that the study listing shows studies in the proper order and grouping
|
|
decorate_task(
|
|
AddonStudies.withStudies([
|
|
addonStudyFactory({
|
|
slug: "fake-study-a",
|
|
userFacingName: "A Fake Add-on Study",
|
|
active: true,
|
|
userFacingDescription: "A fake description",
|
|
studyStartDate: new Date(2018, 0, 4),
|
|
}),
|
|
addonStudyFactory({
|
|
slug: "fake-study-b",
|
|
userFacingName: "B Fake Add-on Study",
|
|
active: false,
|
|
userFacingDescription: "B fake description",
|
|
studyStartDate: new Date(2018, 0, 2),
|
|
}),
|
|
addonStudyFactory({
|
|
slug: "fake-study-c",
|
|
userFacingName: "C Fake Add-on Study",
|
|
active: true,
|
|
userFacingDescription: "C fake description",
|
|
studyStartDate: new Date(2018, 0, 1),
|
|
}),
|
|
]),
|
|
PreferenceExperiments.withMockExperiments([
|
|
preferenceStudyFactory({
|
|
slug: "fake-study-d",
|
|
userFacingName: null,
|
|
userFacingDescription: null,
|
|
lastSeen: new Date(2018, 0, 3),
|
|
expired: false,
|
|
}),
|
|
preferenceStudyFactory({
|
|
slug: "fake-study-e",
|
|
userFacingName: "E Fake Preference Study",
|
|
lastSeen: new Date(2018, 0, 5),
|
|
expired: true,
|
|
}),
|
|
preferenceStudyFactory({
|
|
slug: "fake-study-f",
|
|
userFacingName: "F Fake Preference Study",
|
|
lastSeen: new Date(2018, 0, 6),
|
|
expired: false,
|
|
}),
|
|
]),
|
|
withAboutStudies(),
|
|
async function testStudyListing({ addonStudies, prefExperiments, browser }) {
|
|
await SpecialPowers.spawn(
|
|
browser,
|
|
[{ addonStudies, prefExperiments }],
|
|
async ({ addonStudies, prefExperiments }) => {
|
|
const doc = content.document;
|
|
|
|
function getStudyRow(docElem, slug) {
|
|
return docElem.querySelector(`.study[data-study-slug="${slug}"]`);
|
|
}
|
|
|
|
await ContentTaskUtils.waitForCondition(
|
|
() => doc.querySelectorAll(".active-study-list .study").length
|
|
);
|
|
const activeNames = Array.from(
|
|
doc.querySelectorAll(".active-study-list .study")
|
|
).map(row => row.dataset.studySlug);
|
|
const inactiveNames = Array.from(
|
|
doc.querySelectorAll(".inactive-study-list .study")
|
|
).map(row => row.dataset.studySlug);
|
|
|
|
Assert.deepEqual(
|
|
activeNames,
|
|
[
|
|
prefExperiments[2].slug,
|
|
addonStudies[0].slug,
|
|
prefExperiments[0].slug,
|
|
addonStudies[2].slug,
|
|
],
|
|
"Active studies are grouped by enabled status, and sorted by date"
|
|
);
|
|
Assert.deepEqual(
|
|
inactiveNames,
|
|
[prefExperiments[1].slug, addonStudies[1].slug],
|
|
"Inactive studies are grouped by enabled status, and sorted by date"
|
|
);
|
|
|
|
const activeAddonStudy = getStudyRow(doc, addonStudies[0].slug);
|
|
ok(
|
|
activeAddonStudy
|
|
.querySelector(".study-description")
|
|
.textContent.includes(addonStudies[0].userFacingDescription),
|
|
"Study descriptions are shown in about:studies."
|
|
);
|
|
is(
|
|
activeAddonStudy.querySelector(".study-status").textContent,
|
|
"Active",
|
|
"Active studies show an 'Active' indicator."
|
|
);
|
|
ok(
|
|
activeAddonStudy.querySelector(".remove-button"),
|
|
"Active studies show a remove button"
|
|
);
|
|
is(
|
|
activeAddonStudy
|
|
.querySelector(".study-icon")
|
|
.textContent.toLowerCase(),
|
|
"a",
|
|
"Study icons use the first letter of the study name."
|
|
);
|
|
|
|
const inactiveAddonStudy = getStudyRow(doc, addonStudies[1].slug);
|
|
is(
|
|
inactiveAddonStudy.querySelector(".study-status").textContent,
|
|
"Complete",
|
|
"Inactive studies are marked as complete."
|
|
);
|
|
ok(
|
|
!inactiveAddonStudy.querySelector(".remove-button"),
|
|
"Inactive studies do not show a remove button"
|
|
);
|
|
|
|
const activePrefStudy = getStudyRow(doc, prefExperiments[0].slug);
|
|
const preferenceName = Object.keys(prefExperiments[0].preferences)[0];
|
|
ok(
|
|
activePrefStudy
|
|
.querySelector(".study-description")
|
|
.textContent.includes(preferenceName),
|
|
"Preference studies show the preference they are changing"
|
|
);
|
|
is(
|
|
activePrefStudy.querySelector(".study-status").textContent,
|
|
"Active",
|
|
"Active studies show an 'Active' indicator."
|
|
);
|
|
ok(
|
|
activePrefStudy.querySelector(".remove-button"),
|
|
"Active studies show a remove button"
|
|
);
|
|
|
|
const inactivePrefStudy = getStudyRow(doc, prefExperiments[1].slug);
|
|
is(
|
|
inactivePrefStudy.querySelector(".study-status").textContent,
|
|
"Complete",
|
|
"Inactive studies are marked as complete."
|
|
);
|
|
ok(
|
|
!inactivePrefStudy.querySelector(".remove-button"),
|
|
"Inactive studies do not show a remove button"
|
|
);
|
|
|
|
activeAddonStudy.querySelector(".remove-button").click();
|
|
await ContentTaskUtils.waitForCondition(() =>
|
|
getStudyRow(doc, addonStudies[0].slug).matches(".study.disabled")
|
|
);
|
|
ok(
|
|
getStudyRow(doc, addonStudies[0].slug).matches(".study.disabled"),
|
|
"Clicking the remove button updates the UI to show that the study has been disabled."
|
|
);
|
|
|
|
activePrefStudy.querySelector(".remove-button").click();
|
|
await ContentTaskUtils.waitForCondition(() =>
|
|
getStudyRow(doc, prefExperiments[0].slug).matches(".study.disabled")
|
|
);
|
|
ok(
|
|
getStudyRow(doc, prefExperiments[0].slug).matches(".study.disabled"),
|
|
"Clicking the remove button updates the UI to show that the study has been disabled."
|
|
);
|
|
}
|
|
);
|
|
|
|
const updatedAddonStudy = await AddonStudies.get(addonStudies[0].recipeId);
|
|
ok(
|
|
!updatedAddonStudy.active,
|
|
"Clicking the remove button marks addon studies as inactive in storage."
|
|
);
|
|
|
|
const updatedPrefStudy = await PreferenceExperiments.get(
|
|
prefExperiments[0].slug
|
|
);
|
|
ok(
|
|
updatedPrefStudy.expired,
|
|
"Clicking the remove button marks preference studies as expired in storage."
|
|
);
|
|
}
|
|
);
|
|
|
|
// Test that a message is shown when no studies have been run
|
|
decorate_task(
|
|
AddonStudies.withStudies([]),
|
|
withAboutStudies(),
|
|
async function testStudyListingNoStudies({ browser }) {
|
|
await SpecialPowers.spawn(browser, [], async () => {
|
|
const doc = content.document;
|
|
await ContentTaskUtils.waitForCondition(
|
|
() => doc.querySelectorAll(".study-list-info").length
|
|
);
|
|
const studyRows = doc.querySelectorAll(".study-list .study");
|
|
is(studyRows.length, 0, "There should be no studies");
|
|
is(
|
|
doc.querySelector(".study-list-info").textContent,
|
|
"You have not participated in any studies.",
|
|
"A message is shown when no studies exist"
|
|
);
|
|
});
|
|
}
|
|
);
|
|
|
|
// Test that the message shown when studies are disabled and studies exist
|
|
decorate_task(
|
|
withAboutStudies(),
|
|
AddonStudies.withStudies([
|
|
addonStudyFactory({
|
|
userFacingName: "A Fake Add-on Study",
|
|
slug: "fake-addon-study",
|
|
active: false,
|
|
userFacingDescription: "A fake description",
|
|
studyStartDate: new Date(2018, 0, 4),
|
|
}),
|
|
]),
|
|
PreferenceExperiments.withMockExperiments([
|
|
preferenceStudyFactory({
|
|
slug: "fake-pref-study",
|
|
userFacingName: "B Fake Preference Study",
|
|
lastSeen: new Date(2018, 0, 5),
|
|
expired: true,
|
|
}),
|
|
]),
|
|
async function testStudyListingDisabled({ browser }) {
|
|
try {
|
|
RecipeRunner.disable();
|
|
|
|
await SpecialPowers.spawn(browser, [], async () => {
|
|
const doc = content.document;
|
|
await ContentTaskUtils.waitForCondition(() =>
|
|
doc.querySelector(".info-box-content > span")
|
|
);
|
|
|
|
is(
|
|
doc.querySelector(".info-box-content > span").textContent,
|
|
"This is a list of studies that you have participated in. No new studies will run.",
|
|
"A message is shown when studies are disabled"
|
|
);
|
|
});
|
|
} finally {
|
|
// reset RecipeRunner.enabled
|
|
RecipeRunner.checkPrefs();
|
|
}
|
|
}
|
|
);
|
|
|
|
// Test for bug 1498940 - detects studies disabled when only study opt-out is set
|
|
decorate_task(
|
|
withPrefEnv({
|
|
set: [
|
|
["datareporting.healthreport.uploadEnabled", true],
|
|
["app.normandy.api_url", "https://example.com"],
|
|
["app.shield.optoutstudies.enabled", false],
|
|
],
|
|
}),
|
|
withAboutStudies(),
|
|
AddonStudies.withStudies([]),
|
|
PreferenceExperiments.withMockExperiments([]),
|
|
async function testStudyListingStudiesOptOut({ browser }) {
|
|
RecipeRunner.checkPrefs();
|
|
ok(
|
|
RecipeRunner.enabled,
|
|
"RecipeRunner should be enabled as a Precondition"
|
|
);
|
|
|
|
await SpecialPowers.spawn(browser, [], async () => {
|
|
const doc = content.document;
|
|
await ContentTaskUtils.waitForCondition(() => {
|
|
const span = doc.querySelector(".info-box-content > span");
|
|
return span && span.textContent;
|
|
});
|
|
|
|
is(
|
|
doc.querySelector(".info-box-content > span").textContent,
|
|
"This is a list of studies that you have participated in. No new studies will run.",
|
|
"A message is shown when studies are disabled"
|
|
);
|
|
});
|
|
}
|
|
);
|
|
|
|
// Test that clicking remove on a study that was disabled by an outside source
|
|
// since the page loaded correctly updates.
|
|
decorate_task(
|
|
AddonStudies.withStudies([
|
|
addonStudyFactory({
|
|
slug: "fake-addon-study",
|
|
userFacingName: "Fake Add-on Study",
|
|
active: true,
|
|
userFacingDescription: "A fake description",
|
|
studyStartDate: new Date(2018, 0, 4),
|
|
}),
|
|
]),
|
|
PreferenceExperiments.withMockExperiments([
|
|
preferenceStudyFactory({
|
|
slug: "fake-pref-study",
|
|
userFacingName: "Fake Preference Study",
|
|
lastSeen: new Date(2018, 0, 3),
|
|
expired: false,
|
|
}),
|
|
]),
|
|
withAboutStudies(),
|
|
async function testStudyListing({
|
|
addonStudies: [addonStudy],
|
|
prefExperiments: [prefStudy],
|
|
browser,
|
|
}) {
|
|
// The content page has already loaded. Disabling the studies here shouldn't
|
|
// affect it, since it doesn't live-update.
|
|
await AddonStudies.markAsEnded(addonStudy, "disabled-automatically-test");
|
|
await PreferenceExperiments.stop(prefStudy.slug, {
|
|
resetValue: false,
|
|
reason: "disabled-automatically-test",
|
|
});
|
|
|
|
await SpecialPowers.spawn(
|
|
browser,
|
|
[{ addonStudy, prefStudy }],
|
|
async ({ addonStudy, prefStudy }) => {
|
|
const doc = content.document;
|
|
|
|
function getStudyRow(docElem, slug) {
|
|
return docElem.querySelector(`.study[data-study-slug="${slug}"]`);
|
|
}
|
|
|
|
await ContentTaskUtils.waitForCondition(
|
|
() => doc.querySelectorAll(".remove-button").length == 2
|
|
);
|
|
let activeNames = Array.from(
|
|
doc.querySelectorAll(".active-study-list .study")
|
|
).map(row => row.dataset.studySlug);
|
|
let inactiveNames = Array.from(
|
|
doc.querySelectorAll(".inactive-study-list .study")
|
|
).map(row => row.dataset.studySlug);
|
|
|
|
Assert.deepEqual(
|
|
activeNames,
|
|
[addonStudy.slug, prefStudy.slug],
|
|
"Both studies should be listed as active, even though they have been disabled outside of the page"
|
|
);
|
|
Assert.deepEqual(
|
|
inactiveNames,
|
|
[],
|
|
"No studies should be listed as inactive"
|
|
);
|
|
|
|
const activeAddonStudy = getStudyRow(doc, addonStudy.slug);
|
|
const activePrefStudy = getStudyRow(doc, prefStudy.slug);
|
|
|
|
activeAddonStudy.querySelector(".remove-button").click();
|
|
await ContentTaskUtils.waitForCondition(() =>
|
|
getStudyRow(doc, addonStudy.slug).matches(".study.disabled")
|
|
);
|
|
ok(
|
|
getStudyRow(doc, addonStudy.slug).matches(".study.disabled"),
|
|
"Clicking the remove button updates the UI to show that the study has been disabled."
|
|
);
|
|
|
|
activePrefStudy.querySelector(".remove-button").click();
|
|
await ContentTaskUtils.waitForCondition(() =>
|
|
getStudyRow(doc, prefStudy.slug).matches(".study.disabled")
|
|
);
|
|
ok(
|
|
getStudyRow(doc, prefStudy.slug).matches(".study.disabled"),
|
|
"Clicking the remove button updates the UI to show that the study has been disabled."
|
|
);
|
|
|
|
activeNames = Array.from(
|
|
doc.querySelectorAll(".active-study-list .study")
|
|
).map(row => row.dataset.studySlug);
|
|
|
|
Assert.deepEqual(
|
|
activeNames,
|
|
[],
|
|
"No studies should be listed as active"
|
|
);
|
|
}
|
|
);
|
|
}
|
|
);
|
|
|
|
// Test that clicking remove on a study updates even about:studies pages
|
|
// that are not currently in focus.
|
|
decorate_task(
|
|
AddonStudies.withStudies([
|
|
addonStudyFactory({
|
|
slug: "fake-addon-study",
|
|
userFacingName: "Fake Add-on Study",
|
|
active: true,
|
|
userFacingDescription: "A fake description",
|
|
studyStartDate: new Date(2018, 0, 4),
|
|
}),
|
|
]),
|
|
PreferenceExperiments.withMockExperiments([
|
|
preferenceStudyFactory({
|
|
slug: "fake-pref-study",
|
|
userFacingName: "Fake Preference Study",
|
|
lastSeen: new Date(2018, 0, 3),
|
|
expired: false,
|
|
}),
|
|
]),
|
|
withAboutStudies(),
|
|
async function testOtherTabsUpdated({
|
|
addonStudies: [addonStudy],
|
|
prefExperiments: [prefStudy],
|
|
browser,
|
|
}) {
|
|
// Ensure that both our studies are active in the current tab.
|
|
await SpecialPowers.spawn(
|
|
browser,
|
|
[{ addonStudy, prefStudy }],
|
|
async ({ addonStudy, prefStudy }) => {
|
|
const doc = content.document;
|
|
await ContentTaskUtils.waitForCondition(
|
|
() => doc.querySelectorAll(".remove-button").length == 2,
|
|
"waiting for page to load"
|
|
);
|
|
let activeNames = Array.from(
|
|
doc.querySelectorAll(".active-study-list .study")
|
|
).map(row => row.dataset.studySlug);
|
|
let inactiveNames = Array.from(
|
|
doc.querySelectorAll(".inactive-study-list .study")
|
|
).map(row => row.dataset.studySlug);
|
|
|
|
Assert.deepEqual(
|
|
activeNames,
|
|
[addonStudy.slug, prefStudy.slug],
|
|
"Both studies should be listed as active"
|
|
);
|
|
Assert.deepEqual(
|
|
inactiveNames,
|
|
[],
|
|
"No studies should be listed as inactive"
|
|
);
|
|
}
|
|
);
|
|
|
|
// Open a new about:studies tab.
|
|
await BrowserTestUtils.withNewTab("about:studies", async browser => {
|
|
// Delete both studies in this tab; this should pass if previous tests have passed.
|
|
await SpecialPowers.spawn(
|
|
browser,
|
|
[{ addonStudy, prefStudy }],
|
|
async ({ addonStudy, prefStudy }) => {
|
|
const doc = content.document;
|
|
|
|
function getStudyRow(docElem, slug) {
|
|
return docElem.querySelector(`.study[data-study-slug="${slug}"]`);
|
|
}
|
|
|
|
await ContentTaskUtils.waitForCondition(
|
|
() => doc.querySelectorAll(".remove-button").length == 2,
|
|
"waiting for page to load"
|
|
);
|
|
let activeNames = Array.from(
|
|
doc.querySelectorAll(".active-study-list .study")
|
|
).map(row => row.dataset.studySlug);
|
|
let inactiveNames = Array.from(
|
|
doc.querySelectorAll(".inactive-study-list .study")
|
|
).map(row => row.dataset.studySlug);
|
|
|
|
Assert.deepEqual(
|
|
activeNames,
|
|
[addonStudy.slug, prefStudy.slug],
|
|
"Both studies should be listed as active in the new tab"
|
|
);
|
|
Assert.deepEqual(
|
|
inactiveNames,
|
|
[],
|
|
"No studies should be listed as inactive in the new tab"
|
|
);
|
|
|
|
const activeAddonStudy = getStudyRow(doc, addonStudy.slug);
|
|
const activePrefStudy = getStudyRow(doc, prefStudy.slug);
|
|
|
|
activeAddonStudy.querySelector(".remove-button").click();
|
|
await ContentTaskUtils.waitForCondition(() =>
|
|
getStudyRow(doc, addonStudy.slug).matches(".study.disabled")
|
|
);
|
|
ok(
|
|
getStudyRow(doc, addonStudy.slug).matches(".study.disabled"),
|
|
"Clicking the remove button updates the UI in the new tab"
|
|
);
|
|
|
|
activePrefStudy.querySelector(".remove-button").click();
|
|
await ContentTaskUtils.waitForCondition(() =>
|
|
getStudyRow(doc, prefStudy.slug).matches(".study.disabled")
|
|
);
|
|
ok(
|
|
getStudyRow(doc, prefStudy.slug).matches(".study.disabled"),
|
|
"Clicking the remove button updates the UI in the new tab"
|
|
);
|
|
|
|
activeNames = Array.from(
|
|
doc.querySelectorAll(".active-study-list .study")
|
|
).map(row => row.dataset.studySlug);
|
|
|
|
Assert.deepEqual(
|
|
activeNames,
|
|
[],
|
|
"No studies should be listed as active"
|
|
);
|
|
}
|
|
);
|
|
});
|
|
|
|
// Ensure that the original tab has updated correctly.
|
|
await SpecialPowers.spawn(
|
|
browser,
|
|
[{ addonStudy, prefStudy }],
|
|
async ({ addonStudy, prefStudy }) => {
|
|
const doc = content.document;
|
|
await ContentTaskUtils.waitForCondition(
|
|
() => doc.querySelectorAll(".inactive-study-list .study").length == 2,
|
|
"Two studies should load into the inactive list, since they were disabled in a different tab"
|
|
);
|
|
let activeNames = Array.from(
|
|
doc.querySelectorAll(".active-study-list .study")
|
|
).map(row => row.dataset.studySlug);
|
|
let inactiveNames = Array.from(
|
|
doc.querySelectorAll(".inactive-study-list .study")
|
|
).map(row => row.dataset.studySlug);
|
|
Assert.deepEqual(
|
|
activeNames,
|
|
[],
|
|
"No studies should be listed as active, since they were disabled in a different tab"
|
|
);
|
|
Assert.deepEqual(
|
|
inactiveNames,
|
|
[addonStudy.slug, prefStudy.slug],
|
|
"Both studies should be listed as inactive, since they were disabled in a different tab"
|
|
);
|
|
}
|
|
);
|
|
}
|
|
);
|
|
|
|
add_task(async function test_nimbus_about_studies_experiment() {
|
|
const recipe = ExperimentFakes.recipe("about-studies-foo");
|
|
await ExperimentManager.enroll(recipe);
|
|
await BrowserTestUtils.withNewTab(
|
|
{ gBrowser, url: "about:studies" },
|
|
async browser => {
|
|
const name = await SpecialPowers.spawn(browser, [], async () => {
|
|
await ContentTaskUtils.waitForCondition(
|
|
() => content.document.querySelector(".nimbus .remove-button"),
|
|
"waiting for page/experiment to load"
|
|
);
|
|
return content.document.querySelector(".study-name").innerText;
|
|
});
|
|
// Make sure strings are properly shown
|
|
Assert.equal(
|
|
name,
|
|
recipe.userFacingName,
|
|
"Correct active experiment name"
|
|
);
|
|
}
|
|
);
|
|
ExperimentManager.unenroll(recipe.slug);
|
|
await BrowserTestUtils.withNewTab(
|
|
{ gBrowser, url: "about:studies" },
|
|
async browser => {
|
|
const name = await SpecialPowers.spawn(browser, [], async () => {
|
|
await ContentTaskUtils.waitForCondition(
|
|
() => content.document.querySelector(".nimbus.disabled"),
|
|
"waiting for experiment to become disabled"
|
|
);
|
|
return content.document.querySelector(".study-name").innerText;
|
|
});
|
|
// Make sure strings are properly shown
|
|
Assert.equal(
|
|
name,
|
|
recipe.userFacingName,
|
|
"Correct disabled experiment name"
|
|
);
|
|
}
|
|
);
|
|
// Cleanup for multiple test runs
|
|
ExperimentManager.store._deleteForTests(recipe.slug);
|
|
Assert.equal(ExperimentManager.store.getAll().length, 0, "Cleanup done");
|
|
});
|
|
|
|
add_task(async function test_nimbus_about_studies_rollout() {
|
|
let recipe = ExperimentFakes.recipe("test_nimbus_about_studies_rollout");
|
|
let rollout = {
|
|
...recipe,
|
|
branches: [recipe.branches[0]],
|
|
isRollout: true,
|
|
};
|
|
await ExperimentManager.enroll(rollout);
|
|
await BrowserTestUtils.withNewTab(
|
|
{ gBrowser, url: "about:studies" },
|
|
async browser => {
|
|
const studyCount = await SpecialPowers.spawn(browser, [], async () => {
|
|
await ContentTaskUtils.waitForCondition(
|
|
() => content.document.querySelector("#shield-studies-learn-more"),
|
|
"waiting for page/experiment to load"
|
|
);
|
|
return content.document.querySelectorAll(".study-name").length;
|
|
});
|
|
// Make sure strings are properly shown
|
|
Assert.equal(studyCount, 1, "Rollout loaded in non-debug mode");
|
|
}
|
|
);
|
|
Services.prefs.setBoolPref("nimbus.debug", true);
|
|
await BrowserTestUtils.withNewTab(
|
|
{ gBrowser, url: "about:studies" },
|
|
async browser => {
|
|
const studyName = await SpecialPowers.spawn(browser, [], async () => {
|
|
await ContentTaskUtils.waitForCondition(
|
|
() => content.document.querySelector(".nimbus .remove-button"),
|
|
"waiting for page/experiment to load"
|
|
);
|
|
return content.document.querySelector(".study-header").innerText;
|
|
});
|
|
// Make sure strings are properly shown
|
|
Assert.ok(studyName.includes("Active"), "Rollout loaded in debug mode");
|
|
}
|
|
);
|
|
await BrowserTestUtils.withNewTab(
|
|
{ gBrowser, url: "about:studies" },
|
|
async browser => {
|
|
const name = await SpecialPowers.spawn(browser, [], async () => {
|
|
content.document.querySelector(".remove-button").click();
|
|
await ContentTaskUtils.waitForCondition(
|
|
() => content.document.querySelector(".nimbus.disabled"),
|
|
"waiting for experiment to become disabled"
|
|
);
|
|
return content.document.querySelector(".study-header").innerText;
|
|
});
|
|
// Make sure strings are properly shown
|
|
Assert.ok(name.includes("Complete"), "Rollout was removed");
|
|
}
|
|
);
|
|
// Cleanup for multiple test runs
|
|
ExperimentManager.store._deleteForTests(rollout.slug);
|
|
Services.prefs.clearUserPref("nimbus.debug");
|
|
});
|
|
|
|
add_task(async function test_getStudiesEnabled() {
|
|
RecipeRunner.initializedPromise = Promise.withResolvers();
|
|
let promise = AboutPages.aboutStudies.getStudiesEnabled();
|
|
|
|
RecipeRunner.initializedPromise.resolve();
|
|
let result = await promise;
|
|
|
|
Assert.equal(
|
|
result,
|
|
Services.prefs.getBoolPref("app.shield.optoutstudies.enabled"),
|
|
"about:studies is enabled if the pref is enabled"
|
|
);
|
|
});
|
|
|
|
add_task(async function test_forceEnroll() {
|
|
let sandbox = sinon.createSandbox();
|
|
|
|
// This simulates a succesful enrollment
|
|
let stub = sandbox.stub(RemoteSettingsExperimentLoader, "optInToExperiment");
|
|
|
|
await BrowserTestUtils.withNewTab(
|
|
{
|
|
gBrowser,
|
|
url: "about:studies?optin_collection=collection123&optin_branch=branch123&optin_slug=slug123",
|
|
},
|
|
async browser => {
|
|
await SpecialPowers.spawn(browser, [], async () => {
|
|
await ContentTaskUtils.waitForCondition(
|
|
() => content.document.querySelector(".opt-in-box"),
|
|
"Should show the opt in message"
|
|
);
|
|
|
|
Assert.equal(
|
|
content.document
|
|
.querySelector(".opt-in-box")
|
|
.classList.contains("opt-in-error"),
|
|
false,
|
|
"should not have an error class since the enrollment was successful"
|
|
);
|
|
|
|
return true;
|
|
});
|
|
}
|
|
);
|
|
|
|
// Simulates a problem force enrolling
|
|
stub.rejects(new Error("Testing error"));
|
|
await BrowserTestUtils.withNewTab(
|
|
{
|
|
gBrowser,
|
|
url: "about:studies?optin_collection=collection123&optin_branch=branch123&optin_slug=slug123",
|
|
},
|
|
async browser => {
|
|
await SpecialPowers.spawn(browser, [], async () => {
|
|
await ContentTaskUtils.waitForCondition(
|
|
() => content.document.querySelector(".opt-in-box"),
|
|
"Should show the opt in message"
|
|
);
|
|
|
|
Assert.ok(
|
|
content.document
|
|
.querySelector(".opt-in-box")
|
|
.classList.contains("opt-in-error"),
|
|
"should have an error class since the enrollment rejected"
|
|
);
|
|
|
|
Assert.equal(
|
|
content.document.querySelector(".opt-in-box").textContent,
|
|
"Testing error",
|
|
"should render the error"
|
|
);
|
|
|
|
return true;
|
|
});
|
|
}
|
|
);
|
|
|
|
sandbox.restore();
|
|
});
|