我开始使用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 应用程序中的每个组件都将在自己的时间单独调用自己的生命周期事件,因此很难知道给定控件何时完成其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()
)?
我已经为 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()
方法中,以确保在尝试执行单击之前元素可单击。这适用于我的大多数情况。