Selenium (Java) 正确使用 PageFactory 的显式等待
Selenium (Java) Correctly using explicit waits with PageFactory
查看 selenium 文档后,我想知道我是否在尝试错误地实现显式等待。
在文档中,它总是显示识别一个新元素,然后将定义的等待分配给所述元素
WebDriver driver = new ChromeDriver();
driver.get("https://google.com/ncr");
driver.findElement(By.name("q")).sendKeys("cheese" + Keys.ENTER);
// Initialize and wait till element(link) became clickable - timeout in 10 seconds
WebElement firstResult = new WebDriverWait(driver, Duration.ofSeconds(10))
.until(ExpectedConditions.elementToBeClickable(By.xpath("//a/h3")));
// Print the first result
System.out.println(firstResult.getText());
在此示例中,创建了一个新元素 firstResult,然后将定义的等待分配给它。
这是必需的吗?应该总是这样做吗?
这就是我问的原因。
我正在使用 PageFactory 模型并通过 FindBy 注释定义我的元素,如此处所示。
// Input field for slice ID
@FindBy(how = How.XPATH, using = "//input[@name='id']")
private WebElement inputSliceId;
然后,在同一个 class 中,我定义了一些方便的方法来使用它们。
那么现在,在我的便捷方法中,我应该这样做吗?
inputSliceId = new WebDriverWait(driver, Duration.ofSeconds(10))...
inputSliceId.sendKeys(...
我一直在做的,也是我现在质疑的,是将没有直接分配给相关元素的等待语句。
例如,我一直在做这样的事情。
buttonSubmit.click();
WebDriverWait wait = new WebDriverWait(driver, 5);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//div[@role='alertdialog']")));
wait.until(ExpectedConditions.invisibilityOfElementLocated(By.xpath("//div[@role='alertdialog']")));
为什么? (这里可能完全错了)
点击按钮后,我需要等待弹出窗口显示
一旦它出现,我就会等待它消失,然后再继续
这是主要问题
这两条等待线真的没有做任何事情,因为我没有将它们分配给一个元素吗?还是它们仍然导致网络驱动程序暂停,直到等待指定的条件发生?
不,您不能将上述等待语句分配给您的网络元素。如果您想使用页面工厂模型等待您的元素用于下面的元素,那么您必须创建
public void isLoaded() 抛出错误 {
// 初始加载,在创建页面对象时调用,以确保页面加载到准备好与我们交互的状态,在我们的例子中,这意味着按钮出现在 DOM 中并且可见。
public class BaseClass
{
private void waitForVisibility(WebElement element) throws Error{
new WebDriverWait(driver, 60)
.until(ExpectedConditions.visibilityOf(element));
}
}
然后在您的页面对象模型中 class 您可以扩展此 BaseClass。
public class page extends BaseClass
{
@FindBy(how = How.XPATH, using = "//input[@name='id']")
private WebElement inputSliceId;
waitForVisibility(inputSliceId);
}
我在 BaseClass 中定义了 wait 以实现跨所有页面对象 classes 的 waitForVisibility 代码的可重用性。
此外,如果您想等待弹出窗口出现,请在单击按钮后添加如下代码:
@FindBy(xpath = "//div[@role='alertdialog']")
private WebElementFacade alertPopup;
buttonSubmit.click();
waitForVisibility(alertPopup);
有几件事:
- 如果您的用例是在元素上调用
getText()
,而不是 elementToBeClickable()
,使用 visibilityOfElementLocated()
将是完美的。
要提取文本,您不必创建任何新元素,而是可以在元素返回后直接调用 visibilityOfElementLocated()
,如下所示:
System.out.println(new WebDriverWait(driver, 20).until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//a/h3"))).getText());
如果您的用例不包含对显示和消失的 弹出窗口 的任何验证,您不需要为它并安全地忽略它。因此,一旦您在 buttonSubmit
上调用 click()
,您就可以继续下一个验证点,调整 弹出窗口 显示和消失的时间跨度。
因此,您的优化代码块将是:
buttonSubmit.click();
// consider the total timespan for the wait to be cumulative of: pop-up displayed + pop-up disappear + next interactable element to become clickable
new WebDriverWait(driver, Duration.ofSeconds(20)).until(ExpectedConditions.elementToBeClickable(By.xpath("xpath_next_element_to_click")));
You can find a relevant detailed discussion in
首先,您可以在单独的 class 中声明一个设置等待本身的方法,像 base 或 parent 一样使用,例如:
protected void waitForElementToBeLoaded(WebElement element) {
wait.until(ExpectedConditions.elementToBeClickable(element));
}
然后,您可以在单独的 class 中声明使用第一个方法的第二个方法,就像虚构的页面一样:
public void sendMessageForm( ){
waitForElementToBeLoaded(sendBtn);
sendBtn.click();
}
最后,每次使用之前的方法都会触发等待,例如:
contactUsPage.sendMessageForm();
查看 selenium 文档后,我想知道我是否在尝试错误地实现显式等待。
在文档中,它总是显示识别一个新元素,然后将定义的等待分配给所述元素
WebDriver driver = new ChromeDriver();
driver.get("https://google.com/ncr");
driver.findElement(By.name("q")).sendKeys("cheese" + Keys.ENTER);
// Initialize and wait till element(link) became clickable - timeout in 10 seconds
WebElement firstResult = new WebDriverWait(driver, Duration.ofSeconds(10))
.until(ExpectedConditions.elementToBeClickable(By.xpath("//a/h3")));
// Print the first result
System.out.println(firstResult.getText());
在此示例中,创建了一个新元素 firstResult,然后将定义的等待分配给它。
这是必需的吗?应该总是这样做吗?
这就是我问的原因。
我正在使用 PageFactory 模型并通过 FindBy 注释定义我的元素,如此处所示。
// Input field for slice ID
@FindBy(how = How.XPATH, using = "//input[@name='id']")
private WebElement inputSliceId;
然后,在同一个 class 中,我定义了一些方便的方法来使用它们。
那么现在,在我的便捷方法中,我应该这样做吗?
inputSliceId = new WebDriverWait(driver, Duration.ofSeconds(10))...
inputSliceId.sendKeys(...
我一直在做的,也是我现在质疑的,是将没有直接分配给相关元素的等待语句。
例如,我一直在做这样的事情。
buttonSubmit.click();
WebDriverWait wait = new WebDriverWait(driver, 5);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//div[@role='alertdialog']")));
wait.until(ExpectedConditions.invisibilityOfElementLocated(By.xpath("//div[@role='alertdialog']")));
为什么? (这里可能完全错了)
点击按钮后,我需要等待弹出窗口显示 一旦它出现,我就会等待它消失,然后再继续
这是主要问题 这两条等待线真的没有做任何事情,因为我没有将它们分配给一个元素吗?还是它们仍然导致网络驱动程序暂停,直到等待指定的条件发生?
不,您不能将上述等待语句分配给您的网络元素。如果您想使用页面工厂模型等待您的元素用于下面的元素,那么您必须创建
public void isLoaded() 抛出错误 { // 初始加载,在创建页面对象时调用,以确保页面加载到准备好与我们交互的状态,在我们的例子中,这意味着按钮出现在 DOM 中并且可见。
public class BaseClass
{
private void waitForVisibility(WebElement element) throws Error{
new WebDriverWait(driver, 60)
.until(ExpectedConditions.visibilityOf(element));
}
}
然后在您的页面对象模型中 class 您可以扩展此 BaseClass。
public class page extends BaseClass
{
@FindBy(how = How.XPATH, using = "//input[@name='id']")
private WebElement inputSliceId;
waitForVisibility(inputSliceId);
}
我在 BaseClass 中定义了 wait 以实现跨所有页面对象 classes 的 waitForVisibility 代码的可重用性。
此外,如果您想等待弹出窗口出现,请在单击按钮后添加如下代码:
@FindBy(xpath = "//div[@role='alertdialog']")
private WebElementFacade alertPopup;
buttonSubmit.click();
waitForVisibility(alertPopup);
有几件事:
- 如果您的用例是在元素上调用
getText()
,而不是elementToBeClickable()
,使用visibilityOfElementLocated()
将是完美的。 要提取文本,您不必创建任何新元素,而是可以在元素返回后直接调用
visibilityOfElementLocated()
,如下所示:System.out.println(new WebDriverWait(driver, 20).until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//a/h3"))).getText());
如果您的用例不包含对显示和消失的 弹出窗口 的任何验证,您不需要为它并安全地忽略它。因此,一旦您在
buttonSubmit
上调用click()
,您就可以继续下一个验证点,调整 弹出窗口 显示和消失的时间跨度。因此,您的优化代码块将是:
buttonSubmit.click(); // consider the total timespan for the wait to be cumulative of: pop-up displayed + pop-up disappear + next interactable element to become clickable new WebDriverWait(driver, Duration.ofSeconds(20)).until(ExpectedConditions.elementToBeClickable(By.xpath("xpath_next_element_to_click")));
You can find a relevant detailed discussion in
首先,您可以在单独的 class 中声明一个设置等待本身的方法,像 base 或 parent 一样使用,例如:
protected void waitForElementToBeLoaded(WebElement element) {
wait.until(ExpectedConditions.elementToBeClickable(element));
}
然后,您可以在单独的 class 中声明使用第一个方法的第二个方法,就像虚构的页面一样:
public void sendMessageForm( ){
waitForElementToBeLoaded(sendBtn);
sendBtn.click();
}
最后,每次使用之前的方法都会触发等待,例如:
contactUsPage.sendMessageForm();