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 java.net.URL;
18  import java.util.ArrayList;
19  import java.util.List;
20  
21  import org.htmlunit.CollectingAlertHandler;
22  import org.htmlunit.MockWebConnection;
23  import org.htmlunit.SimpleWebTestCase;
24  import org.htmlunit.WebClient;
25  import org.htmlunit.html.HtmlAnchor;
26  import org.htmlunit.html.HtmlPage;
27  import org.htmlunit.junit.annotation.Alerts;
28  import org.junit.jupiter.api.Test;
29  
30  /**
31   * Tests for {@link Location}.
32   *
33   * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
34   * @author Michael Ottati
35   * @author Marc Guillemot
36   * @author Daniel Gredler
37   * @author Ahmed Ashour
38   * @author Ronald Brill
39   * @author Lai Quang Duong
40   */
41  public class LocationTest extends SimpleWebTestCase {
42  
43      /**
44       * @throws Exception if the test fails
45       */
46      @Test
47      public void href() throws Exception {
48          final WebClient webClient = getWebClient();
49          final MockWebConnection webConnection = new MockWebConnection();
50  
51          final String content = DOCTYPE_HTML
52              + "<html><head><title>First</title><script>\n"
53              + "function test() {\n"
54              + "  alert(window.location.href);\n"
55              + "}\n"
56              + "</script></head><body onload='test()'>\n"
57              + "</body></html>";
58  
59          webConnection.setResponse(new URL("http://myHostName/"), content);
60          webClient.setWebConnection(webConnection);
61  
62          final List<String> collectedAlerts = new ArrayList<>();
63          webClient.setAlertHandler(new CollectingAlertHandler(collectedAlerts));
64  
65          webClient.getPage("http://myHostName");
66          final String[] expectedAlerts = {"http://myHostName/" };
67          assertEquals(expectedAlerts, collectedAlerts);
68      }
69  
70      /**
71       * @throws Exception if the test fails
72       */
73      @Test
74      public void getVariousAttributes() throws Exception {
75          String[] expectedAlerts = {
76              "",               // hash
77              "first",          // host
78              "first",          // hostname
79              "http://first/",  // href
80              "/",              // pathname
81              "",               // port
82              "http:",          // protocol
83              ""                // search
84          };
85          testGetVariousAttributes("http://first", expectedAlerts);
86  
87          // Try page with all the appropriate parts
88          expectedAlerts = new String[] {
89              "#wahoo",                            // hash
90              "www.first:77",                      // host
91              "www.first",                         // hostname
92              "http://www.first:77/foo?bar#wahoo", // href
93              "/foo",                              // pathname
94              "77",                                // port
95              "http:",                             // protocol
96              "?bar"                               // search
97          };
98          testGetVariousAttributes("http://www.first:77/foo?bar#wahoo", expectedAlerts);
99      }
100 
101     private void testGetVariousAttributes(final String url, final String[] expectedAlerts) throws Exception {
102         final WebClient client = getWebClient();
103         final MockWebConnection webConnection = new MockWebConnection();
104 
105         final String content = DOCTYPE_HTML
106             + "<html><head><title>First</title><script>\n"
107             + "function doTest() {\n"
108             + "  var location = document.location;\n"
109             + "  alert(location.hash);\n"
110             + "  alert(location.host);\n"
111             + "  alert(location.hostname);\n"
112             + "  alert(location.href);\n"
113             + "  alert(location.pathname);\n"
114             + "  alert(location.port);\n"
115             + "  alert(location.protocol);\n"
116             + "  alert(location.search);\n"
117             + "}\n</script></head>\n"
118             + "<body onload='doTest()'></body></html>";
119 
120         webConnection.setDefaultResponse(content);
121         client.setWebConnection(webConnection);
122 
123         final List<String> collectedAlerts = new ArrayList<>();
124         client.setAlertHandler(new CollectingAlertHandler(collectedAlerts));
125 
126         // Try page with only a server name
127         client.getPage(url);
128         assertEquals(expectedAlerts, collectedAlerts);
129     }
130 
131     /**
132      * @throws Exception if the test fails
133      */
134     @Test
135     public void setHostname() throws Exception {
136         final WebClient webClient = getWebClient();
137         final MockWebConnection webConnection = new MockWebConnection();
138         final URL url = new URL("http://abc.com/index.html#bottom");
139         final URL url2 = new URL("http://xyz.com/index.html#bottom");
140         final String html = DOCTYPE_HTML
141             + "<html><head><title>Test 1</title></head>\n"
142             + "<body onload='location.hostname=\"xyz.com\"'>...</body></html>";
143         final String html2 = DOCTYPE_HTML
144                 + "<html><head><title>Test 2</title></head><body>...</body></html>";
145         webConnection.setResponse(url, html);
146         webConnection.setResponse(url2, html2);
147         webClient.setWebConnection(webConnection);
148 
149         final HtmlPage page = webClient.getPage(url);
150         assertEquals("Test 2", page.getTitleText());
151         assertEquals(url2.toExternalForm(), page.getUrl().toExternalForm());
152     }
153 
154     /**
155      * @throws Exception if the test fails
156      */
157     @Test
158     public void setHostWithoutPort() throws Exception {
159         final WebClient webClient = getWebClient();
160         final MockWebConnection webConnection = new MockWebConnection();
161         final URL url = new URL("http://abc.com/index.html#bottom");
162         final URL url2 = new URL("http://xyz.com/index.html#bottom");
163         final String html = DOCTYPE_HTML
164             + "<html><head><title>Test 1</title></head>\n"
165             + "<body onload='location.host=\"xyz.com\"'>...</body></html>";
166         final String html2 = DOCTYPE_HTML
167                 + "<html><head><title>Test 2</title></head><body>...</body></html>";
168         webConnection.setResponse(url, html);
169         webConnection.setResponse(url2, html2);
170         webClient.setWebConnection(webConnection);
171 
172         final HtmlPage page = webClient.getPage(url);
173         assertEquals("Test 2", page.getTitleText());
174         assertEquals(url2.toExternalForm(), page.getUrl().toExternalForm());
175     }
176 
177     /**
178      * @throws Exception if the test fails
179      */
180     @Test
181     public void setHostWithPort() throws Exception {
182         final WebClient webClient = getWebClient();
183         final MockWebConnection webConnection = new MockWebConnection();
184         final URL url = new URL("http://abc.com/index.html#bottom");
185         final URL url2 = new URL("http://xyz.com:8080/index.html#bottom");
186         final String html = DOCTYPE_HTML
187             + "<html><head><title>Test 1</title></head>\n"
188             + "<body onload='location.host=\"xyz.com:8080\"'>...</body></html>";
189         final String html2 = DOCTYPE_HTML
190                 + "<html><head><title>Test 2</title></head><body>...</body></html>";
191         webConnection.setResponse(url, html);
192         webConnection.setResponse(url2, html2);
193         webClient.setWebConnection(webConnection);
194 
195         final HtmlPage page = webClient.getPage(url);
196         assertEquals("Test 2", page.getTitleText());
197         assertEquals(url2.toExternalForm(), page.getUrl().toExternalForm());
198     }
199 
200     /**
201      * @throws Exception if the test fails
202      */
203     @Test
204     public void setPathname() throws Exception {
205         final URL url = new URL("http://abc.com/index.html?blah=bleh");
206         final URL url2 = new URL("http://abc.com/en/index.html?blah=bleh");
207         final String html = DOCTYPE_HTML
208             + "<html><head><title>Test 1</title></head>\n"
209             + "<body onload='location.pathname=\"/en/index.html\"'>...</body></html>";
210         final String html2 = DOCTYPE_HTML
211                 + "<html><head><title>Test 2</title></head><body>...</body></html>";
212 
213         getMockWebConnection().setResponse(url, html);
214         getMockWebConnection().setResponse(url2, html2);
215 
216         final HtmlPage page = getWebClientWithMockWebConnection().getPage(url);
217         assertEquals("Test 2", page.getTitleText());
218         assertEquals(url2.toExternalForm(), page.getUrl().toExternalForm());
219     }
220 
221     /**
222      * @throws Exception if the test fails
223      */
224     @Test
225     public void setPort() throws Exception {
226         final WebClient webClient = getWebClient();
227         final MockWebConnection webConnection = new MockWebConnection();
228         final URL url = new URL("http://abc.com/index.html#bottom");
229         final URL url2 = new URL("http://abc.com:88/index.html#bottom");
230         final String html = DOCTYPE_HTML
231             + "<html><head><title>Test 1</title></head>\n"
232             + "<body onload='location.port=\"88\"'>...</body></html>";
233         final String html2 = DOCTYPE_HTML
234                 + "<html><head><title>Test 2</title></head><body>...</body></html>";
235         webConnection.setResponse(url, html);
236         webConnection.setResponse(url2, html2);
237         webClient.setWebConnection(webConnection);
238 
239         final HtmlPage page = webClient.getPage(url);
240         assertEquals("Test 2", page.getTitleText());
241         assertEquals(url2.toExternalForm(), page.getUrl().toExternalForm());
242     }
243 
244     /**
245      * @throws Exception if the test fails
246      */
247     @Test
248     public void setProtocol() throws Exception {
249         final URL url = new URL("http://abc.com/index.html?blah=bleh");
250         final URL url2 = new URL("https://abc.com/index.html?blah=bleh");
251         final String html = DOCTYPE_HTML
252             + "<html><head><title>Test 1</title></head>\n"
253             + "<body onload='location.protocol=\"https\"'>...</body></html>";
254         final String html2 = DOCTYPE_HTML
255                 + "<html><head><title>Test 2</title></head><body>...</body></html>";
256 
257         getMockWebConnection().setResponse(url, html);
258         getMockWebConnection().setResponse(url2, html2);
259 
260         final HtmlPage page = getWebClientWithMockWebConnection().getPage(url);
261         assertEquals("Test 2", page.getTitleText());
262         assertEquals(url2.toExternalForm(), page.getUrl().toExternalForm());
263     }
264 
265     /**
266      * Verifies that modifying <tt>window.location.hash</tt> works, but that it doesn't
267      * force the page to reload from the server. This is very important for the Dojo
268      * unit tests, which will keep reloading themselves if the page gets reloaded.
269      *
270      * @throws Exception if the test fails
271      */
272     @Test
273     public void setHash() throws Exception {
274         final WebClient webClient = getWebClient();
275         final MockWebConnection conn = new MockWebConnection();
276 
277         final String html = DOCTYPE_HTML
278             + "<html><head><title>Test</title></head><body>\n"
279             + "<a id='a' onclick='alert(location.hash);location.hash=\"b\";alert(location.hash);'>go</a>\n"
280             + "<h2 id='b'>...</h2></body></html>";
281 
282         conn.setResponse(URL_FIRST, html);
283         webClient.setWebConnection(conn);
284 
285         final List<String> actual = new ArrayList<>();
286         webClient.setAlertHandler(new CollectingAlertHandler(actual));
287 
288         final HtmlPage page = webClient.getPage(URL_FIRST);
289         final HtmlAnchor anchor = page.getHtmlElementById("a");
290         final HtmlPage page2 = anchor.click();
291 
292         // Verify that it worked.
293         final String[] expected = new String[] {"", "#b"};
294         assertEquals(expected, actual);
295 
296         // Verify that we didn't reload the page.
297         assertTrue(page == page2);
298         assertEquals(URL_FIRST, conn.getLastWebRequest().getUrl());
299     }
300 
301     /**
302      * Regression test for http://sourceforge.net/p/htmlunit/bugs/307/.
303      * @throws Exception if the test fails
304      */
305     @Test
306     public void replaceWithFrame() throws Exception {
307         final WebClient webClient = getWebClient();
308         final MockWebConnection webConnection = new MockWebConnection();
309 
310         final String mainContent = DOCTYPE_HTML
311             + "<html>\n"
312             + "  <frameset rows='100,*'>\n"
313             + "    <frame name='menu' src='menu.html'/>\n"
314             + "    <frame name='content' src='content.html'/>\n"
315             + "  </frameset>\n"
316             + "</html>";
317         final String frameMenu = DOCTYPE_HTML
318             + "<html><body>\n"
319             + "<a href='#' id='myLink' target='content' "
320             + "onclick='parent.frames.content.location.replace(\"test.html\");return false;'>Test2</a>\n"
321             + "</body></html>";
322         final String frameContent = DOCTYPE_HTML
323                 + "<html><head><title>Start content</title></head><body></body></html>";
324         final String frameTest = DOCTYPE_HTML
325                 + "<html><head><title>Test</title></head><body></body></html>";
326 
327         webConnection.setResponse(URL_FIRST, mainContent);
328         webConnection.setResponse(new URL(URL_FIRST, "menu.html"), frameMenu);
329         webConnection.setResponse(new URL(URL_FIRST, "content.html"), frameContent);
330         webConnection.setResponse(new URL(URL_FIRST, "test.html"), frameTest);
331 
332         webClient.setWebConnection(webConnection);
333 
334         final HtmlPage page = webClient.getPage(URL_FIRST);
335         assertEquals(3, webClient.getWebWindows().size());
336         assertEquals("Start content", ((HtmlPage) page.getFrameByName("content").getEnclosedPage()).getTitleText());
337 
338         final HtmlPage menuPage = (HtmlPage) page.getFrameByName("menu").getEnclosedPage();
339         menuPage.getHtmlElementById("myLink").click();
340         assertEquals(3, webClient.getWebWindows().size());
341         assertEquals("Test", ((HtmlPage) page.getFrameByName("content").getEnclosedPage()).getTitleText());
342     }
343 
344     /**
345      * Tests that location.reload() works correctly.
346      * @throws Exception if the test fails
347      */
348     @Test
349     public void reload() throws Exception {
350         final String content = DOCTYPE_HTML
351             + "<html>\n"
352             + "  <head><title>test</title></head>\n"
353             + "  <body>\n"
354             + "    <a href='javascript:window.location.reload();' id='link1'>reload</a>\n"
355             + "  </body>\n"
356             + "</html>";
357 
358         final HtmlPage page1 = loadPage(content);
359         final HtmlAnchor link = page1.getHtmlElementById("link1");
360         final HtmlPage page2 = link.click();
361 
362         assertEquals(page1.getTitleText(), page2.getTitleText());
363         assertNotSame(page1, page2);
364     }
365 
366     /**
367      * @throws Exception if the test fails
368      */
369     @Test
370     @Alerts("c")
371     public void locationWithTarget() throws Exception {
372         final WebClient client = getWebClient();
373         final List<String> alerts = new ArrayList<>();
374         client.setAlertHandler(new CollectingAlertHandler(alerts));
375 
376         final URL url = getClass().getResource("LocationTest_locationWithTarget_a.html");
377         assertNotNull(url);
378 
379         final HtmlPage a = client.getPage(url);
380         final HtmlPage c = (HtmlPage) a.getFrameByName("c").getEnclosedPage();
381         c.getHtmlElementById("anchor").click();
382         assertEquals(getExpectedAlerts(), alerts);
383     }
384 
385     /**
386      * @throws Exception if an error occurs
387      */
388     @Test
389     public void fileUrlFormat() throws Exception {
390         final URL url = getClass().getResource("LocationTest_fileUrlFormat.html");
391         assertNotNull(url);
392 
393         final WebClient client = getWebClient();
394         final List<String> alerts = new ArrayList<>();
395         client.setAlertHandler(new CollectingAlertHandler(alerts));
396         client.getPage(url);
397 
398         assertEquals(1, alerts.size());
399         assertTrue(alerts.get(0).startsWith("file:///"));
400     }
401 }