【问题标题】:Verify element appears or not on the page avoid NoSuchElementException验证元素是否出现在页面上避免 NoSuchElementException
【发布时间】:2018-03-08 19:50:51
【问题描述】:

如果动态发生任何错误,错误消息会显示在网站上。就我而言,如果发生错误,会出现弹出窗口,我需要单击“确定”按钮。

问题是,使用所有 Selenium 技巧,我无法避免 NoSuchElementException 或“无法单击元素”异常。预期:如果出现错误弹窗,点击确定,如果没有,就继续跳过这些ifs。我正在遵循这种方法:

PageFactory 元素和方法。

@FindBy(id='locator')
List<WebElement> errorElement1;

@FindBy(id='locator2')
List<WebElement> errorElement2;

Usage:

if(errorElement1.size() > 0) {
errorElement1.get(0).click();
}

if(errorElement2.size() > 0) {
errorElement2.get(0).click();
}

问题,如果我使用errorElement1.isDisplayed方法,我得到NosuchElementException。

我尝试了所有可以在这里找到的技巧,到目前为止没有成功。谢谢!

【问题讨论】:

  • 谢谢你们,我会尽快标记答案,我正在尝试实施所有选项,并在工作正常时回复您!谢谢大家,不胜感激!
  • 您能否澄清这些错误弹出窗口是否与当前正在执行的测试用例或后台运行的某些与正在执行的测试用例无关的进程有关?如果这些属于前者,则应逐案处理,如果应发生错误且未出现弹出窗口,则测试应失败,反之亦然。但是,如果稍后,在后台进程错误消息中,那么您需要联系开发人员以获得一个框架来关闭这些以进行测试。也许通过设置 cookie 或标志。当弹出窗口出现时,仅处理点击不会管理所有情况。
  • @Grasshopper:谢谢!与我的测试用例无关,根本没有关系。鉴于该站点具有多个外部系统,“A”为我们提供搜索结果,“B”处理计算。没关系。环境出现问题,UI 上出现警告消息。 (不是错误页面,只是在设计上)没有弹出窗口。问题是,当一个外部系统关闭或发生某些事情时,该站点不会关闭,所有 UI 组件都可以正常工作,只会出现一条警告消息。我想查看这些警告信息。如果出现,则抛出异常。如果没有,请继续测试。
  • @Grasshopper:我的想法是,一个帮助类包含所有错误元素(PageFactory),只有一个健壮的方法可以检查所有内容。当我调用此方法时,框架会遍历站点上的所有错误元素,如果其中一个可见,则抛出异常。如果没有,请继续。在这种情况下,我可以在任何地方使用它,因为只有一个大错误验证器处理所有错误消息。 IF 中的 isDisplayed 和 List 大小不起作用。 Try catch 会很有用,但我不知道如何实现这一点。非常感谢!

标签: java selenium selenium-webdriver page-factory


【解决方案1】:

如果你想检查一个元素是否存在,我通常这样做的方式是这样做:

try {
    errorElement1.get(0).click();
} catch (NoSuchElementException e) {
    // the element isn't present on the page, you can do something about it here
}

【讨论】:

  • 我在考虑 try catch 但如果页面上没有显示元素,我只想继续前进,在这种情况下无事可做......
  • 在这种情况下,您可以将 catch 块留空,或者添加一个日志语句,该语句提供一个记录器跟踪,表明如果您愿意,它会以这种方式发生
【解决方案2】:

不要将所有页面元素定义为列表,而仅将实际上可能是列表的元素定义为列表,将其余部分定义为 Web 元素。我所做的是在帮助文件中编写一个函数来检查是否存在通过首先专门检查空值定义的任何元素。该函数对于您要查找的内容可能有点过分,但我将其用作包装器,并为需要在页面对象类内部检查的元素定义一个函数,例如 okButtonIsDisplayed() 并在内部调用下面的包装器,传递定义的 web 元素,一个用于记录错误的描述性字符串,以及一个布尔值,用于确定元素 - 应该 - 是否因通过/失败原因而存在。

public static Boolean pomIsDisplayed(WebElement ele, String eleName, String passOrFail) {
    /*
     * This function returns true if the passed WebElement is displayed
     * 
     * @Param ele - The WebElement being tested
     * 
     * @Param eleName - The textual description of the WebElement for
     * logging purposes.
     * 
     * @Param passOrFail - "Pass" if log should show pass unless unexpected
     * exception occurs. "Fail" is the default if not specified and will log
     * a failure if not displayed.
     * 
     * Returns true - The WebElement is displayed false - The WebElement is
     * not displayed
     */
    String stsStart = " " + passOrFail + ": Element " + eleName;
    Boolean isDisplayed = false;
    String stsMsg = stsStart + " is NOT displayed";
    try {
        if (ele.equals(null))
            stsMsg = stsStart + " is NOT found";
        else if ("checkbox".equals(ele.getAttribute("type")) || "radio".equals(ele.getAttribute("type"))) {
            isDisplayed = true;
            stsMsg = " Pass: Element " + eleName + " is displayed";
        } else if (!ele.isDisplayed())
            stsMsg = stsStart + " is NOT displayed";
        else {
            isDisplayed = true;
            stsMsg = " Pass: Element " + eleName + " is displayed";
        }
    } catch (NoSuchElementException | NullPointerException e) {
        stsMsg = stsStart + " is NOT found. Cause: " + e.getCause();
    } catch (ElementNotVisibleException e1) {
        stsMsg = stsStart + " is NOT displayed. Cause: " + e1.getCause();
    } catch (Exception e2) {
        stsMsg = " Fail: Element " + eleName + " Exception error. Cause: " + e2.getCause();
    }
    addresult(stsMsg);
    return isDisplayed;
}

【讨论】:

  • 问题是,我只定义了那些可以出现在页面上的元素。不同的错误,不同的弹出窗口。如果不显示元素,您的代码如何工作?继续前进,如果页面上存在该元素,继续吗?我不需要任何日志记录,只需执行操作,例如单击。
  • 如果元素存在并显示,则 pomIsDisplayed 函数返回布尔值 true。结果会发生什么取决于测试本身。如果使用 TestNG 或 JUnit,编码人员可以在测试用例中执行 Assert.Fail() 作为结果,这取决于元素是否应该存在,以及如果不存在测试是否可以继续,例如。
【解决方案3】:

有几种方法可以处理这个问题。您可以编写一个click() 方法来处理单击您当前正在使用的元素集合。

public void click(List<WebElement> e)
{
    if (!e.isEmpty())
    {
        e.get(0).click();
    }
}

你会像这样使用它

click(errorElement1);

您可以将 List 更改为 WebElement

@FindBy(id='locator')
WebElement errorElement1;

并使用类似的东西

public void click(WebElement e)
{
    try
    {
        e.click();
    }
    catch (Exception ex)
    {
        // catch and handle various exceptions
    }
}

你会这样称呼它

click(errorElement1);

处理这种情况的另一种方法是编写一个函数来检查每个错误元素并使用上面的click() 方法单击它。

public void handleErrors()
{
    click(errorElement1);
    click(errorElement2);
}

所以你的脚本看起来像

// do some action
handleErrors();
// do another action

如何使用当前定位器检查错误是否存在

public boolean errorsExist()
{
    return !errorElement1.isEmpty() || !errorElement2.isEmpty();
}

您可以检查任一集合是否包含任何元素。如果有,则存在错误。如果您需要知道存在哪个错误,您可能希望将此函数分解为两个函数,一个用于每个错误元素。

【讨论】:

  • 嗨,杰夫,谢谢。所以让我们假设:我使用 try catch 来检查警告可见性。如果页面上显示警告,让我们抛出一个错误。如果没有,请继续并继续。我该如何处理这些“各种案件”?抱歉这个转储问题,但我不确定我应该如何处理这个问题。 (使用 if, if(warning.isDisplayed) {throw error} 没有 else。但我不确定 try catch .. 谢谢!
【解决方案4】:

仍然不完全确定您在寻找什么。所以我提到了我的假设 -

  1. 连接的系统出现故障,但站点运行良好,对 UI 没有干扰。这意味着没有弹出窗口或模式警报。
  2. 页面上显示这些消息的特定区域,不会妨碍任何页面功能。
  3. 当消息可见时,您希望验证消息并引发异常以结束测试。这部分令人困惑,因为在原始帖子中您提到单击“确定”按钮。但是在 cmets 中,您提到了抛出和异常。
  4. 可能有多个系统,因此使用地图而不是页面对象来存储它们。

您需要将 webdriver 传递给 ErrorChecker 类,使用 pico 容器最简单的构造函数。如果你想改变它,你可以看看内部类。要包含新的系统消息,只需创建一个静态键并使用详细信息更新地图。

要调用此ErrorChecker 代码,您需要将其放入try catch 中以获取已检查的SystemFailureException

公共类 ErrorChecker {

  //As you are using picocontainer create a constructor with the driver as argument.
  private WebDriver driver;

  private static final Map<String, ErrorMsg> errMap = new HashMap<>();

  private static final String SYSTEM_A_ID = "sysakey";
  private static final String SYSTEM_B_ID = "sysbkey";
  private static final String SYSTEM_C_ID = "sysckey";

  static {
      //First parameter - By for locating the message
      //Second paremeter - By for locating the OK button
      //Third parameter - Expected Message
      errMap.put(SYSTEM_A_ID, new ErrorMsg(By.id("ida"),By.xpath("xpa"), "ExpectedMsgA"));
      errMap.put(SYSTEM_B_ID, new ErrorMsg(By.id("idb"),By.xpath("xpb"), "ExpectedMsgB"));
      errMap.put(SYSTEM_C_ID, new ErrorMsg(By.id("idc"),By.xpath("xpc"), "ExpectedMsgC"));
  }

  public void verifyErrors() throws SystemFailureException{
      Set<String> keys = errMap.keySet();

      for(String key : keys) {
          ErrorMsg err = errMap.get(key);
          System.out.println(err);

          try {
              //If this fails with NoSuchElement(ie appropriate msg is missing) 
              //then control goes to catch.
              //Loops to next key or system.
              WebElement msgBox = driver.findElement(err.msgBy);

              //Reaches here then msg for failng system found
              String msg = msgBox.getText();

              //Verify if correct. If this is required to be done.
              Assert.assertEquals("Error message mismatch.", err.expectedMessage, msg);

              //Click to make it disappear. Though does not make sense as exception
              //be thrown to break process.
              driver.findElement(err.okbtnBy).click();

              //Throw the exception that systems are failing and break out of loop.
              throw new SystemFailureException(key + " gone kaput.");             

          } catch (NoSuchElementException e) {
              System.out.println("catch do nothing");
          }
      }
  }

  private static class ErrorMsg{
      public By msgBy; 
      public By okbtnBy;
      public String expectedMessage;

      public ErrorMsg(By msgBy, By okbtnBy, String expectedMessage) {
          this.msgBy = msgBy;
          this.okbtnBy = okbtnBy;
          this.expectedMessage = expectedMessage;
      }

      @Override
      public String toString() {
          return "ErrorMsg [msgBy=" + msgBy
                  + ", okbtnBy=" + okbtnBy
                  + ", expectedMessage=" + expectedMessage + "]";
      }

  }
}

自定义异常类。

public class SystemFailureException extends Exception {

  public SystemFailureException() {
  }

  public SystemFailureException(String message) {
      super(message);
  }

  public SystemFailureException(Throwable cause) {
      super(cause);
  }

  public SystemFailureException(String message, Throwable cause) {
      super(message, cause);
  }

}

【讨论】:

  • 嗨!第二点和第三点是正确的。页面上出现这些消息并且消息变得可见的某些特定区域,我想验证/捕获此消息并抛出异常。如果后端没有错误,则此消息对用户不可见。这是我检查 UI 警告的最简单方法。您的解决方案在这种情况下仍然有效吗?对不起,如果我感到困惑。
  • 更重要的是第一点。这些消息不应干扰网页。如果是这样,那么这将间歇性地工作。正如您提到的,没有弹出窗口,因此该解决方案应该有效。用手指交叉试一试...
  • 虽然您需要修改类以删除确定按钮定位器并单击调用..
  • 这是我的坏蚱蜢。我刚刚合并了我的两个问题(以前的问题,强大的错误处理程序)。你是对的,这个问题是处理弹出窗口并单击确定。真丢人。共同点是,有些东西刚刚出现,需要处理。
  • 随着模态弹出窗口从一个单独的进程中动态出现,您需要联系开发人员来禁止它们进行测试。对于错误处理程序,这应该可以工作。
猜你喜欢
  • 1970-01-01
  • 2016-09-18
  • 2017-01-03
  • 2015-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-22
相关资源
最近更新 更多