Robotium学习笔记五

在前面四篇笔记中基本完成了对Solo类大部分方法的记录,在这篇笔记中将对webView的操作做一个记录

还是老套路,先从获取所有的WebElement控件开始,Robotium主要是使用了一套JavaScript脚本,将脚本注入的网页中并执行响应的函数来获取Elements的,下面来看看代码


public WebElement getWebElement(By by, int index){
		int match = index + 1;
		WebElement webElement = waiter.waitForWebElement(by, match, Timeout.getSmallTimeout(), true);

		if(webElement == null) {
			if(match > 1){
				Assert.fail(match + " WebElements with " + webUtils.splitNameByUpperCase(by.getClass().getSimpleName()) + ": '" + by.getValue() + "' are not found!");
			}
			else {
				Assert.fail("WebElement with " + webUtils.splitNameByUpperCase(by.getClass().getSimpleName()) + ": '" + by.getValue() + "' is not found!");
			}
		}
		return webElement;
	}
这个方法主要是调用waitForElement(),继续往下看searcher.searchForWebElement()

这里也没有其他什么特别,一个计时器,然后调用searcher.searchForWebElement(by, minimumNumberOfMatches); 继续往下看,在这里这到了我想要的东西 getWebElement()

打开看到如下:

public ArrayList<WebElement> getWebElements(final By by, boolean onlySufficientlyVisbile){
		boolean javaScriptWasExecuted = executeJavaScript(by, false);
		
		if(config.useJavaScriptToClickWebElements){
			if(!javaScriptWasExecuted){
				return new ArrayList<WebElement>();
			}
			return webElementCreator.getWebElementsFromWebViews();
		}

		return getWebElements(javaScriptWasExecuted, onlySufficientlyVisbile);
	}
这里这首先调用了executeJavaScript(by, false);

public boolean executeJavaScript(final By by, boolean shouldClick){
		if(by instanceof By.Id){
			return executeJavaScriptFunction("id(\""+by.getValue()+"\", \"" + String.valueOf(shouldClick) + "\");");
		}
		else if(by instanceof By.Xpath){
			return executeJavaScriptFunction("xpath(\""+by.getValue()+"\", \"" + String.valueOf(shouldClick) + "\");");
		}
		else if(by instanceof By.CssSelector){
			return executeJavaScriptFunction("cssSelector(\""+by.getValue()+"\", \"" + String.valueOf(shouldClick) + "\");");
		}
		else if(by instanceof By.Name){
			return executeJavaScriptFunction("name(\""+by.getValue()+"\", \"" + String.valueOf(shouldClick) + "\");");
		}
		else if(by instanceof By.ClassName){
			return executeJavaScriptFunction("className(\""+by.getValue()+"\", \"" + String.valueOf(shouldClick) + "\");");
		}
		else if(by instanceof By.Text){
			return executeJavaScriptFunction("textContent(\""+by.getValue()+"\", \"" + String.valueOf(shouldClick) + "\");");
		}
		else if(by instanceof By.TagName){
			return executeJavaScriptFunction("tagName(\""+by.getValue()+"\", \"" + String.valueOf(shouldClick) + "\");");
		}
		return false;
	}
可以看出根据By类传入不同类型的参数执行不同的js方法

private boolean executeJavaScriptFunction(final String function){
		final WebView webView = viewFetcher.getFreshestView(viewFetcher.getCurrentViews(WebView.class, true));

		if(webView == null){
			return false;
		}

		final String javaScript = prepareForStartOfJavascriptExecution();

		activityUtils.getCurrentActivity(false).runOnUiThread(new Runnable() {
			public void run() {
				if(webView != null){
					webView.loadUrl("javascript:" + javaScript + function);
				}
			}
		});
		return true;
	}

这个方法首先拿到一个webView对象,prepareForStartOfJavaScriptExecution()是将RobotiumWeb.js文件加载成字符串,并将RobotiumWebClient.class这个类的实例加载(这个类继承自google的WebChromeClient类,主要用来处理 prompt)

最后LoadUrl 将js字符串和函数拼接成了一个大的js脚本 形成类似这样的脚本: 调用 allWebElement()函数

javascript:  
function allWebElements() {  
    for (var key in document.all){  
        try{  
            promptElement(document.all[key]);   //调用promptElement(element)函数          
        }catch(ignored){}  
    }  
    finished();    //执行完后,调用finished()函数  
}  
  
function promptElement(element) {  
    var id = element.id;  
    var text = element.innerText;  
    if(text.trim().length == 0){  
        text = element.value;  
    }  
    var name = element.getAttribute('name');  
    var className = element.className;  
    var tagName = element.tagName;  
    var attributes = "";  
    var htmlAttributes = element.attributes;  
    for (var i = 0, htmlAttribute; htmlAttribute = htmlAttributes[i]; i++){  
        attributes += htmlAttribute.name + "::" + htmlAttribute.value;  
        if (i + 1 < htmlAttributes.length) {  
            attributes += "#$";  
        }  
    }  
  
    var rect = element.getBoundingClientRect();  
    if(rect.width > 0 && rect.height > 0 && rect.left >= 0 && rect.top >= 0){  
        prompt(id + ';,' + text + ';,' + name + ";," + className + ";," + tagName + ";," + rect.left + ';,' + rect.top + ';,' + rect.width + ';,' + rect.height + ';,' + attributes);   //弹出包含id、text、name等字段的提示框  
    }  
}  
function finished(){  
    prompt('robotium-finished');    //弹出包含robotium-finished字符串的提示框,用于标识脚本注入执行结束  
} 

生成一个prompt 含有 id,text,name等信息,在这里刚才注册的WebChromeClient就起到作用了,他可以处理这个 prompt(当网页弹出prompt时 会自动调用onjsPrompt方法)

public boolean onJsPrompt(WebView view, String url, String message,	String defaultValue, JsPromptResult r) {

		if(message != null && (message.contains(";,") || message.contains("robotium-finished"))){

			if(message.equals("robotium-finished")){
				webElementCreator.setFinished(true);
			}
			else{
				webElementCreator.createWebElementAndAddInList(message, view);
			}
			r.confirm();
			return true;
		}
		else {
			if(originalWebChromeClient != null) {
				return originalWebChromeClient.onJsPrompt(view, url, message, defaultValue, r); 
			}
			return true;
		}

	}
它使用 webElementCreator.createWebElementAndAddInList(message, view);将prompt中的信息解析存贮到 webElements中.

public void createWebElementAndAddInList(String webData, WebView webView){

		WebElement webElement = createWebElementAndSetLocation(webData, webView);

		if((webElement!=null)) 
			webElements.add(webElement);
	}
private WebElement createWebElementAndSetLocation(String information, WebView webView){
		String[] data = information.split(";,");
		String[] elements = null;
		int x = 0;
		int y = 0;
		int width = 0;
		int height = 0;
		Hashtable<String, String> attributes = new Hashtable<String, String>();
		try{
			x = Math.round(Float.valueOf(data[5]));
			y = Math.round(Float.valueOf(data[6]));
			width = Math.round(Float.valueOf(data[7]));
			height = Math.round(Float.valueOf(data[8]));	
			elements = data[9].split("\\#\\$");
		}catch(Exception ignored){}

		if(elements != null) {
			for (int index = 0; index < elements.length; index++){
				String[] element = elements[index].split("::");
				if (element.length > 1) {
					attributes.put(element[0], element[1]);
				} else {
					attributes.put(element[0], element[0]);
				}
			}
		}
createWebElementAndSetLocation这个方法是将 prompt中具体的参数封装成一个 Element对象包括 id,name 坐标等等这个坐标应该是 Element相对于WebView的坐标

回到WebUtils的getWebElements方法,在最后调用getWebElements(javaScriptWasExecuted, onlySufficientlyVisbile)

private ArrayList<WebElement> getWebElements(boolean javaScriptWasExecuted, boolean onlySufficientlyVisbile){
		ArrayList<WebElement> webElements = new ArrayList<WebElement>();

		if(javaScriptWasExecuted){
			for(WebElement webElement : webElementCreator.getWebElementsFromWebViews()){
				if(!onlySufficientlyVisbile){
					webElements.add(webElement);
				}
				else if(isWebElementSufficientlyShown(webElement)){
					webElements.add(webElement);
				}
			}
		}
		return webElements;
	}

getWebElements是筛选出当前可见的的Element并返回集合,就找到了需要的Element

下面来看看点击Element的操作,点击element其实和点击view的原理差不多,使用上面已经得到了element,中坐标属性就可以了

public void clickOnWebElement(By by, int match, boolean scroll, boolean useJavaScriptToClick){
		WebElement webElement = null;
		
		if(useJavaScriptToClick){
			webElement = waiter.waitForWebElement(by, match, Timeout.getSmallTimeout(), false);
			if(webElement == null){
				Assert.fail("WebElement with " + webUtils.splitNameByUpperCase(by.getClass().getSimpleName()) + ": '" + by.getValue() + "' is not found!");
			}
			webUtils.executeJavaScript(by, true);
			return;
		}
		
		WebElement webElementToClick = waiter.waitForWebElement(by, match, Timeout.getSmallTimeout(), scroll);
		
		if(webElementToClick == null){
			if(match > 1) {
				Assert.fail(match + " WebElements with " + webUtils.splitNameByUpperCase(by.getClass().getSimpleName()) + ": '" + by.getValue() + "' are not found!");
			}
			else {
				Assert.fail("WebElement with " + webUtils.splitNameByUpperCase(by.getClass().getSimpleName()) + ": '" + by.getValue() + "' is not found!");
			}
		}
		
		clickOnScreen(webElementToClick.getLocationX(), webElementToClick.getLocationY(), null);
	}

关键的方法和view的click是一样的,其实最开始我在这里有一点不明白,就是获取element的坐标值,不知道是相对于webview还是相对于屏幕的,但是看到这里基本上可以判断这个坐标值是相对于屏幕的了.

Robotium的学习目前告一段落了,其实还有很多地方不是完全明白,可能也有很多说错的地方,希望大家直接指出来,欢迎拍砖



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值