Winappdriver: FindElementByName - Element couldn't be located

Created on 5 Mar 2018  路  10Comments  路  Source: microsoft/WinAppDriver

Hi,

I have a test which passes in Visual Studio debug mode but fails when it is run as normal. The test is:

AppSession.FindElementByAccessibilityId("UsernameTextBox").SendKeys("login");
            AppSession.FindElementByAccessibilityId("PasswordTextBox").SendKeys("password");

            var loginButton = AppSession.FindElementByAccessibilityId("LoginButton");
            loginButton.Click();

            AppSession.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromMilliseconds(5000));
            var window = AppSession.FindElementByName(windowName);

            Assert.IsNotNull(window);

This code is run on test initialization:

private const string ServerURL = "http://127.0.0.1:4723";
        protected DesiredCapabilities AppCapabilities { get; set; }
        protected WindowsDriver<WindowsElement> AppSession { get; set; }

        protected void InitApplication()
        {
            AppCapabilities = new DesiredCapabilities();
            AppCapabilities.SetCapability("app", $"{Environment.CurrentDirectory}\\app.exe");
            AppSession = new WindowsDriver<WindowsElement>(new Uri(ServerURL), AppCapabilities);
        }

When I put breakpoint on the line
var window = AppSession.FindElementByName(windowName);
then test passes in debug mode. Otherwise it fails with exception System.InvalidOperationException: An element could not be located on the page using the given search parameters.

After login button is clicked the Window is maximized and it's name gets updated.

Any help?

Most helpful comment

@lekso81 - here's how I accomplished this in C# for a login workflow scenario. After login, the code waits for the main window using the DefaultWait which will try to find the element every 1 second until it finds it or until the timeout expires...

    loginWindow.FindElementByAccessibilityId("Submit").Click();

    var wait = new DefaultWait<WindowsDriver<WindowsElement>>(_session)
    {
        Timeout = TimeSpan.FromSeconds(60),
        PollingInterval = TimeSpan.FromSeconds(1)
    };
    wait.IgnoreExceptionTypes(typeof(InvalidOperationException));

    WindowsElement mainWindow = null;

    wait.Until(driver =>
    {
        driver.SwitchTo().Window(driver.WindowHandles[0]);

        mainWindow = driver.FindElementByAccessibilityId("MainWindow");

        return mainWindow != null;
    });

...not sure if this is best approach, but it works better than Thread.Sleep() IMHO since I cannot control how long it might actually take for the login process to complete and the main window to finally open.

All 10 comments

Try to put this line : AppSession.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromMilliseconds(5000));
Inside the test initialization

    protected void InitApplication()
    {
        AppCapabilities = new DesiredCapabilities();
        AppCapabilities.SetCapability("app", $"{Environment.CurrentDirectory}\\app.exe");
        AppSession = new WindowsDriver<WindowsElement>(new Uri(ServerURL), AppCapabilities);
        AppSession.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromMilliseconds(5000));
    }

and after loginButton.Click() replace the same line for a Thread.Sleep(5000) (or more depending of how long it takes to load)

Mixing explicit and implicit waits can get hairy if it becomes a regular pattern in your code. It might be worth checking if the appium dotnet driver has implemented Selenium's explicit waits yet and leverage those as needed in some common methods that all of your tests can call into.

An alternative that I've used in certain cases is to create your own wait function that has a try/catch or while loop. So E.G., in a base class you could have something like (and forgive me, I'm totally spacing if the FindElementBy methods throw an exception if it can't find an element. If it does, you would have to wrap that with a try/catch):

WindowsElement WaitForElementToExist(string elementName, int waitTime = 10)
{
   WindowsElement result;
   Stopwatch timer = new Stopwatch();
   timer.Start();
   do
   {
      var elem = AppSession.FindElementByName(elementName)
      if(elem != null)
      {
         return elem;
      }
   }while(timer.Elapsed < TimeSpan.FromSeconds(waitTime))
   // Throw exception here or return an expected value for a failure, e.g. null.
}

Your test would then look something like:
var window = WaitForElementToExist(windowName)

You could make this more flexible by taking in a Func, and then you can pass in some more specific conditions to try on, but that could be overkill for your project.

Hi,

thank you for your responses. My tests now pass, but only a Thread.Sleep(5000) statement after Click event helps. The WaitForElementToExist function doesn't work and always returns null. This is what I implemented using recommendation from PandaMagnus:

protected WindowsElement WaitForElementToExist(Func<string, WindowsElement> findElement, string elementName, int waitTime = 10)
        {
            WindowsElement result = null;
            var timer = new Stopwatch();
            timer.Start();
            do
            {
                try
                {
                    WindowsElement elem = findElement(elementName);
                    if (elem != null)
                    {
                        result = elem;
                        break;
                    }
                }
                catch { }

                Thread.Sleep(100);
            } while (timer.Elapsed < TimeSpan.FromSeconds(waitTime));

            return result;
        }

It is used as:

var window = this.WaitForElementToExist(AppSession.FindElementByName, windowName);
Assert.IsNotNull(window);

If you care to avoid using the Thread.Sleep(5000), I'd recomment placing an AppSession.FindElementByName(windowName); call right after this line:
WindowsElement elem = findElement(elementName);

Then step through the code to see if they return different things.

If you are okay with the five second wait, then disregard. :)

As per my original post, in debug mode everything works just fine.

In execution/Run mode only Thread.Sleep helps. If I put Thread.Sleep inside the WaitFor anywhere before line
WindowsElement elem = findElement(elementName);
then it also works (obviously, it doesn't really iterate because element is found on the first attempt)

I am not really OK with 5 seconds wait because we want to create comprehensive test coverage and I'd like to keep tests execution time to required minimum. Also, it is not a solution. If execution would take more than 5 seconds in an odd test then the test will fail.

@lekso81 - here's how I accomplished this in C# for a login workflow scenario. After login, the code waits for the main window using the DefaultWait which will try to find the element every 1 second until it finds it or until the timeout expires...

    loginWindow.FindElementByAccessibilityId("Submit").Click();

    var wait = new DefaultWait<WindowsDriver<WindowsElement>>(_session)
    {
        Timeout = TimeSpan.FromSeconds(60),
        PollingInterval = TimeSpan.FromSeconds(1)
    };
    wait.IgnoreExceptionTypes(typeof(InvalidOperationException));

    WindowsElement mainWindow = null;

    wait.Until(driver =>
    {
        driver.SwitchTo().Window(driver.WindowHandles[0]);

        mainWindow = driver.FindElementByAccessibilityId("MainWindow");

        return mainWindow != null;
    });

...not sure if this is best approach, but it works better than Thread.Sleep() IMHO since I cannot control how long it might actually take for the login process to complete and the main window to finally open.

Isn't this a bug? Shouldn't setting the ImplicitlyWait property cause the original invocation for finding elements to block until either the element is found or the timeout occurs? I'm running into this with the WindowsDriver driver too with the FindElement methods as well. What am I missing?

@ronjonesjr - I am not using ImplicitlyWait. Please see https://github.com/Microsoft/WinAppDriver/issues/375 for more.

I also have this problem. I have tried various approaches: DefaultWait, ImplicitWait, Sleep.
It is quite frustrating: while debugging everything works, while running nothing works.

Any news or other ideas?

Hi @a-einstein,

Can you be more specific on what's failing for you? E.g. Would you provide a sample test scenario with the log from WinAppDriver.exe indicating certain command you sent that didn't behave the way you expected?

The implicit timeout example below would show that the API works as intended (at the moment, the tests are broken as it is not aligned with the latest updated Alarms & Clock app. Fix is on the way).
https://github.com/Microsoft/WinAppDriver/blob/v1.1/Tests/WebDriverAPI/Timeouts.cs#L60

Was this page helpful?
0 / 5 - 0 ratings

Related issues

SimonKirkhamCL4U picture SimonKirkhamCL4U  路  3Comments

quincycs picture quincycs  路  3Comments

sandeepdroid picture sandeepdroid  路  3Comments

SanjeevKumarmn picture SanjeevKumarmn  路  4Comments

hassanuz picture hassanuz  路  4Comments