【问题标题】:Implicit wait is not working within the framework隐式等待在框架内不起作用
【发布时间】:2019-03-12 18:01:08
【问题描述】:

请给我合理的解决方案。我已经应用了 ImplicitWait 并且它忽略了等待时间并使脚本失败。我应该怎么做才能让它工作。加载该网站大约需要 10-15 秒,我将等待时间设置为 45 秒。它等待大约 3-4 秒并引发错误。

这是我的框架的 BaseClass 代码:

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Keys;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;

import com.ABC.PageObjects.LoginPage;
import com.ABC.Utilities.ReadConfig;

public class BaseClass {

    ReadConfig readconfig = new ReadConfig();
    public String baseUrl = readconfig.getApplicationUrl();
    public String baseUrl1 = readconfig.getApplicationUrl1();
    public String username = readconfig.getUsername();
    public String password = readconfig.getPassword();  
    public static WebDriver driver;
    public static Logger log;

    @Parameters("browser")
    @BeforeClass
    public void SetUp(String br) throws IOException {

        log = Logger.getLogger("ABC");
        PropertyConfigurator.configure("log4j.properties");

        if(br.equals("chrome")) {
            System.setProperty("webdriver.chrome.driver",readconfig.getChropath());
            driver = new ChromeDriver();    
        }
        else if(br.equals("firefox")) {
            System.setProperty("webdriver.gecko.driver",readconfig.getFirefoxpath());
            driver = new FirefoxDriver();   
        }
        else if(br.equals("ie")) {
            //System.setProperty("webdriver.gecko.driver",readconfig.getFirefoxpath());
            driver = new InternetExplorerDriver();  
        }

    driver.manage().timeouts().implicitlyWait(45, TimeUnit.SECONDS);// its waiting only 3-4 sec  
    driver.manage().window().maximize();

    driver.get(baseUrl);

    }



    @AfterClass(enabled = true)
    public void TearDown() {
        driver.quit();
    }
    public void captureScreen(WebDriver driver, String tname) throws IOException {
        TakesScreenshot ts = (TakesScreenshot) driver;
        File source = ts.getScreenshotAs(OutputType.FILE);
        File target = new File(System.getProperty("user.dir") + "/Screenshots/" + tname + ".png");
        FileUtils.copyFile(source, target);
        System.out.println("Screenshot taken");
    }

这是隐式等待不起作用的测试用例

public class TC_001_LoginTest extends BaseClass {

    @Test
        public void Login() throws IOException {
            log.info("url is opened");
            LoginPage lp = new LoginPage(driver);
                lp.setUserName(username);
                log.info("Username entered");
                    lp.setPassword(password);
                    log.info("Password entered");
                        lp.clickSubmit();
                        log.info("clicked");`

有人知道怎么回事吗?

这是我的页面对象类

public class LoginPage {

        WebDriver ldriver;

        public LoginPage(WebDriver rdriver)
        {
            ldriver=rdriver;
            PageFactory.initElements(rdriver, this);
        }

        @FindBy(name="username")
        @CacheLookup
        WebElement txtUserName;

        @FindBy(id="password")
        @CacheLookup
        WebElement txtPassword;

        @FindBy(id="btnLogin")
        @CacheLookup
        WebElement btnLogin;

        public void setUserName(String uname)
        {
            txtUserName.sendKeys(uname);
        }

        public void setPassword(String pwd)
        {
            txtPassword.sendKeys(pwd);
        }


        public void clickSubmit()
        {
            btnLogin.click();
        }   

【问题讨论】:

  • 您的代码暗示您正在使用页面对象并且可能使用页面工厂。也请与您的原始帖子分享相应的代码。当您使用页面工厂初始化页面对象时,它有自己的隐式等待参数。
  • 感谢比尔的回复。是的,我正在使用页面对象。我更新了我的原始帖子并添加了页面对象类。感谢您的帮助
  • 你能比“抛出错误”更具体吗?发布您的堆栈跟踪。此外,您可能将驱动程序参数传递给 initElements 而不是本地副本。对页面对象的后续调用可能会失败。
  • 这里是什么意思:org.openqa.selenium.WebDriverException:未知错误:元素 不可点击 ------------------------- -------------------------------------------------- --------------------------所以它输入用户名和密码然后点击提交。我想在登录后执行几个动作。所以登录大约需要 10 秒,但它会在 2-3 秒后抛出该错误消息。隐式等待根本不起作用
  • 我对不同的项目使用了完全相同的框架,并且隐式等待工作正常。但在这种情况下它根本不起作用

标签: java eclipse selenium


【解决方案1】:

以下是我的重载方法,用于等待元素(或 by)可点击。元素版本被硬编码为等待 10 秒,而另一个则将等待秒数作为第二个参数传递。你明白了。显然,这将被用来代替页面对象元素。

/**
 * Wait until a web element is clickable by WebElement
 * @author Bill Hileman
 * @param ele - WebElement
 */
public void waitUntilClickable(WebElement ele) {

    (new WebDriverWait(driver, 10)).until(ExpectedConditions.elementToBeClickable(ele));

}

/**
 * Wait until a web element is clickable by locator
 * @author Bill Hileman
 * @param by - By
 */
public void waitUntilClickable(By by, int seconds) {

    (new WebDriverWait(driver, seconds)).until(ExpectedConditions.elementToBeClickable(by));

}

【讨论】:

  • 太棒了。我试试这个,让你知道。我应该将此代码粘贴到我的对象类吗?以及如何处理隐式等待,保持不变?谢谢你的时间比尔!
【解决方案2】:
        public static void WaitUntil(this IWebDriver driver, Func<bool> Condition, float timeout = 10f)
    {

        float timer = timeout;
        while (!Condition.Invoke() && timer > 0f) {

            System.Threading.Thread.Sleep(500);
            timer -= 0.5f;

        }
        System.Threading.Thread.Sleep(500);

    }

driver.WaitUntil(() => driver.FindElements(By.XPath(".//*[contains(@class, 'block-ui-wrapper')]").Length == 0);

我有一类扩展,我在其中执行一堆自定义 Selenium 操作。我发现隐含的等待给我带来的麻烦多于它的价值。而且我发现显式硒等待可能会有点冗长,并且它并没有涵盖我在我的框架中需要的所有内容,所以我做了很多扩展。这是其中之一。请注意,我在上面的示例中使用 FindElements,因为我不希望在找不到任何内容时引发异常。这应该适合你。

注意:您需要将其放在静态类中才能正常工作。在逻辑上扩展这样的现有类时要小心,因为当其他人试图确定方法的定义位置时,这可能会使他们感到困惑。

这是我的完整扩展文件,来自 Github gist。我包装了几乎所有的 Selenium 函数。我做了很多 Javascript,因为 JQuery 在查找元素方面是 100% 可靠的,而 Selenium 的查找功能在 IFrame 之类的东西中存在一些问题。此外,JQuery 有一种非常健壮且超级可读的方式来使用任意数量的定位器查询 DOM 中的元素,无论它们是 ID、类、文本包含、伪选择器等;都在同一个查询字符串中! (Selenium css 选择器缺乏对伪选择器的支持可能是一个限制)这就是我使用它的原因。它比 xpath 更具可读性,更容易编写,并且在正确编写时 100% 可靠。如果您在测试页面上没有 JQuery,您可以在每次加载新页面时简单地注入 JQuery 的脚本。

所以我要做的是使用 JQuery 查找并生成一个明确的 XPath,指向我想要在页面上的确切元素,然后将确切的 XPath 传递给 Selenium 的“查找”逻辑。当您握住 Selenium 的手时,找到元素没有问题。

https://gist.github.com/tsibiski/04410e9646ee9ced9f3794266d6c5a82

注意:您可以将此与上述点击逻辑结合起来以延长点击次数,并始终等到您尝试点击的对象准备好点击。使用我的扩展,你可以等待任何你能想到的条件,在显式等待中处理特定场景,当然还有隐式等待中的一般等待。

请注意,在我的扩展方法中,我如何将 Element.Click() 扩展为 Element.ReliableClick()。这不仅可以处理难以找到的元素,而且会在单击之前等待。此外,您可以在这个抽象的扩展功能中做很多事情,例如自定义报告。

【讨论】:

    【解决方案3】:

    如果您想要快速修复,您可以在每个页面对象的构造函数中添加对WebDriverWait.until() 的调用,如下所示:webDriverWait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector(CSS_SELECTOR))) 其中CSS_SELECTOR 将是一个唯一的定位器 em> 到你需要等待的页面。

    例如,如果 CSS_SELECTOR 是一个 id,那么它将是 "#some-unique-id",如果它是某个独特的类,它将是 ".some-unique-class",或者一个独特的标签将只是 "some-unique-tag"

    这将实质上等待页面在使用LoginPage lp = new LoginPage(driver) 或您需要实例化的任何页面进行实例化时加载。

    在您的BaseClass 类中,您需要添加一个public static WebDriverWait webDriverWait 对象并像这样实例化它:webDriverWait = new WebDriverWait(driver, MAX_WAIT_SECONDS); 其中MAX_WAIT_SECONDS 是在它引发异常之前的最大等待秒数。

    【讨论】:

      猜你喜欢
      • 2017-07-17
      • 2018-08-05
      • 1970-01-01
      • 2020-01-20
      • 2022-06-22
      • 1970-01-01
      • 2023-03-05
      • 1970-01-01
      • 2019-01-03
      相关资源
      最近更新 更多