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;
16  
17  import org.htmlunit.WebDriverTestCase;
18  import org.htmlunit.junit.annotation.Alerts;
19  import org.htmlunit.junit.annotation.HtmlUnitNYI;
20  import org.junit.jupiter.api.Test;
21  
22  /**
23   * Tests for {@link Navigator}.
24   *
25   * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
26   * @author Daniel Gredler
27   * @author Marc Guillemot
28   * @author Ahmed Ashour
29   * @author Frank Danek
30   * @author Ronald Brill
31   */
32  public class NavigatorTest extends WebDriverTestCase {
33  
34      /**
35       * Tests the {@code appCodeName} property.
36       * @throws Exception on test failure
37       */
38      @Test
39      public void appCodeName() throws Exception {
40          attribute("appCodeName", getBrowserVersion().getApplicationCodeName());
41      }
42  
43      /**
44       * Tests the {@code appMinorVersion} property.
45       * @throws Exception on test failure
46       */
47      @Test
48      @Alerts("undefined")
49      public void appMinorVersion() throws Exception {
50          attribute("appMinorVersion", getExpectedAlerts()[0]);
51      }
52  
53      /**
54       * Tests the {@code appName} property.
55       * @throws Exception on test failure
56       */
57      @Test
58      public void appName() throws Exception {
59          attribute("appName", getBrowserVersion().getApplicationName());
60      }
61  
62      /**
63       * Tests the {@code appVersion} property.
64       * @throws Exception on test failure
65       */
66      @Test
67      public void appVersion() throws Exception {
68          attribute("appVersion", getBrowserVersion().getApplicationVersion(),
69                  "SLCC2; ", ".NET CLR 2.0.50727; ", ".NET CLR 3.5.30729; ", ".NET CLR 3.0.30729; ",
70                  "Media Center PC 6.0; ", ".NET4.0C; ", ".NET4.0E; ");
71      }
72  
73      /**
74       * Tests the {@code browserLanguage} property.
75       * @throws Exception on test failure
76       */
77      @Test
78      @Alerts("undefined")
79      public void browserLanguage() throws Exception {
80          attribute("browserLanguage", getExpectedAlerts()[0]);
81      }
82  
83      /**
84       * Tests the {@code productSub} property.
85       * @throws Exception on test failure
86       */
87      @Test
88      @Alerts(DEFAULT = {"string", "20100101"},
89              CHROME = {"string", "20030107"},
90              EDGE = {"string", "20030107"})
91      public void productSub() throws Exception {
92          final String html = DOCTYPE_HTML
93              + "<html><head>\n"
94              + "<script>\n"
95              + LOG_TITLE_FUNCTION
96              + "  log(typeof(navigator.productSub));\n"
97              + "  log(navigator.productSub);\n"
98              + "</script>\n"
99              + "</head><body></body>\n"
100             + "</html>";
101 
102         loadPageVerifyTitle2(html);
103     }
104 
105     /**
106      * Tests the {@code cpuClass} property.
107      * @throws Exception on test failure
108      */
109     @Test
110     @Alerts("undefined")
111     public void cpuClass() throws Exception {
112         attribute("cpuClass", getExpectedAlerts()[0]);
113     }
114 
115     /**
116      * Tests the {@code onLine} property.
117      * @throws Exception on test failure
118      */
119     @Test
120     public void onLine() throws Exception {
121         attribute("onLine", String.valueOf(getBrowserVersion().isOnLine()));
122     }
123 
124     /**
125      * Tests the {@code platform} property.
126      * @throws Exception on test failure
127      */
128     @Test
129     public void platform() throws Exception {
130         attribute("platform", getBrowserVersion().getPlatform());
131     }
132 
133     /**
134      * Tests the {@code systemLanguage} property.
135      * @throws Exception on test failure
136      */
137     @Test
138     @Alerts("undefined")
139     public void systemLanguage() throws Exception {
140         attribute("systemLanguage", getExpectedAlerts()[0]);
141     }
142 
143     /**
144      * Tests the {@code userAgent} property.
145      * @throws Exception on test failure
146      */
147     @Test
148     public void userAgent() throws Exception {
149         attribute("userAgent", getBrowserVersion().getUserAgent(),
150                 "SLCC2; ", ".NET CLR 2.0.50727; ", ".NET CLR 3.5.30729; ", ".NET CLR 3.0.30729; ",
151                 "Media Center PC 6.0; ", ".NET4.0C; ", ".NET4.0E; ");
152     }
153 
154     /**
155      * Tests the {@code userLanguage} property.
156      * @throws Exception on test failure
157      */
158     @Test
159     @Alerts("undefined")
160     public void userLanguage() throws Exception {
161         attribute("userLanguage", getExpectedAlerts()[0]);
162     }
163 
164     /**
165      * Tests the {@code plugins} property.
166      * @throws Exception on test failure
167      */
168     @Test
169     @Alerts({"5",
170         "PDF Viewer", "Portable Document Format", "internal-pdf-viewer", "undefined",
171         "Chrome PDF Viewer", "Portable Document Format", "internal-pdf-viewer", "undefined",
172         "Chromium PDF Viewer", "Portable Document Format", "internal-pdf-viewer", "undefined",
173         "Microsoft Edge PDF Viewer", "Portable Document Format", "internal-pdf-viewer", "undefined",
174         "WebKit built-in PDF", "Portable Document Format", "internal-pdf-viewer", "undefined"})
175     public void plugins() throws Exception {
176         final String html = DOCTYPE_HTML
177                 + "<html>\n"
178                 + "<head>\n"
179                 + "  <script>\n"
180                 + LOG_TITLE_FUNCTION
181                 + "    function doTest() {\n"
182                 + "      log(window.navigator.plugins.length);\n"
183                 + "      for (var i = 0; i < window.navigator.plugins.length; i++) {\n"
184                 + "        let pl = window.navigator.plugins[i];\n"
185                 + "        log(pl.name);\n"
186                 + "        log(pl.description);\n"
187                 + "        log(pl.filename);\n"
188                 + "        log(pl.version);\n"
189                 + "      }\n"
190                 + "    }\n"
191                 + "  </script>\n"
192                 + "</head>\n"
193                 + "<body onload='doTest()'>\n"
194                 + "</body>\n"
195                 + "</html>";
196 
197         loadPageVerifyTitle2(html);
198     }
199 
200     /**
201      * Tests the Shockwave Flash plugin property.
202      * @throws Exception on test failure
203      */
204     @Test
205     @Alerts("Shockwave Flash not available")
206     public void pluginsShockwaveFlash() throws Exception {
207         final String html = DOCTYPE_HTML
208                 + "<html>\n"
209                 + "<head>\n"
210                 + "  <script>\n"
211                 + LOG_TITLE_FUNCTION
212                 + "  function doTest() {\n"
213                 + "    var flash = false;\n"
214                 + "    for (var i = 0; i < window.navigator.plugins.length; i++) {\n"
215                 + "      var plugin = window.navigator.plugins[i];\n"
216                 + "      if ('Shockwave Flash' == window.navigator.plugins[i].name) {\n"
217                 + "        flash = true;\n"
218                 + "        log(plugin.name);\n"
219                 + "        log(plugin.description);\n"
220                 + "        log(plugin.version);\n"
221                 + "        log(plugin.filename);\n"
222                 + "      }\n"
223                 + "    }\n"
224                 + "    if (!flash) {\n"
225                 + "      log('Shockwave Flash not available');\n"
226                 + "    }\n"
227                 + "  }\n"
228                 + "  </script>\n"
229                 + "</head>\n"
230                 + "<body onload='doTest()'>\n"
231                 + "</body>\n"
232                 + "</html>";
233 
234         loadPageVerifyTitle2(html);
235     }
236 
237     /**
238      * @throws Exception if the test fails
239      */
240     @Test
241     @Alerts({"2",
242              "application/pdf", "Portable Document Format", "pdf", "[object Plugin]", "true",
243              "text/pdf", "Portable Document Format", "pdf", "[object Plugin]", "true"})
244     public void mimeTypes() throws Exception {
245         final String html = DOCTYPE_HTML
246                 + "<html><head>\n"
247                 + "  <script>\n"
248                 + LOG_TITLE_FUNCTION
249                 + "    function doTest() {\n"
250                 + "      log(window.navigator.mimeTypes.length);\n"
251                 + "      for (var i = 0; i < window.navigator.mimeTypes.length; i++) {\n"
252                 + "        let mt = window.navigator.mimeTypes[i];\n"
253                 + "        log(mt.type);\n"
254                 + "        log(mt.description);\n"
255                 + "        log(mt.suffixes);\n"
256                 + "        log(mt.enabledPlugin);\n"
257                 + "        log(mt.enabledPlugin === window.navigator.plugins[0]);"
258                 + "      }\n"
259                 + "    }\n"
260                 + "  </script>\n"
261             + "</head><body onload='doTest()'></body>\n"
262             + "</html>";
263 
264         loadPageVerifyTitle2(html);
265     }
266 
267     /**
268      * Tests the {@code taintEnabled} property.
269      * @throws Exception on test failure
270      */
271     @Test
272     @Alerts(DEFAULT = "false",
273             CHROME = "TypeError",
274             EDGE = "TypeError")
275     public void taintEnabled() throws Exception {
276         final String html = DOCTYPE_HTML
277                 + "<html>\n"
278                 + "<head>\n"
279                 + "  <script>\n"
280                 + LOG_TITLE_FUNCTION
281                 + "  function doTest() {\n"
282                 + "    try {\n"
283                 + "      log(window.navigator.taintEnabled());\n"
284                 + "    } catch(e) { logEx(e); }\n"
285                 + "  }\n"
286                 + "  </script>\n"
287                 + "</head>\n"
288                 + "<body onload='doTest()'>\n"
289                 + "</body>\n"
290                 + "</html>";
291 
292         loadPageVerifyTitle2(html);
293     }
294 
295     /**
296      * Generic method for testing the value of a specific navigator attribute.
297      * @param name the name of the attribute to test
298      * @param value the expected value for the named attribute
299      * @throws Exception on test failure
300      */
301     void attribute(final String name, final String value, final String... ignore) throws Exception {
302         final String html = DOCTYPE_HTML
303                 + "<html>\n"
304                 + "<head>\n"
305                 + "  <script>\n"
306                 + LOG_TITLE_FUNCTION
307                 + "    function doTest() {\n"
308                 + "      log(window.navigator." + name + ");\n"
309                 + "    }\n"
310                 + "  </script>\n"
311                 + "</head>\n"
312                 + "<body onload='doTest()'>\n"
313                 + "</body>\n"
314                 + "</html>";
315 
316         setExpectedAlerts(value);
317         loadPageVerifyTitle2(html);
318     }
319 
320     /**
321      * Test {@code language} property.
322      * @throws Exception if the test fails
323      */
324     @Test
325     @Alerts("en-US")
326     public void language() throws Exception {
327         final String html = DOCTYPE_HTML
328             + "<html><head>\n"
329             + "  <script>\n"
330             + LOG_TITLE_FUNCTION
331             + "  </script>\n"
332             + "</head>\n"
333             + "<body onload='log(window.navigator.language)'></body>\n"
334             + "</html>";
335 
336         loadPageVerifyTitle2(html);
337     }
338 
339     /**
340      * Test {@code language} property.
341      * @throws Exception if the test fails
342      */
343     @Test
344     @Alerts(DEFAULT = "en-US",
345             FF = "en-US,en",
346             FF_ESR = "en-US,en")
347     @HtmlUnitNYI(CHROME = "en-US,en",
348             EDGE = "en-US,en")
349     public void languages() throws Exception {
350         final String html = DOCTYPE_HTML
351             + "<html><head>\n"
352             + "  <script>\n"
353             + LOG_TITLE_FUNCTION
354             + "  </script>\n"
355             + "</head>\n"
356             + "<body onload='log(window.navigator.languages)'></body>\n"
357             + "</html>";
358 
359         loadPageVerifyTitle2(html);
360     }
361 
362     /**
363      * @throws Exception if the test fails
364      */
365     @Test
366     @Alerts({"number", "number"})
367     public void mozilla() throws Exception {
368         final String html = DOCTYPE_HTML
369             + "<html><head>\n"
370             + "<script>\n"
371             + LOG_TITLE_FUNCTION
372             + "function test() {\n"
373             + "  log(typeof window.navigator.mimeTypes.length);\n"
374             + "  log(typeof window.navigator.plugins.length);\n"
375             + "}\n"
376             + "</script>\n"
377             + "</head><body onload='test()'></body>\n"
378             + "</html>";
379 
380         loadPageVerifyTitle2(html);
381     }
382 
383     /**
384      * @throws Exception if the test fails
385      */
386     @Test
387     @Alerts("Gecko")
388     public void product() throws Exception {
389         final String html = DOCTYPE_HTML
390             + "<html><head>\n"
391             + "<script>\n"
392             + LOG_TITLE_FUNCTION
393             + "function test() {\n"
394             + "  log(navigator.product);\n"
395             + "}\n"
396             + "</script>\n"
397             + "</head><body onload='test()'></body>\n"
398             + "</html>";
399 
400         loadPageVerifyTitle2(html);
401     }
402 
403     /**
404      * @throws Exception if the test fails
405      */
406     @Test
407     @Alerts("[object Geolocation]")
408     public void geolocation() throws Exception {
409         final String html = DOCTYPE_HTML
410             + "<html><head>\n"
411             + "<script>\n"
412             + LOG_TITLE_FUNCTION
413             + "function test() {\n"
414             + "  log(navigator.geolocation);\n"
415             + "}\n"
416             + "</script>\n"
417             + "</head><body onload='test()'></body>\n"
418             + "</html>";
419 
420         loadPageVerifyTitle2(html);
421     }
422 
423     /**
424      * @throws Exception if the test fails
425      */
426     @Test
427     @Alerts(DEFAULT = "undefined",
428             FF = "20181001000000",
429             FF_ESR = "20181001000000")
430     public void buildID() throws Exception {
431         final String html = DOCTYPE_HTML
432             + "<html><head>\n"
433             + "<script>\n"
434             + LOG_TITLE_FUNCTION
435             + "function test() {\n"
436             + "  log(navigator.buildID);\n"
437             + "}\n"
438             + "</script>\n"
439             + "</head><body onload='test()'></body>\n"
440             + "</html>";
441 
442         loadPageVerifyTitle2(html);
443     }
444 
445     /**
446      * @throws Exception if the test fails
447      */
448     @Test
449     @Alerts(DEFAULT = {"Google Inc.", ""},
450             FF = {"", ""},
451             FF_ESR = {"", ""})
452     public void vendor() throws Exception {
453         final String html = DOCTYPE_HTML
454             + "<html><head>\n"
455             + "<script>\n"
456             + LOG_TITLE_FUNCTION
457             + "function test() {\n"
458             + "  log(navigator.vendor);\n"
459             + "  log(navigator.vendorSub);\n"
460             + "}\n"
461             + "</script>\n"
462             + "</head><body onload='test()'></body>\n"
463             + "</html>";
464 
465         loadPageVerifyTitle2(html);
466     }
467 
468     /**
469      * @throws Exception if the test fails
470      */
471     @Test
472     @Alerts(DEFAULT = "false",
473             FF = "true",
474             FF_ESR = "true")
475     public void oscpu() throws Exception {
476         final String html = DOCTYPE_HTML
477             + "<html><head>\n"
478             + "<script>\n"
479             + LOG_TITLE_FUNCTION
480             + "function test() {\n"
481             + "  log(navigator.oscpu != undefined);\n"
482             + "}\n"
483             + "</script>\n"
484             + "</head><body onload='test()'></body>\n"
485             + "</html>";
486 
487         loadPageVerifyTitle2(html);
488     }
489 
490     /**
491      * @throws Exception if the test fails
492      */
493     @Test
494     @Alerts(DEFAULT = {"undefined", "undefined", "undefined"},
495             CHROME = {"[object NetworkInformation]", "undefined", "undefined"},
496             EDGE = {"[object NetworkInformation]", "undefined", "undefined"})
497     public void connection() throws Exception {
498         final String html = DOCTYPE_HTML
499             + "<html><head>\n"
500             + "<script>\n"
501             + LOG_TITLE_FUNCTION
502             + "  function test() {\n"
503             + "    log(navigator.connection);\n"
504             + "    log(navigator.mozConnection);\n"
505             + "    log(navigator.webkitConnection);\n"
506             + "  }\n"
507             + "</script>\n"
508             + "</head><body onload='test()'>\n"
509             + "</body></html>";
510 
511         loadPageVerifyTitle2(html);
512     }
513 
514     /**
515      * @throws Exception if the test fails
516      */
517     @Test
518     @Alerts(DEFAULT = {"unspecified", "undefined", "undefined"},
519             CHROME = {"null", "undefined", "undefined"},
520             EDGE = {"null", "undefined", "undefined"})
521     public void doNotTrack() throws Exception {
522         final String html = DOCTYPE_HTML
523             + "<html><head>\n"
524             + "<script>\n"
525             + LOG_TITLE_FUNCTION
526             + "  function test() {\n"
527             + "    log(navigator.doNotTrack);\n"
528             + "    log(navigator.msDoNotTrack);\n"
529             + "    log(window.doNotTrack);\n"
530             + "  }\n"
531             + "</script>\n"
532             + "</head><body onload='test()'>\n"
533             + "</body></html>";
534 
535         loadPageVerifyTitle2(html);
536     }
537 
538     /**
539      * @throws Exception if the test fails
540      */
541     @Test
542     @Alerts({"[object MediaDevices]", "true"})
543     public void mediaDevices() throws Exception {
544         final String html = DOCTYPE_HTML
545             + "<html><head>\n"
546             + "<script>\n"
547             + LOG_TITLE_FUNCTION
548             + "  function test() {\n"
549             + "    log(navigator.mediaDevices);\n"
550             + "    log(navigator.mediaDevices === navigator.mediaDevices);\n"
551             + "  }\n"
552             + "</script>\n"
553             + "</head><body onload='test()'>\n"
554             + "</body></html>";
555 
556         loadPageVerifyTitle2(html);
557     }
558 
559     /**
560      * @throws Exception if the test fails
561      */
562     @Test
563     @Alerts("true")
564     public void pdfViewerEnabled() throws Exception {
565         final String html = DOCTYPE_HTML
566             + "<html><head>\n"
567             + "<script>\n"
568             + LOG_TITLE_FUNCTION
569             + "  function test() {\n"
570             + "    log(navigator.pdfViewerEnabled);\n"
571             + "  }\n"
572             + "</script>\n"
573             + "</head><body onload='test()'>\n"
574             + "</body></html>";
575 
576         loadPageVerifyTitle2(html);
577     }
578 }