head.js (8847B)
1 /* Any copyright is dedicated to the Public Domain. 2 * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 const TEST_QUOTA_USAGE_HOST = "example.com"; 7 const TEST_QUOTA_USAGE_ORIGIN = "https://" + TEST_QUOTA_USAGE_HOST; 8 const TEST_QUOTA_USAGE_URL = 9 getRootDirectory(gTestPath).replace( 10 "chrome://mochitests/content", 11 TEST_QUOTA_USAGE_ORIGIN 12 ) + "/site_data_test.html"; 13 const TEST_OFFLINE_HOST = "example.org"; 14 const TEST_OFFLINE_ORIGIN = "https://" + TEST_OFFLINE_HOST; 15 const TEST_OFFLINE_URL = 16 getRootDirectory(gTestPath).replace( 17 "chrome://mochitests/content", 18 TEST_OFFLINE_ORIGIN 19 ) + "/offline/offline.html"; 20 const TEST_SERVICE_WORKER_URL = 21 getRootDirectory(gTestPath).replace( 22 "chrome://mochitests/content", 23 TEST_OFFLINE_ORIGIN 24 ) + "/service_worker_test.html"; 25 26 const REMOVE_DIALOG_URL = 27 "chrome://browser/content/preferences/dialogs/siteDataRemoveSelected.xhtml"; 28 29 ChromeUtils.defineESModuleGetters(this, { 30 SiteDataTestUtils: "resource://testing-common/SiteDataTestUtils.sys.mjs", 31 }); 32 33 XPCOMUtils.defineLazyServiceGetter( 34 this, 35 "serviceWorkerManager", 36 "@mozilla.org/serviceworkers/manager;1", 37 Ci.nsIServiceWorkerManager 38 ); 39 40 function promiseSiteDataManagerSitesUpdated() { 41 return TestUtils.topicObserved("sitedatamanager:sites-updated", () => true); 42 } 43 44 function is_element_visible(aElement, aMsg) { 45 isnot(aElement, null, "Element should not be null, when checking visibility"); 46 ok(!BrowserTestUtils.isHidden(aElement), aMsg); 47 } 48 49 function is_element_hidden(aElement, aMsg) { 50 isnot(aElement, null, "Element should not be null, when checking visibility"); 51 ok(BrowserTestUtils.isHidden(aElement), aMsg); 52 } 53 54 function promiseLoadSubDialog(aURL) { 55 return new Promise(resolve => { 56 content.gSubDialog._dialogStack.addEventListener( 57 "dialogopen", 58 function dialogopen(aEvent) { 59 if ( 60 aEvent.detail.dialog._frame.contentWindow.location == "about:blank" 61 ) { 62 return; 63 } 64 content.gSubDialog._dialogStack.removeEventListener( 65 "dialogopen", 66 dialogopen 67 ); 68 69 is( 70 aEvent.detail.dialog._frame.contentWindow.location.toString(), 71 aURL, 72 "Check the proper URL is loaded" 73 ); 74 75 // Check visibility 76 is_element_visible(aEvent.detail.dialog._overlay, "Overlay is visible"); 77 78 // Check that stylesheets were injected 79 let expectedStyleSheetURLs = 80 aEvent.detail.dialog._injectedStyleSheets.slice(0); 81 for (let styleSheet of aEvent.detail.dialog._frame.contentDocument 82 .styleSheets) { 83 let i = expectedStyleSheetURLs.indexOf(styleSheet.href); 84 if (i >= 0) { 85 info("found " + styleSheet.href); 86 expectedStyleSheetURLs.splice(i, 1); 87 } 88 } 89 is( 90 expectedStyleSheetURLs.length, 91 0, 92 "All expectedStyleSheetURLs should have been found" 93 ); 94 95 // Wait for the next event tick to make sure the remaining part of the 96 // testcase runs after the dialog gets ready for input. 97 executeSoon(() => resolve(aEvent.detail.dialog._frame.contentWindow)); 98 } 99 ); 100 }); 101 } 102 103 function openPreferencesViaOpenPreferencesAPI(aPane, aOptions) { 104 return new Promise(resolve => { 105 let finalPrefPaneLoaded = TestUtils.topicObserved( 106 "sync-pane-loaded", 107 () => true 108 ); 109 gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, "about:blank"); 110 openPreferences(aPane); 111 let newTabBrowser = gBrowser.selectedBrowser; 112 113 newTabBrowser.addEventListener( 114 "Initialized", 115 function () { 116 newTabBrowser.contentWindow.addEventListener( 117 "load", 118 async function () { 119 let win = gBrowser.contentWindow; 120 let selectedPane = win.history.state; 121 await finalPrefPaneLoaded; 122 if (!aOptions || !aOptions.leaveOpen) { 123 gBrowser.removeCurrentTab(); 124 } 125 resolve({ selectedPane }); 126 }, 127 { once: true } 128 ); 129 }, 130 { capture: true, once: true } 131 ); 132 }); 133 } 134 135 async function openSiteDataSettingsDialog() { 136 let doc = gBrowser.selectedBrowser.contentDocument; 137 let settingsBtn = doc.getElementById("siteDataSettings"); 138 let dialogOverlay = content.gSubDialog._preloadDialog._overlay; 139 let dialogLoadPromise = promiseLoadSubDialog( 140 "chrome://browser/content/preferences/dialogs/siteDataSettings.xhtml" 141 ); 142 let dialogInitPromise = TestUtils.topicObserved( 143 "sitedata-settings-init", 144 () => true 145 ); 146 let fullyLoadPromise = Promise.all([ 147 dialogLoadPromise, 148 dialogInitPromise, 149 ]).then(() => { 150 is_element_visible(dialogOverlay, "The Settings dialog should be visible"); 151 }); 152 // Wait for the dialog button to be enabled. It is disabled while 153 // SiteDataManager updates the site list and usage. 154 await BrowserTestUtils.waitForMutationCondition( 155 settingsBtn, 156 { 157 attributeFilter: ["disabled"], 158 }, 159 () => { 160 return !settingsBtn.disabled; 161 } 162 ); 163 settingsBtn.click(); 164 await fullyLoadPromise; 165 } 166 167 function promiseSettingsDialogClose() { 168 return new Promise(resolve => { 169 let win = gBrowser.selectedBrowser.contentWindow; 170 let dialogOverlay = win.gSubDialog._topDialog._overlay; 171 let dialogWin = win.gSubDialog._topDialog._frame.contentWindow; 172 dialogWin.addEventListener( 173 "unload", 174 function unload() { 175 if ( 176 dialogWin.document.documentURI === 177 "chrome://browser/content/preferences/dialogs/siteDataSettings.xhtml" 178 ) { 179 is_element_hidden( 180 dialogOverlay, 181 "The Settings dialog should be hidden" 182 ); 183 resolve(); 184 } 185 }, 186 { once: true } 187 ); 188 }); 189 } 190 191 function assertSitesListed(doc, hosts) { 192 let frameDoc = content.gSubDialog._topDialog._frame.contentDocument; 193 let removeAllBtn = frameDoc.getElementById("removeAll"); 194 let sitesList = frameDoc.getElementById("sitesList"); 195 let totalSitesNumber = sitesList.getElementsByTagName("richlistitem").length; 196 is(totalSitesNumber, hosts.length, "Should list the right sites number"); 197 hosts.forEach(host => { 198 let site = sitesList.querySelector(`richlistitem[host="${host}"]`); 199 ok(site, `Should list the site of ${host}`); 200 }); 201 is(removeAllBtn.disabled, false, "Should enable the removeAllBtn button"); 202 } 203 204 // Counter used by addTestData to generate unique cookie names across function 205 // calls. 206 let cookieID = 0; 207 208 async function addTestData(data) { 209 let hosts = new Set(); 210 211 for (let site of data) { 212 is( 213 typeof site.origin, 214 "string", 215 "Passed an origin string into addTestData." 216 ); 217 if (site.persisted) { 218 await SiteDataTestUtils.persist(site.origin); 219 } 220 221 if (site.usage) { 222 await SiteDataTestUtils.addToIndexedDB(site.origin, site.usage); 223 } 224 225 for (let i = 0; i < (site.cookies || 0); i++) { 226 SiteDataTestUtils.addToCookies({ 227 origin: site.origin, 228 name: `cookie${cookieID++}`, 229 }); 230 } 231 232 let principal = 233 Services.scriptSecurityManager.createContentPrincipalFromOrigin( 234 site.origin 235 ); 236 237 hosts.add(principal.baseDomain || principal.host); 238 } 239 240 return Array.from(hosts); 241 } 242 243 function promiseCookiesCleared() { 244 return TestUtils.topicObserved("cookie-changed", subj => { 245 return ( 246 subj.QueryInterface(Ci.nsICookieNotification).action == 247 Ci.nsICookieNotification.ALL_COOKIES_CLEARED 248 ); 249 }); 250 } 251 252 async function loadServiceWorkerTestPage(url) { 253 let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url); 254 await TestUtils.waitForCondition(() => { 255 return SpecialPowers.spawn( 256 tab.linkedBrowser, 257 [], 258 () => 259 content.document.body.getAttribute( 260 "data-test-service-worker-registered" 261 ) === "true" 262 ); 263 }, `Fail to load service worker test ${url}`); 264 BrowserTestUtils.removeTab(tab); 265 } 266 267 function promiseServiceWorkersCleared() { 268 return TestUtils.waitForCondition(() => { 269 let serviceWorkers = serviceWorkerManager.getAllRegistrations(); 270 if (!serviceWorkers.length) { 271 ok(true, "Cleared all service workers"); 272 return true; 273 } 274 return false; 275 }, "Should clear all service workers"); 276 } 277 278 function promiseServiceWorkerRegisteredFor(url) { 279 return TestUtils.waitForCondition(() => { 280 try { 281 let principal = 282 Services.scriptSecurityManager.createContentPrincipalFromOrigin(url); 283 let sw = serviceWorkerManager.getRegistrationByPrincipal( 284 principal, 285 principal.spec 286 ); 287 if (sw) { 288 ok(true, `Found the service worker registered for ${url}`); 289 return true; 290 } 291 } catch (e) {} 292 return false; 293 }, `Should register service worker for ${url}`); 294 }