View Javadoc
1   /*
2    * Copyright (c) 2002-2025 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.javascript.host.html;
16  
17  import org.htmlunit.WebDriverTestCase;
18  import org.htmlunit.junit.annotation.Alerts;
19  import org.htmlunit.junit.annotation.HtmlUnitNYI;
20  import org.htmlunit.util.MimeType;
21  import org.junit.jupiter.api.Test;
22  
23  /**
24   * Tests for {@link HTMLAudioElement}.
25   *
26   * @author Ahmed Ashour
27   * @author Ronald Brill
28   */
29  public class HTMLAudioElementTest extends WebDriverTestCase {
30  
31      /**
32       * @throws Exception if the test fails
33       */
34      @Test
35      @Alerts("false")
36      public void prototype() throws Exception {
37          final String html = DOCTYPE_HTML
38              + "<html><body>\n"
39              + "<script>\n"
40              + LOG_TITLE_FUNCTION
41              + "try {\n"
42              + "log(HTMLAudioElement.prototype == null);\n"
43              + "} catch(e) { logEx(e); }\n"
44              + "</script>\n"
45              + "</body></html>";
46  
47          loadPageVerifyTitle2(html);
48      }
49  
50  
51      /**
52       * @throws Exception if the test fails
53       */
54      @Test
55      @Alerts({"[object HTMLAudioElement]", "function HTMLAudioElement() { [native code] }"})
56      public void type() throws Exception {
57          final String html = DOCTYPE_HTML
58              + "<html><head>\n"
59              + "<script>\n"
60              + LOG_TITLE_FUNCTION
61              + "  function test() {\n"
62              + "    var elem = document.getElementById('a1');\n"
63              + "    try {\n"
64              + "      log(elem);\n"
65              + "      log(HTMLAudioElement);\n"
66              + "    } catch(e) { logEx(e); }\n"
67              + "  }\n"
68              + "</script>\n"
69              + "</head>\n"
70              + "<body onload='test()'>\n"
71              + "  <audio id='a1'/>\n"
72              + "</body></html>";
73  
74          loadPageVerifyTitle2(html);
75      }
76  
77      /**
78       * @throws Exception if the test fails
79       */
80      @Test
81      @Alerts({"1", "AUDIO"})
82      public void nodeTypeName() throws Exception {
83          final String html = DOCTYPE_HTML
84              + "<html><body>\n"
85              + "<audio id='a' src='horse.mp3'></audio>"
86              + "<script>\n"
87              + LOG_TITLE_FUNCTION
88              + "try {\n"
89              + "  var audio = document.getElementById('a');\n"
90              + "  log(audio.nodeType);"
91              + "  log(audio.nodeName);"
92              + "} catch(e) { logEx(e); }\n"
93              + "</script>\n"
94              + "</body></html>";
95  
96          loadPageVerifyTitle2(html);
97      }
98  
99      /**
100      * @throws Exception if the test fails
101      */
102     @Test
103     @Alerts({"[object HTMLAudioElement]", "[object Promise]", "done"})
104     public void audio() throws Exception {
105         final String html = DOCTYPE_HTML
106             + "<html><head>\n"
107             + "<script>\n"
108             + LOG_TITLE_FUNCTION
109             + "  function test() {\n"
110             + "    var a = new Audio('1.mp3');\n"
111             + "    log(a);\n"
112             + "    log(a.play());\n"
113             + "    log('done');\n"
114             + "  }\n"
115             + "</script>\n"
116             + "</head>\n"
117             + "<body onload='test()'>\n"
118             + "</body></html>";
119 
120         getMockWebConnection().setDefaultResponse("Error: not found", 404, "Not Found", MimeType.TEXT_HTML);
121 
122         loadPageVerifyTitle2(html);
123     }
124 
125     /**
126      * Checks whether the specific {@code parent} is an actual parent of the given {@code child}.
127      *
128      * @param parent the parent host name
129      * @param child the child host name
130      * @throws Exception if an error occurs
131      */
132     protected void parentOf(final String parent, final String child) throws Exception {
133         final String html = DOCTYPE_HTML
134             + "<html><head>\n"
135             + "<title>New Tab</title>\n"
136             + "<script>\n"
137             + LOG_TEXTAREA_FUNCTION
138             + "  function test() {\n"
139             + "    try {\n"
140             + "      log(isParentOf(" + parent + ", " + child + "));\n"
141             + "    } catch(e) { log('false'); }\n"
142             + "  }\n"
143 
144             + "  /*\n"
145             + "   * Returns true if o1 prototype is parent/grandparent of o2 prototype\n"
146             + "   */\n"
147             + "  function isParentOf(o1, o2) {\n"
148             + "    o1.prototype.myCustomFunction = function() {};\n"
149             + "    return o2.prototype.myCustomFunction != undefined;\n"
150             + "  }\n"
151             + "</script></head>\n"
152             + "<body onload='test()'>\n"
153             + LOG_TEXTAREA
154             + "</body></html>";
155 
156         loadPageVerifyTextArea2(html);
157     }
158 
159     /**
160      * @throws Exception if the test fails
161      */
162     @Test
163     @Alerts("true")
164     @HtmlUnitNYI(CHROME = "false",
165             EDGE = "false",
166             FF = "false",
167             FF_ESR = "false")
168     public void Audio_HTMLAudioElement() throws Exception {
169         parentOf("Audio", "HTMLAudioElement");
170     }
171 
172     /**
173      * @throws Exception if the test fails
174      */
175     @Test
176     @Alerts("true")
177     public void HTMLAudioElement_Audio() throws Exception {
178         parentOf("HTMLAudioElement", "Audio");
179     }
180 
181     /**
182      * @throws Exception if the test fails
183      */
184     @Test
185     public void doNotRetrieveStream() throws Exception {
186         final String html = DOCTYPE_HTML
187             + "<html><head>\n"
188             + "</head>\n"
189             + "<body>\n"
190             + "  <audio controls>\n"
191             + "    <source src='horse.ogg' type='audio/ogg'>\n"
192             + "    <source src='horse.mp3' type='audio/mpeg'>\n"
193             + "    Your browser does not support the audio element.\n"
194             + "  </audio>\n"
195             + "</body></html>";
196 
197         loadPage2(html);
198         assertEquals(1, getMockWebConnection().getRequestCount());
199     }
200 
201     /**
202      * @throws Exception if the test fails
203      */
204     @Test
205     @Alerts({"[object HTMLAudioElement]", "maybe", "done"})
206     public void nullConstructor() throws Exception {
207         final String html = DOCTYPE_HTML
208             + "<html><head>\n"
209             + "<script>\n"
210             + LOG_TITLE_FUNCTION
211             + "  function test() {\n"
212             + "    var a = new Audio(null);\n"
213             + "    log(a);\n"
214             + "    log(a.canPlayType('audio/ogg'));\n"
215             + "    log('done');\n"
216             + "  }\n"
217             + "</script>\n"
218             + "</head>\n"
219             + "<body onload='test()'>\n"
220             + "</body></html>";
221 
222         getMockWebConnection().setDefaultResponse("Error: not found", 404, "Not Found", MimeType.TEXT_HTML);
223 
224         loadPageVerifyTitle2(html);
225     }
226 
227     /**
228      * @throws Exception if the test fails
229      */
230     @Test
231     @Alerts("true")
232     public void canPlayType() throws Exception {
233         final String html = DOCTYPE_HTML
234             + "<html><head>\n"
235             + "<script>\n"
236             + LOG_TITLE_FUNCTION
237             + "  function test() {\n"
238             + "    var elem = document.getElementById('a1');\n"
239             + "    log(typeof elem.canPlayType === 'function');\n"
240             + "  }\n"
241             + "</script>\n"
242             + "</head>\n"
243             + "<body onload='test()'>\n"
244             + "  <audio id='a1'/>\n"
245             + "</body></html>";
246 
247         loadPageVerifyTitle2(html);
248     }
249 
250     /**
251      * @throws Exception if the test fails
252      */
253     @Test
254     @Alerts("maybe")
255     public void canPlayType_AudioOgg() throws Exception {
256         canPlayType("audio/ogg");
257     }
258 
259     /**
260      * @throws Exception if the test fails
261      */
262     @Test
263     @Alerts("maybe")
264     public void canPlayType_VideoOgg() throws Exception {
265         canPlayType("video/ogg");
266     }
267 
268     /**
269      * @throws Exception if the test fails
270      */
271     @Test
272     @Alerts("maybe")
273     public void canPlayType_ApplicationOgg() throws Exception {
274         canPlayType("application/ogg");
275     }
276 
277     /**
278      * @throws Exception if the test fails
279      */
280     @Test
281     @Alerts("maybe")
282     public void canPlayType_Mp4() throws Exception {
283         canPlayType("video/mp4");
284     }
285 
286     /**
287      * @throws Exception if the test fails
288      */
289     @Test
290     @Alerts(DEFAULT = "",
291             FF = "maybe",
292             FF_ESR = "maybe")
293     @HtmlUnitNYI(CHROME = "maybe",
294             EDGE = "maybe")
295     public void canPlayType_AudioWave() throws Exception {
296         canPlayType("audio/wave");
297     }
298 
299     /**
300      * @throws Exception if the test fails
301      */
302     @Test
303     @Alerts("maybe")
304     public void canPlayType_AudioWav() throws Exception {
305         canPlayType("audio/wav");
306     }
307 
308     /**
309      * @throws Exception if the test fails
310      */
311     @Test
312     @Alerts("maybe")
313     public void canPlayType_AudioXWav() throws Exception {
314         canPlayType("audio/x-wav");
315     }
316 
317     /**
318      * @throws Exception if the test fails
319      */
320     @Test
321     @Alerts(DEFAULT = "",
322             FF = "maybe",
323             FF_ESR = "maybe")
324     @HtmlUnitNYI(CHROME = "maybe",
325             EDGE = "maybe")
326     public void canPlayType_AudioPnWav() throws Exception {
327         canPlayType("audio/x-pn-wav");
328     }
329 
330     /**
331      * @throws Exception if the test fails
332      */
333     @Test
334     @Alerts("maybe")
335     public void canPlayType_AudioWebm() throws Exception {
336         canPlayType("audio/webm");
337     }
338 
339     /**
340      * @throws Exception if the test fails
341      */
342     @Test
343     @Alerts("maybe")
344     public void canPlayType_VideoWebm() throws Exception {
345         canPlayType("video/webm");
346     }
347 
348     /**
349      * @throws Exception if the test fails
350      */
351     @Test
352     @Alerts(DEFAULT = "maybe",
353             CHROME = "probably",
354             EDGE = "probably")
355     @HtmlUnitNYI(CHROME = "maybe",
356             EDGE = "maybe")
357     public void canPlayType_AudioMpeg() throws Exception {
358         canPlayType("audio/mpeg");
359     }
360 
361     /**
362      * @throws Exception if the test fails
363      */
364     @Test
365     @Alerts(DEFAULT = "probably",
366             FF = "maybe",
367             FF_ESR = "maybe")
368     @HtmlUnitNYI(CHROME = "maybe",
369             EDGE = "maybe")
370     public void canPlayType_AudioFlac() throws Exception {
371         canPlayType("audio/flac");
372     }
373 
374     /**
375      * @throws Exception if the test fails
376      */
377     @Test
378     @Alerts(DEFAULT = "",
379             FF = "maybe",
380             FF_ESR = "maybe")
381     @HtmlUnitNYI(CHROME = "maybe",
382             EDGE = "maybe")
383     public void canPlayType_AudioXFlac() throws Exception {
384         canPlayType("audio/x-flac");
385     }
386 
387     /**
388      * @throws Exception if the test fails
389      */
390     private void canPlayType(final String mimeType) throws Exception {
391         final String html = DOCTYPE_HTML
392             + "<html><head>\n"
393             + "<script>\n"
394             + LOG_TITLE_FUNCTION
395             + "  function test() {\n"
396             + "    var elem = document.getElementById('a1');\n"
397             + "    log(elem.canPlayType('" + mimeType + "'));\n"
398             + "  }\n"
399             + "</script>\n"
400             + "</head>\n"
401             + "<body onload='test()'>\n"
402             + "  <audio id='a1'/>\n"
403             + "</body></html>";
404 
405         loadPageVerifyTitle2(html);
406     }
407 
408     /**
409      * @throws Exception if the test fails
410      */
411     @Test
412     @Alerts({"[object HTMLAudioElement]", "1"})
413     public void newAudioNodeType() throws Exception {
414         final String html = DOCTYPE_HTML
415             + "<html><head>\n"
416             + "<script>\n"
417             + LOG_TITLE_FUNCTION
418             + "  function test() {\n"
419             + "    var a = new Audio();\n"
420             + "    log(a);\n"
421             + "    log(a.nodeType);\n"
422             + "  }\n"
423             + "</script>\n"
424             + "</head>\n"
425             + "<body onload='test()'>\n"
426             + "</body></html>";
427 
428         loadPageVerifyTitle2(html);
429     }
430 
431     /**
432      * @throws Exception if the test fails
433      */
434     @Test
435     @Alerts({"[object HTMLAudioElement]", "AUDIO"})
436     public void newAudioNodeName() throws Exception {
437         final String html = DOCTYPE_HTML
438             + "<html><head>\n"
439             + "<script>\n"
440             + LOG_TITLE_FUNCTION
441             + "  function test() {\n"
442             + "    var a = new Audio();\n"
443             + "    log(a);\n"
444             + "    log(a.nodeName);\n"
445             + "  }\n"
446             + "</script>\n"
447             + "</head>\n"
448             + "<body onload='test()'>\n"
449             + "</body></html>";
450 
451         loadPageVerifyTitle2(html);
452     }
453 
454     /**
455      * @throws Exception if the test fails
456      */
457     @Test
458     @Alerts({"string", "§§URL§§horse.mp3", "§§URL§§cow.mp3",
459              "<audio id=\"a\" src=\"cow.mp3\"></audio>"})
460     public void src() throws Exception {
461         final String html = DOCTYPE_HTML
462             + "<html><body>\n"
463             + "<audio id='a' src='horse.mp3'></audio>"
464             + "<script>\n"
465             + LOG_TITLE_FUNCTION
466             + "try {\n"
467             + "  var audio = document.getElementById('a');\n"
468             + "  var src = audio.src;\n"
469             + "  log(typeof src);"
470             + "  log(src);"
471             + "  audio.src = 'cow.mp3';\n"
472             + "  log(audio.src);"
473             + "  log(audio.outerHTML);"
474             + "} catch(e) { logEx(e); }\n"
475             + "</script>\n"
476             + "</body></html>";
477 
478         expandExpectedAlertsVariables(URL_FIRST);
479         loadPageVerifyTitle2(html);
480     }
481 
482     /**
483      * @throws Exception if the test fails
484      */
485     @Test
486     @Alerts({"string", "", "§§URL§§cow.mp3",
487              "<audio id=\"a\" src=\"cow.mp3\"><source src=\"horse.mp3\" type=\"audio/mpeg\"></audio>"})
488     public void srcChild() throws Exception {
489         final String html = DOCTYPE_HTML
490             + "<html><body>\n"
491             + "<audio id='a'><source src='horse.mp3' type='audio/mpeg'></audio>"
492             + "<script>\n"
493             + LOG_TITLE_FUNCTION
494             + "try {\n"
495             + "  var audio = document.getElementById('a');\n"
496             + "  var src = audio.src;\n"
497             + "  log(typeof src);"
498             + "  log(src);"
499             + "  audio.src = 'cow.mp3';\n"
500             + "  log(audio.src);"
501             + "  log(audio.outerHTML);"
502             + "} catch(e) { logEx(e); }\n"
503             + "</script>\n"
504             + "</body></html>";
505 
506         expandExpectedAlertsVariables(URL_FIRST);
507         loadPageVerifyTitle2(html);
508     }
509 
510     /**
511      * @throws Exception if the test fails
512      */
513     @Test
514     @Alerts({"string", ""})
515     public void srcNotDefined() throws Exception {
516         final String html = DOCTYPE_HTML
517             + "<html><body>\n"
518             + "<audio id='a'></audio>"
519             + "<script>\n"
520             + LOG_TITLE_FUNCTION
521             + "try {\n"
522             + "  var src = document.getElementById('a').src;\n"
523             + "  log(typeof src);"
524             + "  log(src);"
525             + "} catch(e) { logEx(e); }\n"
526             + "</script>\n"
527             + "</body></html>";
528 
529         loadPageVerifyTitle2(html);
530     }
531 
532     /**
533      * @throws Exception if the test fails
534      */
535     @Test
536     @Alerts({"string", ""})
537     public void currentSrc() throws Exception {
538         final String html = DOCTYPE_HTML
539             + "<html><body>\n"
540             + "<audio id='a' src='horse.mp3'></audio>"
541             + "<script>\n"
542             + LOG_TITLE_FUNCTION
543             + "try {\n"
544             + "  var currentSrc = document.getElementById('a').currentSrc;\n"
545             + "  log(typeof currentSrc);"
546             + "  log(currentSrc);"
547             + "} catch(e) { logEx(e); }\n"
548             + "</script>\n"
549             + "</body></html>";
550 
551         expandExpectedAlertsVariables(URL_FIRST);
552         loadPageVerifyTitle2(html);
553     }
554 
555     /**
556      * @throws Exception if the test fails
557      */
558     @Test
559     @Alerts({"string", ""})
560     public void currentSrcChild() throws Exception {
561         final String html = DOCTYPE_HTML
562             + "<html><body>\n"
563             + "<audio id='a'><source src='horse.mp3' type='audio/mpeg'></audio>"
564             + "<script>\n"
565             + LOG_TITLE_FUNCTION
566             + "try {\n"
567             + "  var currentSrc = document.getElementById('a').currentSrc;\n"
568             + "  log(typeof currentSrc);"
569             + "  log(currentSrc);"
570             + "} catch(e) { logEx(e); }\n"
571             + "</script>\n"
572             + "</body></html>";
573 
574         expandExpectedAlertsVariables(URL_FIRST);
575         loadPageVerifyTitle2(html);
576     }
577 
578     /**
579      * @throws Exception if the test fails
580      */
581     @Test
582     @Alerts({"string", ""})
583     public void currentSrcNotDefined() throws Exception {
584         final String html = DOCTYPE_HTML
585             + "<html><body>\n"
586             + "<audio id='a'></audio>"
587             + "<script>\n"
588             + LOG_TITLE_FUNCTION
589             + "try {\n"
590             + "  var currentSrc = document.getElementById('a').currentSrc;\n"
591             + "  log(typeof currentSrc);"
592             + "  log(currentSrc);"
593             + "} catch(e) { logEx(e); }\n"
594             + "</script>\n"
595             + "</body></html>";
596 
597         loadPageVerifyTitle2(html);
598     }
599 }