如何使用 Selenium Java WebDriver 测试轮询 javascript ajax 调用

How to test a polling javascript ajax call with Selenium Java WebDriver

我有一个包含 Java 脚本代码的页面,该脚本代码每秒轮询一个 API 并用响应替换 HTML 页面中的元素。我想使用 Selenium WebDriver 测试这个页面。我在我的 Junit 测试中设置了 WebDriver,但我不知道如何处理轮询 Java 脚本。

RemoteWebDriver driver = chrome.getWebDriver();
driver.get("http://localhost:8080");

Java脚本代码配置一个计时器来调用 getMessage() 是这样设置的。

 <body>
    <h1 id="message"> Loading ... </h1>
</body>
<script>
    function getMessage()
    {
        $.ajax({
            url : '/message',
            type: 'GET',
            success: function(data){
                $('#message').text(data.message);
            },
            error: function (data) {
                $('#message').text("Error Response");
            }
        });
    }

    $(document).ready(function() {
        window.setInterval(getMessage, 1000);
    });
</script>

我想测试 H1 消息值每秒更改为大约 30 秒,因此我希望在测试的 30 秒内看到 25 次更改 运行。我如何使用 Selenium WebDriver 做到这一点?

下面是每两秒打印一次消息的一种怪异方式

我们可以编写自己的函数并将该函数传递给 FluentWait 的 Until 方法。它将每 2 秒调用一次此方法,超时设置为 30 秒。我们正在使用计数器 Once count > 10 。它应该从 until 出来。可能需要根据您的需要进行一些重构。

Function<WebDriver, Boolean> function = new Function<WebDriver, Boolean>()
 {
    int count = 1;
    public Boolean apply(WebDriver arg0) {
    count++;
    WebElement element = arg0.findElement(By.id("message"));
    String text= element.getText(); 
    System.out.println("Message " + text); // your logic
    if(count > 10))
    {
       return true;
    }
    return false;
    }
 }

示例使用。假设驱动程序路径等设置正确

public static void main(String[] args) throws InterruptedException {
 
 WebDriver driver = new FirefoxDriver();
 driver.get("http://localhost:8080");
 
 FluentWait<WebDriver> wait = new FluentWait<WebDriver>(driver);
 wait.pollingEvery(Duration.ofSeconds(2));
 wait.withTimeout(Duration.ofSeconds(30));
 wait.ignoring(NoSuchElementException.class);
 
 Function<WebDriver, Boolean> function = new Function<WebDriver, Boolean>()
 {
   int count = 1;
   public Boolean apply(WebDriver arg0) {
   count++;
   WebElement element = arg0.findElement(By.id("message"));
   String text= element.getText(); 
   System.out.println("Message " + text); // your logic
   if(count > 10))
   {
      System.out.println(count + "++++++++++++++++++");
      return true;
   }
   return false;
  }
  };
 
 wait.until(function);// You can handle timeout exception using try-catch as per your 
 //use case
}

这是另一种方法:

private boolean testElementFor1SecChange(SearchContext searchContext, By locator, Duration testDuration){
    String baseElementText = searchContext.findElement(locator).getText();
    for(int i = 0; i < testDuration.get(ChronoUnit.SECONDS); i++){
        try {
            Thread.sleep(1000);
            String nextElementText = searchContext.findElement(locator).getText();
            if(baseElementText == null || baseElementText.equals(nextElementText)){
                return false;
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
            return false;
        }
    }
    return true;
}

所以测试看起来像:

@Test
public void testChanges(){
    driver.get("http://localhost:8080");
    Assert.assertTrue(
            testElementFor1SecChange(driver, By.id("message"), Duration.ofSeconds(30))
    );
}