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.
5 package org.chromium.content.browser.test.util;
7 import android.graphics.Rect;
8 import android.test.ActivityInstrumentationTestCase2;
9 import android.util.JsonReader;
11 import junit.framework.Assert;
13 import org.chromium.content.browser.ContentViewCore;
15 import java.io.IOException;
16 import java.io.StringReader;
17 import java.util.concurrent.TimeoutException;
20 * Collection of DOM-based utilities.
22 public class DOMUtils {
25 * Returns the rect boundaries for a node by its id.
27 public static Rect getNodeBounds(final ContentViewCore viewCore, String nodeId)
28 throws InterruptedException, TimeoutException {
29 StringBuilder sb = new StringBuilder();
30 sb.append("(function() {");
31 sb.append(" var node = document.getElementById('" + nodeId + "');");
32 sb.append(" if (!node) return null;");
33 sb.append(" var width = Math.round(node.offsetWidth);");
34 sb.append(" var height = Math.round(node.offsetHeight);");
35 sb.append(" var x = -window.scrollX;");
36 sb.append(" var y = -window.scrollY;");
38 sb.append(" x += node.offsetLeft;");
39 sb.append(" y += node.offsetTop;");
40 sb.append(" } while (node = node.offsetParent);");
41 sb.append(" return [ Math.round(x), Math.round(y), width, height ];");
44 String jsonText = JavaScriptUtils.executeJavaScriptAndWaitForResult(
45 viewCore, sb.toString());
47 Assert.assertFalse("Failed to retrieve bounds for " + nodeId,
48 jsonText.trim().equalsIgnoreCase("null"));
50 JsonReader jsonReader = new JsonReader(new StringReader(jsonText));
51 int[] bounds = new int[4];
53 jsonReader.beginArray();
55 while (jsonReader.hasNext()) {
56 bounds[i++] = jsonReader.nextInt();
58 jsonReader.endArray();
59 Assert.assertEquals("Invalid bounds returned.", 4, i);
62 } catch (IOException exception) {
63 Assert.fail("Failed to evaluate JavaScript: " + jsonText + "\n" + exception);
66 return new Rect(bounds[0], bounds[1], bounds[0] + bounds[2], bounds[1] + bounds[3]);
70 * Focus a DOM node by its id.
72 public static void focusNode(final ContentViewCore viewCore, String nodeId)
73 throws InterruptedException, TimeoutException {
74 StringBuilder sb = new StringBuilder();
75 sb.append("(function() {");
76 sb.append(" var node = document.getElementById('" + nodeId + "');");
77 sb.append(" if (node) node.focus();");
80 JavaScriptUtils.executeJavaScriptAndWaitForResult(viewCore, sb.toString());
84 * Click a DOM node by its id.
86 public static void clickNode(ActivityInstrumentationTestCase2 activityTestCase,
87 final ContentViewCore viewCore, String nodeId)
88 throws InterruptedException, TimeoutException {
89 int[] clickTarget = getClickTargetForNode(viewCore, nodeId);
90 TouchCommon touchCommon = new TouchCommon(activityTestCase);
91 touchCommon.singleClickView(viewCore.getContainerView(), clickTarget[0], clickTarget[1]);
95 * Long-press a DOM node by its id.
97 public static void longPressNode(ActivityInstrumentationTestCase2 activityTestCase,
98 final ContentViewCore viewCore, String nodeId)
99 throws InterruptedException, TimeoutException {
100 int[] clickTarget = getClickTargetForNode(viewCore, nodeId);
101 TouchCommon touchCommon = new TouchCommon(activityTestCase);
102 touchCommon.longPressView(viewCore.getContainerView(), clickTarget[0], clickTarget[1]);
106 * Scrolls the view to ensure that the required DOM node is visible.
108 public static void scrollNodeIntoView(ContentViewCore viewCore, String nodeId)
109 throws InterruptedException, TimeoutException {
110 JavaScriptUtils.executeJavaScriptAndWaitForResult(viewCore,
111 "document.getElementById('" + nodeId + "').scrollIntoView()");
115 * Returns the contents of the node by its id.
117 public static String getNodeContents(ContentViewCore viewCore, String nodeId)
118 throws InterruptedException, TimeoutException {
119 return getNodeField("textContent", viewCore, nodeId);
123 * Returns the value of the node by its id.
125 public static String getNodeValue(final ContentViewCore viewCore, String nodeId)
126 throws InterruptedException, TimeoutException {
127 return getNodeField("value", viewCore, nodeId);
130 private static String getNodeField(String fieldName, final ContentViewCore viewCore,
132 throws InterruptedException, TimeoutException {
133 StringBuilder sb = new StringBuilder();
134 sb.append("(function() {");
135 sb.append(" var node = document.getElementById('" + nodeId + "');");
136 sb.append(" if (!node) return null;");
137 sb.append(" if (!node." + fieldName + ") return null;");
138 sb.append(" return [ node." + fieldName + " ];");
141 String jsonText = JavaScriptUtils.executeJavaScriptAndWaitForResult(
142 viewCore, sb.toString());
143 Assert.assertFalse("Failed to retrieve contents for " + nodeId,
144 jsonText.trim().equalsIgnoreCase("null"));
146 JsonReader jsonReader = new JsonReader(new StringReader(jsonText));
149 jsonReader.beginArray();
150 if (jsonReader.hasNext()) value = jsonReader.nextString();
151 jsonReader.endArray();
152 Assert.assertNotNull("Invalid contents returned.", value);
155 } catch (IOException exception) {
156 Assert.fail("Failed to evaluate JavaScript: " + jsonText + "\n" + exception);
162 * Wait until a given node has non-zero bounds.
163 * @return Whether the node started having non-zero bounds.
165 public static boolean waitForNonZeroNodeBounds(final ContentViewCore viewCore,
166 final String nodeName)
167 throws InterruptedException {
168 return CriteriaHelper.pollForCriteria(new Criteria() {
170 public boolean isSatisfied() {
172 return !DOMUtils.getNodeBounds(viewCore, nodeName).isEmpty();
173 } catch (InterruptedException e) {
174 // Intentionally do nothing
176 } catch (TimeoutException e) {
177 // Intentionally do nothing
185 * Returns click targets for a given DOM node.
187 private static int[] getClickTargetForNode(ContentViewCore viewCore, String nodeName)
188 throws InterruptedException, TimeoutException {
189 Rect bounds = getNodeBounds(viewCore, nodeName);
190 Assert.assertNotNull("Failed to get DOM element bounds of '" + nodeName + "'.", bounds);
192 int clickX = (int) viewCore.getRenderCoordinates().fromLocalCssToPix(bounds.exactCenterX())
193 + viewCore.getViewportSizeOffsetWidthPix();
194 int clickY = (int) viewCore.getRenderCoordinates().fromLocalCssToPix(bounds.exactCenterY())
195 + viewCore.getViewportSizeOffsetHeightPix();
196 return new int[] { clickX, clickY };