DOMUtils.java revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
1ea91cc579ade536e3a08498a8157921dd4f533d1ager@chromium.org// Copyright (c) 2012 The Chromium Authors. All rights reserved. 243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// Use of this source code is governed by a BSD-style license that can be 343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen// found in the LICENSE file. 443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansenpackage org.chromium.content.browser.test.util; 643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansenimport android.graphics.Rect; 843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansenimport android.test.ActivityInstrumentationTestCase2; 943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansenimport android.util.JsonReader; 1043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 1143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansenimport java.io.IOException; 1243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansenimport java.io.StringReader; 1343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansenimport java.util.concurrent.TimeoutException; 1443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 1543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansenimport junit.framework.Assert; 1643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 1743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansenimport org.chromium.content.browser.ContentView; 1843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 1943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen/** 2043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen * Collection of DOM-based utilities. 2143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen */ 2243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansenpublic class DOMUtils { 2343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 2443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen /** 2543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen * Returns the rect boundaries for a node by its id. 2643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen */ 2743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen public static Rect getNodeBounds( 2843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen final ContentView view, TestCallbackHelperContainer viewClient, String nodeId) 2943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen throws InterruptedException, TimeoutException { 3043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen StringBuilder sb = new StringBuilder(); 3143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen sb.append("(function() {"); 32f5aa83707f1db5aecb22f6c3bfd5042f629d5fcfkasperl@chromium.org sb.append(" var node = document.getElementById('" + nodeId + "');"); 33d236f4d96b5dd21acc5ec57f4e50fa97cdd97bb6ricow@chromium.org sb.append(" if (!node) return null;"); 34a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org sb.append(" var width = node.offsetWidth;"); 3501beca7f8d9f549e04ec575a0bca96d859ab55a5ager@chromium.org sb.append(" var height = node.offsetHeight;"); 3643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen sb.append(" var x = -window.scrollX;"); 37f5aa83707f1db5aecb22f6c3bfd5042f629d5fcfkasperl@chromium.org sb.append(" var y = -window.scrollY;"); 381456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org sb.append(" do {"); 39a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org sb.append(" x += node.offsetLeft;"); 40f5aa83707f1db5aecb22f6c3bfd5042f629d5fcfkasperl@chromium.org sb.append(" y += node.offsetTop;"); 417c537e2abe09729ed6cb827b4dd206470d8c4a42ager@chromium.org sb.append(" } while (node = node.offsetParent);"); 42a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org sb.append(" return [ x, y, width, height ];"); 4343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen sb.append("})();"); 4471affb54842da76b24f0bb3184e9f0960523f89dkasperl@chromium.org 4571affb54842da76b24f0bb3184e9f0960523f89dkasperl@chromium.org String jsonText = JavaScriptUtils.executeJavaScriptAndWaitForResult( 4643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen view, viewClient, sb.toString()); 4743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 4843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen Assert.assertFalse("Failed to retrieve bounds for " + nodeId, 4943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen jsonText.trim().equalsIgnoreCase("null")); 5043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 5143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen JsonReader jsonReader = new JsonReader(new StringReader(jsonText)); 5243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen int[] bounds = new int[4]; 5343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen try { 54ea88ce93dcb41a9200ec8747ae7642a5db1f4ce7sgjesse@chromium.org jsonReader.beginArray(); 5543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen int i = 0; 5643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen while (jsonReader.hasNext()) { 5743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen bounds[i++] = jsonReader.nextInt(); 5843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 5943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen jsonReader.endArray(); 60245aa859d34fd516161c48ef4c69d38d9b889284iposva@chromium.org Assert.assertEquals("Invalid bounds returned.", 4, i); 61245aa859d34fd516161c48ef4c69d38d9b889284iposva@chromium.org 62245aa859d34fd516161c48ef4c69d38d9b889284iposva@chromium.org jsonReader.close(); 6343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } catch (IOException exception) { 6443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen Assert.fail("Failed to evaluate JavaScript: " + jsonText + "\n" + exception); 6543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 6643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 6743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen return new Rect(bounds[0], bounds[1], bounds[0] + bounds[2], bounds[1] + bounds[3]); 6843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 6943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 7043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen /** 7143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen * Focus a DOM node by its id. 7243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen */ 7343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen public static void focusNode(ActivityInstrumentationTestCase2 activityTestCase, 7443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen final ContentView view, TestCallbackHelperContainer viewClient, String nodeId) 7543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen throws InterruptedException, TimeoutException { 7643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen StringBuilder sb = new StringBuilder(); 7743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen sb.append("(function() {"); 7843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen sb.append(" var node = document.getElementById('" + nodeId + "');"); 7943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen sb.append(" if (node) node.focus();"); 8043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen sb.append("})();"); 8143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 8243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen JavaScriptUtils.executeJavaScriptAndWaitForResult(view, viewClient, sb.toString()); 8343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 84245aa859d34fd516161c48ef4c69d38d9b889284iposva@chromium.org 85ea88ce93dcb41a9200ec8747ae7642a5db1f4ce7sgjesse@chromium.org /** 86ea88ce93dcb41a9200ec8747ae7642a5db1f4ce7sgjesse@chromium.org * Click a DOM node by its id. 87ea88ce93dcb41a9200ec8747ae7642a5db1f4ce7sgjesse@chromium.org */ 88245aa859d34fd516161c48ef4c69d38d9b889284iposva@chromium.org public static void clickNode(ActivityInstrumentationTestCase2 activityTestCase, 8943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen final ContentView view, TestCallbackHelperContainer viewClient, String nodeId) 9043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen throws InterruptedException, TimeoutException { 9143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen int[] clickTarget = getClickTargetForNode(view, viewClient, nodeId); 9243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen TouchCommon touchCommon = new TouchCommon(activityTestCase); 936d786c9805481bd13ecb29c3155540f2f32950e1svenpanne@chromium.org touchCommon.singleClickView(view, clickTarget[0], clickTarget[1]); 9443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 9543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 9643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen /** 9743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen * Long-press a DOM node by its id. 9843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen */ 9943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen public static void longPressNode(ActivityInstrumentationTestCase2 activityTestCase, 10043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen final ContentView view, TestCallbackHelperContainer viewClient, String nodeId) 10143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen throws InterruptedException, TimeoutException { 10243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen int[] clickTarget = getClickTargetForNode(view, viewClient, nodeId); 1033811b436bf328d2ace6fe79ce99aeda71f9f06d3ager@chromium.org TouchCommon touchCommon = new TouchCommon(activityTestCase); 1043811b436bf328d2ace6fe79ce99aeda71f9f06d3ager@chromium.org touchCommon.longPressView(view, clickTarget[0], clickTarget[1]); 1053811b436bf328d2ace6fe79ce99aeda71f9f06d3ager@chromium.org } 10643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 10743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen /** 108245aa859d34fd516161c48ef4c69d38d9b889284iposva@chromium.org * Scrolls the view to ensure that the required DOM node is visible. 109245aa859d34fd516161c48ef4c69d38d9b889284iposva@chromium.org */ 110ea88ce93dcb41a9200ec8747ae7642a5db1f4ce7sgjesse@chromium.org public static void scrollNodeIntoView(final ContentView view, 11143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen TestCallbackHelperContainer viewClient, String nodeId) 11243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen throws InterruptedException, TimeoutException { 11343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen JavaScriptUtils.executeJavaScriptAndWaitForResult(view, viewClient, 11443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen "document.getElementById('" + nodeId + "').scrollIntoView()"); 11543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 11643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 11743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen /** 1189a4089a092cad9ff23b6416b92cd5d818dc101d1mads.s.ager@gmail.com * Returns the contents of the node by its id. 11943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen */ 12074f333bce721daf6b1f9d7d3d3faa623f77658d7vegorov@chromium.org public static String getNodeContents(final ContentView view, 121ea88ce93dcb41a9200ec8747ae7642a5db1f4ce7sgjesse@chromium.org TestCallbackHelperContainer viewClient, String nodeId) 122a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org throws InterruptedException, TimeoutException { 12343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen return getNodeField("textContent", view, viewClient, nodeId); 12443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 12543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 1264a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org /** 12743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen * Returns the value of the node by its id. 12843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen */ 12943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen public static String getNodeValue(final ContentView view, 13043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen TestCallbackHelperContainer viewClient, String nodeId) 131a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org throws InterruptedException, TimeoutException { 13243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen return getNodeField("value", view, viewClient, nodeId); 133a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org } 13471affb54842da76b24f0bb3184e9f0960523f89dkasperl@chromium.org 13543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen private static String getNodeField(String fieldName, final ContentView view, 13643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen TestCallbackHelperContainer viewClient, String nodeId) 13743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen throws InterruptedException, TimeoutException { 138a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org StringBuilder sb = new StringBuilder(); 13943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen sb.append("(function() {"); 1405323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org sb.append(" var node = document.getElementById('" + nodeId + "');"); 14143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen sb.append(" if (!node) return null;"); 14243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen sb.append(" if (!node." + fieldName +") return null;"); 14343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen sb.append(" return [ node." + fieldName + " ];"); 14443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen sb.append("})();"); 14543d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 14643d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen String jsonText = JavaScriptUtils.executeJavaScriptAndWaitForResult( 14743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen view, viewClient, sb.toString()); 14843d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen Assert.assertFalse("Failed to retrieve contents for " + nodeId, 14943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen jsonText.trim().equalsIgnoreCase("null")); 15043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 151ea88ce93dcb41a9200ec8747ae7642a5db1f4ce7sgjesse@chromium.org JsonReader jsonReader = new JsonReader(new StringReader(jsonText)); 1526d786c9805481bd13ecb29c3155540f2f32950e1svenpanne@chromium.org String value = null; 1536d786c9805481bd13ecb29c3155540f2f32950e1svenpanne@chromium.org try { 1545d00b60c201d860c74821f553fdc34f4e057b411lrn@chromium.org jsonReader.beginArray(); 1553811b436bf328d2ace6fe79ce99aeda71f9f06d3ager@chromium.org if (jsonReader.hasNext()) value = jsonReader.nextString(); 1563811b436bf328d2ace6fe79ce99aeda71f9f06d3ager@chromium.org jsonReader.endArray(); 1573811b436bf328d2ace6fe79ce99aeda71f9f06d3ager@chromium.org Assert.assertNotNull("Invalid contents returned.", value); 1583811b436bf328d2ace6fe79ce99aeda71f9f06d3ager@chromium.org 159ea88ce93dcb41a9200ec8747ae7642a5db1f4ce7sgjesse@chromium.org jsonReader.close(); 160ea88ce93dcb41a9200ec8747ae7642a5db1f4ce7sgjesse@chromium.org } catch (IOException exception) { 16143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen Assert.fail("Failed to evaluate JavaScript: " + jsonText + "\n" + exception); 16243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 16343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen return value; 16443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 1653811b436bf328d2ace6fe79ce99aeda71f9f06d3ager@chromium.org 1663811b436bf328d2ace6fe79ce99aeda71f9f06d3ager@chromium.org /** 1673811b436bf328d2ace6fe79ce99aeda71f9f06d3ager@chromium.org * Returns click targets for a given DOM node. 168068ea0a6ea115c058d1d9798029bd7fa1eaaa955mstarzinger@chromium.org */ 16943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen private static int[] getClickTargetForNode(final ContentView view, 17043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen TestCallbackHelperContainer viewClient, String nodeName) 17143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen throws InterruptedException, TimeoutException { 17243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen Rect bounds = getNodeBounds(view, viewClient, nodeName); 17343d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen Assert.assertNotNull("Failed to get DOM element bounds of '" + nodeName + "'.", bounds); 17443d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen 175e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.org int clickX = (int) view.getRenderCoordinates().fromLocalCssToPix(bounds.exactCenterX()) 176e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.org + (int) view.getContentViewCore().getViewportSizeOffsetWidthPix(); 17743d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen int clickY = (int) view.getRenderCoordinates().fromLocalCssToPix(bounds.exactCenterY()) 178e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.org + (int) view.getContentViewCore().getViewportSizeOffsetHeightPix(); 17943d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen return new int[] { clickX, clickY }; 18043d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen } 18143d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen} 18243d26ecc3563a46f62a0224030667c8f8f3f6cebchristian.plesner.hansen