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.dom;
16  
17  import java.util.ArrayList;
18  import java.util.List;
19  
20  import org.htmlunit.AlertHandler;
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.DomNode;
26  import org.htmlunit.html.HtmlInput;
27  import org.htmlunit.html.HtmlPage;
28  import org.htmlunit.html.impl.SimpleRange;
29  import org.htmlunit.junit.BrowserRunner;
30  import org.htmlunit.junit.annotation.Alerts;
31  import org.htmlunit.junit.annotation.HtmlUnitNYI;
32  import org.junit.Test;
33  import org.junit.runner.RunWith;
34  
35  /**
36   * Unit tests for {@link Selection}.
37   *
38   * @author Daniel Gredler
39   * @author Marc Guillemot
40   * @author Frank Danek
41   * @author Ronald Brill
42   */
43  @RunWith(BrowserRunner.class)
44  public class Selection2Test extends SimpleWebTestCase {
45  
46      /**
47       * @throws Exception if an error occurs
48       */
49      @Test
50      @Alerts({"", "cx"})
51      public void stringValue() throws Exception {
52          test("", "selection", "x");
53      }
54  
55      /**
56       * @throws Exception if an error occurs
57       */
58      @Test
59      @Alerts({"null", "s1"})
60      public void anchorNode() throws Exception {
61          test("", "selection.anchorNode", "x ? x.parentNode.id : x");
62      }
63  
64      /**
65       * @throws Exception if an error occurs
66       */
67      @Test
68      @Alerts({"0", "2"})
69      public void anchorOffset() throws Exception {
70          test("", "selection.anchorOffset", "x");
71      }
72  
73      /**
74       * @throws Exception if an error occurs
75       */
76      @Test
77      @Alerts({"null", "s2"})
78      public void focusNode() throws Exception {
79          test("", "selection.focusNode", "x ? x.parentNode.id : x");
80      }
81  
82      /**
83       * @throws Exception if an error occurs
84       */
85      @Test
86      @Alerts({"0", "1"})
87      public void focusOffset() throws Exception {
88          test("", "selection.focusOffset", "x");
89      }
90  
91      /**
92       * @throws Exception if an error occurs
93       */
94      @Test
95      @Alerts({"true", "false"})
96      public void isCollapsed() throws Exception {
97          test("", "selection.isCollapsed", "x");
98      }
99  
100     /**
101      * @throws Exception if an error occurs
102      */
103     @Test
104     @Alerts({"0", "1"})
105     public void rangeCount() throws Exception {
106         test("", "selection.rangeCount", "x");
107     }
108 
109     /**
110      * @throws Exception if an error occurs
111      */
112     @Test
113     @Alerts({"0", "1"})
114     public void rangeCount2() throws Exception {
115         test("try{selection.collapseToEnd()}catch(e){alert('exception')}", "selection.rangeCount", "x");
116     }
117 
118     /**
119      * @throws Exception if an error occurs
120      */
121     @Test
122     @Alerts({"null", "null"})
123     public void removeAllRanges_anchorNode() throws Exception {
124         test("try{selection.removeAllRanges()}catch(e){alert('exception')}",
125                 "selection.anchorNode", "x ? x.parentNode.id : x");
126     }
127 
128     /**
129      * @throws Exception if an error occurs
130      */
131     @Test
132     @Alerts({"0", "0"})
133     public void removeAllRanges_anchorOffset() throws Exception {
134         test("try{selection.removeAllRanges()}catch(e){alert('exception')}",
135                 "selection.anchorOffset", "x ? x.parentNode.id : x");
136     }
137 
138     /**
139      * @throws Exception if an error occurs
140      */
141     @Test
142     @Alerts({"null", "null"})
143     public void removeAllRanges_focusNode() throws Exception {
144         test("try{selection.removeAllRanges()}catch(e){alert('exception')}",
145                 "selection.focusNode", "x ? x.parentNode.id : x");
146     }
147 
148     /**
149      * @throws Exception if an error occurs
150      */
151     @Test
152     @Alerts({"0", "0"})
153     public void removeAllRanges_focusOffset() throws Exception {
154         test("try{selection.removeAllRanges()}catch(e){alert('exception')}",
155                 "selection.focusOffset", "x ? x.parentNode.id : x");
156     }
157 
158     /**
159      * @throws Exception if an error occurs
160      */
161     @Test
162     @Alerts({"null", "s1"})
163     public void collapse() throws Exception {
164         test("try{selection.collapse(s1, 1)}catch(e){alert('exception')}",
165                 "selection.focusNode", "x ? x.id : x");
166     }
167 
168     /**
169      * @throws Exception if an error occurs
170      */
171     @Test
172     @Alerts({"null", "s2"})
173     public void collapseToEnd() throws Exception {
174         test("try{selection.collapseToEnd()}catch(e){alert('exception')}",
175                 "selection.anchorNode", "x ? x.parentNode.id : x");
176     }
177 
178     /**
179      * @throws Exception if an error occurs
180      */
181     @Test
182     @Alerts({"null", "s1"})
183     public void collapseToStart() throws Exception {
184         test("try{selection.collapseToStart()}catch(e){alert('exception')}",
185                 "selection.focusNode", "x ? x.parentNode.id : x");
186     }
187 
188     /**
189      * @throws Exception if an error occurs
190      */
191     @Test
192     @Alerts(DEFAULT = {"0", "1"},
193             CHROME = {"0", "3"},
194             EDGE = {"0", "3"})
195     @HtmlUnitNYI(CHROME = {"0", "1"},
196             EDGE = {"0", "1"})
197     public void extend() throws Exception {
198         test("try{selection.extend(s2, 1)}catch(e){alert('exception')}", "selection.focusOffset", "x");
199     }
200 
201     /**
202      * @throws Exception if an error occurs
203      */
204     @Test
205     @Alerts({"0", "0"})
206     public void selectAllChildren() throws Exception {
207         test("try{selection.selectAllChildren(document.body)}catch(e){alert('exception')}",
208                 "selection.anchorOffset", "x");
209     }
210 
211     /**
212      * @throws Exception if an error occurs
213      */
214     @Test
215     @Alerts({"none", "cx"})
216     public void getRangeAt() throws Exception {
217         test("", "selection.rangeCount > 0 ? selection.getRangeAt(0) : 'none'", "x");
218     }
219 
220     /**
221      * @throws Exception if an error occurs
222      */
223     @Test
224     @Alerts({"", "true"})
225     public void getRangeAt_prototype() throws Exception {
226         test("", "selection.rangeCount > 0 ? (selection.getRangeAt(0) instanceof Range) : ''", "x");
227     }
228 
229     /**
230      * @throws Exception if an error occurs
231      */
232     @Test
233     @Alerts({"None", "None"})
234     public void empty() throws Exception {
235         test("try{selection.empty()}catch(e){alert('exception')}", "selection.type", "x ? x : 'undefined'");
236     }
237 
238     /**
239      * @throws Exception if an error occurs
240      */
241     @Test
242     @Alerts({"unsupported action", "unsupported action"})
243     public void createRange() throws Exception {
244         test("", "selection.createRange()", "x");
245     }
246 
247     private void test(final String action, final String x, final String alert)
248         throws Exception {
249 
250         final String html = DOCTYPE_HTML
251             + "<html>\n"
252             + "<body onload='test()'>\n"
253             + "  <span id='s1'>abc</span><span id='s2'>xyz</span><span id='s3'>foo</span>\n"
254             + "  <input type='button' id='b' onclick=\"" + action + ";test();\" value='click'></input>\n"
255             + "<script>\n"
256             + "  var selection = document.selection; // IE\n"
257             + "  if(!selection) selection = window.getSelection(); // FF\n"
258             + "  var s1 = document.getElementById('s1');\n"
259             + "  var s2 = document.getElementById('s2');\n"
260             + "  function test() {\n"
261             + "    try {\n"
262             + "      var x = " + x + ";\n"
263             + "      alert(" + alert + ");\n"
264             + "    } catch(e) {\n"
265             + "      alert('unsupported action');\n"
266             + "    }\n"
267             + "  }\n"
268             + "</script>\n"
269             + "</body></html>";
270 
271         final WebClient client = getWebClient();
272 
273         final MockWebConnection conn = new MockWebConnection();
274         conn.setDefaultResponse(html);
275         client.setWebConnection(conn);
276 
277         final List<String> actual = new ArrayList<>();
278         final AlertHandler alertHandler = new CollectingAlertHandler(actual);
279         client.setAlertHandler(alertHandler);
280 
281         final HtmlPage page = client.getPage(URL_FIRST);
282         final DomNode s1Text = page.getHtmlElementById("s1").getFirstChild();
283         final DomNode s2Text = page.getHtmlElementById("s2").getFirstChild();
284         final HtmlInput input = page.getHtmlElementById("b");
285 
286         final SimpleRange range = new SimpleRange();
287         range.setStart(s1Text, 2);
288         range.setEnd(s2Text, 1);
289         page.setSelectionRange(range);
290         input.click();
291 
292         assertEquals(getExpectedAlerts(), actual);
293     }
294 
295 }