| OLD | NEW |
| 1 <html> | 1 <!DOCTYPE html> |
| 2 <head> | 2 <title>Test the play() behaviour with regards to the returned promise for media
elements.</title> |
| 3 <script src=media-file.js></script> | 3 <script src="../resources/testharness.js"></script> |
| 4 <!-- TODO(mlamouri): use testharness.js, see https://crbug.com/588956 --> | 4 <script src="../resources/testharnessreport.js"></script> |
| 5 <script src=video-test.js></script> | 5 <script src="media-file.js"></script> |
| 6 | |
| 7 <script> | 6 <script> |
| 8 // This is testing the behavior of play() with regards to the returned | 7 // This is testing the behavior of play() with regards to the returned |
| 9 // promise. This test file is creating a small framework in order to be able | 8 // promise. This test file is creating a small framework in order to be able |
| 10 // to test different cases easily and independently of each other. | 9 // to test different cases easily and independently of each other. |
| 11 // | 10 // All tests have to be part of the tests and testsWithUserGesture arrays. |
| 12 // All tests have to be part of the TESTS array. When the page is loaded, | 11 // Each test returns a promise for audio.play() which is either resolved or reje
cted. |
| 13 // first function in the array is run. A test is considered done when the | 12 |
| 14 // promise returned by mediaElement.play() is resolved or rejected. Each | 13 var tests = [ |
| 15 // test then needs to call play() once which wraps this logic. When a test | 14 // Test that play() on an element that doesn't have enough data will |
| 16 // is finished, the next test in the array is run until the entire array | 15 // return a promise that resolves successfully. |
| 17 // was processed. | 16 function playBeforeCanPlay(t, audio) { |
| 18 // | 17 audio.src = findMediaFile("audio", "content/test"); |
| 19 // Each test should start by printing its name in order to facilitate readin
g | 18 assert_equals(audio.readyState, HTMLMediaElement.HAVE_NOTHING); |
| 20 // the output. | 19 playExpectingResolvedPromise(t, audio); |
| 21 | 20 }, |
| 22 function runNextTestOrFinish() | 21 |
| 23 { | 22 // Test that play() on an element that has enough data will return a |
| 24 currentTest++; | 23 // promise that resolves successfully. |
| 25 if (currentTest >= TESTS.length) { | 24 function playWhenCanPlay(t, audio) { |
| 26 endTest(); | 25 audio.src = findMediaFile("audio", "content/test"); |
| 27 return; | 26 |
| 28 } | 27 audio.oncanplay = t.step_func(function() { |
| 29 | 28 assert_greater_than_equal(audio.readyState, HTMLMediaElement.HAVE_FU
TURE_DATA); |
| 30 consoleWrite(""); | 29 assert_true(audio.paused); |
| 31 TESTS[currentTest](); | 30 playExpectingResolvedPromise(t, audio); |
| 31 }); |
| 32 }, |
| 33 |
| 34 // Test that play() on an element that is already playing returns a |
| 35 // promise that resolves successfully. |
| 36 function playAfterPlaybackStarted(t, audio) { |
| 37 audio.preload = "auto"; |
| 38 audio.src = findMediaFile("audio", "content/test"); |
| 39 |
| 40 audio.onplaying = t.step_func(function() { |
| 41 assert_equals(audio.readyState, HTMLMediaElement.HAVE_ENOUGH_DATA); |
| 42 assert_false(audio.paused); |
| 43 playExpectingResolvedPromise(t, audio); |
| 44 }); |
| 45 |
| 46 audio.oncanplaythrough = t.step_func(function() { |
| 47 audio.play(); |
| 48 }); |
| 49 }, |
| 50 |
| 51 // Test that play() on an element with an unsupported content will |
| 52 // return a rejected promise. |
| 53 function playNotSupportedContent(t, audio) { |
| 54 audio.src = findMediaFile("audio", "data:,"); |
| 55 |
| 56 audio.onerror = t.step_func(function() { |
| 57 assert_true(audio.error instanceof MediaError); |
| 58 assert_equals(audio.error.code, MediaError.MEDIA_ERR_SRC_NOT_SUPPORT
ED); |
| 59 }); |
| 60 playExpectingRejectedPromise(t, audio, "NotSupportedError"); |
| 61 }, |
| 62 |
| 63 // Test that play() returns a resolved promise if called after the |
| 64 // element suffered from a decode error. |
| 65 // This test doesn't test a spec behaviour but tests that the Blink |
| 66 // implementation properly changed after the spec changed. |
| 67 function playDecodeError(t, audio) { |
| 68 audio.src = findMediaFile("audio", "content/test"); |
| 69 |
| 70 audio.onerror = t.step_func(function() { |
| 71 assert_true(audio.error instanceof MediaError); |
| 72 assert_equals(audio.error.code, MediaError.MEDIA_ERR_DECODE); |
| 73 }); |
| 74 |
| 75 // The setMediaElementNetworkState() method requires metadata to be avai
lable. |
| 76 audio.onloadedmetadata = t.step_func(function() { |
| 77 internals.setMediaElementNetworkState(audio, 6); // NetworkStateDecode
Error. |
| 78 playExpectingResolvedPromise(t, audio); |
| 79 }); |
| 80 }, |
| 81 |
| 82 // Test that play() returns a resolved promise if called after the |
| 83 // element suffered from a network error. |
| 84 // This test doesn't test a spec behaviour but tests that the Blink |
| 85 // implementation properly changed after the spec changed |
| 86 function playNetworkError(t, audio) { |
| 87 audio.src = findMediaFile("audio", "content/test"); |
| 88 |
| 89 audio.onerror = t.step_func(function() { |
| 90 assert_true(audio.error instanceof MediaError); |
| 91 assert_equals(audio.error.code, MediaError.MEDIA_ERR_NETWORK); |
| 92 }); |
| 93 |
| 94 // The setMediaElementNetworkState() method requires metadata to be avai
lable. |
| 95 audio.onloadedmetadata = t.step_func(function() { |
| 96 internals.setMediaElementNetworkState(audio, 5); // NetworkStateNetwor
kError. |
| 97 playExpectingResolvedPromise(t, audio); |
| 98 }); |
| 99 }, |
| 100 |
| 101 // Test that play() returns a rejected promise if the element is |
| 102 // sufferring from a not supported error. |
| 103 function playWithErrorAlreadySet(t, audio) { |
| 104 audio.src = findMediaFile("audio", "data:,"); |
| 105 |
| 106 audio.onerror = t.step_func(function() { |
| 107 assert_true(audio.error instanceof MediaError); |
| 108 assert_equals(audio.error.code, MediaError.MEDIA_ERR_SRC_NOT_SUPPORT
ED); |
| 109 playExpectingRejectedPromise(t, audio, "NotSupportedError"); |
| 110 }); |
| 111 }, |
| 112 |
| 113 // Test that play() returns a resolved promise if the element had its |
| 114 // source changed after suffering from an error. |
| 115 function playSrcChangedAfterError(t, audio) { |
| 116 audio.src = findMediaFile("audio", "data:,"); |
| 117 |
| 118 audio.onerror = t.step_func(function() { |
| 119 assert_true(audio.error instanceof MediaError); |
| 120 assert_equals(audio.error.code, MediaError.MEDIA_ERR_SRC_NOT_SUPPORT
ED); |
| 121 audio.src = findMediaFile("audio", "content/test"); |
| 122 |
| 123 audio.onloadedmetadata = t.step_func(function() { |
| 124 playExpectingResolvedPromise(t, audio); |
| 125 }); |
| 126 }); |
| 127 }, |
| 128 |
| 129 // Test that play() returns a rejected promise if the element had an |
| 130 // error and just changed its source. |
| 131 function playRaceWithSrcChangeError(t, audio) { |
| 132 audio.src = findMediaFile("audio", "data:,"); |
| 133 |
| 134 audio.onerror = t.step_func(function() { |
| 135 assert_true(audio.error instanceof MediaError); |
| 136 assert_equals(audio.error.code, MediaError.MEDIA_ERR_SRC_NOT_SUPPORT
ED); |
| 137 audio.src = findMediaFile("audio", "content/test"); |
| 138 assert_equals(audio.error, null); |
| 139 assert_equals(audio.readyState, HTMLMediaElement.HAVE_NOTHING); |
| 140 playExpectingResolvedPromise(t, audio); |
| 141 }); |
| 142 }, |
| 143 |
| 144 // Test that play() returns a resolved promise when calling play() then |
| 145 // pause() on an element that already has enough data to play. In other |
| 146 // words, pause() doesn't cancel play() because it was resolved |
| 147 // immediately. |
| 148 function playAndPauseWhenCanplay(t, audio) { |
| 149 audio.src = findMediaFile("audio", "content/test"); |
| 150 |
| 151 audio.oncanplaythrough = t.step_func(function() { |
| 152 assert_equals(audio.readyState, HTMLMediaElement.HAVE_ENOUGH_DATA); |
| 153 playExpectingResolvedPromise(t, audio); |
| 154 assert_false(audio.paused); |
| 155 audio.pause(); |
| 156 assert_true(audio.paused); |
| 157 }); |
| 158 }, |
| 159 |
| 160 // Test that play() returns a rejected promise when calling play() then |
| 161 // pause() on an element that doesn't have enough data to play. In other |
| 162 // words, pause() cancels play() before it can be resolved. |
| 163 function playAndPauseBeforeCanPlay(t, audio) { |
| 164 assert_equals(audio.readyState, HTMLMediaElement.HAVE_NOTHING); |
| 165 playExpectingRejectedPromise(t, audio, "AbortError"); |
| 166 assert_false(audio.paused); |
| 167 audio.pause(); |
| 168 assert_true(audio.paused); |
| 169 }, |
| 170 |
| 171 // Test that load() rejects all the pending play() promises. |
| 172 // This might be tested by other tests in this file but it is present in |
| 173 // order to be explicit. |
| 174 function loadRejectsPendingPromises(t, audio) { |
| 175 playExpectingRejectedPromise(t, audio, "AbortError"); // the promise wil
l be left pending. |
| 176 audio.load(); |
| 177 }, |
| 178 |
| 179 // Test that changing the src rejects the pending play() promises. |
| 180 function newSrcRejectPendingPromises(t, audio) { |
| 181 playExpectingRejectedPromise(t, audio, "AbortError"); // the promise wil
l be left pending. |
| 182 audio.src = findMediaFile("audio", "content/test"); |
| 183 }, |
| 184 |
| 185 // Test ordering of events and promises. |
| 186 // This is testing a bug in Blink, see https://crbug.com/587871 |
| 187 function testEventAndPromiseOrdering(t, audio) { |
| 188 audio.src = findMediaFile("audio", "data:,"); |
| 189 |
| 190 audio.onerror = t.step_func(function() { |
| 191 // Until https://crbug.com/587871 is fixed, the events will be |
| 192 // [ promise, volumechange, volumechange ], it should be |
| 193 // [ volumechange, promise, volumechange ]. Right now test finishes |
| 194 // as soon as promise is rejected, before "volumechange" is fired. |
| 195 var numVolumeChangeEvents = 0; |
| 196 audio.onvolumechange = t.step_func(function() { ++numVolumeChangeEve
nts; }); |
| 197 audio.volume = 0.1; |
| 198 audio.play().then(t.unreached_func(), t.step_func_done(function() { |
| 199 assert_equals(arguments.length, 1); |
| 200 assert_equals(arguments[0].name, "NotSupportedError"); |
| 201 assert_equals(numVolumeChangeEvents, 0); |
| 202 })); |
| 203 audio.volume = 0.2; |
| 204 }); |
| 205 }, |
| 206 |
| 207 // Test that calling pause() then play() on an element that is already |
| 208 // playing returns a promise that resolves successfully. |
| 209 function pausePlayAfterPlaybackStarted(t, audio) { |
| 210 audio.preload = "auto"; |
| 211 audio.src = findMediaFile("audio", "content/test"); |
| 212 |
| 213 audio.onplaying = t.step_func(function() { |
| 214 assert_equals(audio.readyState, HTMLMediaElement.HAVE_ENOUGH_DATA); |
| 215 assert_false(audio.paused); |
| 216 audio.pause(); |
| 217 playExpectingResolvedPromise(t, audio); |
| 218 }); |
| 219 |
| 220 audio.oncanplaythrough = t.step_func(function() { |
| 221 audio.play(); |
| 222 }); |
| 32 } | 223 } |
| 33 | 224 ]; |
| 34 function play() | 225 |
| 35 { | 226 tests.forEach(function(test) { |
| 36 consoleWrite("play()"); | 227 internals.settings.setMediaPlaybackRequiresUserGesture(false); |
| 37 mediaElement.play().then(function() { | 228 async_test(function(t) { |
| 38 consoleWrite("arguments.length: " + arguments.length); | 229 var audio = document.createElement("audio"); |
| 39 consoleWrite("Promise resolved with " + arguments[0]); | 230 test(t, audio); |
| 40 }, function(e) { | 231 }, test.name); |
| 41 consoleWrite("arguments.length: " + arguments.length); | 232 }); |
| 42 consoleWrite("Promise failed with " + e.name + ": " + e.message); | 233 |
| 43 }).then(runNextTestOrFinish); | 234 var testsWithUserGesture = [ |
| 235 // Test that play() on an element when media playback requires a gesture |
| 236 // returns a resolved promise if there is a user gesture. |
| 237 function playRequiresUserGestureAndHasIt(t, audio) { |
| 238 audio.src = findMediaFile("audio", "content/test"); |
| 239 playWithUserGesture(t, audio); |
| 240 }, |
| 241 |
| 242 // Test that play() on an element when media playback requires a gesture |
| 243 // returns a rejected promise if there is no user gesture. |
| 244 function playRequiresUserGestureAndDoesNotHaveIt(t, audio) { |
| 245 audio.src = findMediaFile("audio", "content/test"); |
| 246 playExpectingRejectedPromise(t, audio, "NotAllowedError"); |
| 44 } | 247 } |
| 45 | 248 ]; |
| 46 function playWithUserGesture() | 249 |
| 47 { | 250 testsWithUserGesture.forEach(function(test) { |
| 48 var target = document.querySelector("p"); | 251 internals.settings.setMediaPlaybackRequiresUserGesture(true); |
| 49 target.onclick = function() { | 252 async_test(function(t) { |
| 50 play(); | 253 var audio = document.createElement("audio"); |
| 51 target.onclick = null; | 254 test(t, audio); |
| 52 }; | 255 }, test.name); |
| 53 | 256 }); |
| 54 var boundingRect = target.getBoundingClientRect(); | 257 |
| 55 var x = boundingRect.left + (boundingRect.width / 2); | 258 function playExpectingResolvedPromise(t, audio) { |
| 56 var y = boundingRect.top + (boundingRect.height / 2); | 259 audio.play().then(t.step_func_done(function() { |
| 57 | 260 assert_equals(arguments.length, 1); |
| 58 // Assuming running in Blink LayoutTests. | 261 assert_equals(arguments[0], undefined); |
| 59 eventSender.mouseMoveTo(x, y); | 262 }), t.unreached_func()); |
| 60 eventSender.mouseDown(); | 263 } |
| 61 eventSender.mouseUp(); | 264 |
| 62 } | 265 function playExpectingRejectedPromise(t, audio, error) { |
| 63 | 266 audio.play().then(t.unreached_func(), t.step_func_done(function() { |
| 64 var currentTest = -1; | 267 assert_equals(arguments.length, 1); |
| 65 | 268 assert_equals(arguments[0].name, error); |
| 66 var TESTS = [ | 269 })); |
| 67 // Test that play() on an element that doesn't have enough data will | 270 } |
| 68 // return a promise that resolves successfully. | 271 |
| 69 function playBeforeCanPlay() | 272 function playWithUserGesture(t, audio) { |
| 70 { | 273 document.onclick = function() { |
| 71 consoleWrite("playBeforeCanPlay()"); | 274 playExpectingResolvedPromise(t, audio); |
| 72 internals.settings.setMediaPlaybackRequiresUserGesture(false); | 275 document.onclick = null; |
| 73 | 276 }; |
| 74 run("mediaElement = document.createElement('audio')"); | 277 |
| 75 var mediaFile = findMediaFile("audio", "content/test"); | 278 eventSender.mouseDown(); |
| 76 run("mediaElement.src = '" + mediaFile + "'"); | 279 eventSender.mouseUp(); |
| 77 | 280 } |
| 78 waitForEvent('loadedmetadata'); | 281 </script> |
| 79 waitForEvent('loadeddata'); | |
| 80 waitForEvent('canplay'); | |
| 81 waitForEvent('playing'); | |
| 82 | |
| 83 testExpected("mediaElement.readyState", HTMLMediaElement.HAVE_NOTHIN
G); | |
| 84 play(); | |
| 85 }, | |
| 86 | |
| 87 // Test that play() on an element that has enough data will return a | |
| 88 // promise that resolves successfully. | |
| 89 function playWhenCanPlay() | |
| 90 { | |
| 91 consoleWrite("playWhenCanPlay()"); | |
| 92 internals.settings.setMediaPlaybackRequiresUserGesture(false); | |
| 93 | |
| 94 run("mediaElement = document.createElement('audio')"); | |
| 95 var mediaFile = findMediaFile("audio", "content/test"); | |
| 96 run("mediaElement.src = '" + mediaFile + "'"); | |
| 97 | |
| 98 waitForEvent('playing'); | |
| 99 | |
| 100 waitForEvent('canplay', function() { | |
| 101 testExpected("mediaElement.readyState", HTMLMediaElement.HAVE_FU
TURE_DATA, ">="); | |
| 102 testExpected("mediaElement.paused", true); | |
| 103 | |
| 104 play(); | |
| 105 }); | |
| 106 }, | |
| 107 | |
| 108 // Test that play() on an element that is already playing returns a | |
| 109 // promise that resolves successfully. | |
| 110 function playAfterPlaybackStarted() | |
| 111 { | |
| 112 consoleWrite("playAfterPlaybackStarted()"); | |
| 113 internals.settings.setMediaPlaybackRequiresUserGesture(false); | |
| 114 | |
| 115 run("mediaElement = document.createElement('audio')"); | |
| 116 mediaElement.preload = "auto"; | |
| 117 var mediaFile = findMediaFile("audio", "content/test"); | |
| 118 run("mediaElement.src = '" + mediaFile + "'"); | |
| 119 | |
| 120 waitForEvent('playing', function() { | |
| 121 testExpected("mediaElement.readyState", HTMLMediaElement.HAVE_EN
OUGH_DATA); | |
| 122 testExpected("mediaElement.paused", false); | |
| 123 | |
| 124 play(); | |
| 125 }); | |
| 126 | |
| 127 waitForEvent('canplaythrough', function() { | |
| 128 run("mediaElement.play()"); | |
| 129 }); | |
| 130 }, | |
| 131 | |
| 132 // Test that play() on an element when media playback requires a gesture | |
| 133 // returns a resolved promise if there is a user gesture. | |
| 134 function playRequiresUserGestureAndHasIt() | |
| 135 { | |
| 136 consoleWrite("playRequiresUserGestureAndHasIt()"); | |
| 137 internals.settings.setMediaPlaybackRequiresUserGesture(true); | |
| 138 | |
| 139 run("mediaElement = document.createElement('audio')"); | |
| 140 var mediaFile = findMediaFile("audio", "content/test"); | |
| 141 run("mediaElement.src = '" + mediaFile + "'"); | |
| 142 | |
| 143 waitForEvent('playing'); | |
| 144 playWithUserGesture(); | |
| 145 }, | |
| 146 | |
| 147 // Test that play() on an element when media playback requires a gesture | |
| 148 // returns a rejected promise if there is no user gesture. | |
| 149 function playRequiresUserGestureAndDoesNotHaveIt() | |
| 150 { | |
| 151 consoleWrite("playRequiresUserGestureAndDoesNotHaveIt()"); | |
| 152 internals.settings.setMediaPlaybackRequiresUserGesture(true); | |
| 153 | |
| 154 run("mediaElement = document.createElement('audio')"); | |
| 155 var mediaFile = findMediaFile("audio", "content/test"); | |
| 156 run("mediaElement.src = '" + mediaFile + "'"); | |
| 157 | |
| 158 waitForEvent('playing'); | |
| 159 play(); | |
| 160 }, | |
| 161 | |
| 162 // Test that play() on an element with an unsupported content will | |
| 163 // return a rejected promise. | |
| 164 function playNotSupportedContent() | |
| 165 { | |
| 166 consoleWrite("playNotSupportedContent()"); | |
| 167 internals.settings.setMediaPlaybackRequiresUserGesture(false); | |
| 168 | |
| 169 run("mediaElement = document.createElement('audio')"); | |
| 170 var mediaFile = findMediaFile("audio", "data:,"); | |
| 171 run("mediaElement.src = '" + mediaFile + "'"); | |
| 172 | |
| 173 waitForEvent('playing'); | |
| 174 waitForEvent('error', function() { | |
| 175 testExpected("mediaElement.error", "[object MediaError]"); | |
| 176 testExpected("mediaElement.error.code", MediaError.MEDIA_ERR_SRC
_NOT_SUPPORTED); | |
| 177 }); | |
| 178 play(); | |
| 179 }, | |
| 180 | |
| 181 // Test that play() returns a resolved promise if called after the | |
| 182 // element suffered from a decode error. | |
| 183 // This test doesn't test a spec behaviour but tests that the Blink | |
| 184 // implementation properly changed after the spec changed. | |
| 185 function playDecodeError() | |
| 186 { | |
| 187 consoleWrite("playDecodeError()"); | |
| 188 internals.settings.setMediaPlaybackRequiresUserGesture(false); | |
| 189 | |
| 190 run("mediaElement = document.createElement('audio')"); | |
| 191 var mediaFile = findMediaFile("audio", "content/test"); | |
| 192 run("mediaElement.src = '" + mediaFile + "'"); | |
| 193 | |
| 194 waitForEvent('playing'); | |
| 195 waitForEvent('error', function() { | |
| 196 testExpected("mediaElement.error", "[object MediaError]"); | |
| 197 testExpected("mediaElement.error.code", MediaError.MEDIA_ERR_DEC
ODE); | |
| 198 }); | |
| 199 | |
| 200 // The setMediaElementNetworkState() method requires metadata to be | |
| 201 // available. | |
| 202 waitForEvent('loadedmetadata', function() { | |
| 203 internals.setMediaElementNetworkState(mediaElement, 6 /* NetworkSt
ateDecodeError */); | |
| 204 play(); | |
| 205 }); | |
| 206 }, | |
| 207 | |
| 208 // Test that play() returns a resolved promise if called after the | |
| 209 // element suffered from a network error. | |
| 210 // This test doesn't test a spec behaviour but tests that the Blink | |
| 211 // implementation properly changed after the spec changed | |
| 212 function playNetworkError() | |
| 213 { | |
| 214 consoleWrite("playNetworkError()"); | |
| 215 internals.settings.setMediaPlaybackRequiresUserGesture(false); | |
| 216 | |
| 217 run("mediaElement = document.createElement('audio')"); | |
| 218 var mediaFile = findMediaFile("audio", "content/test"); | |
| 219 run("mediaElement.src = '" + mediaFile + "'"); | |
| 220 | |
| 221 waitForEvent('playing'); | |
| 222 waitForEvent('error', function() { | |
| 223 testExpected("mediaElement.error", "[object MediaError]"); | |
| 224 testExpected("mediaElement.error.code", MediaError.MEDIA_ERR_NET
WORK); | |
| 225 }); | |
| 226 | |
| 227 // The setMediaElementNetworkState() method requires metadata to be | |
| 228 // available. | |
| 229 waitForEvent('loadedmetadata', function() { | |
| 230 internals.setMediaElementNetworkState(mediaElement, 5 /* NetworkSt
ateNetworkError */); | |
| 231 play(); | |
| 232 }); | |
| 233 }, | |
| 234 | |
| 235 // Test that play() returns a rejected promise if the element is | |
| 236 // suferring from a not supported error. | |
| 237 function playWithErrorAlreadySet() | |
| 238 { | |
| 239 consoleWrite("playWithErrorAlreadySet()"); | |
| 240 internals.settings.setMediaPlaybackRequiresUserGesture(false); | |
| 241 | |
| 242 run("mediaElement = document.createElement('audio')"); | |
| 243 var mediaFile = findMediaFile("audio", "data:,"); | |
| 244 run("mediaElement.src = '" + mediaFile + "'"); | |
| 245 | |
| 246 waitForEvent('playing'); | |
| 247 waitForEvent('error', function() { | |
| 248 testExpected("mediaElement.error", "[object MediaError]"); | |
| 249 testExpected("mediaElement.error.code", MediaError.MEDIA_ERR_SRC
_NOT_SUPPORTED); | |
| 250 play(); | |
| 251 }); | |
| 252 }, | |
| 253 | |
| 254 // Test that play() returns a resolved promise if the element had its | |
| 255 // source changed after suffering from an error. | |
| 256 function playSrcChangedAfterError() | |
| 257 { | |
| 258 consoleWrite("playSrcChangedAfterError()"); | |
| 259 internals.settings.setMediaPlaybackRequiresUserGesture(false); | |
| 260 | |
| 261 run("mediaElement = document.createElement('audio')"); | |
| 262 var mediaFile = findMediaFile("audio", "data:,"); | |
| 263 run("mediaElement.src = '" + mediaFile + "'"); | |
| 264 | |
| 265 waitForEvent('error', function() { | |
| 266 testExpected("mediaElement.error", "[object MediaError]"); | |
| 267 testExpected("mediaElement.error.code", MediaError.MEDIA_ERR_SRC
_NOT_SUPPORTED); | |
| 268 | |
| 269 mediaFile = findMediaFile("audio", "content/test"); | |
| 270 run("mediaElement.src = '" + mediaFile + "'"); | |
| 271 | |
| 272 waitForEvent('playing'); | |
| 273 waitForEvent('loadedmetadata', function() { | |
| 274 play(); | |
| 275 }); | |
| 276 }); | |
| 277 }, | |
| 278 | |
| 279 // Test that play() returns a rejected promise if the element had an | |
| 280 // error and just changed its source. | |
| 281 function playRaceWithSrcChangeError() | |
| 282 { | |
| 283 consoleWrite("playRaceWithSrcChangeError()"); | |
| 284 internals.settings.setMediaPlaybackRequiresUserGesture(false); | |
| 285 | |
| 286 run("mediaElement = document.createElement('audio')"); | |
| 287 var mediaFile = findMediaFile("audio", "data:,"); | |
| 288 run("mediaElement.src = '" + mediaFile + "'"); | |
| 289 | |
| 290 waitForEvent('error', function() { | |
| 291 testExpected("mediaElement.error", "[object MediaError]"); | |
| 292 testExpected("mediaElement.error.code", MediaError.MEDIA_ERR_SRC
_NOT_SUPPORTED); | |
| 293 | |
| 294 mediaFile = findMediaFile("audio", "content/test"); | |
| 295 run("mediaElement.src = '" + mediaFile + "'"); | |
| 296 | |
| 297 testExpected("mediaElement.error", null); | |
| 298 testExpected("mediaElement.readyState", HTMLMediaElement.HAVE_NO
THING); | |
| 299 | |
| 300 waitForEvent('playing'); | |
| 301 play(); | |
| 302 }); | |
| 303 }, | |
| 304 | |
| 305 // Test that play() returns a resolved promise when calling play() then | |
| 306 // pause() on an element that already has enough data to play. In other | |
| 307 // words, pause() doesn't cancel play() because it was resolved | |
| 308 // immediately. | |
| 309 function playAndPauseWhenCanPlay() | |
| 310 { | |
| 311 consoleWrite("playAndPauseWhenCanPlay()"); | |
| 312 internals.settings.setMediaPlaybackRequiresUserGesture(false); | |
| 313 | |
| 314 run("mediaElement = document.createElement('audio')"); | |
| 315 var mediaFile = findMediaFile("audio", "content/test"); | |
| 316 run("mediaElement.src = '" + mediaFile + "'"); | |
| 317 | |
| 318 waitForEvent('canplaythrough', function() { | |
| 319 waitForEvent('playing'); | |
| 320 testExpected("mediaElement.readyState", HTMLMediaElement.HAVE_EN
OUGH_DATA); | |
| 321 play(); | |
| 322 testExpected("mediaElement.paused", false); | |
| 323 mediaElement.pause(); | |
| 324 testExpected("mediaElement.paused", true); | |
| 325 }); | |
| 326 }, | |
| 327 | |
| 328 // Test that play() returns a rejected promise when calling play() then | |
| 329 // pause() on an element that doesn't have enough data to play. In other | |
| 330 // words, pause() cancels play() before it can be resolved. | |
| 331 function playAndPauseBeforeCanPlay() | |
| 332 { | |
| 333 consoleWrite("playAndPauseBeforeCanPlay()"); | |
| 334 internals.settings.setMediaPlaybackRequiresUserGesture(false); | |
| 335 | |
| 336 run("mediaElement = document.createElement('audio')"); | |
| 337 | |
| 338 waitForEvent('playing'); | |
| 339 testExpected("mediaElement.readyState", HTMLMediaElement.HAVE_NOTHIN
G); | |
| 340 play(); | |
| 341 testExpected("mediaElement.paused", false); | |
| 342 mediaElement.pause(); | |
| 343 testExpected("mediaElement.paused", true); | |
| 344 }, | |
| 345 | |
| 346 // Test that load() rejects all the pending play() promises. | |
| 347 // This might be tested by other tests in this file but it is present in | |
| 348 // order to be explicit. | |
| 349 function loadRejectsPendingPromises() | |
| 350 { | |
| 351 consoleWrite("loadRejectsPendingPromises()"); | |
| 352 internals.settings.setMediaPlaybackRequiresUserGesture(false); | |
| 353 | |
| 354 run("mediaElement = document.createElement('audio')"); | |
| 355 | |
| 356 play(); // the promise will be left pending. | |
| 357 | |
| 358 waitForEvent('playing'); | |
| 359 run("mediaElement.load()"); | |
| 360 }, | |
| 361 | |
| 362 // Test that changing the src rejects the pending play() promises. | |
| 363 function newSrcRejectPendingPromises() | |
| 364 { | |
| 365 consoleWrite("newSrcRejectPendingPromises()"); | |
| 366 internals.settings.setMediaPlaybackRequiresUserGesture(false); | |
| 367 | |
| 368 run("mediaElement = document.createElement('audio')"); | |
| 369 | |
| 370 play(); // the promise will be left pending. | |
| 371 | |
| 372 var mediaFile = findMediaFile("audio", "content/test"); | |
| 373 run("mediaElement.src = '" + mediaFile + "'"); | |
| 374 }, | |
| 375 | |
| 376 // Test ordering of events and promises. | |
| 377 // This is testing a bug in Blink, see https://crbug.com/587871 | |
| 378 function testEventAndPromiseOrdering() | |
| 379 { | |
| 380 consoleWrite("testEventAndPromiseOrdering"); | |
| 381 internals.settings.setMediaPlaybackRequiresUserGesture(false); | |
| 382 | |
| 383 run("mediaElement = document.createElement('audio')"); | |
| 384 run("mediaElement.src = 'data:,'"); | |
| 385 | |
| 386 waitForEvent('error', function() { | |
| 387 // Until https://crbug.com/587871 is fixed, the events will be | |
| 388 // [ volumechange, volumechange, promise ], it should be | |
| 389 // [ volumechange, promise, volumechange ]. | |
| 390 waitForEvent('volumechange'); | |
| 391 run("mediaElement.volume = 0.1"); | |
| 392 play(); | |
| 393 run("mediaElement.volume = 0.2"); | |
| 394 }); | |
| 395 | |
| 396 }, | |
| 397 | |
| 398 // Test that calling pause() then play() on an element that is already | |
| 399 // playing returns a promise that resolves successfully. | |
| 400 function pausePlayAfterPlaybackStarted() | |
| 401 { | |
| 402 consoleWrite("pausePlayAfterPlaybackStarted()"); | |
| 403 internals.settings.setMediaPlaybackRequiresUserGesture(false); | |
| 404 | |
| 405 run("mediaElement = document.createElement('audio')"); | |
| 406 mediaElement.preload = "auto"; | |
| 407 var mediaFile = findMediaFile("audio", "content/test"); | |
| 408 run("mediaElement.src = '" + mediaFile + "'"); | |
| 409 | |
| 410 waitForEvent('playing', function() { | |
| 411 testExpected("mediaElement.readyState", HTMLMediaElement.HAVE_EN
OUGH_DATA); | |
| 412 testExpected("mediaElement.paused", false); | |
| 413 | |
| 414 run("mediaElement.pause()"); | |
| 415 play(); | |
| 416 }); | |
| 417 | |
| 418 waitForEvent('canplaythrough', function() { | |
| 419 run("mediaElement.play()"); | |
| 420 }); | |
| 421 }, | |
| 422 ]; | |
| 423 | |
| 424 function start() | |
| 425 { | |
| 426 if (!('eventSender' in window) || !('internals' in window)) { | |
| 427 failTest("Not running in LayoutTests."); | |
| 428 return; | |
| 429 } | |
| 430 runNextTestOrFinish(); | |
| 431 } | |
| 432 | |
| 433 </script> | |
| 434 </head> | |
| 435 | |
| 436 <body onload="start()"> | |
| 437 | |
| 438 <p>Test the play() behaviour with regards to the returned promise for media elem
ents.</p> | |
| 439 | |
| 440 </body> | |
| 441 </html> | |
| OLD | NEW |