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