robotium原理之获取WebElement元素

robotium框架支持WebView,在robotium中有getWebElements()、getWebElements(By by)等方法来获取android中的WebView的元素,并提供了 clickOnWebElement方法来完成点击事件.android中的原生控件是比较好攻取的,那么对于WebView这个框架是怎么获取的呢。

第一步:利用JS获取页面中的所有元素

在PC上,获取网页的元素可以通过注入javascript元素来完成,以Chrome浏览器为例,打开工具——JavaScript控制台(快捷方式:Ctrl+Shift+J),输入 javascript:prompt(document.URL)即会弹出含当前页面的URL的提示框,因此通过编写适当的JS脚本是可以在这个弹出框中显示所有页面元素的。RobotiumWeb.js就是此功能实现用的JS脚本。以solo中getWebElements()为例,

[java] view plaincopy

  1. public ArrayList<WebElement> getWebElements(boolean onlySufficientlyVisible){
  2. boolean javaScriptWasExecuted = executeJavaScriptFunction("allWebElements();");
  3. return getWebElements(javaScriptWasExecuted, onlySufficientlyVisible);
  4. }

[java] view plaincopy

  1. private boolean executeJavaScriptFunction(final String function){
  2. final WebView webView = viewFetcher.getFreshestView(viewFetcher.getCurrentViews(WebView.class, true));
  3. if(webView == null){
  4. return false;
  5. }
  6. //做一些JS注入执行前的准备工作,例如将WebView设为可允许执行JS等,并将RobotiumWeb.js中的脚本以String形式返回
  7. final String javaScript = prepareForStartOfJavascriptExecution();
  8. activityUtils.getCurrentActivity(false).runOnUiThread(new Runnable() {
  9. public void run() {
  10. if(webView != null){
  11. webView.loadUrl("javascript:" + javaScript + function);
  12. }
  13. }
  14. });
  15. return true;
  16. }

可以看出这个方法执行的是allWebElements();函数,即类似执行RobotiumWeb.js文件中如下JS代码片段:

可以把如下片段放到JavaScript控制台中看效果

[javascript] view plaincopy

  1. javascript:
  2. function allWebElements() {
  3. for (var key in document.all){
  4. try{
  5. promptElement(document.all[key]);   //调用promptElement(element)函数
  6. }catch(ignored){}
  7. }
  8. finished();    //执行完后,调用finished()函数
  9. }
  10. function promptElement(element) {
  11. var id = element.id;
  12. var text = element.innerText;
  13. if(text.trim().length == 0){
  14. text = element.value;
  15. }
  16. var name = element.getAttribute(‘name‘);
  17. var className = element.className;
  18. var tagName = element.tagName;
  19. var attributes = "";
  20. var htmlAttributes = element.attributes;
  21. for (var i = 0, htmlAttribute; htmlAttribute = htmlAttributes[i]; i++){
  22. attributes += htmlAttribute.name + "::" + htmlAttribute.value;
  23. if (i + 1 < htmlAttributes.length) {
  24. attributes += "#$";
  25. }
  26. }
  27. var rect = element.getBoundingClientRect();
  28. if(rect.width > 0 && rect.height > 0 && rect.left >= 0 && rect.top >= 0){
  29. prompt(id + ‘;,‘ + text + ‘;,‘ + name + ";," + className + ";," + tagName + ";," + rect.left + ‘;,‘ + rect.top + ‘;,‘ + rect.width + ‘;,‘ + rect.height + ‘;,‘ + attributes);   //弹出包含id、text、name等字段的提示框
  30. }
  31. }
  32. function finished(){
  33. prompt(‘robotium-finished‘);    //弹出包含robotium-finished字符串的提示框,用于标识脚本注入执行结束
  34. }

从脚本中可以看出JS获得页面元素后还进行了一定的格式化处理,在每个元素之间加了;,符号,这也是为了在后面代码中更加方便地解析。脚本的最后调用了finished()函数,即弹出包含robotium-finished的提示框。这一步完成了页面元素的获取,那么提示框中包含的内容在Android中怎么获取呢?

第二步:在Android中获取WebView中prompt提示框中的信息

在Android的Webkit包中有个WebChromeClient类,这个类中的onJsPrompt方法就是用于处理WebView中的提示框的,当WebView中有JS提示框时,会回调该方法,String message参数将包含提示框中的信息,因此robotium写了个继承自WebChromeClient类的RobotiumWebClient类。覆写了onJsPrompt

onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result)

[java] view plaincopy

  1. @Override
  2. public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult r) {
  3. if(message != null && (message.contains(";,") || message.contains("robotium-finished"))){
  4. //如果提示框中包含robotium-finished字符串,即表示那段JS注入脚本执行完毕了
  5. if(message.equals("robotium-finished")){
  6. webElementCreator.setFinished(true);
  7. }
  8. else{
  9. webElementCreator.createWebElementAndAddInList(message, view);//有人提示框中的内容,那么就可以对提示框中的内容进行处理了
  10. }
  11. r.confirm();
  12. return true;
  13. }
  14. else {
  15. if(originalWebChromeClient != null) {
  16. return originalWebChromeClient.onJsPrompt(view, url, message, defaultValue, r);
  17. }
  18. return true;
  19. }
  20. }

另外,原本的WebView默认是不允许执行JS的,因此需要先执行enableJavascriptAndSetRobotiumWebClient方法。将JavaScriptEnabled设置为true,将将WebChromeClient设置为robotiumWebClient

[java] view plaincopy

  1. public void enableJavascriptAndSetRobotiumWebClient(List<WebView> webViews, WebChromeClient originalWebChromeClient){
  2. this.originalWebChromeClient = originalWebChromeClient;
  3. for(final WebView webView : webViews){
  4. if(webView != null){
  5. inst.runOnMainSync(new Runnable() {
  6. public void run() {
  7. webView.getSettings().setJavaScriptEnabled(true);
  8. webView.setWebChromeClient(robotiumWebClient);
  9. }
  10. });
  11. }
  12. }
  13. }

第三步:将提示框中的消息存入WebElement Java bean中

获取到了prompt提示框中的消息后,接下来就是对这些已经过处理含特殊格式的消息进行解析处理了,依次得到WebElement的id、text、name等字段。

[java] view plaincopy

  1. private WebElement createWebElementAndSetLocation(String information, WebView webView){
  2. String[] data = information.split(";,");            //将消息按;,符号分割,其中;,符号是在前面执行JS时加入的
  3. String[] elements = null;
  4. int x = 0;
  5. int y = 0;
  6. int width = 0;
  7. int height = 0;
  8. Hashtable<String, String> attributes = new Hashtable<String, String>();
  9. try{
  10. x = Math.round(Float.valueOf(data[5]));
  11. y = Math.round(Float.valueOf(data[6]));
  12. width = Math.round(Float.valueOf(data[7]));
  13. height = Math.round(Float.valueOf(data[8]));
  14. elements = data[9].split("\\#\\$");
  15. }catch(Exception ignored){}
  16. if(elements != null) {
  17. for (int index = 0; index < elements.length; index++){
  18. String[] element = elements[index].split("::");
  19. if (element.length > 1) {
  20. attributes.put(element[0], element[1]);
  21. } else {
  22. attributes.put(element[0], element[0]);
  23. }
  24. }
  25. }
  26. WebElement webElement = null;
  27. try{
  28. webElement = new WebElement(data[0], data[1], data[2], data[3], data[4], attributes);//将id、text、name等字段存入
  29. setLocation(webElement, webView, x, y, width, height);
  30. }catch(Exception ignored) {}
  31. return webElement;
  32. }

[java] view plaincopy

  1. /**
  2. * Sets the location of a {@code WebElement}
  3. *
  4. * @param webElement the {@code TextView} object to set location
  5. * @param webView the {@code WebView} the text is shown in
  6. * @param x the x location to set
  7. * @param y the y location to set
  8. * @param width the width to set
  9. * @param height the height to set
  10. */
  11. private void setLocation(WebElement webElement, WebView webView, int x, int y, int width, int height ){
  12. float scale = webView.getScale();
  13. int[] locationOfWebViewXY = new int[2];
  14. webView.getLocationOnScreen(locationOfWebViewXY);
  15. int locationX = (int) (locationOfWebViewXY[0] + (x + (Math.floor(width / 2))) * scale);
  16. int locationY = (int) (locationOfWebViewXY[1] + (y + (Math.floor(height / 2))) * scale);
  17. webElement.setLocationX(locationX);
  18. webElement.setLocationY(locationY);
  19. }

至此,WebElement对象中包含了id、text、name等字段,还包含了x、y坐标,知道了坐标后就可以像其它Android中的原生View一样根据坐标发送点击事件。

时间: 2024-10-04 19:08:33

robotium原理之获取WebElement元素的相关文章

【金阳光测试】Android自动化 -- 学习历程:Robotium原理初步

章节:自动化基础篇——Monkey原理初步和改良优化(第四讲) 网易云课堂: http://study.163.com/course/courseLearn.htm?courseId=712011#/learn/video?lessonId=876095&courseId=712011 主要讲解内容与笔记: 一.基于控件 1.spinner——下拉菜单 2.TabHost——左右滑动选择菜单,类似电话本 3.Gallery——图形 4.Progressbar——进度条 5.DatePicker—

Selenium 获取隐藏元素的内容

第一种 先获取元素通过 属性获取 WebElement webElemt= webElement.findElement(By.xpath("//*[@class='xxxxxx]/a")); //在ie下使用innerText 在火狐下使用textContent String linktext = webElemt.getAttribute("innerText"); 第二种 通过js获取 WebElement element = ...; ((Javascrip

Robotium原理初步--Android自动化测试学习历程

章节:自动化基础篇——Robotium原理初步(第四讲) 主要讲解内容与笔记: 一.基于控件 1.spinner——下拉菜单 2.TabHost——左右滑动选择菜单,类似电话本 3.Gallery——图形 4.Progressbar——进度条 5.DatePicker——日期与时间选择控件 6.CheckBox——单选框:RadioButton——互斥单选框:Button——一般按钮 7.ToggleButton——双状态按钮控件:选择和未选择两种状态,并且针对不同状态显示不同文本8.EditT

vue获取当前元素

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Vue获取当前元素</title> <script src="https://cdn.bootcss.com/vue/2.2.2/vue.min.js"></script> </head> <body> <div id=&q

jQuery如何获取当前元素的兄弟元素

jQuery如何获取当前元素的兄弟元素:在实际应用中,有时候要获得当前元素的兄弟元素,下面就通过一段实例代码简单介绍一下如何获取当前元素的兄弟元素.实例代码如下: <!DOCTYPE html> <html> <head> <meta charset=" utf-8"> <meta name="author" content="http://www.softwhy.com/" /> &l

用Javascript获取页面元素的位置

制作网页的过程中,你有时候需要知道某个元素在网页上的确切位置. 下面的教程总结了Javascript在网页定位方面的相关知识. 一.网页的大小和浏览器窗口的大小 首先,要明确两个基本概念. 一张网页的全部面积,就是它的大小.通常情况下,网页的大小由内容和CSS样式表决定. 浏览器窗口的大小,则是指在浏览器窗口中看到的那部分网页面积,又叫做viewport(视口). 很显然,如果网页的内容能够在浏览器窗口中全部显示(也就是不出现滚动条),那么网页的大小和浏览器窗口的大小是相等的.如果不能全部显示,

使用jquery获取父元素或父节点的方法

jquery获取父元素方法比较多,比如parent(),parents(),closest()这些都能帮你实现查找父元素或节点,下面我们来一一讲解: <ul class="parent1"> <li><a href="#" id="item1">jquery获取父节点</a></li> <li><a href="#">jquery获取父元素&l

[转载]用Javascript获取页面元素的位置

原文地址:http://www.ruanyifeng.com/blog/2009/09/find_element_s_position_using_javascript.html 制作网页的过程中,你有时候需要知道某个元素在网页上的确切位置. 下面的教程总结了Javascript在网页定位方面的相关知识. 一.网页的大小和浏览器窗口的大小 首先,要明确两个基本概念. 一张网页的全部面积,就是它的大小.通常情况下,网页的大小由内容和CSS样式表决定. 浏览器窗口的大小,则是指在浏览器窗口中看到的那

获取页面元素的几种方式

在JS中我们可以通过以下几种方式获取到页面中的元素: 1.使用id来获取对象的元素(获取到的对象元素是唯一的) document.getElementById("") 例: <input type="text" value="默认的文字" id="txt"/><input type="button" value="按钮" id="btn"/>&