var video = null; var mediaElement = document; // If not set, an event from any element will trigger a waitForEvent() callback. var consoleElement = null; var printFullTestDetails = true; // This is optionaly switched of by test whose tested values can differ. (see disableFullTestDetailsPrinting()) var Failed = false; var Success = true; var track = null; // Current TextTrack being tested. var cues = null; // Current TextTrackCueList being tested. var numberOfTrackTests = 0; var numberOfTracksLoaded = 0; findMediaElement(); logConsole(); if (window.testRunner) { // Some track element rendering tests require text pixel dump. if (typeof requirePixelDump == "undefined") testRunner.dumpAsText(); testRunner.waitUntilDone(); } function disableFullTestDetailsPrinting() { printFullTestDetails = false; } function enableFullTestDetailsPrinting() { printFullTestDetails = true; } function logConsole() { if (!consoleElement && document.body) { consoleElement = document.createElement('div'); document.body.appendChild(consoleElement); } return consoleElement; } function findMediaElement() { try { video = document.getElementsByTagName('video')[0]; if (video) mediaElement = video; } catch (ex) { } } function testAndEnd(testFuncString) { test(testFuncString, true); } function test(testFuncString, endit) { logResult(eval(testFuncString), "TEST(" + testFuncString + ")"); if (endit) endTest(); } function compare(testFuncString, expected, comparison) { var observed = eval(testFuncString); var success = false; switch (comparison) { case '<': success = observed < expected; break; case '<=': success = observed <= expected; break; case '>': success = observed > expected; break; case '>=': success = observed >= expected; break; case '!=': success = observed != expected; break; case '==': success = observed == expected; break; case '===': success = observed === expected; break; case 'instanceof': success = observed instanceof expected; break; } return {success:success, observed:observed}; } function testExpected(testFuncString, expected, comparison) { if (comparison === undefined) comparison = '=='; try { let {success, observed} = compare(testFuncString, expected, comparison); reportExpected(success, testFuncString, comparison, expected, observed) } catch (ex) { consoleWrite(ex); } } function sleepFor(duration) { return new Promise(resolve => { setTimeout(resolve, duration); }); } function testExpectedEventually(testFuncString, expected, comparison, timeout) { return new Promise(async resolve => { var success; var observed; var timeSlept = 0; if (comparison === undefined) comparison = '=='; while (timeout === undefined || timeSlept < timeout) { try { let {success, observed} = compare(testFuncString, expected, comparison); if (success) { reportExpected(success, testFuncString, comparison, expected, observed); resolve(); return; } await sleepFor(1); timeSlept++; } catch (ex) { consoleWrite(ex); resolve(); return; } } reportExpected(success, testFuncString, comparison, expected, observed, "AFTER TIMEOUT"); resolve(); }); } function testArraysEqual(testFuncString, expected) { var observed; try { observed = eval(testFuncString); } catch (ex) { consoleWrite(ex); return; } testExpected(testFuncString + ".length", expected.length); for (var i = 0; i < observed.length; i++) { testExpected(testFuncString + "[" + i + "]", expected[i]); } } var testNumber = 0; function reportExpected(success, testFuncString, comparison, expected, observed, explanation) { testNumber++; var msg = "Test " + testNumber; if (printFullTestDetails || !success) msg = "EXPECTED (" + testFuncString + " " + comparison + " '" + expected + "')"; if (!success) { msg += ", OBSERVED '" + observed + "'"; if (explanation !== undefined) msg += ", " + explanation; } logResult(success, msg); } function runSilently(testFuncString) { if (printFullTestDetails) consoleWrite("RUN(" + testFuncString + ")"); try { eval(testFuncString); } catch (ex) { if (!printFullTestDetails) { // No details were printed previous, give some now. // This will be helpful in case of error. logResult(Failed, "Error in RUN(" + testFuncString + "):"); } logResult(Failed, ""+ex+""); } } function run(testFuncString) { consoleWrite("RUN(" + testFuncString + ")"); try { eval(testFuncString); } catch (ex) { consoleWrite(ex); } } function waitForEventWithTimeout(element, type, time, message) { let listener = new Promise(resolve => { element.addEventListener(type, event => { resolve(event); }, { once: true }); }); let timeout = new Promise((resolve) => { setTimeout(resolve, time, 'timeout'); }); return Promise.race([ listener, timeout, ]).then(result => { if (result === 'timeout') return Promise.reject(new Error(message)); consoleWrite(`EVENT(${result.type})`); return Promise.resolve(result); }); } function waitFor(element, type, silent, success) { return new Promise(resolve => { element.addEventListener(type, event => { if (silent) { resolve(event); return; } if (success !== undefined) logResult(success, `EVENT(${event.type})`); else consoleWrite(`EVENT(${event.type})`); resolve(event); }, { once: true }); }); } function waitForAndSucceed(element, type) { return waitFor(element, type, false, true); } function waitForAndFail(element, type) { return waitFor(element, type, false, false); } function waitForEventOnce(eventName, func, endit) { waitForEvent(eventName, func, endit, true) } function waitForEventAndEnd(eventName, funcString) { waitForEvent(eventName, funcString, true) } function waitForEvent(eventName, func, endit, oneTimeOnly, element) { if (!element) element = mediaElement; function _eventCallback(event) { if (oneTimeOnly) element.removeEventListener(eventName, _eventCallback, true); consoleWrite("EVENT(" + eventName + ")"); if (func) func(event); if (endit) endTest(); } element.addEventListener(eventName, _eventCallback, true); } function waitForEventTestAndEnd(eventName, testFuncString) { waitForEventAndTest(eventName, testFuncString, true); } function waitForEventAndFail(eventName) { waitForEventAndTest(eventName, "false", true); } function waitForEventAndFailFor(element, eventName) { waitForEventAndTest(element, eventName, "false", true); } function waitForEventAndTest(eventName, testFuncString, endit) { waitForEventAndTestFor(mediaElement, eventName, testFuncString, endit) } function waitForEventAndTestFor(element, eventName, testFuncString, endit) { function _eventCallback(event) { logResult(eval(testFuncString), "EVENT(" + eventName + ") TEST(" + testFuncString + ")"); if (endit) endTest(); } element.addEventListener(eventName, _eventCallback, true); } function waitForEventOnceOn(element, eventName, func, endit) { waitForEventOn(element, eventName, func, endit, true); } function waitForEventOn(element, eventName, func, endit, oneTimeOnly) { waitForEvent(eventName, func, endit, oneTimeOnly, element); } function testDOMException(testString, exceptionString) { try { eval(testString); } catch (ex) { var exception = ex; } logResult(exception instanceof DOMException && exception.code === eval(exceptionString), "TEST(" + testString + ") THROWS(" + exceptionString + ")"); } function testException(testString, exceptionString) { try { eval(testString); } catch (ex) { var exception = ex; } logResult(exception !== undefined && exception == eval(exceptionString), "TEST(" + testString + ") THROWS(" + exceptionString + ")"); } var testEnded = false; function endTest() { consoleWrite("END OF TEST"); testEnded = true; if (window.testRunner) { // FIXME (121170): We shouldn't need the zero-delay timer. But text track layout // happens asynchronously, so we need it to run first to have stable test results. setTimeout("testRunner.notifyDone()", 0); } } function endTestLater() { setTimeout(endTest, 250); } function failTestIn(ms) { setTimeout(function () { consoleWrite("FAIL: did not end fast enough"); endTest(); }, ms); } function failTest(text) { logResult(Failed, text); endTest(); } function passTest(text) { logResult(Success, text); endTest(); } function logResult(success, text) { if (success) consoleWrite(text + " OK"); else consoleWrite(text + " FAIL"); } function consoleWrite(text) { if (testEnded) return; logConsole().innerHTML += text + "
"; } function relativeURL(url) { return url.substr(url.lastIndexOf('/media/')+7); } function isInTimeRanges(ranges, time) { var i = 0; for (i = 0; i < ranges.length; ++i) { if (time >= ranges.start(i) && time <= ranges.end(i)) { return true; } } return false; } function testTracks(expected) { tracks = video.textTracks; testExpected("tracks.length", expected.length); for (var i = 0; i < tracks.length; i++) { consoleWrite("
*** Testing text track " + i); track = tracks[i]; for (j = 0; j < expected.tests.length; j++) { var test = expected.tests[j]; testExpected("track." + test.property, test.values[i]); } } } function testCues(index, expected) { consoleWrite("
*** Testing text track " + index); cues = video.textTracks[index].cues; testExpected("cues.length", expected.length); for (var i = 0; i < cues.length; i++) { for (j = 0; j < expected.tests.length; j++) { var test = expected.tests[j]; var propertyString = "cues[" + i + "]." + test.property; var propertyValue = eval(propertyString); if (test["precision"] && typeof(propertyValue) == 'number') propertyValue = propertyValue.toFixed(test["precision"]); reportExpected(test.values[i] == propertyValue, propertyString, "==", test.values[i], propertyValue) } } } function allTestsEnded() { numberOfTrackTests--; if (numberOfTrackTests == 0) endTest(); } function enableAllTextTracks() { findMediaElement(); for (var i = 0; i < video.textTracks.length; i++) { if (video.textTracks[i].mode == "disabled") video.textTracks[i].mode = "hidden"; } } function waitForEventsAndCall(eventList, func) { var requiredEvents = [] function _eventCallback(event) { if (!requiredEvents.length) return; for (var index = 0; index < requiredEvents.length; index++) { if (requiredEvents[index][1] === event.type) { break; } } if (index >= requiredEvents.length) return; requiredEvents[index][0].removeEventListener(event, _eventCallback); requiredEvents.splice(index, 1); if (requiredEvents.length) return; func(); } for (var i = 0; i < eventList.length; i++) { requiredEvents[i] = eventList[i].slice(0); requiredEvents[i][0].addEventListener(requiredEvents[i][1], _eventCallback, true); } } function setCaptionDisplayMode(mode) { if (window.internals) internals.setCaptionDisplayMode(mode); else consoleWrite("
** This test only works in DRT! **<" + "/b>
"); } function runWithKeyDown(fn, preventDefault) { var eventName = 'keypress' function thunk(event) { if (preventDefault && event !== undefined) event.preventDefault(); document.removeEventListener(eventName, thunk, false); if (typeof fn === 'function') fn(); else run(fn); } document.addEventListener(eventName, thunk, false); if (window.internals) internals.withUserGesture(thunk); } function shouldResolve(promise) { return new Promise((resolve, reject) => { promise.then(result => { logResult(Success, 'Promise resolved'); resolve(result); }).catch((error) => { logResult(Failed, 'Promise rejected'); reject(error); }); }); } function shouldReject(promise) { return new Promise((resolve, reject) => { promise.then(result => { logResult(Failed, 'Promise resolved incorrectly'); reject(result); }).catch((error) => { logResult(Success, 'Promise rejected correctly'); resolve(error); }); }); } function handlePromise(promise) { function handle() { } return promise.then(handle, handle); } function checkMediaCapabilitiesInfo(info, expectedSupported, expectedSmooth, expectedPowerEfficient) { logResult(info.supported == expectedSupported, "info.supported == " + expectedSupported); logResult(info.smooth == expectedSmooth, "info.smooth == " + expectedSmooth); logResult(info.powerEfficient == expectedPowerEfficient, "info.powerEfficient == " + expectedPowerEfficient); }