browser_privacy_status_card.js (14551B)
1 /* Any copyright is dedicated to the Public Domain. 2 * https://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 const FEATURE_PREF = "browser.settings-redesign.enabled"; 7 const CARD_NAME = "security-privacy-card"; 8 const ISSUE_CONTROL_ID = "securityWarningsGroup"; 9 10 // Some things are set dangerously in the test environment. 11 // We can supress these errors! 12 const RESET_PROBLEMATIC_TEST_DEFAULTS = [ 13 [ 14 "browser.preferences.config_warning.warningAllowFingerprinters.dismissed", 15 true, 16 ], 17 [ 18 "browser.preferences.config_warning.warningThirdPartyCookies.dismissed", 19 true, 20 ], 21 ["browser.preferences.config_warning.warningPasswordManager.dismissed", true], 22 ["browser.preferences.config_warning.warningPopupBlocker.dismissed", true], 23 [ 24 "browser.preferences.config_warning.warningExtensionInstall.dismissed", 25 true, 26 ], 27 ["browser.preferences.config_warning.warningSafeBrowsing.dismissed", true], 28 ["browser.preferences.config_warning.warningDoH.dismissed", true], 29 ["browser.preferences.config_warning.warningECH.dismissed", true], 30 ["browser.preferences.config_warning.warningCT.dismissed", true], 31 ["browser.preferences.config_warning.warningCRLite.dismissed", true], 32 [ 33 "browser.preferences.config_warning.warningCertificatePinning.dismissed", 34 true, 35 ], 36 ["browser.preferences.config_warning.warningTLSMin.dismissed", true], 37 ["browser.preferences.config_warning.warningTLSMax.dismissed", true], 38 [ 39 "browser.preferences.config_warning.warningProxyAutodetection.dismissed", 40 true, 41 ], 42 [ 43 "browser.preferences.config_warning.warningContentResourceURI.dismissed", 44 true, 45 ], 46 ["browser.preferences.config_warning.warningWorkerMIME.dismissed", true], 47 ["browser.preferences.config_warning.warningTopLevelDataURI.dismissed", true], 48 [ 49 "browser.preferences.config_warning.warningActiveMixedContent.dismissed", 50 true, 51 ], 52 ["browser.preferences.config_warning.warningInnerHTMLltgt.dismissed", true], 53 ["browser.preferences.config_warning.warningFileURIOrigin.dismissed", true], 54 [ 55 "browser.preferences.config_warning.warningPrivelegedConstraint.dismissed", 56 true, 57 ], 58 ["browser.preferences.config_warning.warningProcessSandbox.dismissed", true], 59 ]; 60 61 function getCardAndCheckHeader(document, expectedHeaderL10n) { 62 let elements = document.getElementsByTagName(CARD_NAME); 63 Assert.equal(elements.length, 1, "Card present in preferences"); 64 let card = elements[0]; 65 let header = card.shadowRoot.getElementById("heading"); 66 Assert.equal( 67 header.attributes.getNamedItem("data-l10n-id").value, 68 expectedHeaderL10n 69 ); 70 return card; 71 } 72 73 function assertHappyBullets(card) { 74 let bullets = card.shadowRoot.querySelectorAll("li"); 75 Assert.equal(bullets.length, 2); 76 for (const bullet of bullets) { 77 Assert.equal( 78 bullet.classList.contains("status-ok"), 79 true, 80 "All bullets must be happy!" 81 ); 82 } 83 } 84 85 add_task(async function test_section_hidden_when_feature_flag_disabled() { 86 await SpecialPowers.pushPrefEnv({ 87 set: [[FEATURE_PREF, false]].concat(RESET_PROBLEMATIC_TEST_DEFAULTS), 88 }); 89 90 await BrowserTestUtils.withNewTab( 91 { gBrowser, url: "about:preferences#privacy" }, 92 async function (browser) { 93 let elements = browser.contentDocument.getElementsByTagName(CARD_NAME); 94 Assert.equal(elements.length, 0, "No card present in preferences"); 95 } 96 ); 97 98 await SpecialPowers.popPrefEnv(); 99 }); 100 101 add_task(async function test_section_default_state() { 102 await SpecialPowers.pushPrefEnv({ 103 set: [[FEATURE_PREF, true]].concat(RESET_PROBLEMATIC_TEST_DEFAULTS), 104 }); 105 106 await BrowserTestUtils.withNewTab( 107 { gBrowser, url: "about:preferences#privacy" }, 108 async function (browser) { 109 let card = getCardAndCheckHeader( 110 browser.contentDocument, 111 "security-privacy-status-ok-header" 112 ); 113 assertHappyBullets(card); 114 let strictLabel = card.shadowRoot.getElementById("strictEnabled"); 115 Assert.equal(strictLabel, null, "Strict mustn't be enabled"); 116 } 117 ); 118 119 await SpecialPowers.popPrefEnv(); 120 }); 121 122 add_task(async function test_section_default_state() { 123 await SpecialPowers.pushPrefEnv({ 124 set: [[FEATURE_PREF, true]].concat(RESET_PROBLEMATIC_TEST_DEFAULTS), 125 }); 126 127 await BrowserTestUtils.withNewTab( 128 { gBrowser, url: "about:preferences#privacy" }, 129 async function (browser) { 130 let card = getCardAndCheckHeader( 131 browser.contentDocument, 132 "security-privacy-status-ok-header" 133 ); 134 assertHappyBullets(card); 135 let strictLabel = card.shadowRoot.getElementById("strictEnabled"); 136 Assert.equal(strictLabel, null, "Strict mustn't be enabled"); 137 } 138 ); 139 140 await SpecialPowers.popPrefEnv(); 141 }); 142 143 add_task(async function test_section_strict_indicator() { 144 await SpecialPowers.pushPrefEnv({ 145 set: [ 146 [FEATURE_PREF, true], 147 ["browser.contentblocking.category", "strict"], 148 ].concat(RESET_PROBLEMATIC_TEST_DEFAULTS), 149 }); 150 151 await BrowserTestUtils.withNewTab( 152 { gBrowser, url: "about:preferences#privacy" }, 153 async function (browser) { 154 let card = getCardAndCheckHeader( 155 browser.contentDocument, 156 "security-privacy-status-ok-header" 157 ); 158 assertHappyBullets(card); 159 let strictLabel = card.shadowRoot.getElementById("strictEnabled"); 160 Assert.notEqual(strictLabel, null, "Strict must be indicated"); 161 } 162 ); 163 164 await SpecialPowers.popPrefEnv(); 165 }); 166 167 add_task(async function test_issue_present() { 168 await SpecialPowers.pushPrefEnv({ 169 set: [ 170 [FEATURE_PREF, true], 171 ["browser.contentblocking.category", "strict"], 172 ["privacy.ui.status_card.testing.show_issue", true], 173 ].concat(RESET_PROBLEMATIC_TEST_DEFAULTS), 174 }); 175 176 await BrowserTestUtils.withNewTab( 177 { gBrowser, url: "about:preferences#privacy" }, 178 async function (browser) { 179 let card = getCardAndCheckHeader( 180 browser.contentDocument, 181 "security-privacy-status-problem-header" 182 ); 183 let bulletIcons = card.shadowRoot.querySelectorAll("li"); 184 Assert.equal(bulletIcons.length, 2); 185 let problemsBulletIcon = bulletIcons[0]; 186 Assert.ok(problemsBulletIcon.classList.contains("status-alert")); 187 Assert.notEqual( 188 problemsBulletIcon.querySelector("a"), 189 null, 190 "Link to issues is present" 191 ); 192 193 // config card 194 let configCard = browser.contentDocument.getElementById(ISSUE_CONTROL_ID); 195 Assert.notEqual(configCard, null, "Issue card is present"); 196 let issues = configCard.listItems; 197 Assert.equal(issues.length, 1, "One issue present"); 198 } 199 ); 200 201 await SpecialPowers.popPrefEnv(); 202 }); 203 204 add_task(async function test_issue_fix() { 205 await SpecialPowers.pushPrefEnv({ 206 set: [ 207 [FEATURE_PREF, true], 208 ["privacy.ui.status_card.testing.show_issue", true], 209 ].concat(RESET_PROBLEMATIC_TEST_DEFAULTS), 210 }); 211 Services.fog.testResetFOG(); 212 213 await BrowserTestUtils.withNewTab( 214 { gBrowser, url: "about:preferences#privacy" }, 215 async function (browser) { 216 // config card 217 let configCard = browser.contentDocument.getElementById(ISSUE_CONTROL_ID); 218 Assert.notEqual(configCard, null, "Issue card is present"); 219 let issues = configCard.listItems; 220 Assert.equal(issues.length, 1, "One issue present"); 221 let issue = issues[0]; 222 let fixButton = issue.querySelector( 223 'moz-button[data-l10n-id="issue-card-reset-button"]' 224 ); 225 let prefChange = TestUtils.waitForPrefChange( 226 "privacy.ui.status_card.testing.show_issue" 227 ); 228 fixButton.click(); 229 await prefChange; 230 await configCard.updateComplete; 231 let afterIssues = configCard.listItems; 232 Assert.equal( 233 afterIssues.length, 234 0, 235 "Issues are gone after the pref is fixed" 236 ); 237 Assert.ok( 238 !Services.prefs.prefHasUserValue( 239 "privacy.ui.status_card.testing.show_issue" 240 ), 241 "Pref has no user value after clicking the fix button" 242 ); 243 let events = 244 Glean.securityPreferencesWarnings.warningFixed.testGetValue(); 245 Assert.equal(events.length, 1, "One telemetry event was recorded"); 246 Assert.equal( 247 events[0].category, 248 "security.preferences.warnings", 249 "Category is correct" 250 ); 251 Assert.equal(events[0].name, "warning_fixed", "Event name is correct"); 252 253 let warningsShownEvents = 254 Glean.securityPreferencesWarnings.warningsShown.testGetValue(); 255 Assert.equal( 256 warningsShownEvents.length, 257 1, 258 "warningsShown telemetry was recorded exactly once" 259 ); 260 Assert.equal( 261 warningsShownEvents[0].extra.count, 262 "1", 263 "Count of warnings shown is correct" 264 ); 265 } 266 ); 267 268 await SpecialPowers.popPrefEnv(); 269 }); 270 271 add_task(async function test_issue_dismiss() { 272 await SpecialPowers.pushPrefEnv({ 273 set: [ 274 [FEATURE_PREF, true], 275 ["privacy.ui.status_card.testing.show_issue", true], 276 ].concat(RESET_PROBLEMATIC_TEST_DEFAULTS), 277 }); 278 Services.fog.testResetFOG(); 279 280 await BrowserTestUtils.withNewTab( 281 { gBrowser, url: "about:preferences#privacy" }, 282 async function (browser) { 283 // config card 284 let configCard = browser.contentDocument.getElementById(ISSUE_CONTROL_ID); 285 Assert.notEqual(configCard, null, "Issue card is present"); 286 let issues = configCard.listItems; 287 Assert.equal(issues.length, 1, "One issue present"); 288 let issue = issues[0]; 289 let dismissButton = issue.querySelector( 290 'moz-button[data-l10n-id="issue-card-dismiss-button"]' 291 ); 292 let prefChange = TestUtils.waitForPrefChange( 293 "browser.preferences.config_warning.warningTest.dismissed" 294 ); 295 dismissButton.click(); 296 await prefChange; 297 await configCard.updateComplete; 298 let afterIssues = configCard.listItems; 299 Assert.equal( 300 afterIssues.length, 301 0, 302 "Issues are gone after the setting is dismissed" 303 ); 304 Assert.ok( 305 Services.prefs.prefHasUserValue( 306 "browser.preferences.config_warning.warningTest.dismissed" 307 ), 308 "Pref has no user value after clicking the fix button" 309 ); 310 let events = 311 Glean.securityPreferencesWarnings.warningDismissed.testGetValue(); 312 Assert.equal(events.length, 1, "One telemetry event was recorded"); 313 Assert.equal( 314 events[0].category, 315 "security.preferences.warnings", 316 "Category is correct" 317 ); 318 Assert.equal( 319 events[0].name, 320 "warning_dismissed", 321 "Event name is correct" 322 ); 323 let warningsShownEvents = 324 Glean.securityPreferencesWarnings.warningsShown.testGetValue(); 325 Assert.equal( 326 warningsShownEvents.length, 327 1, 328 "warningsShown telemetry was recorded exactly once" 329 ); 330 Assert.equal( 331 warningsShownEvents[0].extra.count, 332 "1", 333 "Count of warnings shown is correct" 334 ); 335 Services.prefs.clearUserPref( 336 "browser.preferences.config_warning.warningTest.dismissed" 337 ); 338 } 339 ); 340 341 await SpecialPowers.popPrefEnv(); 342 }); 343 344 add_task(async function test_dismiss_all_hides_issues() { 345 await SpecialPowers.pushPrefEnv({ 346 set: [ 347 [FEATURE_PREF, true], 348 ["privacy.ui.status_card.testing.show_issue", true], 349 ["browser.preferences.config_warning.dismissAll", true], 350 ].concat(RESET_PROBLEMATIC_TEST_DEFAULTS), 351 }); 352 353 await BrowserTestUtils.withNewTab( 354 { gBrowser, url: "about:preferences#privacy" }, 355 async function (browser) { 356 let card = getCardAndCheckHeader( 357 browser.contentDocument, 358 "security-privacy-status-ok-header" 359 ); 360 assertHappyBullets(card); 361 362 let configCard = browser.contentDocument.getElementById(ISSUE_CONTROL_ID); 363 Assert.ok( 364 BrowserTestUtils.isHidden(configCard), 365 "Issue card is not present when dismissAll is true" 366 ); 367 } 368 ); 369 370 await SpecialPowers.popPrefEnv(); 371 }); 372 373 add_task(async function test_update_status_indicator() { 374 await SpecialPowers.pushPrefEnv({ 375 set: [[FEATURE_PREF, true]].concat(RESET_PROBLEMATIC_TEST_DEFAULTS), 376 }); 377 378 // Define testers for each UI state. 379 let absent = card => { 380 let label = card.shadowRoot.querySelector("li:nth-child(3) p"); 381 Assert.equal(label, null, "No install status label is present"); 382 }; 383 let issue = card => { 384 let label = card.shadowRoot.querySelector("li:nth-child(3) p"); 385 Assert.equal( 386 label.attributes.getNamedItem("data-l10n-id").value, 387 "security-privacy-status-update-error-label", 388 "Label correctly identifies an issue" 389 ); 390 }; 391 let needed = card => { 392 let label = card.shadowRoot.querySelector("li:nth-child(3) p"); 393 Assert.equal( 394 label.attributes.getNamedItem("data-l10n-id").value, 395 "security-privacy-status-update-needed-label", 396 "Label correctly identifies an update is needed" 397 ); 398 }; 399 let ok = card => { 400 let label = card.shadowRoot.querySelector("li:nth-child(3) p"); 401 Assert.equal( 402 label.attributes.getNamedItem("data-l10n-id").value, 403 "security-privacy-status-up-to-date-label", 404 "Label correctly identifies software up to date" 405 ); 406 }; 407 let checking = card => { 408 let label = card.shadowRoot.querySelector("li:nth-child(3) p"); 409 Assert.equal( 410 label.attributes.getNamedItem("data-l10n-id").value, 411 "security-privacy-status-update-checking-label", 412 "Label correctly identifies software update checking now" 413 ); 414 }; 415 416 // Define the expected result for each different test case. 417 // The keys are different AppUpdater.STATUS values. 418 let cases = {}; 419 cases[0] = issue; 420 cases[1] = absent; 421 cases[2] = absent; 422 cases[3] = absent; 423 cases[4] = issue; 424 cases[5] = needed; 425 cases[6] = checking; 426 cases[7] = ok; 427 cases[8] = needed; 428 cases[9] = issue; 429 cases[10] = needed; 430 cases[11] = needed; 431 cases[12] = needed; 432 cases[13] = issue; 433 cases[14] = issue; 434 435 await BrowserTestUtils.withNewTab( 436 { gBrowser, url: "about:preferences#privacy" }, 437 async function (browser) { 438 let elements = browser.contentDocument.getElementsByTagName(CARD_NAME); 439 Assert.equal(elements.length, 1, "Card present in preferences"); 440 let card = elements[0]; 441 for (const status in cases) { 442 info(`testing AppUpdateStatus ${status}`); 443 card.appUpdateStatus = parseInt(status); 444 await card.updateComplete; 445 cases[status](card); 446 } 447 } 448 ); 449 450 await SpecialPowers.popPrefEnv(); 451 });