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