验证元素是否出现在页面上避免NoSuchElementException

时间:2018-03-08 19:50:52

标签: java selenium selenium-webdriver page-factory

如果动态发生任何错误,网站上会出现错误消息。在我的情况下,如果发生错误,弹出窗口,我需要单击确定按钮。

问题是,使用所有Selenium技巧,我无法避免NoSuchElementException,或者'无法点击元素'例外。期望:如果出现错误弹出窗口,请单击确定,如果没有,请继续并跳过这些ifs.I' m遵循此方法:

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。

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

4 个答案:

答案 0 :(得分:0)

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

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

答案 1 :(得分:0)

不是将所有页面元素定义为列表,而是仅将实际可能列出的列表定义为列表,而将其余元素定义为Web元素。我所做的是在辅助文件中编写一个函数,以检查是否存在通过首先专门检查空值而定义的任何元素。对于你正在寻找的东西,这个函数可能有些过分,但是我将它用作包装器并简单地为我需要在页面对象类中检查的元素定义一个函数,比如okButtonIsDisplayed()和内部调用下面的包装器,传递定义的webelement,一个用于记录错误的描述性字符串,以及一个布尔值,用于确定元素是否存在 - 是否存在通过/失败原因。

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;
}

答案 2 :(得分:0)

有几种方法可以解决这个问题。您可以编写一个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();
}

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

答案 3 :(得分:0)

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

  1. 连接的系统出现故障,但网站运行正常,不会干扰用户界面。这意味着没有弹出窗口或模态警报。
  2. 页面上显示这些消息的某些特定区域,这些区域不会妨碍任何页面功能。
  3. 当消息可见时,您要验证消息并抛出异常以结束测试。这部分令人困惑,因为在原帖中你提到点击OK按钮。但是在评论中你提到了抛出和异常。
  4. 可能有多个系统因此使用地图而不是页面对象来存储它们。
  5. 您需要将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);
      }
    
    }