始终等待页面加载到 PageObjects
Always wait for the page to load on PageObjects
所以,当出现问题时,我只是在创建一个简单的 selenium/JBehave 代码。
我会先post简化代码,然后再解释我的问题。
所以这里我们有一个简单的抽象类,它将在我的 PageObjects 上继承。这个 class 只包含一个方法来等待页面上的某些元素被加载。您可以看到我如何在 PageObject class 中使用它(在那里添加了评论)。
AbstractPage.java
public abstract class AbstractPage {
public void waitPageLoad() {
WebDriverWait wait = new WebDriverWait(webDriverProvider.get(), 30);
wait.until(ExpectedConditions.visibilityOfAllElements(elementsToWait()));
}
protected List<WebElement> elementsToWait() {
return null;
}
}
PageObject.java
public class PageObject extends AbstractPage{
@FindBy(id = "webElement1")
private WebElement webElement1;
@FindBy(id = "webElement2")
private WebElement webElement2;
public void clickWebElement1() {
webElement1.click();
}
public void sendKeysWebElement2(String strKeys) {
webElement2.sendKeys(strKeys);
}
//Note how im using the elementsToWait here
@Override
protected List<WebElement> elementsToWait() {
return Arrays.asList(webElement1, webElement2);
}
}
现在在我的步骤中,如果我想先等待页面加载然后执行我想要的操作,我需要从我的抽象 [=67= 中调用 'waitPageLoad()' 方法] 在其中一个步骤(或所有步骤中)。
PageObjectSteps.java
@Component
public class PageObjectSteps {
private PageObject pageObject;
@When("User wants to click on webElement1")
public void accountToDeposit () {
pageObject.waitPageLoad(); //Calling here just as an example
pageObject.clickWebElement1();
}
@When("User wants to type on webElement2 '$strType'")
public void amountToDeposit(@Named("strType") String strType) {
pageObject.sendKeysWebElement2(strType);
}
}
现在我的问题是:
有没有一种方法可以在每次使用我的 pageObject 时调用 waitPageLoad() 但 WITHOUT 调用方法步骤?
例如,对于每个 pageObject,我会有不同的 waitPageLoad(),具体取决于我需要等待的内容。
在这个例子中,我会等待 webElement1 和 webElement2 可见。
selenium 是否有类似的东西:@AlwaysWait 我可以在方法之前使用它,每次使用页面对象时都会调用它(同样,无需在步骤中调用它)?或者每次使用页面对象时都会调用一个方法的表示法?
示例:
@AlwaysWait
public void waitPageObjectLoad() {
WebDriverWait wait = new WebDriverWait(webDriverProvider.get(), 30);
wait.until(ExpectedConditions.visibilityOfAllElements(webElement1, webElement2));
}
希望我让自己能被理解,
提前致谢。
PS:四处打听,我知道你可以用 java 反射框架来做,但我想知道你是否可以只用 selenium 来做。
这是您学会爱上多态性和代理模式的地方。
创建一个新的具体 class 实现名为 LazyWebDriver
的 WebDriver
接口。创建另外两个 class 延迟加载 Web 元素:LazyWebElement 和 LazyWebElementList。
LazyWebDriver 中的方法应该 return LazyWebElement 或 LazyWebElementList 对象,但这些方法的 return 值应该是 WebElement 或 List。
现在您只需像使用任何其他 Web 驱动程序一样使用 LazyWebDriver。使用标准 WebDriver 接口查找元素总是会等待一定的秒数:
WebDriver driver = new ChromeDriver();
int secondsToWait = 15;
WebDriver lazyDriver = new LazyWebDriver(driver, secondsToWait);
// findElement(...) returns immediately
WebElement element = lazyDriver.findElement(By.id("foo"));
// Implicitly waits up to 15 seconds for the element
// to become visible before attempting to click on it
element.click();
// Returns immediately since the "wrapped" element
// has already been fetched after waiting.
String name = element.getAttribute("name");
LazyWebDriver Class
public class LazyWebDriver implements WebDriver {
private WebDriver driver;
public LazyWebDriver(WebDriver driver, int secondsToWait) {
this.driver = driver;
this.wait = new WebDriverWait(driver, secondsToWait);
}
public void close() {
driver.close();
}
public WebElement findElement(By by) {
return new LazyWebElement(driver, by, wait);
}
public List<WebElement> findElements(By by) {
return new LazyWebElementList(driver, by, wait);
}
// ... other methods just call through to driver.foo(...)
}
LazyWebElement Class
public class LazyWebElement implements WebElement {
private final WebDriver driver;
private final WebDriverWait wait;
private final By by;
private WebElement element;
public LazyWebElement(WebDriver driver, By by, WebDriverWait wait) {
this.driver = driver;
this.by = by;
this.wait = wait;
}
private WebElement getElement() {
if (element == null) {
wait.until(ExpectedConditions.visibilityOfElementLocated(by));
element = driver.findElement(by);
}
return element;
}
public void clear() {
getElement().clear();
}
public void click() {
getElement().click();
}
public String getAttribute(String attributeName) {
return getElement().getAttribute(attributeName);
}
// Other methods in WebElement interface must first call getElement()
}
LazyWebElementList Class
public class LazyWebElementList implements List<WebElement> {
private final WebDriver driver;
private final WebDriverWait wait;
private final By by;
private List<WebElement> elements;
public LazyWebElementList(WebDriver driver, By by, WebDriverWait wait) {
this.driver = driver;
this.by = by;
this.wait = wait;
}
private List<WebElement> getElements() {
if (elements == null) {
wait.until(ExpectedConditions.visibilityOfAllElementsLocated(by));
elements = driver.findElements(by);
}
return elements;
}
public boolean add(WebElement element) {
getElements().add(element);
}
public void clear() {
getElements().clear();
}
// Other methods defined in List<E> interface must call getElements() first
}
我在您的代码示例中看到您正在从 webDriverProvider
获取 WebDriver 对象。您可以继续使用它,除了 Web 驱动程序提供程序 return 是一个投射到 WebDriver 接口的 LazyWebDriver。您的其余代码仍然完全不知道 LazyWebDriver、LazyWebElement 和 LazyWebElementList 甚至存在。这应该很容易插入到您现有的测试代码中。
所以,当出现问题时,我只是在创建一个简单的 selenium/JBehave 代码。
我会先post简化代码,然后再解释我的问题。
所以这里我们有一个简单的抽象类,它将在我的 PageObjects 上继承。这个 class 只包含一个方法来等待页面上的某些元素被加载。您可以看到我如何在 PageObject class 中使用它(在那里添加了评论)。
AbstractPage.java
public abstract class AbstractPage {
public void waitPageLoad() {
WebDriverWait wait = new WebDriverWait(webDriverProvider.get(), 30);
wait.until(ExpectedConditions.visibilityOfAllElements(elementsToWait()));
}
protected List<WebElement> elementsToWait() {
return null;
}
}
PageObject.java
public class PageObject extends AbstractPage{
@FindBy(id = "webElement1")
private WebElement webElement1;
@FindBy(id = "webElement2")
private WebElement webElement2;
public void clickWebElement1() {
webElement1.click();
}
public void sendKeysWebElement2(String strKeys) {
webElement2.sendKeys(strKeys);
}
//Note how im using the elementsToWait here
@Override
protected List<WebElement> elementsToWait() {
return Arrays.asList(webElement1, webElement2);
}
}
现在在我的步骤中,如果我想先等待页面加载然后执行我想要的操作,我需要从我的抽象 [=67= 中调用 'waitPageLoad()' 方法] 在其中一个步骤(或所有步骤中)。
PageObjectSteps.java
@Component
public class PageObjectSteps {
private PageObject pageObject;
@When("User wants to click on webElement1")
public void accountToDeposit () {
pageObject.waitPageLoad(); //Calling here just as an example
pageObject.clickWebElement1();
}
@When("User wants to type on webElement2 '$strType'")
public void amountToDeposit(@Named("strType") String strType) {
pageObject.sendKeysWebElement2(strType);
}
}
现在我的问题是:
有没有一种方法可以在每次使用我的 pageObject 时调用 waitPageLoad() 但 WITHOUT 调用方法步骤?
例如,对于每个 pageObject,我会有不同的 waitPageLoad(),具体取决于我需要等待的内容。 在这个例子中,我会等待 webElement1 和 webElement2 可见。
selenium 是否有类似的东西:@AlwaysWait 我可以在方法之前使用它,每次使用页面对象时都会调用它(同样,无需在步骤中调用它)?或者每次使用页面对象时都会调用一个方法的表示法?
示例:
@AlwaysWait
public void waitPageObjectLoad() {
WebDriverWait wait = new WebDriverWait(webDriverProvider.get(), 30);
wait.until(ExpectedConditions.visibilityOfAllElements(webElement1, webElement2));
}
希望我让自己能被理解, 提前致谢。
PS:四处打听,我知道你可以用 java 反射框架来做,但我想知道你是否可以只用 selenium 来做。
这是您学会爱上多态性和代理模式的地方。
创建一个新的具体 class 实现名为 LazyWebDriver
的 WebDriver
接口。创建另外两个 class 延迟加载 Web 元素:LazyWebElement 和 LazyWebElementList。
LazyWebDriver 中的方法应该 return LazyWebElement 或 LazyWebElementList 对象,但这些方法的 return 值应该是 WebElement 或 List。
现在您只需像使用任何其他 Web 驱动程序一样使用 LazyWebDriver。使用标准 WebDriver 接口查找元素总是会等待一定的秒数:
WebDriver driver = new ChromeDriver();
int secondsToWait = 15;
WebDriver lazyDriver = new LazyWebDriver(driver, secondsToWait);
// findElement(...) returns immediately
WebElement element = lazyDriver.findElement(By.id("foo"));
// Implicitly waits up to 15 seconds for the element
// to become visible before attempting to click on it
element.click();
// Returns immediately since the "wrapped" element
// has already been fetched after waiting.
String name = element.getAttribute("name");
LazyWebDriver Class
public class LazyWebDriver implements WebDriver {
private WebDriver driver;
public LazyWebDriver(WebDriver driver, int secondsToWait) {
this.driver = driver;
this.wait = new WebDriverWait(driver, secondsToWait);
}
public void close() {
driver.close();
}
public WebElement findElement(By by) {
return new LazyWebElement(driver, by, wait);
}
public List<WebElement> findElements(By by) {
return new LazyWebElementList(driver, by, wait);
}
// ... other methods just call through to driver.foo(...)
}
LazyWebElement Class
public class LazyWebElement implements WebElement {
private final WebDriver driver;
private final WebDriverWait wait;
private final By by;
private WebElement element;
public LazyWebElement(WebDriver driver, By by, WebDriverWait wait) {
this.driver = driver;
this.by = by;
this.wait = wait;
}
private WebElement getElement() {
if (element == null) {
wait.until(ExpectedConditions.visibilityOfElementLocated(by));
element = driver.findElement(by);
}
return element;
}
public void clear() {
getElement().clear();
}
public void click() {
getElement().click();
}
public String getAttribute(String attributeName) {
return getElement().getAttribute(attributeName);
}
// Other methods in WebElement interface must first call getElement()
}
LazyWebElementList Class
public class LazyWebElementList implements List<WebElement> {
private final WebDriver driver;
private final WebDriverWait wait;
private final By by;
private List<WebElement> elements;
public LazyWebElementList(WebDriver driver, By by, WebDriverWait wait) {
this.driver = driver;
this.by = by;
this.wait = wait;
}
private List<WebElement> getElements() {
if (elements == null) {
wait.until(ExpectedConditions.visibilityOfAllElementsLocated(by));
elements = driver.findElements(by);
}
return elements;
}
public boolean add(WebElement element) {
getElements().add(element);
}
public void clear() {
getElements().clear();
}
// Other methods defined in List<E> interface must call getElements() first
}
我在您的代码示例中看到您正在从 webDriverProvider
获取 WebDriver 对象。您可以继续使用它,除了 Web 驱动程序提供程序 return 是一个投射到 WebDriver 接口的 LazyWebDriver。您的其余代码仍然完全不知道 LazyWebDriver、LazyWebElement 和 LazyWebElementList 甚至存在。这应该很容易插入到您现有的测试代码中。