pointerlock_utils.js (3623B)
1 const { ChromeUtils } = SpecialPowers; 2 const { TestUtils } = ChromeUtils.importESModule( 3 "resource://testing-common/TestUtils.sys.mjs" 4 ); 5 6 // Get test filename for page being run in popup so errors are more useful 7 var testName = location.pathname.split("/").pop(); 8 9 // Wrap test functions and pass to parent window 10 window.ok = function (a, msg) { 11 opener.ok(a, testName + ": " + msg); 12 }; 13 14 window.is = function (a, b, msg) { 15 opener.is(a, b, testName + ": " + msg); 16 }; 17 18 window.isnot = function (a, b, msg) { 19 opener.isnot(a, b, testName + ": " + msg); 20 }; 21 22 window.todo = function (a, msg) { 23 opener.todo(a, testName + ": " + msg); 24 }; 25 26 window.todo_is = function (a, b, msg) { 27 opener.todo_is(a, b, testName + ": " + msg); 28 }; 29 30 window.todo_isnot = function (a, b, msg) { 31 opener.todo_isnot(a, b, testName + ": " + msg); 32 }; 33 34 window.info = function (msg) { 35 opener.info(testName + ": " + msg); 36 }; 37 38 // Override bits of SimpleTest so test files work stand-alone 39 var SimpleTest = SimpleTest || {}; 40 41 SimpleTest.waitForExplicitFinish = function () { 42 dump("[POINTERLOCK] Starting " + testName + "\n"); 43 }; 44 45 SimpleTest.finish = function () { 46 dump("[POINTERLOCK] Finishing " + testName + "\n"); 47 opener.nextTest(); 48 }; 49 50 // Keep track of how many fullscreenChange enters we've received, so that 51 // we can balance them with the number of exits we receive. We reset this 52 // to 0 when we load a test. 53 var fullscreenChangeEnters = 0; 54 55 addLoadEvent(function () { 56 info(`Resetting fullscreen enter count.`); 57 fullscreenChangeEnters = 0; 58 if (typeof start !== "undefined") { 59 // Delay one event loop to stabilize the initial state of the page. 60 SimpleTest.executeSoon(start); 61 } 62 }); 63 64 // Returns true if the window believes it is in fullscreen. This may be true even 65 // before an asynchronous fullscreen transition is complete. 66 function inFullscreenMode(win) { 67 return win.document.fullscreenElement; 68 } 69 70 // Adds a listener that will be called once a fullscreen transition 71 // is complete. When type==='enter', callback is called when we've 72 // received a fullscreenchange event, and the fullscreen transition is 73 // complete. When type==='exit', callback is called when we've 74 // received a fullscreenchange event and the window is out of 75 // fullscreen. inDoc is the document which the listeners are added on, 76 // if absent, the listeners are added to the current document. 77 function addFullscreenChangeContinuation(type, callback, inDoc) { 78 var doc = inDoc || document; 79 var topWin = doc.defaultView.top; 80 function checkCondition() { 81 if (type == "enter") { 82 fullscreenChangeEnters++; 83 return inFullscreenMode(topWin); 84 } else if (type == "exit") { 85 fullscreenChangeEnters--; 86 return fullscreenChangeEnters 87 ? inFullscreenMode(topWin) 88 : !inFullscreenMode(topWin); 89 } else { 90 throw "'type' must be either 'enter', or 'exit'."; 91 } 92 } 93 function onFullscreenChange(event) { 94 doc.removeEventListener("fullscreenchange", onFullscreenChange); 95 ok(checkCondition(), `Should ${type} fullscreen.`); 96 97 // Invoke the callback after the browsingContext has become active 98 // (or we've timed out waiting for it to become active). 99 let bc = SpecialPowers.wrap(topWin).browsingContext; 100 TestUtils.waitForCondition( 101 () => bc.isActive, 102 "browsingContext should become active" 103 ) 104 .catch(e => 105 ok(false, `Wait for browsingContext.isActive failed with ${e}`) 106 ) 107 .finally(() => { 108 requestAnimationFrame(() => setTimeout(() => callback(event), 0), 0); 109 }); 110 } 111 doc.addEventListener("fullscreenchange", onFullscreenChange); 112 }