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.net.URL;
18  import java.util.ArrayList;
19  import java.util.List;
20  import java.util.Map;
21  
22  import org.htmlunit.CollectingAlertHandler;
23  import org.htmlunit.HttpHeader;
24  import org.htmlunit.MockWebConnection;
25  import org.htmlunit.SimpleWebTestCase;
26  import org.htmlunit.WebClient;
27  import org.htmlunit.WebWindow;
28  import org.htmlunit.junit.annotation.Alerts;
29  import org.htmlunit.junit.annotation.HtmlUnitNYI;
30  import org.junit.jupiter.api.Test;
31  
32  /**
33   * Tests for {@link HtmlFrameSet}.
34   *
35   * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
36   * @author Marc Guillemot
37   * @author Hans Donner
38   * @author Ahmed Ashour
39   * @author Ronald Brill
40   */
41  public class HtmlFrameSetTest extends SimpleWebTestCase {
42  
43      /**
44       * @throws Exception if the test fails
45       */
46      @Test
47      public void loadingFrameSet() throws Exception {
48          final String firstContent = DOCTYPE_HTML
49              + "<html><head><title>First</title></head>\n"
50              + "<frameset cols='130,*'>\n"
51              + "  <frame scrolling='no' name='left' src='" + URL_SECOND + "' frameborder='1' />\n"
52              + "  <frame scrolling='auto' name='right' src='" + URL_THIRD + "' frameborder='1' />\n"
53              + "  <noframes>\n"
54              + "    <body>Frames not supported</body>\n"
55              + "  </noframes>\n"
56              + "</frameset>\n"
57              + "</html>";
58          final String secondContent = DOCTYPE_HTML + "<html><head><title>Second</title></head><body></body></html>";
59          final String thirdContent  = DOCTYPE_HTML + "<html><head><title>Third</title></head><body></body></html>";
60  
61          final WebClient webClient = getWebClientWithMockWebConnection();
62  
63          final MockWebConnection webConnection = getMockWebConnection();
64          webConnection.setResponse(URL_FIRST, firstContent);
65          webConnection.setResponse(URL_SECOND, secondContent);
66          webConnection.setResponse(URL_THIRD, thirdContent);
67  
68          final HtmlPage firstPage = webClient.getPage(URL_FIRST);
69          assertEquals("First", firstPage.getTitleText());
70  
71          final WebWindow secondWebWindow = webClient.getWebWindowByName("left");
72          assertSame(firstPage, ((FrameWindow) secondWebWindow).getEnclosingPage());
73          assertEquals("Second", ((HtmlPage) secondWebWindow.getEnclosedPage()).getTitleText());
74  
75          final WebWindow thirdWebWindow = webClient.getWebWindowByName("right");
76          assertTrue(FrameWindow.class.isInstance(thirdWebWindow));
77          assertSame(firstPage, ((FrameWindow) thirdWebWindow).getEnclosingPage());
78          assertEquals("Third", ((HtmlPage) thirdWebWindow.getEnclosedPage()).getTitleText());
79      }
80  
81      /**
82       * @throws Exception if the test fails
83       */
84      @Test
85      public void loadingIFrames() throws Exception {
86          final String firstContent = DOCTYPE_HTML
87              + "<html><head><title>First</title></head>\n"
88              + "<body>\n"
89              + "  <iframe name='left' src='" + URL_SECOND + "' />\n"
90              + "  some stuff"
91              + "</html>";
92          final String secondContent = DOCTYPE_HTML + "<html><head><title>Second</title></head><body></body></html>";
93  
94          final WebClient webClient = getWebClientWithMockWebConnection();
95  
96          final MockWebConnection webConnection = getMockWebConnection();
97          webConnection.setResponse(URL_FIRST, firstContent);
98          webConnection.setResponse(URL_SECOND, secondContent);
99  
100         final HtmlPage firstPage = webClient.getPage(URL_FIRST);
101         assertEquals("First", firstPage.getTitleText());
102 
103         final WebWindow secondWebWindow = webClient.getWebWindowByName("left");
104         assertTrue(FrameWindow.class.isInstance(secondWebWindow));
105         assertSame(firstPage, ((FrameWindow) secondWebWindow).getEnclosingPage());
106         assertEquals("Second", ((HtmlPage) secondWebWindow.getEnclosedPage()).getTitleText());
107     }
108 
109     /**
110      * Regression test for Bug #203.
111      * @throws Exception if the test fails
112      */
113     @Test
114     public void loadingFrameSetWithRelativePaths() throws Exception {
115         final String framesContent = DOCTYPE_HTML
116             + "<html><head><title>Frames</title></head>\n"
117             + "<frameset rows='110,*'>\n"
118             + "  <frame src='subdir1/menu.html' name='menu' scrolling='no' border='0' noresize>\n"
119             + "  <frame src='subdir2/first.html' name='test' border='0' auto>\n"
120             + "</frameset>\n"
121             + "<noframes>\n"
122             + "  <body>Frames not supported</body>\n"
123             + "</noframes>\n"
124             + "</html>";
125         final String menuContent = DOCTYPE_HTML
126             + "<html><head><title>Menu</title></head>\n"
127             + "<body>\n"
128             + "  <script language='javascript'>\n"
129             + "    function changeEditPage() {parent.test.location='../second.html';}\n"
130             + "  </script>\n"
131             + "  <a name ='changePage' onClick='javascript:changeEditPage();' href='#'>Click</a>."
132             + "</body>\n"
133             + "</html>";
134         final String firstContent = DOCTYPE_HTML
135             + "<html><head><title>First</title></head>\n"
136             + "<body>First/body>\n"
137             + "</html>";
138         final String secondContent = DOCTYPE_HTML
139             + "<html><head><title>Second</title></head>\n"
140             + "<body>Second</body>\n"
141             + "</html>";
142         final String baseUrl = "http://framestest";
143 
144         final URL framesURL = new URL(baseUrl + "/frames.html");
145         final URL menuURL = new URL(baseUrl + "/subdir1/menu.html");
146         final URL firstURL = new URL(baseUrl + "/subdir2/first.html");
147         final URL secondURL = new URL(baseUrl + "/second.html");
148 
149         final WebClient webClient = getWebClientWithMockWebConnection();
150 
151         final MockWebConnection webConnection = getMockWebConnection();
152         webConnection.setResponse(framesURL, framesContent);
153         webConnection.setResponse(menuURL, menuContent);
154         webConnection.setResponse(firstURL, firstContent);
155         webConnection.setResponse(secondURL, secondContent);
156 
157         final HtmlPage framesPage = webClient.getPage(framesURL);
158         assertEquals("Frames", framesPage.getTitleText());
159 
160         final WebWindow menuWebWindow = webClient.getWebWindowByName("menu");
161         final HtmlPage menuPage = (HtmlPage) menuWebWindow.getEnclosedPage();
162         assertEquals("Menu", menuPage.getTitleText());
163 
164         final WebWindow testWebWindow = webClient.getWebWindowByName("test");
165         assertEquals("First", ((HtmlPage) testWebWindow.getEnclosedPage()).getTitleText());
166 
167         final HtmlAnchor changePage = menuPage.getAnchorByName("changePage");
168         changePage.click();
169         assertEquals("Second", ((HtmlPage) testWebWindow.getEnclosedPage()).getTitleText());
170     }
171 
172     /**
173      * Forward referencing issue in FrameSet.
174      * Test for bug #291
175      * @throws Exception if the test fails
176      */
177     @Test
178     public void frameOnloadAccessOtherFrame() throws Exception {
179         final String framesContent = DOCTYPE_HTML
180             + "<html><head><title>Main</title>\n"
181             + "</head>\n"
182             + "  <frameset cols='18%,*'>\n"
183             + "    <frame name='menu' src='" + URL_SECOND + "'>\n"
184             + "    <frame name='button_pallete' src='about:blank'>\n"
185             + "  </frameset>\n"
186             + "</html>";
187 
188         final String menuContent = DOCTYPE_HTML
189             + "<html><head><title>Menu</title>\n"
190             + "  <script>\n"
191             + "    function init() {\n"
192             + "      var oFrame = top.button_pallete;\n"
193             + "      alert((oFrame == null) ? 'Failure' : 'Success');\n"
194             + "    }\n"
195             + "  </script>\n"
196             + "</head>\n"
197             + "<body onload='init()'></body></html>";
198 
199         final WebClient webClient = getWebClientWithMockWebConnection();
200 
201         final MockWebConnection webConnection = getMockWebConnection();
202 
203         final List<String> collectedAlerts = new ArrayList<>();
204         final String[] expectedAlerts = {"Success"};
205         webClient.setAlertHandler(new CollectingAlertHandler(collectedAlerts));
206 
207         webConnection.setResponse(URL_FIRST, framesContent);
208         webConnection.setResponse(URL_SECOND, menuContent);
209 
210         final HtmlPage framesPage = webClient.getPage(URL_FIRST);
211         assertEquals("Main", framesPage.getTitleText());
212 
213         assertEquals(expectedAlerts, collectedAlerts);
214     }
215 
216     /**
217      * @throws Exception if the test fails
218      */
219     @Test
220     public void refererHeader() throws Exception {
221         final String firstContent = DOCTYPE_HTML
222             + "<html><head><title>First</title></head>\n"
223             + "<frameset cols='130,*'>\n"
224             + "  <frame scrolling='no' name='left' src='" + URL_SECOND + "' frameborder='1' />\n"
225             + "  <noframes>\n"
226             + "    <body>Frames not supported</body>\n"
227             + "  </noframes>\n"
228             + "</frameset>\n"
229             + "</html>";
230         final String secondContent = DOCTYPE_HTML + "<html><head><title>Second</title></head><body></body></html>";
231 
232         final WebClient webClient = getWebClientWithMockWebConnection();
233 
234         final MockWebConnection webConnection = getMockWebConnection();
235         webConnection.setResponse(URL_FIRST, firstContent);
236         webConnection.setResponse(URL_SECOND, secondContent);
237 
238         final HtmlPage firstPage = webClient.getPage(URL_FIRST);
239         assertEquals("First", firstPage.getTitleText());
240 
241         final Map<String, String> lastAdditionalHeaders = webConnection.getLastAdditionalHeaders();
242         assertEquals(URL_FIRST.toString(), lastAdditionalHeaders.get(HttpHeader.REFERER));
243     }
244 
245     /**
246      * @throws Exception if the test fails
247      */
248     @Test
249     public void scriptUnderNoFrames() throws Exception {
250         final String firstContent = DOCTYPE_HTML
251             + "<html><head><title>first</title></head>\n"
252             + "<frameset cols='100%'>\n"
253             + "  <frame src='" + URL_SECOND + "'' id='frame1'/>\n"
254             + "  <noframes>\n"
255             + "    <div><script>alert(1);</script></div>\n"
256             + "    <script src='" + URL_THIRD + "'></script>\n"
257             + "   </noframes>\n"
258             + "</frameset></html>";
259         final String secondContent = DOCTYPE_HTML
260             + "<html><body><script>alert(2);</script></body></html>";
261         final String thirdContent
262             = "alert('3');\n";
263         final WebClient client = getWebClientWithMockWebConnection();
264 
265         final MockWebConnection webConnection = getMockWebConnection();
266         webConnection.setResponse(URL_FIRST, firstContent);
267         webConnection.setResponse(URL_SECOND, secondContent);
268         webConnection.setResponse(URL_THIRD, thirdContent, "text/javascript");
269 
270         final String[] expectedAlerts = {"2"};
271         final ArrayList<String> collectedAlerts = new ArrayList<>();
272         client.setAlertHandler(new CollectingAlertHandler(collectedAlerts));
273 
274         client.getPage(URL_FIRST);
275         assertEquals(expectedAlerts, collectedAlerts);
276     }
277 
278     /**
279      * Regression test for Bug #521.
280      * @throws Exception if the test fails
281      */
282     @Test
283     public void frameReloadsAnother() throws Exception {
284         final URL framesetURL = new URL("http://domain/frameset.html");
285         final URL leftURL = new URL("http://domain/left.html");
286         final URL rightURL = new URL("http://domain/right.html");
287         final URL right2URL = new URL("http://domain/right2.html");
288 
289         final String framesetHtml = DOCTYPE_HTML
290             + "<html><head><title>Test Frameset</title><script>\n"
291             + "function writeLeftFrame() {\n"
292             + "  var leftDoc = leftFrame.document;\n"
293             + "  leftDoc.open();\n"
294             + "  leftDoc.writeln('<HTML><BODY>This is the left frame.<br><br>'\n"
295             + "    + '<A HREF=\"javaScript:parent.showNextPage()\" id=\"node_0\">Show version 2 '\n"
296             + "    + 'of right frame</A></BODY></HTML>');\n"
297             + "  leftDoc.close();\n"
298             + "}\n"
299             + "\n"
300             + "function showNextPage() {\n"
301             + "  rightFrame.location = 'right2.html';\n"
302             + "}\n"
303             + "</script></head>\n"
304             + "<frameset cols='300,*' border=1>\n"
305             + "  <frame name='leftFrame' src='left.html'>\n"
306             + "  <frame name='rightFrame' src='right.html'>\n"
307             + "</frameset>\n"
308             + "</html>";
309 
310         final String leftHtml = DOCTYPE_HTML
311             + "<html>\n"
312             + "<body onLoad=\"parent.writeLeftFrame()\">\n"
313             + "  This is the initial left frame, to be overwritten immediately (onLoad).\n"
314             + "</body></html>";
315 
316         final String rightHtml = DOCTYPE_HTML
317             + "<html>\n"
318             + "<body>\n"
319             + "  This is the right frame, version 1.\n"
320             + "</body></html>";
321 
322         final String right2Html = DOCTYPE_HTML
323             + "<html>\n"
324             + "<body>\n"
325             + "  This is the right frame, version 2.\n"
326             + "</body></html>";
327 
328         final WebClient client = getWebClientWithMockWebConnection();
329         final List<String> collectedAlerts = new ArrayList<>();
330         client.setAlertHandler(new CollectingAlertHandler(collectedAlerts));
331 
332         final MockWebConnection webConnection = getMockWebConnection();
333         webConnection.setResponse(framesetURL, framesetHtml);
334         webConnection.setResponse(leftURL, leftHtml);
335         webConnection.setResponse(rightURL, rightHtml);
336         webConnection.setResponse(right2URL, right2Html);
337 
338         final HtmlPage page = client.getPage(framesetURL);
339         final HtmlPage leftPage = (HtmlPage) page.getFrames().get(0).getEnclosedPage();
340         final WebWindow rightWindow = page.getFrames().get(1);
341         assertTrue(((HtmlPage) rightWindow.getEnclosedPage()).asXml().contains("version 1"));
342         leftPage.getAnchors().get(0).click();
343         assertTrue(((HtmlPage) rightWindow.getEnclosedPage()).asXml().contains("version 2"));
344     }
345 
346     /**
347      * @throws Exception if the test fails
348      */
349     @Test
350     @Alerts("3")
351     @HtmlUnitNYI(CHROME = "2",
352             EDGE = "2",
353             FF = "2",
354             FF_ESR = "2")
355     public void onunload() throws Exception {
356         final String mainHtml =
357             "<frameset onunload=\"document.location.href='3.html'\">\n"
358             + "<frame name='f1' src='1.html'/>\n"
359             + "</frameset>";
360 
361         final String frame1 = DOCTYPE_HTML
362             + "<html><head><title>1</title></head>\n"
363             + "<body><button id='myButton' onclick=\"top.location.href='2.html'\"/></body>\n"
364             + "</html>";
365 
366         final String html2 = DOCTYPE_HTML
367             + "<html><head><title>2</title></head>\n"
368             + "<body>hello</body>\n"
369             + "</html>";
370 
371         final String html3 = DOCTYPE_HTML
372             + "<html><head><title>3</title></head>\n"
373             + "<body>hello</body>\n"
374             + "</html>";
375 
376         final WebClient webClient = getWebClientWithMockWebConnection();
377         final List<String> collectedAlerts = new ArrayList<>();
378         webClient.setAlertHandler(new CollectingAlertHandler(collectedAlerts));
379 
380         final MockWebConnection conn = getMockWebConnection();
381         conn.setResponse(URL_FIRST, mainHtml);
382         conn.setResponse(new URL(URL_FIRST, "1.html"), frame1);
383         conn.setResponse(new URL(URL_FIRST, "2.html"), html2);
384         conn.setResponse(new URL(URL_FIRST, "3.html"), html3);
385 
386         final HtmlPage mainPage = webClient.getPage(URL_FIRST);
387         final HtmlPage framePage = (HtmlPage) mainPage.getFrameByName("f1").getEnclosedPage();
388         final HtmlPage page = framePage.getHtmlElementById("myButton").click();
389         assertEquals(getExpectedAlerts()[0], page.getTitleText());
390     }
391 
392     /**
393      * @throws Exception if the test fails
394      */
395     @Test
396     public void closeShouldRemoveFramesetWindows() throws Exception {
397         final String firstContent = DOCTYPE_HTML
398             + "<html><head><title>First</title></head>\n"
399             + "<frameset cols='130,*'>\n"
400             + "  <frame scrolling='no' name='left' src='" + URL_SECOND + "' frameborder='1' />\n"
401             + "  <frame scrolling='auto' name='right' src='" + URL_THIRD + "' frameborder='1' />\n"
402             + "  <noframes>\n"
403             + "    <body>Frames not supported</body>\n"
404             + "  </noframes>\n"
405             + "</frameset>\n"
406             + "</html>";
407         final String secondContent = DOCTYPE_HTML + "<html><head><title>Second</title></head><body></body></html>";
408         final String thirdContent  = DOCTYPE_HTML + "<html><head><title>Third</title></head><body></body></html>";
409 
410         @SuppressWarnings("resource")
411         final WebClient webClient = getWebClientWithMockWebConnection();
412 
413         final MockWebConnection webConnection = getMockWebConnection();
414         webConnection.setResponse(URL_FIRST, firstContent);
415         webConnection.setResponse(URL_SECOND, secondContent);
416         webConnection.setResponse(URL_THIRD, thirdContent);
417 
418         final HtmlPage firstPage = webClient.getPage(URL_FIRST);
419         assertEquals("First", firstPage.getTitleText());
420 
421         assertEquals(3, webClient.getWebWindows().size());
422 
423         webClient.close();
424 
425         assertEquals(0, webClient.getWebWindows().size());
426         assertEquals(0, webClient.getTopLevelWindows().size());
427         assertNull(webClient.getCurrentWindow());
428     }
429 
430     /**
431      * @throws Exception if the test fails
432      */
433     @Test
434     public void navigateShouldRemoveFramesetWindows() throws Exception {
435         final String firstContent = DOCTYPE_HTML
436             + "<html><head><title>First</title></head>\n"
437             + "<frameset cols='130,*'>\n"
438             + "  <frame scrolling='no' name='left' src='" + URL_SECOND + "' frameborder='1' />\n"
439             + "  <frame scrolling='auto' name='right' src='" + URL_THIRD + "' frameborder='1' />\n"
440             + "  <noframes>\n"
441             + "    <body>Frames not supported</body>\n"
442             + "  </noframes>\n"
443             + "</frameset>\n"
444             + "</html>";
445         final String secondContent = DOCTYPE_HTML + "<html><head><title>Second</title></head><body></body></html>";
446         final String thirdContent  = DOCTYPE_HTML + "<html><head><title>Third</title></head><body></body></html>";
447 
448         final WebClient webClient = getWebClientWithMockWebConnection();
449 
450         final MockWebConnection webConnection = getMockWebConnection();
451         webConnection.setResponse(URL_FIRST, firstContent);
452         webConnection.setResponse(URL_SECOND, secondContent);
453         webConnection.setResponse(URL_THIRD, thirdContent);
454 
455         HtmlPage page = webClient.getPage(URL_FIRST);
456         assertEquals("First", page.getTitleText());
457 
458         assertEquals(3, webClient.getWebWindows().size());
459 
460         page = webClient.getPage(URL_SECOND);
461         assertEquals("Second", page.getTitleText());
462 
463         assertEquals(1, webClient.getWebWindows().size());
464     }
465 
466 }