在使用 WinAppDriver 单击之前等待元素
Waiting for element before clicking with WinAppDriver
我有一个如此微不足道的问题,但我很难让我的代码在继续之前正确地等待一个对象。
我为我的驱动程序设置了以下配置
session.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(60);
我原以为这意味着它会在抛出与元素识别相关的错误之前至少等待 60 秒,例如
Message: System.InvalidOperationException : An element could not be located on the page using the given search parameters.
然而事实并非如此。尝试调用以下命令时,我在大约 2 秒内收到错误。
WindowsElement btn = session.FindElementByXPath("//Button[@Name='NEXT']");
btn.Click();
错误是在我刚刚定义按钮属性的那一行抛出的,而不是在实际的 Click() 方法上。我没有正确传递元素属性吗?为什么按钮的实例化也会进行搜索?
有 open issue on the winappdriver github. Take a look at this 评论。这似乎是一个 Appium 问题。我不知道这个问题的状态。
基本上,这意味着您将不得不求助于解决方法。使用 Thread.Sleep(/*milliseconds*/)
是 bad idea.
我在一个函数中实现了一个 while
循环,以通过 Automation ID 获取控件,如下所示:
/// <summary>
/// Gets a UI element based on a AutomationId.
/// </summary>
/// <param name="automationId">The AutomationId is a unique value that can be found with UI inspector tools.</param>
/// <param name="controlName">The name of the UI element.</param>
/// <param name="timeOut">TimeOut in milliseconds</param>
/// <returns></returns>
protected WindowsElement GetElement(string automationId, string controlName, int timeOut = 10000)
{
bool iterate = true;
WindowsElement control = null;
_elementTimeOut = TimeSpan.FromMilliseconds(timeOut);
timer.Start();
while (timer.Elapsed <= _elementTimeOut && iterate == true)
{
try
{
control = Driver.FindElementByAccessibilityId(automationId);
iterate = false;
}
catch (WebDriverException ex)
{
LogSearchError(ex, automationId, controlName);
}
}
timer.Stop();
Assert.IsFalse(timer.Elapsed > _elementTimeOut, "Timeout Elapsed, element not found.");
timer.Reset();
return control;
}
与 Thread.Sleep()
相比,使用循环有一些优势,它更灵活,而且与简单地阻止代码执行相比,您有更多的选择。
一些优点:
- 您的测试脚本继续执行:假设您的脚本暂停 5 秒,而被测应用程序继续运行。在您的脚本可能想知道的那 5 秒内可能会发生很多事情。但是不能,因为如果使用'Thread.Sleep()'.
,代码执行会被阻塞
- 动态等待:while 循环将迭代直到满足条件。这会使您的脚本在满足此条件后立即继续测试,从而使您的脚本 运行 更快。例如。您正在等待页面加载。
Thread.Sleep(5000)
将 假定 可以继续,而循环 知道 可以继续测试了
- 使用 timer/time out 组合,您可以检查操作花费了多长时间(例如保存一些编辑),如果花费的时间超过超时时间,您就知道不能继续。
或者,此代码也同样有效:
protected WindowsElement GetElement(string automationId, string propertyName, int timeOut = 10000)
{
WindowsElement element = null;
var wait = new DefaultWait<WindowsDriver<WindowsElement>>(Driver)
{
Timeout = TimeSpan.FromMilliseconds(timeOut),
Message = $"Element with automationId \"{automationId}\" not found."
};
wait.IgnoreExceptionTypes(typeof(WebDriverException));
try
{
wait.Until(Driver =>
{
element = Driver.FindElementByAccessibilityId(automationId);
return element != null;
});
}
catch(WebDriverTimeoutException ex)
{
LogSearchError(ex, automationId, propertyName);
Assert.Fail(ex.Message);
}
return element;
}
以上代码只会抛出一个WebDriverTimeoutException
,而不是连续抛出NoSuchElementException
。它不使用 while 循环,但我怀疑 wait.Until(...)
正在做类似的事情,因为 WinAppDriver 每 500 毫秒轮询一次 gui(请参阅 DefaultWait
对象上的 PollingInterval
属性。
希望对您有所帮助:
public void WaitTillControlToDisplay(WindowsElement control , int Waittime=30)
{
int startTime = 0;
while (startTime < Waittime)
{
try
{
if (!control.Displayed)
startTime += 1;
else
{
Thread.Sleep(1000);
return;
}
}
catch (OpenQA.Selenium.WebDriverException)
{
Thread.Sleep(1000);
return; // We should have Control loaded by now
}
Thread.Sleep(1000);
}
Assert.Fail("Time Out : Control - "+control+" Did not loaded within "+Waittime+" Seconds");
}
这里control
应该在传递给方法之前进行识别。有时控件会在另一个容器中,所以最好识别它并传递给方法。
我有一个如此微不足道的问题,但我很难让我的代码在继续之前正确地等待一个对象。
我为我的驱动程序设置了以下配置
session.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(60);
我原以为这意味着它会在抛出与元素识别相关的错误之前至少等待 60 秒,例如
Message: System.InvalidOperationException : An element could not be located on the page using the given search parameters.
然而事实并非如此。尝试调用以下命令时,我在大约 2 秒内收到错误。
WindowsElement btn = session.FindElementByXPath("//Button[@Name='NEXT']");
btn.Click();
错误是在我刚刚定义按钮属性的那一行抛出的,而不是在实际的 Click() 方法上。我没有正确传递元素属性吗?为什么按钮的实例化也会进行搜索?
有 open issue on the winappdriver github. Take a look at this 评论。这似乎是一个 Appium 问题。我不知道这个问题的状态。
基本上,这意味着您将不得不求助于解决方法。使用 Thread.Sleep(/*milliseconds*/)
是 bad idea.
我在一个函数中实现了一个 while
循环,以通过 Automation ID 获取控件,如下所示:
/// <summary>
/// Gets a UI element based on a AutomationId.
/// </summary>
/// <param name="automationId">The AutomationId is a unique value that can be found with UI inspector tools.</param>
/// <param name="controlName">The name of the UI element.</param>
/// <param name="timeOut">TimeOut in milliseconds</param>
/// <returns></returns>
protected WindowsElement GetElement(string automationId, string controlName, int timeOut = 10000)
{
bool iterate = true;
WindowsElement control = null;
_elementTimeOut = TimeSpan.FromMilliseconds(timeOut);
timer.Start();
while (timer.Elapsed <= _elementTimeOut && iterate == true)
{
try
{
control = Driver.FindElementByAccessibilityId(automationId);
iterate = false;
}
catch (WebDriverException ex)
{
LogSearchError(ex, automationId, controlName);
}
}
timer.Stop();
Assert.IsFalse(timer.Elapsed > _elementTimeOut, "Timeout Elapsed, element not found.");
timer.Reset();
return control;
}
与 Thread.Sleep()
相比,使用循环有一些优势,它更灵活,而且与简单地阻止代码执行相比,您有更多的选择。
一些优点:
- 您的测试脚本继续执行:假设您的脚本暂停 5 秒,而被测应用程序继续运行。在您的脚本可能想知道的那 5 秒内可能会发生很多事情。但是不能,因为如果使用'Thread.Sleep()'. ,代码执行会被阻塞
- 动态等待:while 循环将迭代直到满足条件。这会使您的脚本在满足此条件后立即继续测试,从而使您的脚本 运行 更快。例如。您正在等待页面加载。
Thread.Sleep(5000)
将 假定 可以继续,而循环 知道 可以继续测试了 - 使用 timer/time out 组合,您可以检查操作花费了多长时间(例如保存一些编辑),如果花费的时间超过超时时间,您就知道不能继续。
或者,此代码也同样有效:
protected WindowsElement GetElement(string automationId, string propertyName, int timeOut = 10000)
{
WindowsElement element = null;
var wait = new DefaultWait<WindowsDriver<WindowsElement>>(Driver)
{
Timeout = TimeSpan.FromMilliseconds(timeOut),
Message = $"Element with automationId \"{automationId}\" not found."
};
wait.IgnoreExceptionTypes(typeof(WebDriverException));
try
{
wait.Until(Driver =>
{
element = Driver.FindElementByAccessibilityId(automationId);
return element != null;
});
}
catch(WebDriverTimeoutException ex)
{
LogSearchError(ex, automationId, propertyName);
Assert.Fail(ex.Message);
}
return element;
}
以上代码只会抛出一个WebDriverTimeoutException
,而不是连续抛出NoSuchElementException
。它不使用 while 循环,但我怀疑 wait.Until(...)
正在做类似的事情,因为 WinAppDriver 每 500 毫秒轮询一次 gui(请参阅 DefaultWait
对象上的 PollingInterval
属性。
希望对您有所帮助:
public void WaitTillControlToDisplay(WindowsElement control , int Waittime=30)
{
int startTime = 0;
while (startTime < Waittime)
{
try
{
if (!control.Displayed)
startTime += 1;
else
{
Thread.Sleep(1000);
return;
}
}
catch (OpenQA.Selenium.WebDriverException)
{
Thread.Sleep(1000);
return; // We should have Control loaded by now
}
Thread.Sleep(1000);
}
Assert.Fail("Time Out : Control - "+control+" Did not loaded within "+Waittime+" Seconds");
}
这里control
应该在传递给方法之前进行识别。有时控件会在另一个容器中,所以最好识别它并传递给方法。