| Index: third_party/WebKit/LayoutTests/media/media-play-promise.html
|
| diff --git a/third_party/WebKit/LayoutTests/media/media-play-promise.html b/third_party/WebKit/LayoutTests/media/media-play-promise.html
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..2c18fbb70f37deaf5133d8b68c619af8e7f8004d
|
| --- /dev/null
|
| +++ b/third_party/WebKit/LayoutTests/media/media-play-promise.html
|
| @@ -0,0 +1,390 @@
|
| +<html>
|
| +<head>
|
| +<script src=media-file.js></script>
|
| +<script src=video-test.js></script>
|
| +
|
| +<script>
|
| + // This is testing the behavior of play() with regards to the returned
|
| + // promise. This test file is creating a small framework in order to be able
|
| + // to test different cases easily and independently of each other.
|
| + //
|
| + // All tests have to be part of the TESTS array. When the page is loaded,
|
| + // first function in the array is ran. A test is considered done when the
|
| + // promise returned by mediaElement.play() is resolved or rejected. Each
|
| + // test then needs to call play() once which wraps this logic. When a test
|
| + // is finished, the next test in the array is ran until the entire array
|
| + // was processed.
|
| + //
|
| + // Each test should start by prting its name in order to facilitate reading
|
| + // the output.
|
| +
|
| + function runNextTestOrFinish()
|
| + {
|
| + currentTest++;
|
| + if (currentTest >= TESTS.length) {
|
| + endTest();
|
| + return;
|
| + }
|
| +
|
| + consoleWrite("");
|
| + TESTS[currentTest]();
|
| + }
|
| +
|
| + function play()
|
| + {
|
| + return mediaElement.play().then(function() {
|
| + consoleWrite("Promise Resolved");
|
| + }, function(e) {
|
| + consoleWrite("Promise Failed with " + e.name);
|
| + }).then(runNextTestOrFinish);
|
| + }
|
| +
|
| + function playWithUserGesture()
|
| + {
|
| + if (!window.eventSender) {
|
| + failTest("No window.eventSender");
|
| + return;
|
| + }
|
| +
|
| + var target = document.querySelector("p");
|
| + target.onclick = function() {
|
| + play();
|
| + target.onclick = null;
|
| + };
|
| +
|
| + var boundingRect = target.getBoundingClientRect();
|
| + var x = boundingRect.left + (boundingRect.width / 2);
|
| + var y = boundingRect.top + (boundingRect.height / 2);
|
| +
|
| + eventSender.mouseMoveTo(x, y);
|
| + eventSender.mouseDown();
|
| + eventSender.mouseUp();
|
| + }
|
| +
|
| + var currentTest = -1;
|
| +
|
| + var TESTS = [
|
| + // Test that play() on an element that is currently loading returns a
|
| + // promise which resolves successfuly.
|
| + function playLoading()
|
| + {
|
| + consoleWrite("playLoading()");
|
| + internals.settings.setMediaPlaybackRequiresUserGesture(false);
|
| +
|
| + run("mediaElement = document.createElement('audio')");
|
| + var mediaFile = findMediaFile("audio", "content/test");
|
| + run("mediaElement.src = '" + mediaFile + "'");
|
| +
|
| + waitForEvent('playing');
|
| + play();
|
| + },
|
| +
|
| + // Test that play() on an element that is already loaded returns a
|
| + // promise which which resolves successfuly.
|
| + function playLoaded()
|
| + {
|
| + consoleWrite("playLoaded()");
|
| + internals.settings.setMediaPlaybackRequiresUserGesture(false);
|
| +
|
| + run("mediaElement = document.createElement('audio')");
|
| + var mediaFile = findMediaFile("audio", "content/test");
|
| + run("mediaElement.src = '" + mediaFile + "'");
|
| +
|
| + waitForEvent('playing');
|
| +
|
| + waitForEvent('canplaythrough', function() {
|
| + testExpected(HTMLMediaElement.HAVE_ENOUGH_DATA, mediaElement.readyState);
|
| + testExpected(true, mediaElement.paused)
|
| +
|
| + play();
|
| + });
|
| +
|
| + mediaElement.load();
|
| + },
|
| +
|
| + // Test that play() on an element when media playback requires a gesture
|
| + // returns a rejected promise if there is no user gesture.
|
| + function playRequiresUserGestureAndHasIt()
|
| + {
|
| + consoleWrite("playRequiresUserGestureAndHasIt()");
|
| + internals.settings.setMediaPlaybackRequiresUserGesture(true);
|
| +
|
| + run("mediaElement = document.createElement('audio')");
|
| + var mediaFile = findMediaFile("audio", "content/test");
|
| + run("mediaElement.src = '" + mediaFile + "'");
|
| +
|
| + waitForEvent('playing');
|
| + playWithUserGesture();
|
| + },
|
| +
|
| + // Test that play() on an element when media playback requires a gesture
|
| + // returns a resolved promise if there is a user gesture.
|
| + function playRequiresUserGestureAndDoesNotHaveIt()
|
| + {
|
| + consoleWrite("playRequiresUserGestureAndDoesNotHaveIt()");
|
| + internals.settings.setMediaPlaybackRequiresUserGesture(true);
|
| +
|
| + run("mediaElement = document.createElement('audio')");
|
| + var mediaFile = findMediaFile("audio", "content/test");
|
| + run("mediaElement.src = '" + mediaFile + "'");
|
| +
|
| + waitForEvent('playing');
|
| + play();
|
| + },
|
| +
|
| + // Test that play() on an element with an unsupported content will
|
| + // return a rejected promise.
|
| + function playNotSupportedContent()
|
| + {
|
| + consoleWrite("playNotSupportedContent()");
|
| + internals.settings.setMediaPlaybackRequiresUserGesture(false);
|
| +
|
| + run("mediaElement = document.createElement('audio')");
|
| + var mediaFile = findMediaFile("audio", "content/garbage");
|
| + run("mediaElement.src = '" + mediaFile + "'");
|
| +
|
| + waitForEvent('playing');
|
| + waitForEvent('error', function() {
|
| + testExpected("mediaElement.error", "[object MediaError]");
|
| + testExpected("mediaElement.error.code", MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED);
|
| + });
|
| + play();
|
| + },
|
| +
|
| + // Test that play() returns a resolved promise if called after the
|
| + // element suffered from a decode error.
|
| + function playDecodeError()
|
| + {
|
| + consoleWrite("playDecodeError()");
|
| + internals.settings.setMediaPlaybackRequiresUserGesture(false);
|
| +
|
| + run("mediaElement = document.createElement('audio')");
|
| + var mediaFile = findMediaFile("audio", "content/test");
|
| + run("mediaElement.src = '" + mediaFile + "'");
|
| +
|
| + waitForEvent('playing');
|
| + waitForEvent('error', function() {
|
| + testExpected("mediaElement.error", "[object MediaError]");
|
| + testExpected("mediaElement.error.code", MediaError.MEDIA_ERR_DECODE);
|
| + });
|
| +
|
| + // The setMediaElementNetworkState() method requires metadata to be
|
| + // available.
|
| + waitForEvent('loadedmetadata', function() {
|
| + internals.setMediaElementNetworkState(mediaElement, 6 /* NetworkStateDecodeError */);
|
| + play();
|
| + });
|
| + },
|
| +
|
| + // Test that play() returns a resolved promise if called after the
|
| + // element suffered from a network error.
|
| + function playNetworkError()
|
| + {
|
| + consoleWrite("playNetworkError()");
|
| + internals.settings.setMediaPlaybackRequiresUserGesture(false);
|
| +
|
| + run("mediaElement = document.createElement('audio')");
|
| + var mediaFile = findMediaFile("audio", "content/test");
|
| + run("mediaElement.src = '" + mediaFile + "'");
|
| +
|
| + waitForEvent('playing');
|
| + waitForEvent('error', function() {
|
| + testExpected("mediaElement.error", "[object MediaError]");
|
| + testExpected("mediaElement.error.code", MediaError.MEDIA_ERR_NETWORK);
|
| + });
|
| +
|
| + // The setMediaElementNetworkState() method requires metadata to be
|
| + // available.
|
| + waitForEvent('loadedmetadata', function() {
|
| + internals.setMediaElementNetworkState(mediaElement, 5 /* NetworkStateNetworkError */);
|
| + play();
|
| + });
|
| + },
|
| +
|
| + // Test that play() returns a rejected promise if the element is
|
| + // suferring from a not supported error.
|
| + function playWithErrorAlreadySet()
|
| + {
|
| + consoleWrite("playWithErrorAlreadySet()");
|
| + internals.settings.setMediaPlaybackRequiresUserGesture(false);
|
| +
|
| + run("mediaElement = document.createElement('audio')");
|
| + var mediaFile = findMediaFile("audio", "content/garbage");
|
| + run("mediaElement.src = '" + mediaFile + "'");
|
| +
|
| + run("mediaElement.load()");
|
| +
|
| + waitForEvent('playing');
|
| + waitForEvent('error', function() {
|
| + testExpected("mediaElement.error", "[object MediaError]");
|
| + testExpected("mediaElement.error.code", MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED);
|
| + play();
|
| + });
|
| + },
|
| +
|
| + // Test that play() returns a resolved promise if the element had its
|
| + // source changed after suffering from an error.
|
| + function playSrcChangedAfterError()
|
| + {
|
| + consoleWrite("playSrcChangedAfterError()");
|
| + internals.settings.setMediaPlaybackRequiresUserGesture(false);
|
| +
|
| + run("mediaElement = document.createElement('audio')");
|
| + var mediaFile = findMediaFile("audio", "content/garbage");
|
| + run("mediaElement.src = '" + mediaFile + "'");
|
| +
|
| + run("mediaElement.load()");
|
| +
|
| + waitForEvent('error', function() {
|
| + testExpected("mediaElement.error", "[object MediaError]");
|
| + testExpected("mediaElement.error.code", MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED);
|
| +
|
| + mediaFile = findMediaFile("audio", "content/test");
|
| + run("mediaElement.src = '" + mediaFile + "'");
|
| +
|
| + waitForEvent('playing');
|
| + waitForEvent('loadedmetadata', function() {
|
| + play();
|
| + });
|
| + });
|
| + },
|
| +
|
| + // Test that play() returns a rejected promise if the element had an
|
| + // error and just changed its source.
|
| + function playRaceWithSrcChangeError()
|
| + {
|
| + consoleWrite("playRaceWithSrcChangeError()");
|
| + internals.settings.setMediaPlaybackRequiresUserGesture(false);
|
| +
|
| + run("mediaElement = document.createElement('audio')");
|
| + var mediaFile = findMediaFile("audio", "content/garbage");
|
| + run("mediaElement.src = '" + mediaFile + "'");
|
| +
|
| + run("mediaElement.load()");
|
| +
|
| + waitForEvent('error', function() {
|
| + testExpected("mediaElement.error", "[object MediaError]");
|
| + testExpected("mediaElement.error.code", MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED);
|
| +
|
| + mediaFile = findMediaFile("audio", "content/test");
|
| + run("mediaElement.src = '" + mediaFile + "'");
|
| +
|
| + // TODO(mlamouri): if we print the 'playing' event, it seems
|
| + // that it actually happens later. It's unclear why.
|
| + play();
|
| + });
|
| + },
|
| +
|
| + // Test that play() returns a resolved promise when calling play() then
|
| + // pause() on an element that already has enough data to play. In other
|
| + // words, pause() doesn't cancel play() because it was resolved
|
| + // immediately.
|
| + function playFollowedByPauseWhenLoaded()
|
| + {
|
| + consoleWrite("playFollowedByPauseWhenLoaded()");
|
| + internals.settings.setMediaPlaybackRequiresUserGesture(false);
|
| +
|
| + run("mediaElement = document.createElement('audio')");
|
| + var mediaFile = findMediaFile("audio", "content/test");
|
| + run("mediaElement.src = '" + mediaFile + "'");
|
| +
|
| + run("mediaElement.load()");
|
| +
|
| + waitForEvent('canplaythrough', function() {
|
| + waitForEvent('playing');
|
| + testExpected("mediaElement.readyState", HTMLMediaElement.HAVE_ENOUGH_DATA);
|
| + play();
|
| + testExpected("mediaElement.paused", false);
|
| + mediaElement.pause();
|
| + testExpected("mediaElement.paused", true);
|
| + });
|
| + },
|
| +
|
| + // Test that play() returns a rejected promise when calling play() then
|
| + // pause() on an element that doesn't have enough data to play. In other
|
| + // words, pause() cancels play() before it can be resolved.
|
| + function playFollowedByPauseWhenLoading()
|
| + {
|
| + consoleWrite("playFollowedByPauseWhenLoaded()");
|
| + internals.settings.setMediaPlaybackRequiresUserGesture(false);
|
| +
|
| + run("mediaElement = document.createElement('audio')");
|
| + var mediaFile = findMediaFile("audio", "content/test");
|
| + run("mediaElement.src = '" + mediaFile + "'");
|
| +
|
| + waitForEvent('playing');
|
| + testExpected("mediaElement.readyState", HTMLMediaElement.HAVE_NOTHING);
|
| + play();
|
| + testExpected("mediaElement.paused", false);
|
| + mediaElement.pause();
|
| + testExpected("mediaElement.paused", true);
|
| + },
|
| +
|
| + // Test that load() rejects all the pending play() promises.
|
| + function loadRejectPendingPromises()
|
| + {
|
| + consoleWrite("loadRejectPendingPromises()");
|
| + internals.settings.setMediaPlaybackRequiresUserGesture(false);
|
| +
|
| + run("mediaElement = document.createElement('audio')");
|
| +
|
| + play(); // the promise will be left pending.
|
| +
|
| + waitForEvent('playing');
|
| + run("mediaElement.load()");
|
| + },
|
| +
|
| + // Test that changing the src rejects the pending play() promises.
|
| + function newSrcRejectPendingPromises()
|
| + {
|
| + consoleWrite("newSrcRejectPendingPromises()");
|
| + internals.settings.setMediaPlaybackRequiresUserGesture(false);
|
| +
|
| + run("mediaElement = document.createElement('audio')");
|
| +
|
| + play(); // the promise will be left pending.
|
| +
|
| + var mediaFile = findMediaFile("audio", "content/test");
|
| + run("mediaElement.src = '" + mediaFile + "'");
|
| + },
|
| +
|
| + // Test ordering of events and promises.
|
| + // This is testing a bug in Blink, see https://crbug.com/587871
|
| + function testEventAndPromiseOrdering()
|
| + {
|
| + consoleWrite("testEventAndPromiseOrdering");
|
| + internals.settings.setMediaPlaybackRequiresUserGesture(false);
|
| +
|
| + var promiseResolver = null;
|
| + var p = new Promise(function(resolve, reject) {
|
| + promiseResolver = resolve;
|
| + });
|
| + p.then(function() {
|
| + consoleWrite("Should be after the play() promise is resolved");
|
| + });
|
| +
|
| + run("mediaElement = document.createElement('audio')");
|
| + var mediaFile = findMediaFile("audio", "content/test");
|
| + run("mediaElement.src = '" + mediaFile + "'");
|
| +
|
| + play();
|
| + waitForEvent('playing', function() {
|
| + promiseResolver();
|
| + });
|
| + }
|
| + ];
|
| +
|
| + function start()
|
| + {
|
| + runNextTestOrFinish();
|
| + }
|
| +
|
| +</script>
|
| +</head>
|
| +
|
| +<body onload="start()">
|
| +
|
| +<p>Test the play() behaviour with regards to the returned promise for media elements.</p>
|
| +
|
| +</body>
|
| +</html>
|
|
|