test_setting_control_extension_controlled.html (31593B)
1 <!doctype html> 2 <html> 3 <head> 4 <meta charset="utf-8" /> 5 <title>setting-control extension controlled tests</title> 6 <style> 7 /* Force text color to ensure settings controls unit tested by 8 this test are visible (eg. to aid investigating test failures 9 that may only be hit in CI). */ 10 body { 11 color: black; 12 } 13 </style> 14 <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> 15 <link 16 rel="stylesheet" 17 href="chrome://mochikit/content/tests/SimpleTest/test.css" 18 /> 19 <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script> 20 <script src="../../../../../toolkit/content/tests/widgets/lit-test-helpers.js"></script> 21 <script src="./head.js"></script> 22 <script 23 type="module" 24 src="chrome://browser/content/preferences/widgets/setting-group.mjs" 25 ></script> 26 <script 27 type="module" 28 src="chrome://browser/content/preferences/widgets/setting-control.mjs" 29 ></script> 30 <script 31 type="module" 32 src="chrome://global/content/elements/moz-message-bar.mjs" 33 ></script> 34 <script 35 type="application/javascript" 36 src="chrome://global/content/preferencesBindings.js" 37 ></script> 38 <script src="chrome://mochikit/content/tests/SimpleTest/ExtensionTestUtils.js"></script> 39 <script> 40 const { Assert } = ChromeUtils.importESModule( 41 "resource://testing-common/Assert.sys.mjs" 42 ); 43 // Import the ExtensionSettingsStore and AddonManager as we need 44 // them to correctly disable the extension on click and re-enable 45 // the extension in the same task. 46 ChromeUtils.defineESModuleGetters(this, { 47 ExtensionSettingsStore: 48 "resource://gre/modules/ExtensionSettingsStore.sys.mjs", 49 AddonManager: "resource://gre/modules/AddonManager.sys.mjs", 50 BrowserWindowTracker: 51 "resource:///modules/BrowserWindowTracker.sys.mjs", 52 }); 53 54 /* import-globals-from /toolkit/content/preferencesBindings.js */ 55 let html, testHelpers; 56 57 const PREF_ID = "test.setting-control.bar"; 58 async function renderTemplate(itemConfig) { 59 let config = { 60 items: [itemConfig], 61 }; 62 let result = await testHelpers.renderTemplate(html` 63 <setting-group 64 .config=${config} 65 .getSetting=${(...args) => Preferences.getSetting(...args)} 66 ></setting-group> 67 `); 68 if (document.hasPendingL10nMutations) { 69 await BrowserTestUtils.waitForEvent( 70 document, 71 "L10nMutationsFinished" 72 ); 73 } 74 return result.querySelector("setting-control"); 75 } 76 77 async function disableExtensionByMouse(elem) { 78 await synthesizeMouseAtCenter(elem, {}); 79 } 80 81 const getExtensionControlledMessageBar = control => 82 control.querySelector(".extension-controlled-message-bar"); 83 const getReenableExtensionMessageBar = control => 84 control.querySelector(".reenable-extensions-message-bar"); 85 86 add_setup(async function setup() { 87 testHelpers = new InputTestHelpers(); 88 ({ html } = await testHelpers.setupLit()); 89 testHelpers.setupTests({ 90 templateFn: () => html`<setting-group></setting-group>`, 91 }); 92 MozXULElement.insertFTLIfNeeded("branding/brand.ftl"); 93 MozXULElement.insertFTLIfNeeded("browser/preferences/preferences.ftl"); 94 Preferences.addAll([{ id: PREF_ID }]); 95 // Add mock Fluent source to define the test-fluent-id l10n id 96 // used in these tests. 97 const mockL10nSource = L10nFileSource.createMock( 98 "test", 99 "app", 100 ["en-US"], 101 "/localization/{locale}/", 102 [ 103 { 104 path: "/localization/en-US/mock.ftl", 105 source: 106 "test-fluent-id =\n .label = TestLabel\n .description = TestDescription", 107 }, 108 ] 109 ); 110 L10nRegistry.getInstance().registerSources([mockL10nSource]); 111 MozXULElement.insertFTLIfNeeded("mock.ftl"); 112 SimpleTest.registerCleanupFunction(() => { 113 Preferences.onUnload(); 114 SpecialPowers.popPrefEnv(); 115 }); 116 }); 117 118 add_task(async function testExtensionControlledConfigBasedControl() { 119 // Setup pre-test items: extension, Preferences, ExtensionSettingStore 120 const SETTING_ID = "extension-controlled-setting"; 121 const ADDON_ID = "ext-controlled@mochi.test"; 122 const ADDON_NAME = "Ext Controlled"; 123 const STORE_ID = "privacy.containers"; 124 const TEST_FLUENT_ID = "test-fluent-id"; 125 const SUPPORT_PAGE = "support-test"; 126 const SUPPORT_URL = Services.prefs.getStringPref("app.support.baseURL"); 127 await SpecialPowers.pushPrefEnv({ 128 set: [[PREF_ID, false]], 129 }); 130 let extension = ExtensionTestUtils.loadExtension({ 131 manifest: { 132 browser_specific_settings: { gecko: { id: ADDON_ID } }, 133 name: ADDON_NAME, 134 permissions: ["contextualIdentities", "cookies"], 135 }, 136 // We need to be able to find the extension using AddonManager. 137 useAddonManager: "temporary", 138 }); 139 await extension.startup(); 140 141 // Assert there is no markup that is generated by pre-test setup since we 142 // don't have a setting that is being controlled by the STORE_ID 143 144 let settingControl = document.getElementById(SETTING_ID); 145 is( 146 settingControl, 147 null, 148 "The setting control under test should not exist yet." 149 ); 150 151 // Add setting that is being controlled by our test extension 152 Preferences.addSetting({ 153 id: SETTING_ID, 154 pref: PREF_ID, 155 controllingExtensionInfo: { 156 storeId: STORE_ID, 157 l10nId: TEST_FLUENT_ID, 158 supportPage: SUPPORT_PAGE, 159 }, 160 }); 161 162 // Create itemConfig for expected setting-control element 163 let itemConfig = { 164 l10nId: "test-fluent-id", 165 id: SETTING_ID, 166 }; 167 168 // Wait for setting-control element to be rendered 169 let setting = Preferences.getSetting(SETTING_ID); 170 let control = await renderTemplate(itemConfig, setting); 171 172 // Checking if the setting is controlled by an extension 173 // and retrieve the addon details to be shown is asynchronous 174 // and so there is a chance the control may not be immediately 175 // disabled right after being created. 176 await TestUtils.waitForCondition( 177 () => control.controlEl.disabled, 178 "Wait for the control to become disabled as a side-effect of controlling extension metadata to be found" 179 ); 180 181 // Assert checkbox control is created and disabled due to extension controlling the pref 182 is( 183 control.controlEl.localName, 184 "moz-checkbox", 185 "The control rendered the default checkbox" 186 ); 187 is( 188 control.controlEl.disabled, 189 true, 190 "The control should be disabled since it is controlled by an extension" 191 ); 192 193 // Assert that moz-message-bar appears with the correct Fluent attributes/args 194 let messageBar = control.querySelector("moz-message-bar"); 195 ok( 196 messageBar, 197 "There should be an extension controlled message bar element" 198 ); 199 200 is( 201 messageBar.messageL10nId, 202 TEST_FLUENT_ID, 203 "The l10nId should be the same as the one in the config" 204 ); 205 is( 206 messageBar.messageL10nArgs.name, 207 ADDON_NAME, 208 "The name used within the message-bar should be the extension name" 209 ); 210 211 // Assert that moz-message-bar appears with an actions button with correct Fluent attributes 212 let disableExtensionButton = messageBar.querySelector( 213 "moz-button[slot='actions']" 214 ); 215 ok( 216 disableExtensionButton, 217 "There should be a button to disable the extension" 218 ); 219 is( 220 disableExtensionButton.getAttribute("data-l10n-id"), 221 "disable-extension", 222 "The disable extension button should have the correct data-l10n-id" 223 ); 224 225 // Assert that moz-message-bar appears with a support link with correct attributes 226 let supportLink = messageBar.querySelector("a[slot='support-link']"); 227 ok(supportLink, "There should be a slotted support link element"); 228 is( 229 supportLink.getAttribute("support-page"), 230 SUPPORT_PAGE, 231 "The support link should have the correct value for 'support-page'" 232 ); 233 is( 234 supportLink.href, 235 `${SUPPORT_URL}${SUPPORT_PAGE}`, 236 "The support link should have the correct generated href value" 237 ); 238 239 // Unload the test extension and remove the setting-control element 240 await extension.unload(); 241 control.remove(); 242 }); 243 244 add_task(async function testDisablingExtensionControlledSetting() { 245 // Setup pre-test items like extension, AddonManager, ExtensionSettingStore 246 const SETTING_ID = "extension-controlled-setting"; 247 const ADDON_ID = "ext-controlled@mochi.test"; 248 const ADDON_NAME = "Ext Controlled"; 249 const STORE_ID = "privacy.containers"; 250 const TEST_FLUENT_ID = "test-fluent-id"; 251 await SpecialPowers.pushPrefEnv({ 252 set: [[PREF_ID, false]], 253 }); 254 let extension = ExtensionTestUtils.loadExtension({ 255 manifest: { 256 browser_specific_settings: { gecko: { id: ADDON_ID } }, 257 name: ADDON_NAME, 258 permissions: ["contextualIdentities", "cookies"], 259 }, 260 // We need to be able to find the extension using AddonManager. 261 useAddonManager: "temporary", 262 }); 263 await extension.startup(); 264 265 // We need to get the addon via the AddonManager to re-enable it later 266 let addon = await AddonManager.getAddonByID(ADDON_ID); 267 await ExtensionSettingsStore.initialize(); 268 269 // Assert there is no markup that is generated by pre-test setup since we 270 // don't have a setting that is being controlled by the STORE_ID 271 272 let settingControl = document.getElementById(SETTING_ID); 273 is( 274 settingControl, 275 null, 276 "The setting control under test should not exist yet." 277 ); 278 279 // Add setting that is being controlled by our test extension 280 Preferences.addSetting({ 281 id: SETTING_ID, 282 pref: PREF_ID, 283 controllingExtensionInfo: { 284 storeId: STORE_ID, 285 l10nId: TEST_FLUENT_ID, 286 }, 287 }); 288 289 // Create itemConfig for expected setting-control element 290 let itemConfig = { 291 l10nId: "test-fluent-id", 292 id: SETTING_ID, 293 }; 294 295 // Wait for setting-control element to be rendered 296 let setting = Preferences.getSetting(SETTING_ID); 297 let control = await renderTemplate(itemConfig, setting); 298 // Assert that moz-message-bar appears with the correct Fluent attributes/args 299 let extensionControlledMessageBar = 300 getExtensionControlledMessageBar(control); 301 302 ok( 303 extensionControlledMessageBar, 304 "There should be an extension controlled message bar element" 305 ); 306 307 is( 308 extensionControlledMessageBar.messageL10nId, 309 TEST_FLUENT_ID, 310 "The l10nId should be the same as the one in the config" 311 ); 312 is( 313 extensionControlledMessageBar.messageL10nArgs.name, 314 ADDON_NAME, 315 "The name used within the message-bar should be the extension name" 316 ); 317 318 // Assert that moz-message-bar appears with an actions button with correct Fluent attributes 319 let disableExtensionButton = 320 extensionControlledMessageBar.querySelector( 321 "moz-button[slot='actions']" 322 ); 323 ok( 324 disableExtensionButton, 325 "There should be a button to disable the extension" 326 ); 327 is( 328 disableExtensionButton.getAttribute("data-l10n-id"), 329 "disable-extension", 330 "The disable extension button should have the correct data-l10n-id" 331 ); 332 333 await disableExtensionByMouse(disableExtensionButton); 334 335 await TestUtils.waitForCondition( 336 () => 337 !control.isDisablingExtension && 338 !getExtensionControlledMessageBar(control), 339 "Wait for the extension controlled message bar to be removed after disabling the only controlling extension" 340 ); 341 342 await TestUtils.waitForCondition( 343 () => getReenableExtensionMessageBar(control), 344 "Wait for the re-enable extension message bar to be rendered" 345 ); 346 let enableExtensionMessageBar = getReenableExtensionMessageBar(control); 347 ok( 348 enableExtensionMessageBar, 349 "there should be a message bar for re-enabling extensions" 350 ); 351 352 let addonsLink = enableExtensionMessageBar.querySelector("[slot] a"); 353 is( 354 enableExtensionMessageBar 355 .querySelector("[slot]") 356 .getAttribute("data-l10n-id"), 357 "extension-controlled-enable-2", 358 "The re-enable extension message bar should have a slot with the correct data-l10n-id" 359 ); 360 361 is( 362 addonsLink.getAttribute("data-l10n-name"), 363 "addons-link", 364 "The slot within the re-enable extension bar should have the correct data-l10n-name" 365 ); 366 367 await addon.enable(); 368 await TestUtils.waitForCondition( 369 () => control.controlEl.disabled, 370 "Wait for the control to become disabled as a side-effect of enabling the controlling extension" 371 ); 372 373 await TestUtils.waitForCondition( 374 () => !getReenableExtensionMessageBar(control), 375 "The re-enable extension message bar should be removed when the extension is enabled again." 376 ); 377 extensionControlledMessageBar = 378 getExtensionControlledMessageBar(control); 379 ok( 380 extensionControlledMessageBar, 381 "The extension controlled message bar should be rendered when the controlling addon is enabled elsewhere." 382 ); 383 384 await addon.disable(); 385 await TestUtils.waitForCondition( 386 () => !control.controlEl.disabled, 387 "Wait for the control to become mutable as a side-effect of disabling the controlling extension" 388 ); 389 enableExtensionMessageBar = getReenableExtensionMessageBar(control); 390 is( 391 enableExtensionMessageBar 392 .querySelector("[slot]") 393 .getAttribute("data-l10n-id"), 394 "extension-controlled-enable-2", 395 "The re-enable extension message bar should have a slot with the correct data-l10n-id" 396 ); 397 ok( 398 !getExtensionControlledMessageBar(control), 399 "The message bar should not be rendered when the controlling addon is disabled elsewhere." 400 ); 401 402 await addon.enable(); 403 await TestUtils.waitForCondition( 404 () => control.controlEl.disabled, 405 "Wait for the control to become disabled as a side-effect of enabling the controlling extension" 406 ); 407 408 control.focus(); 409 // Assert that action button can be navigated to with keyboard 410 await synthesizeKey("KEY_Tab", {}); 411 // Assert that action button can be activated with keyboard 412 await synthesizeKey(" "); 413 414 await TestUtils.waitForCondition( 415 () => !control.isDisablingExtension && !control.controlEl.disabled, 416 "Wait for the control to become mutable as a side-effect of disabling the controlling extension" 417 ); 418 extensionControlledMessageBar = 419 getExtensionControlledMessageBar(control); 420 ok( 421 !extensionControlledMessageBar, 422 "The extension controlled message bar should not be rendered after hitting Space on the disable extension button." 423 ); 424 425 enableExtensionMessageBar = getReenableExtensionMessageBar(control); 426 ok( 427 enableExtensionMessageBar, 428 "The message bar to re-enable the extension should be rendered" 429 ); 430 431 // Unload the test extension and remove the setting control 432 await extension.unload(); 433 control.remove(); 434 }); 435 436 add_task(async function testMultipleControllingExtensions() { 437 const SETTING_ID = "extension-controlled-setting"; 438 const ADDON_ID = "ext-controlled@mochi.test"; 439 const ADDON_NAME = "Ext Controlled"; 440 const STORE_ID = "privacy.containers"; 441 const TEST_FLUENT_ID = "test-fluent-id"; 442 await SpecialPowers.pushPrefEnv({ 443 set: [[PREF_ID, false]], 444 }); 445 let extension = ExtensionTestUtils.loadExtension({ 446 manifest: { 447 browser_specific_settings: { gecko: { id: ADDON_ID } }, 448 name: ADDON_NAME, 449 permissions: ["contextualIdentities", "cookies"], 450 }, 451 // We need to be able to find the extension using AddonManager. 452 useAddonManager: "temporary", 453 }); 454 await extension.startup(); 455 456 const ADDON_ID_2 = "ext-controlled2@mochi.test"; 457 const ADDON_NAME_2 = "Ext Controlled 2"; 458 459 let secondExtension = ExtensionTestUtils.loadExtension({ 460 manifest: { 461 browser_specific_settings: { gecko: { id: ADDON_ID_2 } }, 462 name: ADDON_NAME_2, 463 permissions: [ 464 "browserSettings", 465 "contextualIdentities", 466 "privacy", 467 "proxy", 468 "storage", 469 "<all_urls>", 470 ], 471 }, 472 useAddonManager: "temporary", 473 }); 474 await secondExtension.startup(); 475 476 // Assert there is no markup that is generated by pre-test setup since we 477 // don't have a setting that is being controlled by the STORE_ID 478 479 let settingControl = document.getElementById(SETTING_ID); 480 is( 481 settingControl, 482 null, 483 "The setting control under test should not exist yet." 484 ); 485 486 // Add setting that is being controlled by both our test extensions 487 Preferences.addSetting({ 488 id: SETTING_ID, 489 pref: PREF_ID, 490 controllingExtensionInfo: { 491 storeId: STORE_ID, 492 l10nId: TEST_FLUENT_ID, 493 }, 494 }); 495 496 // Create itemConfig for expected setting-control element 497 let itemConfig = { 498 l10nId: "test-fluent-id", 499 id: SETTING_ID, 500 }; 501 502 // Wait for setting-control element to be rendered 503 let setting = Preferences.getSetting(SETTING_ID); 504 let control = await renderTemplate(itemConfig, setting); 505 506 // Assert checkbox control is created and disabled due to extensions controlling the pref 507 is( 508 control.controlEl.localName, 509 "moz-checkbox", 510 "The control rendered the default checkbox" 511 ); 512 is( 513 control.controlEl.disabled, 514 true, 515 "The control should be disabled since it is controlled by an extension" 516 ); 517 518 // Assert that moz-message-bar appears with the correct Fluent attributes/args 519 let extensionControlledMessageBar = 520 getExtensionControlledMessageBar(control); 521 ok( 522 extensionControlledMessageBar, 523 "There should be an extension controlled message bar element" 524 ); 525 is( 526 extensionControlledMessageBar.messageL10nId, 527 TEST_FLUENT_ID, 528 "The l10nId should be the same as the one in the config" 529 ); 530 is( 531 extensionControlledMessageBar.messageL10nArgs.name, 532 ADDON_NAME_2, 533 "The name used within the message-bar should be the most recently enabled extension name" 534 ); 535 536 // Assert that moz-message-bar appears with an actions button with correct Fluent attributes 537 let disableExtensionButton = 538 extensionControlledMessageBar.querySelector( 539 "moz-button[slot='actions']" 540 ); 541 ok( 542 disableExtensionButton, 543 "There should be a button to disable the extension" 544 ); 545 is( 546 disableExtensionButton.getAttribute("data-l10n-id"), 547 "disable-extension", 548 "The disable extension button should have the correct data-l10n-id" 549 ); 550 551 await disableExtensionByMouse(disableExtensionButton); 552 553 await TestUtils.waitForCondition( 554 () => 555 !control.isDisablingExtension && 556 getExtensionControlledMessageBar(control)?.messageL10nArgs.name === 557 ADDON_NAME, 558 "Wait for the message bar to be refreshed after disabling the controlling extension" 559 ); 560 561 extensionControlledMessageBar = 562 getExtensionControlledMessageBar(control); 563 disableExtensionButton = extensionControlledMessageBar.querySelector( 564 "moz-button[slot='actions']" 565 ); 566 ok( 567 extensionControlledMessageBar, 568 "The message bar should still be present due to multiple extensions controlling the setting" 569 ); 570 571 is( 572 extensionControlledMessageBar.messageL10nArgs.name, 573 ADDON_NAME, 574 "The name used within the message-bar should be the oldest enabled extension name" 575 ); 576 577 is( 578 control.controlEl.disabled, 579 true, 580 "The control element should still be disabled since there is still a controlling extension" 581 ); 582 583 await disableExtensionByMouse(disableExtensionButton); 584 585 await TestUtils.waitForCondition( 586 () => !getExtensionControlledMessageBar(control), 587 "Wait for the message bar to be removed after disabling the last controlling extension" 588 ); 589 590 is( 591 control.controlEl.disabled, 592 false, 593 "The control element should not be disabled since there are no more controlling extensions" 594 ); 595 596 await TestUtils.waitForCondition( 597 () => getReenableExtensionMessageBar(control), 598 "Wait for the re-enable extension message bar to render" 599 ); 600 let enableExtensionMessageBar = getReenableExtensionMessageBar(control); 601 ok( 602 enableExtensionMessageBar, 603 "The message bar for enabling extensions should be rendered" 604 ); 605 is( 606 enableExtensionMessageBar 607 .querySelector("[slot]") 608 .getAttribute("data-l10n-id"), 609 "extension-controlled-enable-2", 610 "The re-enable extension message bar should have a slot with the correct data-l10n-id" 611 ); 612 613 // Clean up extensions and rendered setting control element 614 await extension.unload(); 615 await secondExtension.unload(); 616 control.remove(); 617 }); 618 619 add_task(async function test_no_initial_controlling_extension() { 620 // Setup pre-test items: extension, Preferences, ExtensionSettingStore 621 const SETTING_ID = "extension-controlled-setting"; 622 const STORE_ID = "privacy.containers"; 623 const TEST_FLUENT_ID = "test-fluent-id"; 624 const ADDON_ID = "ext-controlled@mochi.test"; 625 const ADDON_NAME = "Ext Controlled"; 626 627 // Assert there is no markup that is generated by pre-test setup since we 628 // don't have a setting that is being controlled by the STORE_ID 629 630 let settingControl = document.getElementById(SETTING_ID); 631 is( 632 settingControl, 633 null, 634 "The setting control under test should not exist yet." 635 ); 636 637 // Add setting that is not initially controlled by an extension, 638 // but is configured so that it can be controlled. 639 Preferences.addSetting({ 640 id: SETTING_ID, 641 pref: PREF_ID, 642 controllingExtensionInfo: { 643 storeId: STORE_ID, 644 l10nId: TEST_FLUENT_ID, 645 }, 646 }); 647 648 // Create itemConfig for expected setting-control element 649 let itemConfig = { 650 l10nId: "test-fluent-id", 651 id: SETTING_ID, 652 }; 653 654 // Wait for setting-control element to be rendered 655 let setting = Preferences.getSetting(SETTING_ID); 656 let control = await renderTemplate(itemConfig, setting); 657 ok(await control.updateComplete, "No pending updates"); 658 659 // Assert checkbox control is created and NOT disabled due to 660 // no extension controlling the pref. 661 662 is( 663 control.controlEl.localName, 664 "moz-checkbox", 665 "The control rendered the default checkbox" 666 ); 667 is( 668 control.controlEl.disabled, 669 false, 670 "The control should not disabled since it is not controlled by an extension" 671 ); 672 673 // Assert that there are no moz-message-bar elements rendered since 674 // the setting is not controlled by an extension 675 let messageBars = control.querySelectorAll("moz-message-bar"); 676 677 ok( 678 !messageBars.length, 679 "There should be no rendered message bar elements" 680 ); 681 682 let extension = ExtensionTestUtils.loadExtension({ 683 manifest: { 684 browser_specific_settings: { gecko: { id: ADDON_ID } }, 685 name: ADDON_NAME, 686 permissions: ["contextualIdentities", "cookies"], 687 }, 688 // We need to be able to find the extension using AddonManager. 689 useAddonManager: "temporary", 690 }); 691 692 let settingChanged = waitForSettingChange(setting); 693 await extension.startup(); 694 await settingChanged; 695 await control.updateComplete; 696 697 is( 698 control.controlEl.disabled, 699 true, 700 "Control is now disabled due to extension" 701 ); 702 703 let messageBar = control.querySelector("moz-message-bar"); 704 ok(messageBar, "Message bar was rendered"); 705 706 settingChanged = waitForSettingChange(setting); 707 await extension.unload(); 708 await settingChanged; 709 await control.updateComplete; 710 711 is(control.controlEl.disabled, false, "Control is enabled again"); 712 messageBar = control.querySelector("moz-message-bar"); 713 ok(!messageBar, "Message bar was removed"); 714 715 control.remove(); 716 }); 717 718 add_task(async function test_addons_link_in_message_bar() { 719 // Setup pre-test items like extension, AddonManager, ExtensionSettingStore 720 const SETTING_ID = "extension-controlled-setting"; 721 const ADDON_ID = "ext-controlled@mochi.test"; 722 const ADDON_NAME = "Ext Controlled"; 723 const STORE_ID = "privacy.containers"; 724 const TEST_FLUENT_ID = "test-fluent-id"; 725 await SpecialPowers.pushPrefEnv({ 726 set: [[PREF_ID, false]], 727 }); 728 let extension = ExtensionTestUtils.loadExtension({ 729 manifest: { 730 browser_specific_settings: { gecko: { id: ADDON_ID } }, 731 name: ADDON_NAME, 732 permissions: ["contextualIdentities", "cookies"], 733 }, 734 // We need to be able to find the extension using AddonManager. 735 useAddonManager: "temporary", 736 }); 737 await extension.startup(); 738 739 await ExtensionSettingsStore.initialize(); 740 741 // Assert there is no markup that is generated by pre-test setup since we 742 // don't have a setting that is being controlled by the STORE_ID 743 744 let settingControl = document.getElementById(SETTING_ID); 745 is( 746 settingControl, 747 null, 748 "The setting control under test should not exist yet." 749 ); 750 751 // Add setting that is being controlled by our test extension 752 Preferences.addSetting({ 753 id: SETTING_ID, 754 pref: PREF_ID, 755 controllingExtensionInfo: { 756 storeId: STORE_ID, 757 l10nId: TEST_FLUENT_ID, 758 }, 759 }); 760 761 // Create itemConfig for expected setting-control element 762 let itemConfig = { 763 l10nId: "test-fluent-id", 764 id: SETTING_ID, 765 }; 766 767 // Wait for setting-control element to be rendered 768 let setting = Preferences.getSetting(SETTING_ID); 769 let control = await renderTemplate(itemConfig, setting); 770 let messageBar = control.querySelector("moz-message-bar"); 771 let disableExtensionButton = messageBar.querySelector( 772 "moz-button[slot='actions']" 773 ); 774 775 await disableExtensionByMouse(disableExtensionButton); 776 777 await TestUtils.waitForCondition( 778 () => !getExtensionControlledMessageBar(control), 779 "Wait for the extension controlled message bar to be removed after disabling the only controlling extension" 780 ); 781 782 await TestUtils.waitForCondition( 783 () => getReenableExtensionMessageBar(control), 784 "Wait for the re-enable extension message bar to be rendered" 785 ); 786 let enableExtensionMessageBar = getReenableExtensionMessageBar(control); 787 ok( 788 enableExtensionMessageBar, 789 "there should be a message bar for re-enabling extensions" 790 ); 791 let addonsLink = enableExtensionMessageBar.querySelector("[slot] a"); 792 793 is( 794 enableExtensionMessageBar 795 .querySelector("[slot]") 796 .getAttribute("data-l10n-id"), 797 "extension-controlled-enable-2", 798 "The re-enable extension message bar should have a slot with the correct data-l10n-id" 799 ); 800 801 is( 802 addonsLink.getAttribute("data-l10n-name"), 803 "addons-link", 804 "The slot within the re-enable extension bar should have the correct data-l10n-name" 805 ); 806 807 let gBrowser = BrowserWindowTracker.getTopWindow().top.gBrowser; 808 let addonsTabPromise = BrowserTestUtils.waitForNewTab( 809 gBrowser, 810 "about:addons" 811 ); 812 await synthesizeMouseAtCenter(addonsLink, {}); 813 814 let tab = await addonsTabPromise; 815 is( 816 tab.linkedBrowser.currentURI.spec, 817 "about:addons", 818 "addons link correctly navigates to about:addons" 819 ); 820 821 BrowserTestUtils.removeTab(tab); 822 enableExtensionMessageBar = getReenableExtensionMessageBar(control); 823 addonsLink = enableExtensionMessageBar.querySelector("[slot] a"); 824 825 ok( 826 enableExtensionMessageBar, 827 "there should still be a message bar for re-enabling extensions after navigating back to about:preferences" 828 ); 829 is( 830 enableExtensionMessageBar 831 .querySelector("[slot]") 832 .getAttribute("data-l10n-id"), 833 "extension-controlled-enable-2", 834 "The re-enable extension message bar should have a slot with the correct data-l10n-id after navigating back to about:preferences" 835 ); 836 837 is( 838 addonsLink.getAttribute("data-l10n-name"), 839 "addons-link", 840 "The slot within the re-enable extension bar should have the correct data-l10n-name after navigating back to about:preferences" 841 ); 842 843 // Unload the test extension and remove the setting control 844 await extension.unload(); 845 control.remove(); 846 }); 847 </script> 848 </head> 849 850 <body> 851 <p id="display"></p> 852 <div id="content" style="display: none"></div> 853 <pre id="test"></pre> 854 </body> 855 </html>