等待Selenium和React

时间:2019-06-14 17:33:15

标签: c# reactjs selenium selenium-webdriver

我开始使用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);
}

但是,如果我们要测试React应用程序,事情会变得更加复杂。鉴于您的React应用程序中的每个组件都将在各自时间内分别调用 their own lifecycle events,因此很难知道给定控件何时完成其Render()生命周期。

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

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

然后我可以在测试中执行以下操作:

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

但是,这似乎是种麻烦的解决方法。

是否有人遇到过相同的问题或是否知道可能的解决方法(仅使用Thread.Sleep()除外)?

1 个答案:

答案 0 :(得分:4)

我已经为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();
    }
}

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

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

如果您要检查的组件一直在变化,即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"));
    }

正如我提到的那样,没有万能的方法可以做到这一点,不建议在任何地方使用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();
}

我的React UI自动化问题涉及到元素加载时间太长。页面的大部分将加载,但是我尝试单击的组件有时不存在。因此,我将Click()包装在WaitAndClick()方法中,以确保在尝试执行单击之前该元素是可单击的。这适用于我的大多数情况。