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 |