我开始使用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()
除外)?
答案 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()
方法中,以确保在尝试执行单击之前该元素是可单击的。这适用于我的大多数情况。