file_fullscreen-api.html (12086B)
1 <!DOCTYPE HTML> 2 <html> 3 <!-- 4 https://bugzilla.mozilla.org/show_bug.cgi?id=545812 5 6 Test DOM full-screen API. 7 8 --> 9 <head> 10 <title>Test for Bug 545812</title> 11 <script src="/tests/SimpleTest/EventUtils.js"></script> 12 <script src="/tests/SimpleTest/SimpleTest.js"></script> 13 <script type="application/javascript" src="file_fullscreen-utils.js"></script> 14 <style> 15 body { 16 background-color: black; 17 } 18 </style> 19 </head> 20 <body> 21 <div id="fullscreen-element"></div> 22 <script type="application/javascript"> 23 24 /** Test for Bug 545812 */ 25 26 function ok(condition, msg) { 27 opener.ok(condition, "[fullscreen] " + msg); 28 } 29 30 function is(a, b, msg) { 31 opener.is(a, b, "[fullscreen] " + msg); 32 } 33 34 /* 35 <html> 36 <body onload='document.body.requestFullscreen();'> 37 <iframe id='inner-frame'></iframe> 38 </body> 39 </html> 40 */ 41 var iframeContents = "<html><body onload='parent.SimpleTest.waitForFocus(function(){document.body.requestFullscreen();});'><iframe id='inner-frame'></iframe></body></html>"; 42 43 var iframe = null; 44 var outOfDocElement = null; 45 var inDocElement = null; 46 var container = null; 47 var button = null; 48 49 50 function sendMouseClick(element) { 51 synthesizeMouseAtCenter(element, {}); 52 } 53 54 function assertPromiseResolved(promise, msg) { 55 let { state, value } = SpecialPowers.PromiseDebugging.getState(promise); 56 is(state, "fulfilled", "Promise should have been resolved " + msg); 57 is(value, undefined, "Promise should be resolved with undefined " + msg); 58 } 59 60 function assertPromiseRejected(promise, msg) { 61 let { state, reason } = SpecialPowers.PromiseDebugging.getState(promise); 62 is(state, "rejected", "Promise should have been rejected " + msg); 63 // XXX Actually we should be testing "instanceof TypeError", but it 64 // doesn't work as expected currently. See bug 1412856. 65 is(reason.name, "TypeError", 66 "Promise should be rejected with TypeError " + msg); 67 } 68 69 const FULLSCREEN_ELEMENT = document.getElementById("fullscreen-element"); 70 let promise; 71 72 function enter1(event) { 73 is(event.target, FULLSCREEN_ELEMENT, 74 "Event target should be the fullscreen element #1"); 75 ok(document.fullscreen, "Document should be in fullscreen"); 76 is(document.fullscreenElement, FULLSCREEN_ELEMENT, 77 "Full-screen element should be div element."); 78 ok(document.fullscreenElement.matches(":fullscreen"), 79 "FSE should match :fullscreen"); 80 addFullscreenChangeContinuation("exit", exit1); 81 FULLSCREEN_ELEMENT.remove(); 82 is(document.fullscreenElement, null, 83 "Full-screen element should be null after removing."); 84 } 85 86 function exit1(event) { 87 document.body.appendChild(FULLSCREEN_ELEMENT); 88 is(document.fullscreenElement, null, 89 "Full-screen element should still be null after re-adding former FSE."); 90 is(event.target, document, "Event target should be the document #2"); 91 ok(!document.fullscreen, "Document should not be in fullscreen"); 92 is(document.fullscreenElement, null, "Full-screen element should be null."); 93 iframe = document.createElement("iframe"); 94 iframe.allowFullscreen = true; 95 addFullscreenChangeContinuation("enter", enter2); 96 document.body.appendChild(iframe); 97 iframe.srcdoc = iframeContents; 98 } 99 100 function enter2(event) { 101 is(event.target, iframe, 102 "Event target should be the fullscreen iframe #3"); 103 is(document.fullscreenElement, iframe, 104 "Full-screen element should be iframe element."); 105 is(iframe.contentDocument.fullscreenElement, iframe.contentDocument.body, 106 "Full-screen element in subframe should be body"); 107 108 // The iframe's body is full-screen. Cancel full-screen in the subdocument to return 109 // the full-screen element to the previous full-screen element. This causes 110 // a fullscreenchange event. 111 addFullscreenChangeContinuation("exit", exit2); 112 promise = document.exitFullscreen(); 113 } 114 115 function exit2() { 116 is(document.fullscreenElement, null, 117 "Full-screen element should have rolled back."); 118 is(iframe.contentDocument.fullscreenElement, null, 119 "Full-screen element in subframe should be null"); 120 assertPromiseResolved(promise, "in exit2"); 121 122 addFullscreenChangeContinuation("enter", enter3); 123 promise = FULLSCREEN_ELEMENT.requestFullscreen(); 124 } 125 126 function enter3(event) { 127 is(event.target, FULLSCREEN_ELEMENT, 128 "Event target should be the fullscreen element #3"); 129 is(document.fullscreenElement, FULLSCREEN_ELEMENT, 130 "Full-screen element should be div."); 131 assertPromiseResolved(promise, "in enter3"); 132 133 // Transplant the FSE into subdoc. Should exit full-screen. 134 addFullscreenChangeContinuation("exit", exit3); 135 var _innerFrame = iframe.contentDocument.getElementById("inner-frame"); 136 _innerFrame.contentDocument.body.appendChild(FULLSCREEN_ELEMENT); 137 is(document.fullscreenElement, null, 138 "Full-screen element transplanted, should be null."); 139 is(iframe.contentDocument.fullscreenElement, null, 140 "Full-screen element in outer frame should be null."); 141 is(_innerFrame.contentDocument.fullscreenElement, null, 142 "Full-screen element in inner frame should be null."); 143 } 144 145 function exit3(event) { 146 document.body.appendChild(FULLSCREEN_ELEMENT); 147 is(event.target, document, "Event target should be the document #3"); 148 is(document.fullscreenElement, null, "Full-screen element should be null."); 149 document.body.removeChild(iframe); 150 iframe = null; 151 152 // Do a request out of document. It should be denied. 153 // Continue test in the following fullscreenerror handler. 154 outOfDocElement = document.createElement("div"); 155 addFullscreenErrorContinuation(error1); 156 promise = outOfDocElement.requestFullscreen(); 157 } 158 159 function error1() { 160 ok(!document.fullscreenElement, 161 "Requests for full-screen from not-in-doc elements should fail."); 162 assertPromiseRejected(promise, "in error1"); 163 container = document.createElement("div"); 164 inDocElement = document.createElement("div"); 165 container.appendChild(inDocElement); 166 FULLSCREEN_ELEMENT.appendChild(container); 167 168 addFullscreenChangeContinuation("enter", enter4); 169 inDocElement.requestFullscreen(); 170 } 171 172 function enter4(event) { 173 is(event.target, inDocElement, 174 "Event target should be the fullscreen element #4"); 175 is(document.fullscreenElement, inDocElement, "FSE should be inDocElement."); 176 177 // Remove full-screen ancestor element from document, verify it stops being reported as current FSE. 178 addFullscreenChangeContinuation("exit", exit_to_arg_test_1); 179 container.remove(); 180 is(document.fullscreenElement, null, 181 "Should not have a full-screen element again."); 182 } 183 184 async function exit_to_arg_test_1() { 185 ok(!document.fullscreenElement, 186 "Should have left full-screen mode (third time)."); 187 addFullscreenChangeContinuation("enter", enter_from_arg_test_1); 188 var threw = false; 189 try { 190 await FULLSCREEN_ELEMENT.requestFullscreen(123); 191 } catch (e) { 192 threw = true; 193 // trigger normal fullscreen so that we continue 194 FULLSCREEN_ELEMENT.requestFullscreen(); 195 } 196 ok(!threw, "requestFullscreen with bogus arg (123) shouldn't throw exception"); 197 } 198 199 function enter_from_arg_test_1() { 200 ok(document.fullscreenElement, 201 "Should have entered full-screen after calling with bogus (ignored) argument (fourth time)"); 202 addFullscreenChangeContinuation("exit", exit_to_arg_test_2); 203 document.exitFullscreen(); 204 } 205 206 async function exit_to_arg_test_2() { 207 ok(!document.fullscreenElement, 208 "Should have left full-screen mode (fourth time)."); 209 addFullscreenChangeContinuation("enter", enter_from_arg_test_2); 210 var threw = false; 211 try { 212 await FULLSCREEN_ELEMENT.requestFullscreen({ vrDisplay: null }); 213 } catch (e) { 214 threw = true; 215 // trigger normal fullscreen so that we continue 216 FULLSCREEN_ELEMENT.requestFullscreen(); 217 } 218 ok(!threw, "requestFullscreen with { vrDisplay: null } shouldn't throw exception"); 219 } 220 221 function enter_from_arg_test_2() { 222 ok(document.fullscreenElement, 223 "Should have entered full-screen after calling with vrDisplay null argument (fifth time)"); 224 addFullscreenChangeContinuation("exit", exit4); 225 document.exitFullscreen(); 226 } 227 228 function exit4() { 229 ok(!document.fullscreenElement, 230 "Should be back in non-full-screen mode (fifth time)"); 231 SpecialPowers.pushPrefEnv({"set":[["full-screen-api.allow-trusted-requests-only", true]]}, function() { 232 addFullscreenErrorContinuation(error2); 233 FULLSCREEN_ELEMENT.requestFullscreen(); 234 }); 235 } 236 237 function error2() { 238 ok(!document.fullscreenElement, 239 "Should still be in normal mode, because calling context isn't trusted."); 240 button = document.createElement("button"); 241 button.onclick = function() { 242 FULLSCREEN_ELEMENT.requestFullscreen(); 243 }; 244 FULLSCREEN_ELEMENT.appendChild(button); 245 addFullscreenChangeContinuation("enter", enter5); 246 sendMouseClick(button); 247 } 248 249 function enter5() { 250 ok(document.fullscreenElement, "Moved to full-screen after mouse click"); 251 addFullscreenChangeContinuation("exit", exit5); 252 document.exitFullscreen(); 253 } 254 255 function exit5() { 256 ok(!document.fullscreenElement, 257 "Should have left full-screen mode (last time)."); 258 SpecialPowers.pushPrefEnv({ 259 "set":[["full-screen-api.allow-trusted-requests-only", false], 260 ["full-screen-api.enabled", false]]}, function() { 261 is(document.fullscreenEnabled, false, "document.fullscreenEnabled should be false if full-screen-api.enabled is false"); 262 addFullscreenErrorContinuation(error3); 263 FULLSCREEN_ELEMENT.requestFullscreen(); 264 }); 265 } 266 267 function error3() { 268 ok(!document.fullscreenElement, 269 "Should still be in normal mode, because pref is not enabled."); 270 271 SpecialPowers.pushPrefEnv({"set":[["full-screen-api.enabled", true]]}, function() { 272 is(document.fullscreenEnabled, true, "document.fullscreenEnabled should be true if full-screen-api.enabled is true"); 273 opener.nextTest(); 274 }); 275 } 276 277 function begin() { 278 testNamespaces(() => { 279 addFullscreenChangeContinuation("enter", enter1); 280 FULLSCREEN_ELEMENT.requestFullscreen(); 281 }); 282 } 283 284 function testNamespaces(followupTestFn) { 285 let tests = [ 286 {allowed: false, name: "element", ns: "http://www.w3.org/XML/1998/namespace"}, 287 {allowed: false, name: "element", ns: "http://www.w3.org/1999/xlink"}, 288 {allowed: false, name: "element", ns: "http://www.w3.org/2000/svg"}, 289 {allowed: false, name: "element", ns: "http://www.w3.org/1998/Math/MathML"}, 290 {allowed: false, name: "mathml", ns: "unknown"}, 291 {allowed: false, name: "svg", ns: "unknown"}, 292 {allowed: true, name: "element", ns: "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"}, 293 {allowed: true, name: "element", ns: "http://www.w3.org/1999/xhtml"}, 294 {allowed: true, name: "svg", ns: "http://www.w3.org/1999/xhtml"}, 295 {allowed: true, name: "math", ns: "http://www.w3.org/1999/xhtml"}, 296 {allowed: true, name: "svg", ns: "http://www.w3.org/2000/svg"}, 297 {allowed: true, name: "math", ns: "http://www.w3.org/1998/Math/MathML"}, 298 {allowed: true, name: "element"}, 299 ]; 300 301 function runNextNamespaceTest() { 302 let test = tests.shift(); 303 if (!test) { 304 followupTestFn(); 305 return; 306 } 307 308 let elem = test.ns ? document.createElementNS(test.ns, test.name) : 309 document.createElement(test.name); 310 document.body.appendChild(elem); 311 312 if (test.allowed) { 313 addFullscreenChangeContinuation("enter", () => { 314 ok(document.fullscreen, "Document should be in fullscreen"); 315 is(document.fullscreenElement, elem, 316 `Element named '${test.name}' in this namespace should be allowed: ${test.ns}`); 317 addFullscreenChangeContinuation("exit", () => { 318 document.body.removeChild(elem); 319 runNextNamespaceTest(); 320 }); 321 document.exitFullscreen(); 322 }); 323 } else { 324 addFullscreenErrorContinuation(() => { 325 ok(!document.fullscreenElement, 326 `Element named '${test.name}' in this namespace should not be allowed: ${test.ns}`); 327 document.body.removeChild(elem); 328 runNextNamespaceTest(); 329 }); 330 } 331 332 SimpleTest.waitForFocus(() => elem.requestFullscreen()); 333 } 334 335 runNextNamespaceTest(); 336 } 337 </script> 338 </pre> 339 </body> 340 </html>