/* Any copyright is dedicated to the Public Domain. * https://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; const FEATURE_PREF = "privacy.ui.status_card"; const CARD_NAME = "security-privacy-card"; const ISSUE_CONTROL_ID = "securityWarningsGroup"; // Some things are set dangerously in the test environment. // We can supress these errors! const RESET_PROBLEMATIC_TEST_DEFAULTS = [ [ "browser.preferences.config_warning.warningAllowFingerprinters.dismissed", true, ], [ "browser.preferences.config_warning.warningThirdPartyCookies.dismissed", true, ], ["browser.preferences.config_warning.warningPasswordManager.dismissed", true], ["browser.preferences.config_warning.warningPopupBlocker.dismissed", true], [ "browser.preferences.config_warning.warningExtensionInstall.dismissed", true, ], ["browser.preferences.config_warning.warningSafeBrowsing.dismissed", true], ["browser.preferences.config_warning.warningDoH.dismissed", true], ["browser.preferences.config_warning.warningECH.dismissed", true], ["browser.preferences.config_warning.warningCT.dismissed", true], ["browser.preferences.config_warning.warningCRLite.dismissed", true], [ "browser.preferences.config_warning.warningCertificatePinning.dismissed", true, ], ["browser.preferences.config_warning.warningTLSMin.dismissed", true], ["browser.preferences.config_warning.warningTLSMax.dismissed", true], [ "browser.preferences.config_warning.warningProxyAutodetection.dismissed", true, ], [ "browser.preferences.config_warning.warningContentResourceURI.dismissed", true, ], ["browser.preferences.config_warning.warningWorkerMIME.dismissed", true], ["browser.preferences.config_warning.warningTopLevelDataURI.dismissed", true], [ "browser.preferences.config_warning.warningActiveMixedContent.dismissed", true, ], ["browser.preferences.config_warning.warningInnerHTMLltgt.dismissed", true], ["browser.preferences.config_warning.warningFileURIOrigin.dismissed", true], [ "browser.preferences.config_warning.warningPrivelegedConstraint.dismissed", true, ], ["browser.preferences.config_warning.warningProcessSandbox.dismissed", true], ]; function getCardAndCheckHeader(document, expectedHeaderL10n) { let elements = document.getElementsByTagName(CARD_NAME); Assert.equal(elements.length, 1, "Card present in preferences"); let card = elements[0]; let header = card.shadowRoot.getElementById("heading"); Assert.equal( header.attributes.getNamedItem("data-l10n-id").value, expectedHeaderL10n ); return card; } function assertHappyBullets(card) { let bullets = card.shadowRoot.querySelectorAll(".status-bullet > img"); Assert.equal(bullets.length, 2); for (const bullet of bullets) { Assert.equal( bullet.classList.contains("check-bullet"), true, "All bullets must be happy!" ); } } add_task(async function test_section_hidden_when_feature_flag_disabled() { await SpecialPowers.pushPrefEnv({ set: [[FEATURE_PREF, false]].concat(RESET_PROBLEMATIC_TEST_DEFAULTS), }); await BrowserTestUtils.withNewTab( { gBrowser, url: "about:preferences#privacy" }, async function (browser) { let elements = browser.contentDocument.getElementsByTagName(CARD_NAME); Assert.equal(elements.length, 0, "No card present in preferences"); } ); await SpecialPowers.popPrefEnv(); }); add_task(async function test_section_default_state() { await SpecialPowers.pushPrefEnv({ set: [[FEATURE_PREF, true]].concat(RESET_PROBLEMATIC_TEST_DEFAULTS), }); await BrowserTestUtils.withNewTab( { gBrowser, url: "about:preferences#privacy" }, async function (browser) { let card = getCardAndCheckHeader( browser.contentDocument, "security-privacy-status-ok-header" ); assertHappyBullets(card); let strictLabel = card.shadowRoot.getElementById("strictEnabled"); Assert.equal(strictLabel, null, "Strict mustn't be enabled"); } ); await SpecialPowers.popPrefEnv(); }); add_task(async function test_section_default_state() { await SpecialPowers.pushPrefEnv({ set: [[FEATURE_PREF, true]].concat(RESET_PROBLEMATIC_TEST_DEFAULTS), }); await BrowserTestUtils.withNewTab( { gBrowser, url: "about:preferences#privacy" }, async function (browser) { let card = getCardAndCheckHeader( browser.contentDocument, "security-privacy-status-ok-header" ); assertHappyBullets(card); let strictLabel = card.shadowRoot.getElementById("strictEnabled"); Assert.equal(strictLabel, null, "Strict mustn't be enabled"); } ); await SpecialPowers.popPrefEnv(); }); add_task(async function test_section_strict_indicator() { await SpecialPowers.pushPrefEnv({ set: [ [FEATURE_PREF, true], ["browser.contentblocking.category", "strict"], ].concat(RESET_PROBLEMATIC_TEST_DEFAULTS), }); await BrowserTestUtils.withNewTab( { gBrowser, url: "about:preferences#privacy" }, async function (browser) { let card = getCardAndCheckHeader( browser.contentDocument, "security-privacy-status-ok-header" ); assertHappyBullets(card); let strictLabel = card.shadowRoot.getElementById("strictEnabled"); Assert.notEqual(strictLabel, null, "Strict must be indicated"); } ); await SpecialPowers.popPrefEnv(); }); add_task(async function test_issue_present() { await SpecialPowers.pushPrefEnv({ set: [ [FEATURE_PREF, true], ["browser.contentblocking.category", "strict"], ["privacy.ui.status_card.testing.show_issue", true], ].concat(RESET_PROBLEMATIC_TEST_DEFAULTS), }); await BrowserTestUtils.withNewTab( { gBrowser, url: "about:preferences#privacy" }, async function (browser) { let card = getCardAndCheckHeader( browser.contentDocument, "security-privacy-status-problem-header" ); let bulletIcons = card.shadowRoot.querySelectorAll( ".status-bullet > img" ); Assert.equal(bulletIcons.length, 2); let problemsBulletIcon = bulletIcons[0]; Assert.ok(problemsBulletIcon.classList.contains("alert-bullet")); let bulletLink = card.shadowRoot.querySelector(".status-bullet"); Assert.notEqual( bulletLink.querySelector("a"), null, "Link to issues is present" ); // config card let configCard = browser.contentDocument.getElementById(ISSUE_CONTROL_ID); Assert.notEqual(configCard, null, "Issue card is present"); let issues = configCard.listItems; Assert.equal(issues.length, 1, "One issue present"); } ); await SpecialPowers.popPrefEnv(); }); add_task(async function test_issue_fix() { await SpecialPowers.pushPrefEnv({ set: [ [FEATURE_PREF, true], ["privacy.ui.status_card.testing.show_issue", true], ].concat(RESET_PROBLEMATIC_TEST_DEFAULTS), }); await BrowserTestUtils.withNewTab( { gBrowser, url: "about:preferences#privacy" }, async function (browser) { // config card let configCard = browser.contentDocument.getElementById(ISSUE_CONTROL_ID); Assert.notEqual(configCard, null, "Issue card is present"); let issues = configCard.listItems; Assert.equal(issues.length, 1, "One issue present"); let issue = issues[0]; let fixButton = issue.querySelector( 'moz-button[data-l10n-id="issue-card-reset-button"]' ); let prefChange = TestUtils.waitForPrefChange( "privacy.ui.status_card.testing.show_issue" ); fixButton.click(); await prefChange; await configCard.updateComplete; let afterIssues = configCard.listItems; Assert.equal( afterIssues.length, 0, "Issues are gone after the pref is fixed" ); Assert.ok( !Services.prefs.prefHasUserValue( "privacy.ui.status_card.testing.show_issue" ), "Pref has no user value after clicking the fix button" ); } ); await SpecialPowers.popPrefEnv(); }); add_task(async function test_issue_dismiss() { await SpecialPowers.pushPrefEnv({ set: [ [FEATURE_PREF, true], ["privacy.ui.status_card.testing.show_issue", true], ].concat(RESET_PROBLEMATIC_TEST_DEFAULTS), }); await BrowserTestUtils.withNewTab( { gBrowser, url: "about:preferences#privacy" }, async function (browser) { // config card let configCard = browser.contentDocument.getElementById(ISSUE_CONTROL_ID); Assert.notEqual(configCard, null, "Issue card is present"); let issues = configCard.listItems; Assert.equal(issues.length, 1, "One issue present"); let issue = issues[0]; let dismissButton = issue.querySelector( 'moz-button[data-l10n-id="issue-card-dismiss-button"]' ); let prefChange = TestUtils.waitForPrefChange( "browser.preferences.config_warning.warningTest.dismissed" ); dismissButton.click(); await prefChange; await configCard.updateComplete; let afterIssues = configCard.listItems; Assert.equal( afterIssues.length, 0, "Issues are gone after the setting is dismissed" ); Assert.ok( Services.prefs.prefHasUserValue( "browser.preferences.config_warning.warningTest.dismissed" ), "Pref has no user value after clicking the fix button" ); Services.prefs.clearUserPref( "browser.preferences.config_warning.warningTest.dismissed" ); } ); await SpecialPowers.popPrefEnv(); }); add_task(async function test_update_status_indicator() { await SpecialPowers.pushPrefEnv({ set: [[FEATURE_PREF, true]].concat(RESET_PROBLEMATIC_TEST_DEFAULTS), }); // Define testers for each UI state. let absent = card => { let label = card.shadowRoot.querySelector( "div.status-bullet:nth-child(4) > .status-label-holder > div" ); Assert.equal(label, null, "No install status label is present"); }; let issue = card => { let label = card.shadowRoot.querySelector( "div.status-bullet:nth-child(4) > .status-label-holder > div" ); Assert.equal( label.attributes.getNamedItem("data-l10n-id").value, "security-privacy-status-update-error-label", "Label correctly identifies an issue" ); }; let needed = card => { let label = card.shadowRoot.querySelector( "div.status-bullet:nth-child(4) > .status-label-holder > div" ); Assert.equal( label.attributes.getNamedItem("data-l10n-id").value, "security-privacy-status-update-needed-label", "Label correctly identifies an update is needed" ); }; let ok = card => { let label = card.shadowRoot.querySelector( "div.status-bullet:nth-child(4) > div" ); Assert.equal( label.attributes.getNamedItem("data-l10n-id").value, "security-privacy-status-up-to-date-label", "Label correctly identifies software up to date" ); }; let checking = card => { let label = card.shadowRoot.querySelector( "div.status-bullet:nth-child(4) > div" ); Assert.equal( label.attributes.getNamedItem("data-l10n-id").value, "security-privacy-status-update-checking-label", "Label correctly identifies software update checking now" ); }; // Define the expected result for each different test case. // The keys are different AppUpdater.STATUS values. let cases = {}; cases[0] = issue; cases[1] = absent; cases[2] = absent; cases[3] = absent; cases[4] = issue; cases[5] = needed; cases[6] = checking; cases[7] = ok; cases[8] = needed; cases[9] = issue; cases[10] = needed; cases[11] = needed; cases[12] = needed; cases[13] = issue; cases[14] = issue; await BrowserTestUtils.withNewTab( { gBrowser, url: "about:preferences#privacy" }, async function (browser) { let elements = browser.contentDocument.getElementsByTagName(CARD_NAME); Assert.equal(elements.length, 1, "Card present in preferences"); let card = elements[0]; for (const status in cases) { info(`testing AppUpdateStatus ${status}`); card.appUpdateStatus = parseInt(status); await card.updateComplete; cases[status](card); } } ); await SpecialPowers.popPrefEnv(); });