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