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