api.js (4848B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 // These globals are available to extensions using privileged APIs. 6 /* globals XPCOMUtils, ExtensionAPI */ 7 8 const Cm = Components.manager; 9 10 var OnRefTestLoad, OnRefTestUnload; 11 12 XPCOMUtils.defineLazyServiceGetter( 13 this, 14 "resProto", 15 "@mozilla.org/network/protocol;1?name=resource", 16 Ci.nsISubstitutingProtocolHandler 17 ); 18 19 XPCOMUtils.defineLazyServiceGetter( 20 this, 21 "aomStartup", 22 "@mozilla.org/addons/addon-manager-startup;1", 23 Ci.amIAddonManagerStartup 24 ); 25 26 function processTerminated() { 27 return new Promise(resolve => { 28 Services.obs.addObserver(function observe(subject, topic) { 29 if (topic == "ipc:content-shutdown") { 30 Services.obs.removeObserver(observe, topic); 31 resolve(); 32 } 33 }, "ipc:content-shutdown"); 34 }); 35 } 36 37 function startAndroid(win) { 38 // Add setTimeout here because windows.innerWidth/Height are not set yet. 39 win.setTimeout(function () { 40 OnRefTestLoad(win); 41 }, 0); 42 } 43 44 function GetMainWindow() { 45 let win = Services.wm.getMostRecentWindow("navigator:browser"); 46 if (!win) { 47 // There is no navigator:browser in the geckoview TestRunnerActivity; 48 // try navigator.geckoview instead. 49 win = Services.wm.getMostRecentWindow("navigator:geckoview"); 50 } 51 return win; 52 } 53 54 this.reftest = class extends ExtensionAPI { 55 onStartup() { 56 let uri = Services.io.newURI( 57 "chrome/reftest/res/", 58 null, 59 this.extension.rootURI 60 ); 61 resProto.setSubstitutionWithFlags( 62 "reftest", 63 uri, 64 resProto.ALLOW_CONTENT_ACCESS 65 ); 66 67 const manifestURI = Services.io.newURI( 68 "manifest.json", 69 null, 70 this.extension.rootURI 71 ); 72 73 let manifestDirectives = [ 74 [ 75 "content", 76 "reftest", 77 "chrome/reftest/content/", 78 "contentaccessible=yes", 79 ], 80 ]; 81 if (Services.appinfo.OS == "Android") { 82 manifestDirectives.push([ 83 "override", 84 "chrome://global/skin/global.css", 85 "chrome://reftest/content/fake-global.css", 86 ]); 87 } 88 this.chromeHandle = aomStartup.registerChrome( 89 manifestURI, 90 manifestDirectives 91 ); 92 93 // Starting tests is handled quite differently on android and desktop. 94 // On Android, OnRefTestLoad() takes over the main browser window so 95 // we just need to call it as soon as the browser window is available. 96 // On desktop, a separate window (dummy) is created and explicitly given 97 // focus (see bug 859339 for details), then tests are launched in a new 98 // top-level window. 99 let win = GetMainWindow(); 100 if (Services.appinfo.OS == "Android") { 101 ({ OnRefTestLoad, OnRefTestUnload } = ChromeUtils.importESModule( 102 "resource://reftest/reftest.sys.mjs" 103 )); 104 if (win) { 105 startAndroid(win); 106 } else { 107 // The window type parameter is only available once the window's document 108 // element has been created. The main window has already been created 109 // however and it is in an in-between state which means that you can't 110 // find it by its type nor will domwindowcreated be fired. 111 // So we listen to either initial-document-element-inserted which 112 // indicates when it's okay to search for the main window by type again. 113 Services.obs.addObserver(function observer(aSubject, aTopic) { 114 Services.obs.removeObserver(observer, aTopic); 115 startAndroid(GetMainWindow()); 116 }, "initial-document-element-inserted"); 117 } 118 return; 119 } 120 121 Services.io.manageOfflineStatus = false; 122 Services.io.offline = false; 123 124 let dummy = Services.ww.openWindow( 125 null, 126 "about:blank", 127 "dummy", 128 "chrome,dialog=no,left=800,height=200,width=200,all", 129 null 130 ); 131 dummy.setTimeout(async function () { 132 // Close pre-existing window 133 win.close(); 134 135 const { PerTestCoverageUtils } = ChromeUtils.importESModule( 136 "resource://reftest/PerTestCoverageUtils.sys.mjs" 137 ); 138 if (PerTestCoverageUtils.enabled) { 139 // In PerTestCoverage mode, wait for the process belonging to the window we just closed 140 // to be terminated, to avoid its shutdown interfering when we reset the counters. 141 await processTerminated(); 142 } 143 144 dummy.focus(); 145 Services.ww.openWindow( 146 null, 147 "chrome://reftest/content/reftest.xhtml", 148 "_blank", 149 "chrome,dialog=no,all", 150 {} 151 ); 152 }, 0); 153 } 154 155 onShutdown() { 156 resProto.setSubstitution("reftest", null); 157 158 this.chromeHandle.destruct(); 159 this.chromeHandle = null; 160 161 if (Services.appinfo.OS == "Android") { 162 OnRefTestUnload(); 163 } 164 } 165 };