1、未使用LoadableComponent前的做法
比如我们经常需要写一些js的代码来判断页面是否加载完整
如:JavascriptExecutor je=(JavascriptExecutor) driver;
final String docstate=(String) je.executeScript("return document.readyState");
ExpectedCondition<Boolean> ec = new ExpectedCondition<Boolean>() {
@Override
public Boolean apply(WebDriver d) {
return (docstate.equals("complete"));
}
};
但这样只是说明页面加载好了,所以这样写也是不能保证页面的元素是可见、可点击等所需要的特性
一般情况下我们可以使用wait来解决该问题
如:
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
.withTimeout(30, TimeUnit.SECONDS)
.pollingEvery(500, TimeUnit.MILLISECONDS)
.ignoring(NoSuchElementException.class);
wait.until(ExpectedConditions.presenceOfElementLocated(by));
wait.until(ExpectedConditions.visibilityOfElementLocated(by));
但是这个对于想用一个通用的方法来评估页面加载状态,却不是最好的方法
2、使用LoadableComponent
则我们可以使用LoadableComponent,它是selenium的一个基础类,为我们提供了一个加载页面的标准方式
下面我们修改以前写的BaiduHome_page.java
首先,让类继承LoadableComponent
这里我们需要实现两个方法: load() 和 isLoaded()
load()方法中的代码一般是用来写跳转到某个页面,如driver.get(url)
isLoaded() 方法中的代码一般是用来验证页面是否加载完成并成功
则该类的代码改为
import com.helpermethods.PageLoad;
import org.openqa.selenium.*;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.*;
import java.util.concurrent.TimeUnit;
public class BaiduHome_page extends LoadableComponent<BaiduHome_page> {
public WebDriver driver;
public BaiduHome_page(WebDriver driver,String Url){
this.driver = driver;
PageFactory.initElements(driver, this);
driver.get(Url);
}
@Override
protected void load() {
}
@Override
protected void isLoaded() throws Error {
System.out.println("=====判断BaiduHome_page是否加载完成=====");
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
.withTimeout(30, TimeUnit.SECONDS)
.pollingEvery(500, TimeUnit.MILLISECONDS)
.ignoring(NoSuchElementException.class);
wait.until((new ExpectedCondition<Boolean>() {
@Override
public Boolean apply(WebDriver driverObject) {
System.out.println("Waiting BaiduHome_page Dom loading complete\n ");
return (Boolean) ((JavascriptExecutor) driverObject).executeScript("return document.readyState === 'complete'");
}
}));
if(!PageLoad.myElementIsClickable(this.driver, By.id("kw"))) {
throw new Error("BaiduHome_page was not successfully loaded");
}
System.out.println("*****BaiduHome_page is loading complete*****");
}
//百度logo
@FindBy(xpath="//div[@id='lg']/img")
private WebElement ElementBaiduLogo;
//输入框
@FindBy(id="kw")
private WebElement ElementBaiduInput;
//按钮 查询一下
@FindBy(id="su")
private WebElement ElementSubmit;
public WebElement getBaiduLogo(){
return ElementBaiduLogo;
}
//获取当前页面title
public String getPageTitle(){
return driver.getTitle();
}
// 输入查询内容,并点击查询按钮
public void enterSearch(String searchText){
WebDriverWait wait = new WebDriverWait(driver,30);
wait.until(ExpectedConditions.elementToBeClickable(ElementBaiduInput));
ElementBaiduInput.clear();
ElementBaiduInput.sendKeys(searchText);
}
// 输入查询内容,并点击查询按钮
public void submit(){
WebDriverWait wait = new WebDriverWait(driver,30);
wait.until(ExpectedConditions.elementToBeClickable(ElementSubmit));
ElementSubmit.click();
}
}
其中myElementIsClickable() 方法是为了验证页面是否真的加载成功。当做一种通用的方法来判断页面加载完成后必须存在某个指定的元素
该方法的代码如下(在com目录下新建helpermethods,之后在该目录下新建PageLoad.java):
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
public class PageLoad {
public static boolean myElementIsClickable (WebDriver driver, By by) {
try
{
new WebDriverWait(driver,30).until(ExpectedConditions.elementToBeClickable(by));
}
catch (WebDriverException ex)
{
return false;
}
return true;
}
}
另外在BaiduHome_page类中,可发现load()里面没有写任何代码,这是因为对于大部分应用程序来说,页面的跳转一般是通过触发某个动作完成的,而不是直接跳到某个页面
但在应用程序的首个页面中,会把driver.get(url)写在页面的构造方法中。因为这样的话,我们就不必在跳转页面前,先等待isload()超时然后在执行driver.get(url)
则在使用时,需要new BaiduHome_page(driver).get()
其中get()方法的内部实现是这样的:
public T get() {
try {
isLoaded();
return (T) this;
} catch (Error e) {
load();
}
isLoaded();
return (T) this;
}
可看到是先调用isLoaded()来判断页面是否如预期一样的加载成功,如果没有加载成功,则调用load()来加载页面,之后再调用isLoaded()查看页面是否加载成功
3、修改类BaiduSearchStepfs.java
注意和之前代码的差别,即修改的地方
import com.BaiduHome_page;
import com.cucumber.config.ConfigManager;
import com.cucumber.utl.SharedDriver;
import cucumber.api.PendingException;
import cucumber.api.java.en.And;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import org.junit.Assert;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import java.util.concurrent.TimeUnit;
public class BaiduSearchStepfs {
private final WebDriver driver;
private final ConfigManager config;
private BaiduHome_page baiduHome_page;
private static String baseUrl;
public BaiduSearchStepfs(SharedDriver driver, ConfigManager config) { //这里删除了BaiduHome_page的初始化,改放到下面去
this.driver = driver;
this.config = config;
}
@Given("^Go to baidu home$")
public void go_to_baidu_home() throws Exception {
baseUrl = this.config.get("base_path");
baiduHome_page = new BaiduHome_page(driver,baseUrl); //新增
baiduHome_page.get(); //新增
}
@When("^I find baidu logo")
public WebElement i_find_baidu_logo() {
WebElement element = this.baiduHome_page.getBaiduLogo();
return element;
}
@And("^Type the search text \"([^\"]*)\"$")
public void type_the_search_text(String searchText) throws Throwable {
this.baiduHome_page.enterSearch(searchText);
}
@And("^Click the submit$")
public void click_the_submit() {
this.baiduHome_page.submit();
}
@Then("^Wait the query result")
public void wait_the_query_result() throws InterruptedException {
Thread.sleep(10000); //后面可以用显示等待或者隐示等待来优化代码
Assert.assertEquals("selenium_百度搜索", this.baiduHome_page.getPageTitle());
}
}
4、其他则不做任何修改,运行cucumber代码
可看到新添加方法打印出来的日志信息,如图所示
则上述就是使用LoadableComponent的一个简易例子
官网也有例子:https://github.com/SeleniumHQ/selenium/wiki/LoadableComponent
在官网中也有介绍了LoadableComponent的高级用法,可以具体看是否需要使用这个高级用法,则《页面嵌套》
该文档参考,这些链接有的如果打不开则是需要翻墙才能查看:
http://www.ontestautomation.com/using-the-loadablecomponent-pattern-for-better-page-object-handling-in-selenium/
http://blog.wedoqa.com/2014/10/simple-and-advanced-usage-of-loadablecomponent/
http://www.johnantony.com/using-selenium-to-test-tumblr/