Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(68)

Unified Diff: third_party/WebKit/LayoutTests/media/media-play-promise.html

Issue 1576283003: Have HTMLMediaElement::play() return a Promise. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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..f92fd19d80dc69c3398c8216306b484f57141b40
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/media/media-play-promise.html
@@ -0,0 +1,365 @@
+<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
philipj_slow 2016/02/02 09:56:33 This is a very big test with a mini runner harness
mlamouri (slow - plz ping) 2016/02/03 19:28:57 Ack.
+ // 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()
philipj_slow 2016/02/02 09:56:33 This could also be a problem for w-p-t. What I did
mlamouri (slow - plz ping) 2016/02/03 19:28:57 Where do media/ tests ready for w-p-t live? Are th
philipj_slow 2016/02/04 10:54:20 Imported w-p-t tests all live in LayoutTests/impor
mlamouri (slow - plz ping) 2016/02/18 17:06:06 I would be interested to help converting media tes
philipj_slow 2016/02/19 08:21:47 I was hoping to avoid reviewing these tests in the
+ {
+ 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 */);
philipj_slow 2016/02/02 09:56:33 Not a fan of this. It's weird that WebMediaPlayer:
mlamouri (slow - plz ping) 2016/02/03 19:28:57 This is actually testing that the error doesn't re
philipj_slow 2016/02/19 08:21:48 It's the use of setMediaElementNetworkState to sig
+ 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 + "'");
+ },
+ ];
+
+ 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>

Powered by Google App Engine
This is Rietveld 408576698