Chromium Code Reviews| 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 audio.onloadedmetadata = t.step_func(function() {}); |
|
Srirama
2016/07/18 09:36:10
Should we remove these events? Or should we keep t
fs
2016/07/18 10:51:02
I think the interesting cases will be where events
Srirama
2016/07/18 13:58:10
Even the order mentioned in that function isn't co
fs
2016/07/18 14:14:43
unreached_func probably isn't the right thing to d
Srirama
2016/07/19 07:15:44
You are right, but i couldn't find a way to mix ev
fs
2016/07/19 08:30:11
Maybe something fairly simple like:
var numVolume
Srirama
2016/07/19 09:21:57
Done.
| |
| 20 // the output. | 19 audio.onloadeddata = t.step_func(function() {}); |
| 21 | 20 audio.oncanplay = t.step_func(function() {}); |
| 22 function runNextTestOrFinish() | 21 audio.onplaying = t.step_func(function() {}); |
| 23 { | 22 assert_equals(audio.readyState, HTMLMediaElement.HAVE_NOTHING); |
| 24 currentTest++; | 23 play(t, audio, false); |
| 25 if (currentTest >= TESTS.length) { | 24 }, |
| 26 endTest(); | 25 |
| 27 return; | 26 // Test that play() on an element that has enough data will return a |
| 28 } | 27 // promise that resolves successfully. |
| 29 | 28 function playWhenCanPlay(t, audio) { |
| 30 consoleWrite(""); | 29 audio.src = findMediaFile("audio", "content/test"); |
| 31 TESTS[currentTest](); | 30 audio.onplaying = t.step_func(function() {}); |
| 31 | |
| 32 audio.oncanplay = t.step_func(function() { | |
| 33 assert_greater_than_equal(audio.readyState, HTMLMediaElement.HAVE_FU TURE_DATA); | |
| 34 assert_true(audio.paused); | |
| 35 play(t, audio, false); | |
| 36 }); | |
| 37 }, | |
| 38 | |
| 39 // Test that play() on an element that is already playing returns a | |
| 40 // promise that resolves successfully. | |
| 41 function playAfterPlaybackStarted(t, audio) { | |
| 42 audio.preload = "auto"; | |
| 43 audio.src = findMediaFile("audio", "content/test"); | |
| 44 | |
| 45 audio.onplaying = t.step_func(function() { | |
| 46 assert_equals(audio.readyState, HTMLMediaElement.HAVE_ENOUGH_DATA); | |
| 47 assert_false(audio.paused); | |
| 48 play(t, audio, false); | |
| 49 }); | |
| 50 | |
| 51 audio.oncanplaythrough = t.step_func(function() { | |
| 52 audio.play(); | |
| 53 }); | |
| 54 }, | |
| 55 | |
| 56 // Test that play() on an element with an unsupported content will | |
| 57 // return a rejected promise. | |
| 58 function playNotSupportedContent(t, audio) { | |
| 59 audio.src = findMediaFile("audio", "data:,"); | |
| 60 audio.onplaying = t.step_func(function() {}); | |
| 61 | |
| 62 audio.onerror = t.step_func(function() { | |
| 63 assert_true(audio.error instanceof MediaError); | |
| 64 assert_equals(audio.error.code, MediaError.MEDIA_ERR_SRC_NOT_SUPPORT ED); | |
| 65 }); | |
| 66 play(t, audio, true, "NotSupportedError"); | |
| 67 }, | |
| 68 | |
| 69 // Test that play() returns a resolved promise if called after the | |
| 70 // element suffered from a decode error. | |
| 71 // This test doesn't test a spec behaviour but tests that the Blink | |
| 72 // implementation properly changed after the spec changed. | |
| 73 function playDecodeError(t, audio) { | |
| 74 audio.src = findMediaFile("audio", "content/test"); | |
| 75 audio.onplaying = t.step_func(function() {}); | |
| 76 | |
| 77 audio.onerror = t.step_func(function() { | |
| 78 assert_true(audio.error instanceof MediaError); | |
| 79 assert_equals(audio.error.code, MediaError.MEDIA_ERR_DECODE); | |
| 80 }); | |
| 81 | |
| 82 // The setMediaElementNetworkState() method requires metadata to be avai lable. | |
| 83 audio.onloadedmetadata = t.step_func(function() { | |
| 84 internals.setMediaElementNetworkState(audio, 6); // NetworkStateDecode Error. | |
| 85 play(t, audio, false); | |
| 86 }); | |
| 87 }, | |
| 88 | |
| 89 // Test that play() returns a resolved promise if called after the | |
| 90 // element suffered from a network error. | |
| 91 // This test doesn't test a spec behaviour but tests that the Blink | |
| 92 // implementation properly changed after the spec changed | |
| 93 function playNetworkError(t, audio) { | |
| 94 audio.src = findMediaFile("audio", "content/test"); | |
| 95 audio.onplaying = t.step_func(function() {}); | |
| 96 | |
| 97 audio.onerror = t.step_func(function() { | |
| 98 assert_true(audio.error instanceof MediaError); | |
| 99 assert_equals(audio.error.code, MediaError.MEDIA_ERR_NETWORK); | |
| 100 }); | |
| 101 | |
| 102 // The setMediaElementNetworkState() method requires metadata to be avai lable. | |
| 103 audio.onloadedmetadata = t.step_func(function() { | |
| 104 internals.setMediaElementNetworkState(audio, 5); // NetworkStateNetwor kError. | |
| 105 play(t, audio, false); | |
| 106 }); | |
| 107 }, | |
| 108 | |
| 109 // Test that play() returns a rejected promise if the element is | |
| 110 // suferring from a not supported error. | |
|
fs
2016/07/18 10:51:02
Nit: suffering
Srirama
2016/07/18 13:58:10
Done.
| |
| 111 function playWithErrorAlreadySet(t, audio) { | |
| 112 audio.src = findMediaFile("audio", "data:,"); | |
| 113 audio.onplaying = t.step_func(function() {}); | |
| 114 | |
| 115 audio.onerror = t.step_func(function() { | |
| 116 assert_true(audio.error instanceof MediaError); | |
| 117 assert_equals(audio.error.code, MediaError.MEDIA_ERR_SRC_NOT_SUPPORT ED); | |
| 118 play(t, audio, true, "NotSupportedError"); | |
| 119 }); | |
| 120 }, | |
| 121 | |
| 122 // Test that play() returns a resolved promise if the element had its | |
| 123 // source changed after suffering from an error. | |
| 124 function playSrcChangedAfterError(t, audio) { | |
| 125 audio.src = findMediaFile("audio", "data:,"); | |
| 126 | |
| 127 audio.onerror = t.step_func(function() { | |
| 128 assert_true(audio.error instanceof MediaError); | |
| 129 assert_equals(audio.error.code, MediaError.MEDIA_ERR_SRC_NOT_SUPPORT ED); | |
| 130 audio.src = findMediaFile("audio", "content/test"); | |
| 131 audio.onplaying = t.step_func(function() {}); | |
| 132 | |
| 133 audio.onloadedmetadata = t.step_func(function() { | |
| 134 play(t, audio, false); | |
| 135 }); | |
| 136 }); | |
| 137 }, | |
| 138 | |
| 139 // Test that play() returns a rejected promise if the element had an | |
| 140 // error and just changed its source. | |
| 141 function playRaceWithSrcChangeError(t, audio) { | |
| 142 audio.src = findMediaFile("audio", "data:,"); | |
| 143 | |
| 144 audio.onerror = t.step_func(function() { | |
| 145 assert_true(audio.error instanceof MediaError); | |
| 146 assert_equals(audio.error.code, MediaError.MEDIA_ERR_SRC_NOT_SUPPORT ED); | |
| 147 audio.src = findMediaFile("audio", "content/test"); | |
| 148 assert_equals(audio.error, null); | |
| 149 assert_equals(audio.readyState, HTMLMediaElement.HAVE_NOTHING); | |
| 150 audio.onplaying = t.step_func(function() {}); | |
| 151 play(t, audio, false); | |
| 152 }); | |
| 153 }, | |
| 154 | |
| 155 // Test that play() returns a resolved promise when calling play() then | |
| 156 // pause() on an element that already has enough data to play. In other | |
| 157 // words, pause() doesn't cancel play() because it was resolved | |
| 158 // immediately. | |
| 159 function playAndPauseWhenCanPlay(t, audio) { | |
| 160 audio.src = findMediaFile("audio", "content/test"); | |
| 161 | |
| 162 audio.oncanplaythrough = t.step_func(function() { | |
| 163 audio.onplaying = t.step_func(function() {}); | |
| 164 assert_equals(audio.readyState, HTMLMediaElement.HAVE_ENOUGH_DATA); | |
| 165 play(t, audio, false); | |
| 166 assert_false(audio.paused); | |
| 167 audio.pause(); | |
| 168 assert_true(audio.paused); | |
| 169 }); | |
| 170 }, | |
| 171 | |
| 172 // Test that play() returns a rejected promise when calling play() then | |
| 173 // pause() on an element that doesn't have enough data to play. In other | |
| 174 // words, pause() cancels play() before it can be resolved. | |
| 175 function playAndPauseBeforeCanPlay(t, audio) { | |
| 176 audio.onplaying = t.step_func(function() {}); | |
| 177 assert_equals(audio.readyState, HTMLMediaElement.HAVE_NOTHING); | |
| 178 play(t, audio, true, "AbortError"); | |
| 179 assert_false(audio.paused); | |
| 180 audio.pause(); | |
| 181 assert_true(audio.paused); | |
| 182 }, | |
| 183 | |
| 184 // Test that load() rejects all the pending play() promises. | |
| 185 // This might be tested by other tests in this file but it is present in | |
| 186 // order to be explicit. | |
| 187 function loadRejectsPendingPromises(t, audio) { | |
| 188 play(t, audio, true, "AbortError"); // the promise will be left pending. | |
| 189 audio.onplaying = t.step_func(function() {}); | |
| 190 audio.load(); | |
| 191 }, | |
| 192 | |
| 193 // Test that changing the src rejects the pending play() promises. | |
| 194 function newSrcRejectPendingPromises(t, audio) { | |
| 195 play(t, audio, true, "AbortError"); // the promise will be left pending. | |
| 196 audio.src = findMediaFile("audio", "content/test"); | |
| 197 }, | |
| 198 | |
| 199 // Test ordering of events and promises. | |
| 200 // This is testing a bug in Blink, see https://crbug.com/587871 | |
| 201 function testEventAndPromiseOrdering(t, audio) { | |
| 202 audio.src = findMediaFile("audio", "data:,"); | |
| 203 | |
| 204 audio.onerror = t.step_func(function() { | |
| 205 // Until https://crbug.com/587871 is fixed, the events will be | |
| 206 // [ volumechange, volumechange, promise ], it should be | |
| 207 // [ volumechange, promise, volumechange ]. | |
| 208 audio.onvolumechange = t.step_func(function() {}); | |
| 209 audio.volume = 0.1; | |
| 210 play(t, audio, true, "NotSupportedError"); | |
| 211 audio.volume = 0.2; | |
| 212 }); | |
| 213 }, | |
| 214 | |
| 215 // Test that calling pause() then play() on an element that is already | |
| 216 // playing returns a promise that resolves successfully. | |
| 217 function pausePlayAfterPlaybackStarted(t, audio) { | |
| 218 audio.preload = "auto"; | |
| 219 audio.src = findMediaFile("audio", "content/test"); | |
| 220 | |
| 221 audio.onplaying = t.step_func(function() { | |
| 222 assert_equals(audio.readyState, HTMLMediaElement.HAVE_ENOUGH_DATA); | |
| 223 assert_false(audio.paused); | |
| 224 audio.pause(); | |
| 225 play(t, audio, false); | |
| 226 }); | |
| 227 | |
| 228 audio.oncanplaythrough = t.step_func(function() { | |
| 229 audio.play(); | |
| 230 }); | |
| 32 } | 231 } |
| 33 | 232 ]; |
| 34 function play() | 233 |
| 35 { | 234 tests.forEach(function(test) { |
| 36 consoleWrite("play()"); | 235 internals.settings.setMediaPlaybackRequiresUserGesture(false); |
| 37 mediaElement.play().then(function() { | 236 async_test(function(t) { |
| 38 consoleWrite("arguments.length: " + arguments.length); | 237 var audio = document.createElement("audio"); |
| 39 consoleWrite("Promise resolved with " + arguments[0]); | 238 test(t, audio); |
| 40 }, function(e) { | 239 }, test.name); |
| 41 consoleWrite("arguments.length: " + arguments.length); | 240 }); |
| 42 consoleWrite("Promise failed with " + e.name + ": " + e.message); | 241 |
| 43 }).then(runNextTestOrFinish); | 242 var testsWithUserGesture = [ |
| 243 // Test that play() on an element when media playback requires a gesture | |
| 244 // returns a resolved promise if there is a user gesture. | |
| 245 function playRequiresUserGestureAndHasIt(t, audio) { | |
| 246 audio.src = findMediaFile("audio", "content/test"); | |
| 247 audio.onplaying = t.step_func(function() {}); | |
| 248 playWithUserGesture(t, audio); | |
| 249 }, | |
| 250 | |
| 251 // Test that play() on an element when media playback requires a gesture | |
| 252 // returns a rejected promise if there is no user gesture. | |
| 253 function playRequiresUserGestureAndDoesNotHaveIt(t, audio) { | |
| 254 audio.src = findMediaFile("audio", "content/test"); | |
| 255 audio.onplaying = t.step_func(function() {}); | |
| 256 play(t, audio, true, "NotAllowedError"); | |
| 44 } | 257 } |
| 45 | 258 ]; |
| 46 function playWithUserGesture() | 259 |
| 47 { | 260 testsWithUserGesture.forEach(function(test) { |
| 48 var target = document.querySelector("p"); | 261 internals.settings.setMediaPlaybackRequiresUserGesture(true); |
| 49 target.onclick = function() { | 262 async_test(function(t) { |
| 50 play(); | 263 var audio = document.createElement("audio"); |
| 51 target.onclick = null; | 264 test(t, audio); |
| 52 }; | 265 }, test.name); |
| 53 | 266 }); |
| 54 var boundingRect = target.getBoundingClientRect(); | 267 |
| 55 var x = boundingRect.left + (boundingRect.width / 2); | 268 function play(t, audio, failPromise, error) { |
|
fs
2016/07/18 10:51:02
Doesn't |failPromise|===true imply |error| is set
Srirama
2016/07/18 13:58:10
Done.
| |
| 56 var y = boundingRect.top + (boundingRect.height / 2); | 269 if (failPromise) { |
| 57 | 270 audio.play().then(t.unreached_func(), t.step_func_done(function(e) { |
| 58 // Assuming running in Blink LayoutTests. | 271 assert_equals(arguments.length, 1); |
| 59 eventSender.mouseMoveTo(x, y); | 272 assert_equals(arguments[0].name, error); |
| 60 eventSender.mouseDown(); | 273 })); |
| 61 eventSender.mouseUp(); | 274 } else { |
| 275 audio.play().then(t.step_func_done(function(e) { | |
| 276 assert_equals(arguments.length, 1); | |
| 277 assert_equals(arguments[0], undefined); | |
| 278 }), t.unreached_func()); | |
| 62 } | 279 } |
| 63 | 280 } |
| 64 var currentTest = -1; | 281 |
| 65 | 282 function playWithUserGesture(t, audio) { |
| 66 var TESTS = [ | 283 document.onclick = function() { |
| 67 // Test that play() on an element that doesn't have enough data will | 284 play(t, audio, false); |
| 68 // return a promise that resolves successfully. | 285 document.onclick = null; |
| 69 function playBeforeCanPlay() | 286 }; |
| 70 { | 287 |
| 71 consoleWrite("playBeforeCanPlay()"); | 288 eventSender.mouseDown(); |
| 72 internals.settings.setMediaPlaybackRequiresUserGesture(false); | 289 eventSender.mouseUp(); |
| 73 | 290 } |
| 74 run("mediaElement = document.createElement('audio')"); | 291 </script> |
| 75 var mediaFile = findMediaFile("audio", "content/test"); | |
| 76 run("mediaElement.src = '" + mediaFile + "'"); | |
| 77 | |
| 78 waitForEvent('loadedmetadata'); | |
| 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 |