等待元素,然后单击WinAppDriver

时间:2019-05-13 18:01:34

标签: c# 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()方法上。我没有正确传递元素属性吗?为什么按钮的实例化也会对其进行搜索?

2 个答案:

答案 0 :(得分:1)

在winappdriver github上有一个open issue。看一下this对此的评论。这似乎是一个Appium问题。我不知道这个问题的状态。

基本上,这意味着您将不得不采用解决方法。使用Thread.Sleep(/*milliseconds*/)bad idea

我在函数中实现了while循环,以通过自动化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) 假设 可以继续,而循环 知道 则可以继续测试。
  • 使用“计时器/超时”组合,您可以检查操作花费了多长时间(例如,保存了一些修改),并且如果花费的时间超过了超时时间,则无法继续操作。

或者,此代码也可以正常工作:

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(请参阅PollingInterval对象的DefaultWait属性。

答案 1 :(得分:0)

我希望这会有所帮助:

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传递给方法之前,应先在此处进行标识。有时控件会在另一个容器内,因此最好将其识别并将其传递给方法。