DOMUtils.java revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
1// Copyright (c) 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 5package org.chromium.content.browser.test.util; 6 7import android.graphics.Rect; 8import android.test.ActivityInstrumentationTestCase2; 9import android.util.JsonReader; 10 11import java.io.IOException; 12import java.io.StringReader; 13import java.util.concurrent.TimeoutException; 14 15import junit.framework.Assert; 16 17import org.chromium.content.browser.ContentView; 18 19/** 20 * Collection of DOM-based utilities. 21 */ 22public class DOMUtils { 23 24 /** 25 * Returns the rect boundaries for a node by its id. 26 */ 27 public static Rect getNodeBounds( 28 final ContentView view, TestCallbackHelperContainer viewClient, String nodeId) 29 throws InterruptedException, TimeoutException { 30 StringBuilder sb = new StringBuilder(); 31 sb.append("(function() {"); 32 sb.append(" var node = document.getElementById('" + nodeId + "');"); 33 sb.append(" if (!node) return null;"); 34 sb.append(" var width = node.offsetWidth;"); 35 sb.append(" var height = node.offsetHeight;"); 36 sb.append(" var x = -window.scrollX;"); 37 sb.append(" var y = -window.scrollY;"); 38 sb.append(" do {"); 39 sb.append(" x += node.offsetLeft;"); 40 sb.append(" y += node.offsetTop;"); 41 sb.append(" } while (node = node.offsetParent);"); 42 sb.append(" return [ x, y, width, height ];"); 43 sb.append("})();"); 44 45 String jsonText = JavaScriptUtils.executeJavaScriptAndWaitForResult( 46 view, viewClient, sb.toString()); 47 48 Assert.assertFalse("Failed to retrieve bounds for " + nodeId, 49 jsonText.trim().equalsIgnoreCase("null")); 50 51 JsonReader jsonReader = new JsonReader(new StringReader(jsonText)); 52 int[] bounds = new int[4]; 53 try { 54 jsonReader.beginArray(); 55 int i = 0; 56 while (jsonReader.hasNext()) { 57 bounds[i++] = jsonReader.nextInt(); 58 } 59 jsonReader.endArray(); 60 Assert.assertEquals("Invalid bounds returned.", 4, i); 61 62 jsonReader.close(); 63 } catch (IOException exception) { 64 Assert.fail("Failed to evaluate JavaScript: " + jsonText + "\n" + exception); 65 } 66 67 return new Rect(bounds[0], bounds[1], bounds[0] + bounds[2], bounds[1] + bounds[3]); 68 } 69 70 /** 71 * Focus a DOM node by its id. 72 */ 73 public static void focusNode(ActivityInstrumentationTestCase2 activityTestCase, 74 final ContentView view, TestCallbackHelperContainer viewClient, String nodeId) 75 throws InterruptedException, TimeoutException { 76 StringBuilder sb = new StringBuilder(); 77 sb.append("(function() {"); 78 sb.append(" var node = document.getElementById('" + nodeId + "');"); 79 sb.append(" if (node) node.focus();"); 80 sb.append("})();"); 81 82 JavaScriptUtils.executeJavaScriptAndWaitForResult(view, viewClient, sb.toString()); 83 } 84 85 /** 86 * Click a DOM node by its id. 87 */ 88 public static void clickNode(ActivityInstrumentationTestCase2 activityTestCase, 89 final ContentView view, TestCallbackHelperContainer viewClient, String nodeId) 90 throws InterruptedException, TimeoutException { 91 int[] clickTarget = getClickTargetForNode(view, viewClient, nodeId); 92 TouchCommon touchCommon = new TouchCommon(activityTestCase); 93 touchCommon.singleClickView(view, clickTarget[0], clickTarget[1]); 94 } 95 96 /** 97 * Long-press a DOM node by its id. 98 */ 99 public static void longPressNode(ActivityInstrumentationTestCase2 activityTestCase, 100 final ContentView view, TestCallbackHelperContainer viewClient, String nodeId) 101 throws InterruptedException, TimeoutException { 102 int[] clickTarget = getClickTargetForNode(view, viewClient, nodeId); 103 TouchCommon touchCommon = new TouchCommon(activityTestCase); 104 touchCommon.longPressView(view, clickTarget[0], clickTarget[1]); 105 } 106 107 /** 108 * Scrolls the view to ensure that the required DOM node is visible. 109 */ 110 public static void scrollNodeIntoView(final ContentView view, 111 TestCallbackHelperContainer viewClient, String nodeId) 112 throws InterruptedException, TimeoutException { 113 JavaScriptUtils.executeJavaScriptAndWaitForResult(view, viewClient, 114 "document.getElementById('" + nodeId + "').scrollIntoView()"); 115 } 116 117 /** 118 * Returns the contents of the node by its id. 119 */ 120 public static String getNodeContents(final ContentView view, 121 TestCallbackHelperContainer viewClient, String nodeId) 122 throws InterruptedException, TimeoutException { 123 StringBuilder sb = new StringBuilder(); 124 sb.append("(function() {"); 125 sb.append(" var node = document.getElementById('" + nodeId + "');"); 126 sb.append(" if (!node) return null;"); 127 sb.append(" return [ node.textContent ];"); 128 sb.append("})();"); 129 130 String jsonText = JavaScriptUtils.executeJavaScriptAndWaitForResult( 131 view, viewClient, sb.toString()); 132 Assert.assertFalse("Failed to retrieve contents for " + nodeId, 133 jsonText.trim().equalsIgnoreCase("null")); 134 135 JsonReader jsonReader = new JsonReader(new StringReader(jsonText)); 136 String contents = null; 137 try { 138 jsonReader.beginArray(); 139 if (jsonReader.hasNext()) contents = jsonReader.nextString(); 140 jsonReader.endArray(); 141 Assert.assertNotNull("Invalid contents returned.", contents); 142 143 jsonReader.close(); 144 } catch (IOException exception) { 145 Assert.fail("Failed to evaluate JavaScript: " + jsonText + "\n" + exception); 146 } 147 return contents; 148 } 149 150 /** 151 * Returns click targets for a given DOM node. 152 */ 153 private static int[] getClickTargetForNode(final ContentView view, 154 TestCallbackHelperContainer viewClient, String nodeName) 155 throws InterruptedException, TimeoutException { 156 Rect bounds = getNodeBounds(view, viewClient, nodeName); 157 Assert.assertNotNull("Failed to get DOM element bounds of '" + nodeName + "'.", bounds); 158 159 int clickX = (int) view.getRenderCoordinates().fromLocalCssToPix(bounds.exactCenterX()); 160 int clickY = (int) view.getRenderCoordinates().fromLocalCssToPix(bounds.exactCenterY()); 161 return new int[] { clickX, clickY }; 162 } 163} 164