Upstream version 9.37.195.0
[platform/framework/web/crosswalk.git] / src / content / public / test / android / javatests / src / org / chromium / content / browser / test / util / DOMUtils.java
1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.content.browser.test.util;
6
7 import android.graphics.Rect;
8 import android.test.ActivityInstrumentationTestCase2;
9 import android.util.JsonReader;
10
11 import junit.framework.Assert;
12
13 import org.chromium.content.browser.ContentViewCore;
14
15 import java.io.IOException;
16 import java.io.StringReader;
17 import java.util.concurrent.TimeoutException;
18
19 /**
20  * Collection of DOM-based utilities.
21  */
22 public class DOMUtils {
23
24     /**
25      * Returns whether the video with given {@code nodeId} has ended.
26      */
27     public static boolean hasVideoEnded(final ContentViewCore viewCore, final String nodeId)
28             throws InterruptedException, TimeoutException {
29         return getNodeField("ended", viewCore, nodeId, Boolean.class);
30     }
31
32     /**
33      * Wait until the end of the video with given {@code nodeId}.
34      * @return Whether the video has ended.
35      */
36     public static boolean waitForEndOfVideo(final ContentViewCore viewCore, final String nodeId)
37             throws InterruptedException {
38         return CriteriaHelper.pollForCriteria(new Criteria() {
39             @Override
40             public boolean isSatisfied() {
41                 try {
42                     return DOMUtils.hasVideoEnded(viewCore, nodeId);
43                 } catch (InterruptedException e) {
44                     // Intentionally do nothing
45                     return false;
46                 } catch (TimeoutException e) {
47                     // Intentionally do nothing
48                     return false;
49                 }
50             }
51         });
52     }
53
54     /**
55      * Makes the document exit fullscreen.
56      */
57     public static void exitFullscreen(final ContentViewCore viewCore) {
58         StringBuilder sb = new StringBuilder();
59         sb.append("(function() {");
60         sb.append("  if (document.webkitExitFullscreen) document.webkitExitFullscreen();");
61         sb.append("})();");
62
63         JavaScriptUtils.executeJavaScript(viewCore, sb.toString());
64     }
65
66     /**
67      * Returns the rect boundaries for a node by its id.
68      */
69     public static Rect getNodeBounds(final ContentViewCore viewCore, String nodeId)
70             throws InterruptedException, TimeoutException {
71         StringBuilder sb = new StringBuilder();
72         sb.append("(function() {");
73         sb.append("  var node = document.getElementById('" + nodeId + "');");
74         sb.append("  if (!node) return null;");
75         sb.append("  var width = Math.round(node.offsetWidth);");
76         sb.append("  var height = Math.round(node.offsetHeight);");
77         sb.append("  var x = -window.scrollX;");
78         sb.append("  var y = -window.scrollY;");
79         sb.append("  do {");
80         sb.append("    x += node.offsetLeft;");
81         sb.append("    y += node.offsetTop;");
82         sb.append("  } while (node = node.offsetParent);");
83         sb.append("  return [ Math.round(x), Math.round(y), width, height ];");
84         sb.append("})();");
85
86         String jsonText = JavaScriptUtils.executeJavaScriptAndWaitForResult(
87                 viewCore, sb.toString());
88
89         Assert.assertFalse("Failed to retrieve bounds for " + nodeId,
90                 jsonText.trim().equalsIgnoreCase("null"));
91
92         JsonReader jsonReader = new JsonReader(new StringReader(jsonText));
93         int[] bounds = new int[4];
94         try {
95             jsonReader.beginArray();
96             int i = 0;
97             while (jsonReader.hasNext()) {
98                 bounds[i++] = jsonReader.nextInt();
99             }
100             jsonReader.endArray();
101             Assert.assertEquals("Invalid bounds returned.", 4, i);
102
103             jsonReader.close();
104         } catch (IOException exception) {
105             Assert.fail("Failed to evaluate JavaScript: " + jsonText + "\n" + exception);
106         }
107
108         return new Rect(bounds[0], bounds[1], bounds[0] + bounds[2], bounds[1] + bounds[3]);
109     }
110
111     /**
112      * Focus a DOM node by its id.
113      */
114     public static void focusNode(final ContentViewCore viewCore, String nodeId)
115             throws InterruptedException, TimeoutException {
116         StringBuilder sb = new StringBuilder();
117         sb.append("(function() {");
118         sb.append("  var node = document.getElementById('" + nodeId + "');");
119         sb.append("  if (node) node.focus();");
120         sb.append("})();");
121
122         JavaScriptUtils.executeJavaScriptAndWaitForResult(viewCore, sb.toString());
123     }
124
125     /**
126      * Click a DOM node by its id.
127      */
128     public static void clickNode(ActivityInstrumentationTestCase2 activityTestCase,
129             final ContentViewCore viewCore, String nodeId)
130             throws InterruptedException, TimeoutException {
131         int[] clickTarget = getClickTargetForNode(viewCore, nodeId);
132         TouchCommon touchCommon = new TouchCommon(activityTestCase);
133         touchCommon.singleClickView(viewCore.getContainerView(), clickTarget[0], clickTarget[1]);
134     }
135
136     /**
137      * Long-press a DOM node by its id.
138      */
139     public static void longPressNode(ActivityInstrumentationTestCase2 activityTestCase,
140             final ContentViewCore viewCore, String nodeId)
141             throws InterruptedException, TimeoutException {
142         int[] clickTarget = getClickTargetForNode(viewCore, nodeId);
143         TouchCommon touchCommon = new TouchCommon(activityTestCase);
144         touchCommon.longPressView(viewCore.getContainerView(), clickTarget[0], clickTarget[1]);
145     }
146
147     /**
148      * Scrolls the view to ensure that the required DOM node is visible.
149      */
150     public static void scrollNodeIntoView(ContentViewCore viewCore, String nodeId)
151             throws InterruptedException, TimeoutException {
152         JavaScriptUtils.executeJavaScriptAndWaitForResult(viewCore,
153                 "document.getElementById('" + nodeId + "').scrollIntoView()");
154     }
155
156     /**
157      * Returns the contents of the node by its id.
158      */
159     public static String getNodeContents(ContentViewCore viewCore, String nodeId)
160             throws InterruptedException, TimeoutException {
161         return getNodeField("textContent", viewCore, nodeId, String.class);
162     }
163
164     /**
165      * Returns the value of the node by its id.
166      */
167     public static String getNodeValue(final ContentViewCore viewCore, String nodeId)
168             throws InterruptedException, TimeoutException {
169         return getNodeField("value", viewCore, nodeId, String.class);
170     }
171
172     /**
173      * Returns the string value of a field of the node by its id.
174      */
175     public static String getNodeField(String fieldName, final ContentViewCore viewCore,
176             String nodeId)
177             throws InterruptedException, TimeoutException {
178         return getNodeField(fieldName, viewCore, nodeId, String.class);
179     }
180
181     private static <T> T getNodeField(String fieldName, final ContentViewCore viewCore,
182             String nodeId, Class<T> valueType)
183             throws InterruptedException, TimeoutException {
184         StringBuilder sb = new StringBuilder();
185         sb.append("(function() {");
186         sb.append("  var node = document.getElementById('" + nodeId + "');");
187         sb.append("  if (!node) return null;");
188         sb.append("  return [ node." + fieldName + " ];");
189         sb.append("})();");
190
191         String jsonText = JavaScriptUtils.executeJavaScriptAndWaitForResult(
192                 viewCore, sb.toString());
193         Assert.assertFalse("Failed to retrieve contents for " + nodeId,
194                 jsonText.trim().equalsIgnoreCase("null"));
195
196         JsonReader jsonReader = new JsonReader(new StringReader(jsonText));
197         T value = null;
198         try {
199             jsonReader.beginArray();
200             if (jsonReader.hasNext()) value = readValue(jsonReader, valueType);
201             jsonReader.endArray();
202             Assert.assertNotNull("Invalid contents returned.", value);
203
204             jsonReader.close();
205         } catch (IOException exception) {
206             Assert.fail("Failed to evaluate JavaScript: " + jsonText + "\n" + exception);
207         }
208         return value;
209     }
210
211     @SuppressWarnings("unchecked")
212     private static <T> T readValue(JsonReader jsonReader, Class<T> valueType)
213             throws IOException {
214         if (valueType.equals(String.class)) return ((T) jsonReader.nextString());
215         if (valueType.equals(Boolean.class)) return ((T) ((Boolean) jsonReader.nextBoolean()));
216         if (valueType.equals(Integer.class)) return ((T) ((Integer) jsonReader.nextInt()));
217         if (valueType.equals(Long.class)) return ((T) ((Long) jsonReader.nextLong()));
218         if (valueType.equals(Double.class)) return ((T) ((Double) jsonReader.nextDouble()));
219
220         throw new IllegalArgumentException("Cannot read values of type " + valueType);
221     }
222
223     /**
224      * Wait until a given node has non-zero bounds.
225      * @return Whether the node started having non-zero bounds.
226      */
227     public static boolean waitForNonZeroNodeBounds(final ContentViewCore viewCore,
228             final String nodeName)
229             throws InterruptedException {
230         return CriteriaHelper.pollForCriteria(new Criteria() {
231             @Override
232             public boolean isSatisfied() {
233                 try {
234                     return !DOMUtils.getNodeBounds(viewCore, nodeName).isEmpty();
235                 } catch (InterruptedException e) {
236                     // Intentionally do nothing
237                     return false;
238                 } catch (TimeoutException e) {
239                     // Intentionally do nothing
240                     return false;
241                 }
242             }
243         });
244     }
245
246     /**
247      * Returns click targets for a given DOM node.
248      */
249     private static int[] getClickTargetForNode(ContentViewCore viewCore, String nodeName)
250             throws InterruptedException, TimeoutException {
251         Rect bounds = getNodeBounds(viewCore, nodeName);
252         Assert.assertNotNull("Failed to get DOM element bounds of '" + nodeName + "'.", bounds);
253
254         int clickX = (int) viewCore.getRenderCoordinates().fromLocalCssToPix(bounds.exactCenterX())
255                 + viewCore.getViewportSizeOffsetWidthPix();
256         int clickY = (int) viewCore.getRenderCoordinates().fromLocalCssToPix(bounds.exactCenterY())
257                 + viewCore.getViewportSizeOffsetHeightPix();
258         return new int[] { clickX, clickY };
259     }
260 }