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.html;
16  
17  import java.io.InputStream;
18  import java.net.URL;
19  import java.util.Collections;
20  import java.util.Map;
21  
22  import org.apache.commons.io.IOUtils;
23  import org.htmlunit.HttpHeader;
24  import org.htmlunit.Page;
25  import org.htmlunit.WebDriverTestCase;
26  import org.htmlunit.junit.annotation.Alerts;
27  import org.htmlunit.junit.annotation.BuggyWebDriver;
28  import org.htmlunit.util.ArrayUtils;
29  import org.junit.jupiter.api.Test;
30  import org.openqa.selenium.By;
31  import org.openqa.selenium.WebDriver;
32  import org.openqa.selenium.WebDriverException;
33  import org.openqa.selenium.htmlunit.HtmlUnitDriver;
34  
35  /**
36   * Tests for {@link HtmlArea}.
37   *
38   * @author Ahmed Ashour
39   * @author Ronald Brill
40   */
41  public class HtmlAreaTest extends WebDriverTestCase {
42  
43      private WebDriver createWebClient(final String onClick) throws Exception {
44          final URL urlImage = new URL(URL_FIRST, "img.jpg");
45          try (InputStream is = getClass().getClassLoader().getResourceAsStream("testfiles/tiny-jpg.img")) {
46              final byte[] directBytes = IOUtils.toByteArray(is);
47              getMockWebConnection().setResponse(urlImage, directBytes, 200, "ok", "image/jpg", Collections.emptyList());
48          }
49  
50          final String firstContent = DOCTYPE_HTML
51              + "<html><head><title>first</title></head>\n"
52              + "<body>\n"
53              + "  <img src='" + urlImage + "' width='145' height='126' usemap='#planetmap'>\n"
54              + "  <map id='planetmap' name='planetmap'>\n"
55              + "    <area shape='rect' onClick=\"" + onClick + "\" coords='0,0,82,126' id='second' "
56                          + "href='" + URL_SECOND + "'>\n"
57              + "    <area shape='circle' coords='90,58,3' id='third' href='" + URL_THIRD + "'>\n"
58              + "  </map>\n"
59              + "</body></html>";
60          final String secondContent = DOCTYPE_HTML + "<html><head><title>second</title></head><body></body></html>";
61          final String thirdContent = DOCTYPE_HTML + "<html><head><title>third</title></head><body></body></html>";
62  
63          getMockWebConnection().setResponse(URL_SECOND, secondContent);
64          getMockWebConnection().setResponse(URL_THIRD, thirdContent);
65  
66          return loadPage2(firstContent);
67      }
68  
69      /**
70       * @throws Exception if the test fails
71       */
72      @Test
73      @Alerts("§§URL§§")
74      @BuggyWebDriver(FF = "WebDriverException",
75                      FF_ESR = "WebDriverException")
76      public void referer() throws Exception {
77          expandExpectedAlertsVariables(URL_FIRST);
78  
79          final WebDriver driver = createWebClient("");
80          driver.get(URL_FIRST.toExternalForm());
81          try {
82              driver.findElement(By.id("third")).click();
83  
84              final Map<String, String> lastAdditionalHeaders = getMockWebConnection().getLastAdditionalHeaders();
85              assertEquals(getExpectedAlerts()[0], lastAdditionalHeaders.get(HttpHeader.REFERER));
86          }
87          catch (final WebDriverException e) {
88              e.printStackTrace();
89              assertEquals(getExpectedAlerts()[0], "WebDriverException");
90          }
91      }
92  
93      /**
94       * @throws Exception if an error occurs
95       */
96      @Test
97      public void isDisplayedRect() throws Exception {
98          final String html = DOCTYPE_HTML
99                  + "<html><head><title>Page A</title></head>\n"
100                 + "<body>\n"
101                 + "  <img id='myImg' usemap='#imgmap'"
102                         + " src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAA"
103                         + "HElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='>\n"
104                 + "  <map id='myMap' name='imgmap'>\n"
105                 + "    <area id='myArea' shape='rect' coords='0,0,1,1'>\n"
106                 + "  </map>\n"
107                 + "</body></html>";
108 
109         final WebDriver driver = loadPage2(html);
110 
111         boolean displayed = driver.findElement(By.id("myImg")).isDisplayed();
112         assertTrue(displayed);
113 
114         displayed = driver.findElement(By.id("myMap")).isDisplayed();
115         assertTrue(displayed);
116 
117         displayed = driver.findElement(By.id("myArea")).isDisplayed();
118         assertTrue(displayed);
119     }
120 
121     /**
122      * @throws Exception if an error occurs
123      */
124     @Test
125     public void isDisplayedCircle() throws Exception {
126         final String html = DOCTYPE_HTML
127                 + "<html><head><title>Page A</title></head>\n"
128                 + "<body>\n"
129                 + "  <img id='myImg' usemap='#imgmap'"
130                         + " src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAA"
131                         + "HElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='>\n"
132                 + "  <map id='myMap' name='imgmap'>\n"
133                 + "    <area id='myArea' shape='circle' coords='0,0,1'>\n"
134                 + "  </map>\n"
135                 + "</body></html>";
136 
137         final WebDriver driver = loadPage2(html);
138 
139         boolean displayed = driver.findElement(By.id("myImg")).isDisplayed();
140         assertTrue(displayed);
141 
142         displayed = driver.findElement(By.id("myMap")).isDisplayed();
143         assertTrue(displayed);
144 
145         displayed = driver.findElement(By.id("myArea")).isDisplayed();
146         assertTrue(displayed);
147     }
148 
149     /**
150      * @throws Exception if an error occurs
151      */
152     @Test
153     public void isDisplayedPolygon() throws Exception {
154         final String html = DOCTYPE_HTML
155                 + "<html><head><title>Page A</title></head>\n"
156                 + "<body>\n"
157                 + "  <img id='myImg' usemap='#imgmap'"
158                         + " src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAA"
159                         + "HElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='>\n"
160                 + "  <map id='myMap' name='imgmap'>\n"
161                 + "    <area id='myArea' shape='poly' coords='7,9,5,1,2,2'>\n"
162                 + "  </map>\n"
163                 + "</body></html>";
164 
165         final WebDriver driver = loadPage2(html);
166 
167         boolean displayed = driver.findElement(By.id("myImg")).isDisplayed();
168         assertTrue(displayed);
169 
170         displayed = driver.findElement(By.id("myMap")).isDisplayed();
171         assertTrue(displayed);
172 
173         displayed = driver.findElement(By.id("myArea")).isDisplayed();
174         assertTrue(displayed);
175     }
176 
177     /**
178      * @throws Exception if an error occurs
179      */
180     @Test
181     public void isDisplayedHiddenImage() throws Exception {
182         final String html = DOCTYPE_HTML
183                 + "<html><head><title>Page A</title></head>\n"
184                 + "<body>\n"
185                 + "  <img id='myImg' usemap='#imgmap' style='display: none'"
186                         + " src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAA"
187                         + "HElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='>\n"
188                 + "  <map id='myMap' name='imgmap'>\n"
189                 + "    <area id='myArea' shape='rect' coords='0,0,1,1'>\n"
190                 + "  </map>\n"
191                 + "</body></html>";
192 
193         final WebDriver driver = loadPage2(html);
194 
195         boolean displayed = driver.findElement(By.id("myImg")).isDisplayed();
196         assertFalse(displayed);
197 
198         displayed = driver.findElement(By.id("myMap")).isDisplayed();
199         assertFalse(displayed);
200 
201         displayed = driver.findElement(By.id("myArea")).isDisplayed();
202         assertFalse(displayed);
203     }
204 
205     /**
206      * @throws Exception if an error occurs
207      */
208     @Test
209     public void isDisplayedHiddenMap() throws Exception {
210         final String html = DOCTYPE_HTML
211                 + "<html><head><title>Page A</title></head>\n"
212                 + "<body>\n"
213                 + "  <img id='myImg' usemap='#imgmap'"
214                         + " src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAA"
215                         + "HElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='>\n"
216                 + "  <map id='myMap' name='imgmap' style='display: none'>\n"
217                 + "    <area id='myArea' shape='rect' coords='0,0,1,1'>\n"
218                 + "  </map>\n"
219                 + "</body></html>";
220 
221         final WebDriver driver = loadPage2(html);
222 
223         boolean displayed = driver.findElement(By.id("myImg")).isDisplayed();
224         assertTrue(displayed);
225 
226         displayed = driver.findElement(By.id("myMap")).isDisplayed();
227         assertTrue(displayed);
228 
229         displayed = driver.findElement(By.id("myArea")).isDisplayed();
230         assertTrue(displayed);
231     }
232 
233     /**
234      * @throws Exception if an error occurs
235      */
236     @Test
237     @Alerts({"false", "false", "false", "false", "false", "true"})
238     public void isDisplayedEmptyRect() throws Exception {
239         final String html = DOCTYPE_HTML
240                 + "<html><head><title>Page A</title></head>\n"
241                 + "<body>\n"
242                 + "  <img id='myImg' usemap='#imgmap'"
243                         + " src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAA"
244                         + "HElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='>\n"
245                 + "  <map id='myMap' name='imgmap'>\n"
246                 + "    <area id='myArea1' shape='rect' coords='0,0,0,1'>\n"
247                 + "    <area id='myArea2' shape='rect' coords='0,0,1,0'>\n"
248                 + "    <area id='myArea3' shape='rect' coords='0,0,0,0'>\n"
249                 + "    <area id='myArea4' shape='rect' >\n"
250                 + "    <area id='myArea5' >\n"
251                 + "    <area id='myArea6' shape='rect' coords='0,0,1,1'>\n"
252                 + "  </map>\n"
253                 + "</body></html>";
254 
255         final String[] expected = getExpectedAlerts();
256 
257         setExpectedAlerts(ArrayUtils.EMPTY_STRING_ARRAY);
258         final WebDriver driver = loadPage2(html);
259 
260         boolean displayed = driver.findElement(By.id("myArea1")).isDisplayed();
261         assertEquals(Boolean.parseBoolean(expected[0]), displayed);
262 
263         displayed = driver.findElement(By.id("myArea2")).isDisplayed();
264         assertEquals(Boolean.parseBoolean(expected[1]), displayed);
265 
266         displayed = driver.findElement(By.id("myArea3")).isDisplayed();
267         assertEquals(Boolean.parseBoolean(expected[2]), displayed);
268 
269         displayed = driver.findElement(By.id("myArea4")).isDisplayed();
270         assertEquals(Boolean.parseBoolean(expected[3]), displayed);
271 
272         displayed = driver.findElement(By.id("myArea5")).isDisplayed();
273         assertEquals(Boolean.parseBoolean(expected[4]), displayed);
274 
275         displayed = driver.findElement(By.id("myArea6")).isDisplayed();
276         assertEquals(Boolean.parseBoolean(expected[5]), displayed);
277     }
278 
279     /**
280      * @throws Exception if an error occurs
281      */
282     @Test
283     @Alerts({"false", "false", "true"})
284     public void isDisplayedEmptyCircle() throws Exception {
285         final String html = DOCTYPE_HTML
286                 + "<html><head><title>Page A</title></head>\n"
287                 + "<body>\n"
288                 + "  <img id='myImg' usemap='#imgmap'"
289                         + " src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAA"
290                         + "HElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='>\n"
291                 + "  <map id='myMap' name='imgmap'>\n"
292                 + "    <area id='myArea1' shape='circle' coords='0,0,0'>\n"
293                 + "    <area id='myArea2' shape='circle' >\n"
294                 + "    <area id='myArea3' shape='circle' coords='0,0,0.8'>\n"
295                 + "  </map>\n"
296                 + "</body></html>";
297 
298         final String[] expected = getExpectedAlerts();
299 
300         setExpectedAlerts(ArrayUtils.EMPTY_STRING_ARRAY);
301         final WebDriver driver = loadPage2(html);
302 
303         boolean displayed = driver.findElement(By.id("myArea1")).isDisplayed();
304         assertEquals(Boolean.parseBoolean(expected[0]), displayed);
305 
306         displayed = driver.findElement(By.id("myArea2")).isDisplayed();
307         assertEquals(Boolean.parseBoolean(expected[1]), displayed);
308 
309         displayed = driver.findElement(By.id("myArea3")).isDisplayed();
310         assertEquals(Boolean.parseBoolean(expected[2]), displayed);
311     }
312 
313 
314     /**
315      * @throws Exception if an error occurs
316      */
317     @Test
318     @Alerts({"false", "true", "false", "true"})
319     public void isDisplayedEmptyPolygon() throws Exception {
320         final String html = DOCTYPE_HTML
321                 + "<html><head><title>Page A</title></head>\n"
322                 + "<body>\n"
323                 + "  <img id='myImg' usemap='#imgmap'"
324                         + " src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAA"
325                         + "HElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='>\n"
326                 + "  <map id='myMap' name='imgmap'>\n"
327                 + "    <area id='myArea1' shape='poly' coords='0,0'>\n"
328                 + "    <area id='myArea2' shape='poly' coords='0,0,1,1'>\n"
329                 + "    <area id='myArea3' shape='poly' >\n"
330                 + "    <area id='myArea4' shape='poly' coords='0,0,1,0,0,1'>\n"
331                 + "  </map>\n"
332                 + "</body></html>";
333 
334         final String[] expected = getExpectedAlerts();
335 
336         setExpectedAlerts(ArrayUtils.EMPTY_STRING_ARRAY);
337         final WebDriver driver = loadPage2(html);
338 
339         boolean displayed = driver.findElement(By.id("myArea1")).isDisplayed();
340         assertEquals(Boolean.parseBoolean(expected[0]), displayed);
341 
342         displayed = driver.findElement(By.id("myArea2")).isDisplayed();
343         assertEquals(Boolean.parseBoolean(expected[1]), displayed);
344 
345         displayed = driver.findElement(By.id("myArea3")).isDisplayed();
346         assertEquals(Boolean.parseBoolean(expected[2]), displayed);
347 
348         displayed = driver.findElement(By.id("myArea4")).isDisplayed();
349         assertEquals(Boolean.parseBoolean(expected[3]), displayed);
350     }
351 
352     /**
353      * @throws Exception if an error occurs
354      */
355     @Test
356     public void isDisplayedMissingImage() throws Exception {
357         final String html = DOCTYPE_HTML
358                 + "<html><head><title>Page A</title></head>\n"
359                 + "<body>\n"
360                 + "  <map id='myMap' name='imgmap' style='display: none'>\n"
361                 + "    <area id='myArea' shape='rect' coords='0,0,1,1'>\n"
362                 + "  </map>\n"
363                 + "</body></html>";
364 
365         final WebDriver driver = loadPage2(html);
366 
367         boolean displayed = driver.findElement(By.id("myMap")).isDisplayed();
368         assertFalse(displayed);
369 
370         displayed = driver.findElement(By.id("myArea")).isDisplayed();
371         assertFalse(displayed);
372     }
373 
374     /**
375      * @throws Exception if the test fails
376      */
377     @Test
378     public void click_javascriptUrl() throws Exception {
379         try (InputStream is = getClass().getClassLoader().getResourceAsStream("testfiles/tiny-jpg.img")) {
380             final byte[] directBytes = IOUtils.toByteArray(is);
381             final URL urlImage = new URL(URL_FIRST, "img.jpg");
382             getMockWebConnection().setResponse(urlImage, directBytes, 200, "ok", "image/jpg", Collections.emptyList());
383         }
384 
385         final String html = DOCTYPE_HTML
386             + "<html><head><script>" + LOG_TITLE_FUNCTION + "</script></head><body>\n"
387             + "<img src='img.jpg' width='145' height='126' usemap='#somename'>\n"
388             + "<map name='somename'>\n"
389             + "  <area href='javascript:log(\"clicked\")' id='a2' shape='rect' coords='0,0,30,30'/>\n"
390             + "</map></body></html>";
391 
392         final WebDriver driver = loadPage2(html);
393         final Page page;
394         if (driver instanceof HtmlUnitDriver) {
395             page = getEnclosedPage();
396         }
397         else {
398             page = null;
399         }
400 
401         verifyTitle2(driver);
402 
403         driver.findElement(By.id("a2")).click();
404 
405         verifyTitle2(driver, "clicked");
406         if (driver instanceof HtmlUnitDriver) {
407             final Page secondPage = getEnclosedPage();
408             assertSame(page, secondPage);
409         }
410     }
411 
412     /**
413      * @throws Exception if the test fails
414      */
415     @Test
416     @Alerts("clicked")
417     @BuggyWebDriver(FF = "Todo", FF_ESR = "Todo")
418     public void click_javascriptUrlMixedCase() throws Exception {
419         try (InputStream is = getClass().getClassLoader().getResourceAsStream("testfiles/tiny-jpg.img")) {
420             final byte[] directBytes = IOUtils.toByteArray(is);
421             final URL urlImage = new URL(URL_FIRST, "img.jpg");
422             getMockWebConnection().setResponse(urlImage, directBytes, 200, "ok", "image/jpg", Collections.emptyList());
423         }
424 
425         final String html = DOCTYPE_HTML
426             + "<html><head><script>" + LOG_TITLE_FUNCTION + "</script></head><body>\n"
427             + "<img src='img.jpg' width='145' height='126' usemap='#somename'>\n"
428             + "<map name='somename'>\n"
429             + "  <area href='javasCRIpT:log(\"clicked\")' id='a2' shape='rect' coords='0,0,30,30'/>\n"
430             + "</map>\n"
431             + "</body></html>";
432 
433         final WebDriver driver = loadPage2(html);
434         final Page page;
435         if (driver instanceof HtmlUnitDriver) {
436             page = getEnclosedPage();
437         }
438         else {
439             page = null;
440         }
441 
442         verifyTitle2(driver);
443 
444         driver.findElement(By.id("a2")).click();
445 
446         verifyTitle2(driver, getExpectedAlerts());
447         if (driver instanceof HtmlUnitDriver) {
448             final Page secondPage = getEnclosedPage();
449             assertSame(page, secondPage);
450         }
451     }
452 
453     /**
454      * @throws Exception if the test fails
455      */
456     @Test
457     @Alerts("clicked")
458     @BuggyWebDriver(FF = "Todo", FF_ESR = "Todo")
459     public void click_javascriptUrlLeadingWhitespace() throws Exception {
460         try (InputStream is = getClass().getClassLoader().getResourceAsStream("testfiles/tiny-jpg.img")) {
461             final byte[] directBytes = IOUtils.toByteArray(is);
462             final URL urlImage = new URL(URL_FIRST, "img.jpg");
463             getMockWebConnection().setResponse(urlImage, directBytes, 200, "ok", "image/jpg", Collections.emptyList());
464         }
465 
466         final String html = DOCTYPE_HTML
467             + "<html><head><script>" + LOG_TITLE_FUNCTION + "</script></head><body>\n"
468             + "<img src='img.jpg' width='145' height='126' usemap='#somename'>\n"
469             + "<map name='somename'>\n"
470             + "  <area href='    javascript:log(\"clicked\")' id='a2' shape='rect' coords='0,0,30,30'/>\n"
471             + "</map></body></html>";
472 
473         final WebDriver driver = loadPage2(html);
474         final Page page;
475         if (driver instanceof HtmlUnitDriver) {
476             page = getEnclosedPage();
477         }
478         else {
479             page = null;
480         }
481 
482         verifyTitle2(driver);
483 
484         driver.findElement(By.id("a2")).click();
485 
486         verifyTitle2(driver, getExpectedAlerts());
487         if (driver instanceof HtmlUnitDriver) {
488             final Page secondPage = getEnclosedPage();
489             assertSame(page, secondPage);
490         }
491     }
492 
493     /**
494      * In action "this" should be the window and not the area.
495      * @throws Exception if the test fails
496      */
497     @Test
498     @Alerts("true")
499     @BuggyWebDriver(FF = "Todo", FF_ESR = "Todo")
500     public void thisInJavascriptHref() throws Exception {
501         try (InputStream is = getClass().getClassLoader().getResourceAsStream("testfiles/tiny-jpg.img")) {
502             final byte[] directBytes = IOUtils.toByteArray(is);
503             final URL urlImage = new URL(URL_FIRST, "img.jpg");
504             getMockWebConnection().setResponse(urlImage, directBytes, 200, "ok", "image/jpg", Collections.emptyList());
505         }
506 
507         final String html = DOCTYPE_HTML
508             + "<html><head><script>" + LOG_TITLE_FUNCTION + "</script></head><body>\n"
509             + "<img src='img.jpg' width='145' height='126' usemap='#somename'>\n"
510             + "<map name='somename'>\n"
511             + "  <area href='javascript:log(this == window)' id='a2' shape='rect' coords='0,0,30,30'/>\n"
512             + "</map></body></html>";
513 
514         final WebDriver driver = loadPage2(html);
515         final Page page;
516         if (driver instanceof HtmlUnitDriver) {
517             page = getEnclosedPage();
518         }
519         else {
520             page = null;
521         }
522 
523         verifyTitle2(driver);
524 
525         driver.findElement(By.id("a2")).click();
526 
527         verifyTitle2(driver, getExpectedAlerts());
528         if (driver instanceof HtmlUnitDriver) {
529             final Page secondPage = getEnclosedPage();
530             assertSame(page, secondPage);
531         }
532     }
533 
534 }