forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			275 lines
		
	
	
	
		
			8.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			275 lines
		
	
	
	
		
			8.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /* Any copyright is dedicated to the Public Domain.
 | |
|  * http://creativecommons.org/publicdomain/zero/1.0/ */
 | |
| 
 | |
| const { PermissionTestUtils } = ChromeUtils.import(
 | |
|   "resource://testing-common/PermissionTestUtils.jsm"
 | |
| );
 | |
| 
 | |
| const kDefaultWait = 2000;
 | |
| 
 | |
| function is_element_visible(aElement, aMsg) {
 | |
|   isnot(aElement, null, "Element should not be null, when checking visibility");
 | |
|   ok(!BrowserTestUtils.is_hidden(aElement), aMsg);
 | |
| }
 | |
| 
 | |
| function is_element_hidden(aElement, aMsg) {
 | |
|   isnot(aElement, null, "Element should not be null, when checking visibility");
 | |
|   ok(BrowserTestUtils.is_hidden(aElement), aMsg);
 | |
| }
 | |
| 
 | |
| function open_preferences(aCallback) {
 | |
|   gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, "about:preferences");
 | |
|   let newTabBrowser = gBrowser.getBrowserForTab(gBrowser.selectedTab);
 | |
|   newTabBrowser.addEventListener(
 | |
|     "Initialized",
 | |
|     function() {
 | |
|       aCallback(gBrowser.contentWindow);
 | |
|     },
 | |
|     { capture: true, once: true }
 | |
|   );
 | |
| }
 | |
| 
 | |
| function openAndLoadSubDialog(
 | |
|   aURL,
 | |
|   aFeatures = null,
 | |
|   aParams = null,
 | |
|   aClosingCallback = null
 | |
| ) {
 | |
|   let promise = promiseLoadSubDialog(aURL);
 | |
|   content.gSubDialog.open(
 | |
|     aURL,
 | |
|     { features: aFeatures, closingCallback: aClosingCallback },
 | |
|     aParams
 | |
|   );
 | |
|   return promise;
 | |
| }
 | |
| 
 | |
| function promiseLoadSubDialog(aURL) {
 | |
|   return new Promise((resolve, reject) => {
 | |
|     content.gSubDialog._dialogStack.addEventListener(
 | |
|       "dialogopen",
 | |
|       function dialogopen(aEvent) {
 | |
|         if (
 | |
|           aEvent.detail.dialog._frame.contentWindow.location == "about:blank"
 | |
|         ) {
 | |
|           return;
 | |
|         }
 | |
|         content.gSubDialog._dialogStack.removeEventListener(
 | |
|           "dialogopen",
 | |
|           dialogopen
 | |
|         );
 | |
| 
 | |
|         is(
 | |
|           aEvent.detail.dialog._frame.contentWindow.location.toString(),
 | |
|           aURL,
 | |
|           "Check the proper URL is loaded"
 | |
|         );
 | |
| 
 | |
|         // Check visibility
 | |
|         is_element_visible(aEvent.detail.dialog._overlay, "Overlay is visible");
 | |
| 
 | |
|         // Check that stylesheets were injected
 | |
|         let expectedStyleSheetURLs = aEvent.detail.dialog._injectedStyleSheets.slice(
 | |
|           0
 | |
|         );
 | |
|         for (let styleSheet of aEvent.detail.dialog._frame.contentDocument
 | |
|           .styleSheets) {
 | |
|           let i = expectedStyleSheetURLs.indexOf(styleSheet.href);
 | |
|           if (i >= 0) {
 | |
|             info("found " + styleSheet.href);
 | |
|             expectedStyleSheetURLs.splice(i, 1);
 | |
|           }
 | |
|         }
 | |
|         is(
 | |
|           expectedStyleSheetURLs.length,
 | |
|           0,
 | |
|           "All expectedStyleSheetURLs should have been found"
 | |
|         );
 | |
| 
 | |
|         // Wait for the next event tick to make sure the remaining part of the
 | |
|         // testcase runs after the dialog gets ready for input.
 | |
|         executeSoon(() => resolve(aEvent.detail.dialog._frame.contentWindow));
 | |
|       }
 | |
|     );
 | |
|   });
 | |
| }
 | |
| 
 | |
| async function openPreferencesViaOpenPreferencesAPI(aPane, aOptions) {
 | |
|   let finalPaneEvent = Services.prefs.getBoolPref("identity.fxaccounts.enabled")
 | |
|     ? "sync-pane-loaded"
 | |
|     : "privacy-pane-loaded";
 | |
|   let finalPrefPaneLoaded = TestUtils.topicObserved(finalPaneEvent, () => true);
 | |
|   gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, "about:blank");
 | |
|   openPreferences(aPane, aOptions);
 | |
|   let newTabBrowser = gBrowser.selectedBrowser;
 | |
| 
 | |
|   if (!newTabBrowser.contentWindow) {
 | |
|     await BrowserTestUtils.waitForEvent(newTabBrowser, "Initialized", true);
 | |
|     await BrowserTestUtils.waitForEvent(newTabBrowser.contentWindow, "load");
 | |
|     await finalPrefPaneLoaded;
 | |
|   }
 | |
| 
 | |
|   let win = gBrowser.contentWindow;
 | |
|   let selectedPane = win.history.state;
 | |
|   if (!aOptions || !aOptions.leaveOpen) {
 | |
|     gBrowser.removeCurrentTab();
 | |
|   }
 | |
|   return { selectedPane };
 | |
| }
 | |
| 
 | |
| async function runSearchInput(input) {
 | |
|   let searchInput = gBrowser.contentDocument.getElementById("searchInput");
 | |
|   searchInput.focus();
 | |
|   let searchCompletedPromise = BrowserTestUtils.waitForEvent(
 | |
|     gBrowser.contentWindow,
 | |
|     "PreferencesSearchCompleted",
 | |
|     evt => evt.detail == input
 | |
|   );
 | |
|   EventUtils.sendString(input);
 | |
|   await searchCompletedPromise;
 | |
| }
 | |
| 
 | |
| async function evaluateSearchResults(
 | |
|   keyword,
 | |
|   searchReults,
 | |
|   includeExperiments = false
 | |
| ) {
 | |
|   searchReults = Array.isArray(searchReults) ? searchReults : [searchReults];
 | |
|   searchReults.push("header-searchResults");
 | |
| 
 | |
|   await runSearchInput(keyword);
 | |
| 
 | |
|   let mainPrefTag = gBrowser.contentDocument.getElementById("mainPrefPane");
 | |
|   for (let i = 0; i < mainPrefTag.childElementCount; i++) {
 | |
|     let child = mainPrefTag.children[i];
 | |
|     if (!includeExperiments && child.id?.startsWith("pane-experimental")) {
 | |
|       continue;
 | |
|     }
 | |
|     if (searchReults.includes(child.id)) {
 | |
|       is_element_visible(child, `${child.id} should be in search results`);
 | |
|     } else if (child.id) {
 | |
|       is_element_hidden(child, `${child.id} should not be in search results`);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| function waitForMutation(target, opts, cb) {
 | |
|   return new Promise(resolve => {
 | |
|     let observer = new MutationObserver(() => {
 | |
|       if (!cb || cb(target)) {
 | |
|         observer.disconnect();
 | |
|         resolve();
 | |
|       }
 | |
|     });
 | |
|     observer.observe(target, opts);
 | |
|   });
 | |
| }
 | |
| 
 | |
| // Used to add sample experimental features for testing. To use, create
 | |
| // a DefinitionServer, then call addDefinition as needed.
 | |
| class DefinitionServer {
 | |
|   constructor(definitionOverrides = []) {
 | |
|     let { HttpServer } = ChromeUtils.import(
 | |
|       "resource://testing-common/httpd.js"
 | |
|     );
 | |
| 
 | |
|     this.server = new HttpServer();
 | |
|     this.server.registerPathHandler("/definitions.json", this);
 | |
|     this.definitions = {};
 | |
| 
 | |
|     for (const override of definitionOverrides) {
 | |
|       this.addDefinition(override);
 | |
|     }
 | |
| 
 | |
|     this.server.start();
 | |
|     registerCleanupFunction(
 | |
|       () => new Promise(resolve => this.server.stop(resolve))
 | |
|     );
 | |
|   }
 | |
| 
 | |
|   // for nsIHttpRequestHandler
 | |
|   handle(request, response) {
 | |
|     response.write(JSON.stringify(this.definitions));
 | |
|   }
 | |
| 
 | |
|   get definitionsUrl() {
 | |
|     const { primaryScheme, primaryHost, primaryPort } = this.server.identity;
 | |
|     return `${primaryScheme}://${primaryHost}:${primaryPort}/definitions.json`;
 | |
|   }
 | |
| 
 | |
|   addDefinition(overrides = {}) {
 | |
|     const definition = {
 | |
|       id: "test-feature",
 | |
|       // These l10n IDs are just random so we have some text to display
 | |
|       title: "experimental-features-media-jxl",
 | |
|       description: "pane-experimental-description2",
 | |
|       restartRequired: false,
 | |
|       type: "boolean",
 | |
|       preference: "test.feature",
 | |
|       defaultValue: false,
 | |
|       isPublic: false,
 | |
|       ...overrides,
 | |
|     };
 | |
|     // convert targeted values, used by fromId
 | |
|     definition.isPublic = { default: definition.isPublic };
 | |
|     definition.defaultValue = { default: definition.defaultValue };
 | |
|     this.definitions[definition.id] = definition;
 | |
|     return definition;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Creates observer that waits for and then compares all perm-changes with the observances in order.
 | |
|  * @param {Array} observances permission changes to observe (order is important)
 | |
|  * @returns {Promise} Promise object that resolves once all permission changes have been observed
 | |
|  */
 | |
| function createObserveAllPromise(observances) {
 | |
|   // Create new promise that resolves once all items
 | |
|   // in observances array have been observed.
 | |
|   return new Promise(resolve => {
 | |
|     let permObserver = {
 | |
|       observe(aSubject, aTopic, aData) {
 | |
|         if (aTopic != "perm-changed") {
 | |
|           return;
 | |
|         }
 | |
| 
 | |
|         if (!observances.length) {
 | |
|           // See bug 1063410
 | |
|           return;
 | |
|         }
 | |
| 
 | |
|         let permission = aSubject.QueryInterface(Ci.nsIPermission);
 | |
|         let expected = observances.shift();
 | |
| 
 | |
|         info(
 | |
|           `observed perm-changed for ${permission.principal.origin} (remaining ${observances.length})`
 | |
|         );
 | |
| 
 | |
|         is(aData, expected.data, "type of message should be the same");
 | |
|         for (let prop of ["type", "capability", "expireType"]) {
 | |
|           if (expected[prop]) {
 | |
|             is(
 | |
|               permission[prop],
 | |
|               expected[prop],
 | |
|               `property: "${prop}" should be equal (${permission.principal.origin})`
 | |
|             );
 | |
|           }
 | |
|         }
 | |
| 
 | |
|         if (expected.origin) {
 | |
|           is(
 | |
|             permission.principal.origin,
 | |
|             expected.origin,
 | |
|             `property: "origin" should be equal (${permission.principal.origin})`
 | |
|           );
 | |
|         }
 | |
| 
 | |
|         if (!observances.length) {
 | |
|           Services.obs.removeObserver(permObserver, "perm-changed");
 | |
|           executeSoon(resolve);
 | |
|         }
 | |
|       },
 | |
|     };
 | |
|     Services.obs.addObserver(permObserver, "perm-changed");
 | |
|   });
 | |
| }
 | 
