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.html.HtmlPageTest;
19  import org.htmlunit.junit.annotation.Alerts;
20  import org.junit.jupiter.api.Test;
21  
22  /**
23   * Tests for Symbol.
24   *
25   * @author Ahmed Ashour
26   * @author Ronald Brill
27   */
28  public class SymbolTest extends WebDriverTestCase {
29  
30      /**
31       * @throws Exception if the test fails
32       */
33      @Test
34      @Alerts({"symbol", "Symbol(Symbol.iterator)", "true"})
35      public void iterator() throws Exception {
36          name("iterator");
37      }
38  
39      /**
40       * @throws Exception if the test fails
41       */
42      @Test
43      @Alerts({"symbol", "Symbol(Symbol.match)", "true"})
44      public void match() throws Exception {
45          name("match");
46      }
47  
48      /**
49       * @throws Exception if the test fails
50       */
51      @Test
52      @Alerts({"symbol", "Symbol(Symbol.replace)", "true"})
53      public void replace() throws Exception {
54          name("replace");
55      }
56  
57      /**
58       * @throws Exception if the test fails
59       */
60      @Test
61      @Alerts({"symbol", "Symbol(Symbol.search)", "true"})
62      public void search() throws Exception {
63          name("search");
64      }
65  
66      /**
67       * @throws Exception if the test fails
68       */
69      @Test
70      @Alerts({"symbol", "Symbol(Symbol.split)", "true"})
71      public void split() throws Exception {
72          name("split");
73      }
74  
75      /**
76       * @throws Exception if the test fails
77       */
78      @Test
79      @Alerts({"symbol", "Symbol(Symbol.hasInstance)", "true"})
80      public void hasInstance() throws Exception {
81          name("hasInstance");
82      }
83  
84      /**
85       * @throws Exception if the test fails
86       */
87      @Test
88      @Alerts({"symbol", "Symbol(Symbol.isConcatSpreadable)", "true"})
89      public void isConcatSpreadable() throws Exception {
90          name("isConcatSpreadable");
91      }
92  
93      /**
94       * @throws Exception if the test fails
95       */
96      @Test
97      @Alerts({"symbol", "Symbol(Symbol.unscopables)", "true"})
98      public void unscopables() throws Exception {
99          name("unscopables");
100     }
101 
102     /**
103      * @throws Exception if the test fails
104      */
105     @Test
106     @Alerts({"symbol", "Symbol(Symbol.species)", "true"})
107     public void species() throws Exception {
108         name("species");
109     }
110 
111     /**
112      * @throws Exception if the test fails
113      */
114     @Test
115     @Alerts({"symbol", "Symbol(Symbol.toPrimitive)", "true"})
116     public void toPrimitive() throws Exception {
117         name("toPrimitive");
118     }
119 
120     /**
121      * @throws Exception if the test fails
122      */
123     @Test
124     @Alerts({"symbol", "Symbol(Symbol.toStringTag)", "true"})
125     public void toStringTag() throws Exception {
126         name("toStringTag");
127     }
128 
129     private void name(final String name) throws Exception {
130         final String html = DOCTYPE_HTML
131             + "<html>\n"
132             + "<head>\n"
133             + "<script>\n"
134             + LOG_TITLE_FUNCTION
135             + "  function test() {\n"
136             + "    if (!window.Symbol) { log('not supported'); return; }\n"
137             + "    log(typeof Symbol." + name + ");\n"
138             + "    log(Symbol." + name + " ? Symbol." + name + ".toString() : '-');\n"
139             + "    log(Symbol." + name + " === Symbol." + name + ");\n"
140             + "  }\n"
141             + "</script>\n"
142             + "</head>\n"
143             + "<body onload='test()'>\n"
144             + "</body></html>";
145 
146         loadPageVerifyTitle2(html);
147     }
148 
149     /**
150      * @throws Exception if the test fails
151      */
152     @Test
153     @Alerts({"Symbol()", "Symbol(foo)", "Symbol(Symbol.iterator)", "TypeError"})
154     public void string() throws Exception {
155         final String html =
156             HtmlPageTest.STANDARDS_MODE_PREFIX_
157             + "<html>\n"
158             + "<head>\n"
159             + "<script>\n"
160             + LOG_TITLE_FUNCTION
161             + "  function test() {\n"
162             + "    if (!window.Symbol) { log('not supported'); return; }\n"
163             + "    log(Symbol().toString());\n"
164             + "    log(Symbol('foo').toString());\n"
165             + "    log(Symbol.iterator.toString());\n"
166             + "    try { log(Symbol.replace) } catch(e) { logEx(e); };\n"
167             + "  }\n"
168             + "</script>\n"
169             + "</head>\n"
170             + "<body onload='test()'>\n"
171             + "</body></html>";
172 
173         loadPageVerifyTitle2(html);
174     }
175 
176     /**
177      * @throws Exception if the test fails
178      */
179     @Test
180     @Alerts({"Symbol()", "Symbol(foo)", "Symbol(Symbol.iterator)"})
181     public void defaultValue() throws Exception {
182         final String html = DOCTYPE_HTML
183             + "<html>\n"
184             + "<head>\n"
185             + "<script>\n"
186             + LOG_TITLE_FUNCTION
187             + "  function test() {\n"
188             + "    if (!window.Symbol) { log('not supported'); return; }\n"
189             + "    try {\n"
190             + "      log(Symbol().toString());\n"
191             + "      log(Symbol('foo').toString());\n"
192             + "      log(Symbol.iterator.toString());\n"
193             + "    } catch(e) { logEx(e) }\n"
194             + "  }\n"
195             + "</script>\n"
196             + "</head>\n"
197             + "<body onload='test()'>\n"
198             + "</body></html>";
199 
200         loadPageVerifyTitle2(html);
201     }
202 
203     /**
204      * @throws Exception if the test fails
205      */
206     @Test
207     @Alerts({"function", "symbol", "symbol", "symbol"})
208     public void typeOf() throws Exception {
209         final String html = DOCTYPE_HTML
210             + "<html>\n"
211             + "<head>\n"
212             + "<script>\n"
213             + LOG_TITLE_FUNCTION
214             + "  function test() {\n"
215             + "    if (!window.Symbol) { log('not supported'); return; }\n"
216             + "    try {\n"
217             + "      log(typeof Symbol);\n"
218             + "      log(typeof Symbol());\n"
219             + "      log(typeof Symbol('foo'));\n"
220             + "      log(typeof Symbol.iterator);\n"
221             + "    } catch(e) { logEx(e) }\n"
222             + "  }\n"
223             + "</script>\n"
224             + "</head>\n"
225             + "<body onload='test()'>\n"
226             + "</body></html>";
227 
228         loadPageVerifyTitle2(html);
229     }
230 
231     /**
232      * @throws Exception if the test fails
233      */
234     @Test
235     @Alerts({"false", "true", "Symbol(mario)"})
236     public void symbolFor() throws Exception {
237         final String html = DOCTYPE_HTML
238             + "<html>\n"
239             + "<head>\n"
240             + "<script>\n"
241             + LOG_TITLE_FUNCTION
242             + "  function test() {\n"
243             + "    if (!window.Symbol) { log('not supported'); return; }\n"
244             + "    try {\n"
245             + "      log(Symbol('bar') === Symbol('bar'));\n"
246             + "      log(Symbol.for('bar') === Symbol.for('bar'));\n"
247 
248             + "      var sym = Symbol.for('mario');\n"
249             + "      log(sym.toString());\n"
250             + "    } catch(e) { logEx(e) }\n"
251             + "  }\n"
252             + "</script>\n"
253             + "</head>\n"
254             + "<body onload='test()'>\n"
255             + "</body></html>";
256 
257         loadPageVerifyTitle2(html);
258     }
259 
260     /**
261      * @throws Exception if the test fails
262      */
263     @Test
264     @Alerts({"true", "false"})
265     public void symbolForGlobal() throws Exception {
266         final String html = DOCTYPE_HTML
267             + "<html>\n"
268             + "<head>\n"
269             + "<script>\n"
270             + "  if (window.Symbol) { globSym = Symbol.for('global'); }\n"
271             + "</script>\n"
272             + "<script>\n"
273             + LOG_TITLE_FUNCTION
274             + "  function test() {\n"
275             + "    if (!window.Symbol) { log('not supported'); return; }\n"
276             + "    try {\n"
277             + "      log(Symbol.for('global') === globSym);\n"
278             + "      log(Symbol('global') === globSym);\n"
279             + "    } catch(e) { logEx(e) }\n"
280             + "  }\n"
281             + "</script>\n"
282             + "</head>\n"
283             + "<body onload='test()'>\n"
284             + "</body></html>";
285 
286         loadPageVerifyTitle2(html);
287     }
288 
289     /**
290      * @throws Exception if the test fails
291      */
292     @Test
293     @Alerts({"TypeError", "TypeError"})
294     public void symbolNew() throws Exception {
295         final String html = DOCTYPE_HTML
296             + "<html>\n"
297             + "<head>\n"
298             + "<script>\n"
299             + LOG_TITLE_FUNCTION
300             + "  function test() {\n"
301             + "    if (!window.Symbol) { log('not supported'); return; }\n"
302             + "    try {\n"
303             + "      new Symbol();\n"
304             + "    } catch(e) { logEx(e) }\n"
305             + "    try {\n"
306             + "      new Symbol('foo');\n"
307             + "    } catch(e) { logEx(e) }\n"
308             + "  }\n"
309             + "</script>\n"
310             + "</head>\n"
311             + "<body onload='test()'>\n"
312             + "</body></html>";
313 
314         loadPageVerifyTitle2(html);
315     }
316 
317     /**
318      * @throws Exception if the test fails
319      */
320     @Test
321     @Alerts({"TypeError", "TypeError"})
322     public void globalSymbolRegistry() throws Exception {
323         final String html = DOCTYPE_HTML
324             + "<html>\n"
325             + "<head>\n"
326             + "<script>\n"
327             + LOG_TITLE_FUNCTION
328             + "  function test() {\n"
329             + "    if (!window.Symbol) { log('not supported'); return; }\n"
330             + "    try {\n"
331             + "      new Symbol();\n"
332             + "    } catch(e) { logEx(e) }\n"
333             + "    try {\n"
334             + "      new Symbol('foo');\n"
335             + "    } catch(e) { logEx(e) }\n"
336             + "  }\n"
337             + "</script>\n"
338             + "</head>\n"
339             + "<body onload='test()'>\n"
340             + "</body></html>";
341 
342         loadPageVerifyTitle2(html);
343     }
344 
345     /**
346      * @throws Exception if an error occurs
347      */
348     @Test
349     @Alerts("called")
350     public void inFunction() throws Exception {
351         final String html = DOCTYPE_HTML
352             + "<html><head>\n"
353             + "<script>\n"
354             + LOG_TITLE_FUNCTION
355             + "function test() {\n"
356             + "  if (window.Symbol) {\n"
357             + "    [].forEach.call('_', function(e) {\n"
358             + "      var x = Symbol.toPrimitive;\n"
359             + "      log('called');\n"
360             + "    });\n"
361             + "  }\n"
362             + "}\n"
363             + "</script></head><body onload='test()'>\n"
364             + "</body></html>\n";
365 
366         loadPageVerifyTitle2(html);
367     }
368 
369     /**
370      * @throws Exception if an error occurs
371      */
372     @Test
373     @Alerts("called")
374     public void inFunction2() throws Exception {
375         final String html = DOCTYPE_HTML
376             + "<html><head>\n"
377             + "<script>\n"
378             + LOG_TITLE_FUNCTION
379             + "function test() {\n"
380             + "  if (window.Symbol) {\n"
381             + "    [].forEach.call('_', function(e) {\n"
382             + "      try {\n"
383             + "        var x = Symbol('hello');\n"
384             + "        log('called');\n"
385             + "      } catch(e) {logEx(e);}\n"
386             + "    });\n"
387             + "  }\n"
388             + "}\n"
389             + "</script></head><body onload='test()'>\n"
390             + "</body></html>\n";
391 
392         loadPageVerifyTitle2(html);
393     }
394 
395     /**
396      * @throws Exception if the test fails
397      */
398     @Test
399     @Alerts("function")
400     public void prototypeAddFunction() throws Exception {
401         final String html = DOCTYPE_HTML
402                 + "<html><head>\n"
403                 + "<script>\n"
404                 + LOG_TITLE_FUNCTION
405                 + "function test() {\n"
406                 + "  if (window.Symbol) {\n"
407                 + "    Symbol.prototype.myCustomFunction = function() {};\n"
408                 + "    log(typeof Symbol.prototype.myCustomFunction);\n"
409                 + "  }\n"
410                 + "}\n"
411                 + "</script></head><body onload='test()'>\n"
412                 + "</body></html>\n";
413 
414         loadPageVerifyTitle2(html);
415     }
416 
417     /**
418      * @throws Exception if the test fails
419      */
420     @Test
421     @Alerts("object")
422     public void prototypeTypeOf() throws Exception {
423         final String html = DOCTYPE_HTML
424                 + "<html><head>\n"
425                 + "<script>\n"
426                 + LOG_TITLE_FUNCTION
427                 + "function test() {\n"
428                 + "  if (window.Symbol) {\n"
429                 + "    log(typeof Symbol.prototype);\n"
430                 + "  }\n"
431                 + "}\n"
432                 + "</script></head><body onload='test()'>\n"
433                 + "</body></html>\n";
434 
435         loadPageVerifyTitle2(html);
436     }
437 }