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 |