I have the following elements identified in a page object..
public WindowsElement usernameField => _session.FindElementByAccessibilityId("UserName");
public WindowsElement passwordField => _session.FindElementByAccessibilityId("Password");
public WindowsElement menuButton => _session.FindElementByXPath("//Button[contains(@Name, 'Menu')]");
I have a test with the following steps..
WaitForObject(usernameField)
usernameField.SendKeys("...")
WaitForObject(passwordField)
passwordField.SendKeys("...")
ClickButton("Sign In");
WaitForObject(menuButton);
menuButton.Click();
And below, here is my WaitForObject method..
// Wait for an Object to be accessible
public void WaitForObject(WindowsElement element)
{
var wait = new DefaultWait<WindowsDriver<WindowsElement>>(_session)
{
Timeout = TimeSpan.FromSeconds(10),
PollingInterval = TimeSpan.FromSeconds(1)
};
wait.IgnoreExceptionTypes(typeof(WebDriverException));
wait.IgnoreExceptionTypes(typeof(InvalidOperationException));
wait.IgnoreExceptionTypes(typeof(StaleElementReferenceException));
wait.IgnoreExceptionTypes(typeof(NoSuchElementException));
wait.IgnoreExceptionTypes(typeof(NotFoundException));
WindowsElement waitElement = null;
wait.Until(driver =>
{
waitElement = element;
return waitElement != null && waitElement.Enabled && waitElement.Displayed;
});
}
The WaitForObject method works great for the usernameField & passwordField checks, but for some reason it fails immediately when passing in the menuButton. I know it was checking properly for usernameField & passwordField because I included some Console.WriteLines() to print out whenever it would detect one of those exceptions. As soon as it gets to the menuButton, nothing is logged it just fails immediately with a WebDriverException
OpenQA.Selenium.WebDriverException : An element could not be located on the page using the given search parameters.
Why would it not act the same for the menuButton? I have tried other approaches using while loops catching general Exceptions, but still it fails immediately when it gets to this element with a WebDriverException.
If I use a Thread.Sleep(10000) before trying to check for the element, it works fine and performs the click..
I am using WinAppDriver / Appium libraries.
Oh wait, sorry, I looked at your code more closely. Basically what's happening is because the method parameter is asking for the type itself, when C# goes to hand in the element to WaitForObject, it tries to evaluate the "WindowsElement menuButton" expression when it's handed to WaitForObject. By changing the WaitForObject method to accept a delegate, you'll defer that evaluation until you're inside the wait.
You'll need to change your WaitForObject to be something like:
public void WaitForObject(Func<WindowsElement> element)
// Unchanged code here
wait.Until(driver =>
{
waitElement = element();
return waitElement != null && waitElement.Enabled && waitElement.Displayed;
});
THEN call it like: WaitForObject(() => menuButton); menuButton.Click();