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.event;
16  
17  import java.util.ArrayList;
18  import java.util.List;
19  
20  import org.htmlunit.CollectingAlertHandler;
21  import org.htmlunit.MockWebConnection;
22  import org.htmlunit.SimpleWebTestCase;
23  import org.htmlunit.WebClient;
24  import org.htmlunit.html.HtmlAnchor;
25  import org.htmlunit.html.HtmlButton;
26  import org.htmlunit.html.HtmlPage;
27  import org.htmlunit.html.Keyboard;
28  import org.htmlunit.junit.BrowserRunner;
29  import org.htmlunit.junit.annotation.Alerts;
30  import org.junit.Test;
31  import org.junit.runner.RunWith;
32  
33  /**
34   * Tests that when DOM events such as "onclick" have access
35   * to an {@link Event} object with context information.
36   *
37   * @author <a href="mailto:chriseldredge@comcast.net">Chris Eldredge</a>
38   * @author Ahmed Ashour
39   * @author Daniel Gredler
40   * @author Marc Guillemot
41   * @author Frank Danek
42   */
43  @RunWith(BrowserRunner.class)
44  public class Event3Test extends SimpleWebTestCase {
45  
46      /**
47       * @throws Exception if the test fails
48       */
49      @Test
50      public void eventOnKeyDown_Shift_Ctrl_Alt() throws Exception {
51          testEventOnKeyDown_Shift_Ctrl_Alt(false, false, false, "false,false,false");
52          testEventOnKeyDown_Shift_Ctrl_Alt(true,  false, false, "true,false,false", "true,false,false");
53          testEventOnKeyDown_Shift_Ctrl_Alt(false, true,  false, "false,true,false", "false,true,false");
54          testEventOnKeyDown_Shift_Ctrl_Alt(false, false, true, "false,false,true", "false,false,true");
55          testEventOnKeyDown_Shift_Ctrl_Alt(true,  true,  true, "false,true,false", "false,true,true",
56                  "true,true,true", "true,true,true");
57      }
58  
59      private void testEventOnKeyDown_Shift_Ctrl_Alt(
60              final boolean shiftKey, final boolean ctrlKey, final boolean altKey,
61              final String... expectedAlerts) throws Exception {
62          final String content = DOCTYPE_HTML
63              + "<html>\n"
64              + "<head></head>\n"
65              + "<body>\n"
66              + "  <button type='button' id='clickId'/>\n"
67              + "  <script>\n"
68              + "    function handler(_e) {\n"
69              + "      var e = _e ? _e : window.event;\n"
70              + "      alert(e.shiftKey + ',' + e.ctrlKey + ',' + e.altKey);\n"
71              + "    }\n"
72              + "    document.getElementById('clickId').onkeydown = handler;\n"
73              + "  </script>\n"
74              + "</body></html>";
75  
76          final List<String> collectedAlerts = new ArrayList<>();
77          final HtmlPage page = loadPage(content, collectedAlerts);
78          final Keyboard keyboard = new Keyboard();
79          if (ctrlKey) {
80              keyboard.press(KeyboardEvent.DOM_VK_CONTROL);
81          }
82          if (altKey) {
83              keyboard.press(KeyboardEvent.DOM_VK_ALT);
84          }
85          if (shiftKey) {
86              keyboard.press(KeyboardEvent.DOM_VK_SHIFT);
87          }
88          keyboard.type('a');
89          if (ctrlKey) {
90              keyboard.release(KeyboardEvent.DOM_VK_CONTROL);
91          }
92          if (altKey) {
93              keyboard.release(KeyboardEvent.DOM_VK_ALT);
94          }
95          if (shiftKey) {
96              keyboard.release(KeyboardEvent.DOM_VK_SHIFT);
97          }
98          page.getHtmlElementById("clickId").type(keyboard);
99          assertEquals(expectedAlerts, collectedAlerts);
100     }
101 
102     /**
103      * @throws Exception if the test fails
104      */
105     @Test
106     public void eventOnClick_Shift_Ctrl_Alt() throws Exception {
107         testEventOnClick_Shift_Ctrl_Alt(false, false, false, new String[] {"false,false,false"});
108         testEventOnClick_Shift_Ctrl_Alt(true,  false, false, new String[] {"true,false,false"});
109         testEventOnClick_Shift_Ctrl_Alt(false, true,  false, new String[] {"false,true,false"});
110         testEventOnClick_Shift_Ctrl_Alt(false, false, true,  new String[] {"false,false,true"});
111         testEventOnClick_Shift_Ctrl_Alt(true,  true,  true,  new String[] {"true,true,true"});
112     }
113 
114     private void testEventOnClick_Shift_Ctrl_Alt(final boolean shiftKey,
115             final boolean ctrlKey, final boolean altKey, final String[] expectedAlerts) throws Exception {
116         final String htmlContent = DOCTYPE_HTML
117             + "<html><head><title>foo</title></head><body>\n"
118             + "<form id='form1'>\n"
119             + "  <button name='button' type='button' id='button'>Push me</button>\n"
120             + "</form>\n"
121             + "<script>\n"
122             + "function handler(_e) {\n"
123             + "  var e = _e ? _e : window.event;\n"
124             + "  alert(e.shiftKey + ',' + e.ctrlKey + ',' + e.altKey);\n"
125             + "}\n"
126             + "document.getElementById('button').onclick = handler;\n"
127             + "</script>\n"
128             + "</body></html>";
129         final List<String> collectedAlerts = new ArrayList<>();
130         final HtmlPage page = loadPage(htmlContent, collectedAlerts);
131         final HtmlButton button = page.getHtmlElementById("button");
132 
133         final HtmlPage secondPage = button.click(shiftKey, ctrlKey, altKey);
134 
135         assertEquals(expectedAlerts, collectedAlerts);
136 
137         assertSame(page, secondPage);
138     }
139 
140     /**
141      * @throws Exception if the test fails
142      */
143     @Test
144     public void eventOnBlur() throws Exception {
145         final String content = DOCTYPE_HTML
146             + "<html><head></head><body>\n"
147             + "<form action='foo'>\n"
148             + "<input name='textField' id='textField' onblur='alert(event != null)'>\n"
149             + "<input type='submit' id='otherField'>\n"
150             + "</form>\n"
151             + "</body></html>";
152 
153         final List<String> collectedAlerts = new ArrayList<>();
154         final HtmlPage page = loadPage(content, collectedAlerts);
155         page.getHtmlElementById("textField").focus();
156         page.getHtmlElementById("otherField").focus();
157         final String[] expectedAlerts = {"true"};
158         assertEquals(expectedAlerts, collectedAlerts);
159     }
160 
161     /**
162      * Test for bug 1976960: what happens with different return values at different levels?
163      * @throws Exception if an error occurs
164      */
165     @Test
166     public void eventBubblingReturns_1() throws Exception {
167         testEventBubblingReturns("", "", "", true);
168         testEventBubblingReturns("return false;", "             ", "             ", false);
169         testEventBubblingReturns("             ", "return false;", "             ", false);
170         testEventBubblingReturns("             ", "             ", "return false;", false);
171 
172         testEventBubblingReturns("return true; ", "return true; ", "return true; ", true);
173         testEventBubblingReturns("return false;", "return true; ", "return true; ", false);
174 
175         testEventBubblingReturns("             ", "return false;", "return true; ", false);
176         testEventBubblingReturns("return false;", "return true; ", "             ", false);
177         testEventBubblingReturns("return false;", "             ", "return true; ", false);
178     }
179 
180     /**
181      * Test for bug 1976960: what happens with different return values at different levels?
182      * @throws Exception if an error occurs
183      */
184     @Test
185     @Alerts("false") // here not alerts! ;-)
186     public void eventBubblingReturns_2() throws Exception {
187         final boolean changesPage = Boolean.parseBoolean(getExpectedAlerts()[0]);
188         testEventBubblingReturns("return true; ", "return false;", "return true; ", changesPage);
189         testEventBubblingReturns("return true; ", "return true; ", "return false;", changesPage);
190 
191         testEventBubblingReturns("return true; ", "             ", "return false;", changesPage);
192         testEventBubblingReturns("             ", "return true; ", "return false;", changesPage);
193         testEventBubblingReturns("return true; ", "return false;", "             ", changesPage);
194     }
195 
196     private void testEventBubblingReturns(final String onclick1,
197         final String onclick2, final String onclick3, final boolean changesPage) throws Exception {
198 
199         final String html1 = DOCTYPE_HTML
200             + "<html><head><title>First</title></head><body>\n"
201             + "<div onclick='alert(\"d\"); " + onclick1 + "'>\n"
202             + "<span onclick='alert(\"s\"); " + onclick2 + "'>\n"
203             + "<a href='" + URL_SECOND + "' id='a' onclick='alert(\"a\"); " + onclick3 + "'>go</a>\n"
204             + "</span>\n"
205             + "</div>\n"
206             + "</body></html>";
207 
208         final String html2 = DOCTYPE_HTML + "<html><head><title>Second</title></head><body></body></html>";
209 
210         final WebClient client = getWebClientWithMockWebConnection();
211         final List<String> collectedAlerts = new ArrayList<>();
212         client.setAlertHandler(new CollectingAlertHandler(collectedAlerts));
213 
214         final MockWebConnection webConnection = getMockWebConnection();
215         webConnection.setResponse(URL_FIRST, html1);
216         webConnection.setResponse(URL_SECOND, html2);
217 
218         final HtmlPage page = client.getPage(URL_FIRST);
219         final HtmlAnchor anchor = page.getHtmlElementById("a");
220 
221         final HtmlPage secondPage = anchor.click();
222         assertEquals(new String[] {"a", "s", "d"}, collectedAlerts);
223 
224         if (changesPage) {
225             assertNotSame(page, secondPage);
226         }
227         else {
228             assertSame(page, secondPage);
229         }
230     }
231 
232 }