使用 Selenium 和 React 等待渲染事件

Max*_*ich 8 c# selenium selenium-webdriver reactjs

我开始使用 Selenium 来测试我构建的 React 应用程序。

在大多数简单的 JavaScript 应用程序中,连接一个测试是微不足道的,其中使用WebDriverWait类来等待某个事件来表示测试可以继续下一步。

例如:

using (IWebDriver driver = new ChromeDriver())
{
    driver.Navigate().GoToUrl($"{Properties.Settings.Default.ApplicationUrl}/Dashboard");

    var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
    wait.Until(d => d.Title.StartsWith("dashboard", StringComparison.OrdinalIgnoreCase));

    //Can do next thing....

    Assert.IsTrue(true);
}
Run Code Online (Sandbox Code Playgroud)

然而,如果我们想测试一个 React 应用程序,事情会变得有点复杂。鉴于您的 React 应用程序中的每个组件都会 在各自的时间内单独调用自己的生命周期事件,因此很难知道给定控件何时完成其Render()生命周期。

我玩过一个简单的解决方案,如:

//Add something like this to each React component
componentDidMount() {
    if (!window.document.hasMyComponentMounted)
        window.document.hasMyComponentMounted = true;
}
Run Code Online (Sandbox Code Playgroud)

然后我可以在我的测试中做这样的事情:

using (IWebDriver driver = new ChromeDriver())
{
    IJavaScriptExecutor js = (IJavaScriptExecutor)driver;

    driver.Navigate().GoToUrl($"{Properties.Settings.Default.ApplicationUrl}/Dashboard");

    var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
    wait.Until(d => js.ExecuteScript("return window.document.hasHomeMounted"));

    //Can do next thing....

    Assert.IsTrue(true);
}
Run Code Online (Sandbox Code Playgroud)

但这似乎是一个有点糟糕的解决方案。

有没有人遇到过同样的问题或知道潜在的解决方法(除了只使用Thread.Sleep())?

Chr*_*ine 11

我已经为 React.js 应用程序编写了大量的自动化程序,正如你提到的,等待组件渲染是一个非常困难的问题。

没有具体的解决方案可以解决所有问题。您提到的等待组件安装的解决方案是一个很好的解决方案。您可以通过使用 WebDriver 调用将其包装起来使其更清晰,以便它们自动等待组件安装,并且您不必在测试用例中指定该代码。

这是一个想法:

public static class WebDriverExtensions()
{
    public static void WaitForComponents(this IWebDriver driver)
    {
        var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
        wait.Until(d => js.ExecuteScript("return window.document.hasHomeMounted"));
    }

    public static void GoToUrl(this IWebDriver driver, string url)
    {
        driver.Navigate().GoToUrl(url);
        driver.WaitForComponents();
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,您的测试用例将如下所示:

using WebDriverExtensions;

using (IWebDriver driver = new ChromeDriver())
{
    IJavaScriptExecutor js = (IJavaScriptExecutor)driver;

    driver.GoToUrl($"{Properties.Settings.Default.ApplicationUrl}/Dashboard");


    //Can do next thing....

    Assert.IsTrue(true);
}
Run Code Online (Sandbox Code Playgroud)

如果您正在检查的组件不断变化,即hasHomeMounted只能在主页上工作,则解决方案有点难看。您可以尝试将组件名称作为参数来检查它是否已安装:

    public static void WaitForComponent(this IWebDriver driver, string componentName)
    {
        var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
        wait.Until(d => js.ExecuteScript($"return window.document.has{componentName}Mounted"));
    }
Run Code Online (Sandbox Code Playgroud)

正如我所提到的,没有万能的方法可以做到这一点,并且Thread.Sleep()不建议在任何地方使用。您检查反应组件安装的解决方案是一个很好的解决方案。

如果你不喜欢上面的解决方案,这里是我专门用来处理我的大部分 React UI 测试的:

public static void WaitAndClick(this IWebDriver driver, By by)
{
     var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
     wait.Until(ExpectedConditions.ElementToBeClickable(by));

     driver.FindElement(by).Click();
}
Run Code Online (Sandbox Code Playgroud)

我在自动化 React UI 方面的问题涉及元素加载时间过长。大部分页面都会加载,但我尝试单击的组件有时不存在。所以我封装Click()了一个WaitAndClick()方法,以确保在我尝试执行点击之前元素是可点击的。这适用于我的大多数情况。