WinAppDriver icon indicating copy to clipboard operation
WinAppDriver copied to clipboard

Taking time to find an element by name

Open ritusenleo opened this issue 3 years ago • 18 comments

Taking 31.6s just to find the element by name and click on it.

Any suggestion on it please?

ritusenleo avatar Sep 12 '22 15:09 ritusenleo

From my experience with our 1 application we test... For performance:

  • Do not find elements from root.
  • .FindElement has an Enabled expectation which will fail at the implicit timeout. (This can be a while)
  • We use some caching to save controls. Then search more locally using the cached controls.
  • Datagrid controls are a performance challenge, use XPath to narrow down results as quickly as possible.

liljohnak avatar Sep 12 '22 18:09 liljohnak

From my experience with our 1 application we test... For performance:

  • Do not find elements from root.
  • .FindElement has an Enabled expectation which will fail at the implicit timeout. (This can be a while)
  • We use some caching to save controls. Then search more locally using the cached controls.
  • Datagrid controls are a performance challenge, use XPath to narrow down results as quickly as possible.

How do you cache control?

anunay1 avatar Sep 13 '22 04:09 anunay1

if you kindly share in details. Not finding element from root , in my case it is finding out the element but taking loads of time... regarding cache control if you share in details.

ritusenleo avatar Sep 13 '22 10:09 ritusenleo

@anunay1 we set them to a variable in our class property and reset them on test cleanup. Now the number of searched through elements are reduced. This helps us because of how large our application is. A note of caution: Microsoft could change, reuse runtimeIds for virtlized controls. To know if controls are virtual, you can use inspect.exe to see that only a subset of the controls are rendered; the rest are visible upon scroll. Controls of this nature cannot be counted on after scroll, so must be checked twice.

@ritusenleo searching from the driver is slow. Typically we spend 8 seconds a call when we search from the driver. But, searching from the first window (another cached control), we can find elements much faster (usually around 50 milliseconds)

liljohnak avatar Sep 13 '22 14:09 liljohnak

@liljohnak, could you please share an example. I am just using this below code: _driver.Current.FindElementByName("XXXXXXXXXX").Click();

My code performs number of click events /sendkeys on the same page but while finding one particular element and clicking on it its taking time.

ritusenleo avatar Sep 13 '22 15:09 ritusenleo

I used cached class property for each control and parent controls also and IWebElement to check is cached control exists.

public class LoginPage
{       
	private IWebElement userNameField;
	private IWebElement parentElement;

	public LoginPage(IWebDriver Session)
	{
		Session = Session;
	}
	
	private IWebElement ParentElement
	{
		get
		{
			if (parentElement.IsControlNotExists())
				parentElement = Session.FindElement(By.XPath("//*[@class='parent']"));
			return parentElement;
		}
	}      
	
	private IWebElement UserNameField
	{
		get
		{
			if (userNameField.IsControlNotExists())
				userNameField = ParentElement.FindElement(By.XPath("//Button"));
			return userNameField;
		}
	}      
}

public static class WebElementExtensions
{        

	public static bool IsControlNotExists(this IWebElement element)
	{
		try
		{
			return element == null || !element.Displayed || !element.Enabled ||
				   Convert.ToBoolean(element.GetAttribute("IsOffscreen"));
		}
		catch (Exception e)
		{
			//
		}

		return true;
	}
}

Shakevg avatar Sep 13 '22 15:09 Shakevg

can you check with findelements how much time does it take.

anunay1 avatar Sep 13 '22 16:09 anunay1

AppiumWebElement.FindElement() will wait for an element to exist and be enabled. AppiumWebElement.FindElements() will not wait.

liljohnak avatar Sep 13 '22 19:09 liljohnak

i get this error if i use find elements: error: The HTTP request to the remote WebDriver server for URL http://127.0.0.1:4723/session/86B7578F-9AD7-40F8-8E8A-D4FBE14FAE4F/elements timed out after 60 seconds. (60.2s)

My code: var count=_driver.Current.FindElementsByName("XXXXXXXXXXX").Count; Console.WriteLine("Element Num=" + count); // _driver.Current.FindElementByName("xxxxxxxxx").Click();

ritusenleo avatar Sep 14 '22 08:09 ritusenleo

We made an AppiumWebElement extension for these. .Click() can easily be blocked by other elements. If you plan on only testing with 1 monitor, you can use the .Location property to move your mouse and click to the location. Secondly, you will need to use .FindElements() and wait until .Count>0 to return the first element. We also made extension methods for these since it was common.

liljohnak avatar Sep 14 '22 14:09 liljohnak

I tried to use this.. just to find the element on other thread and click on it , but it can't find the element.(waitTime=3000)

public static void ClickElement(this WindowsDriver<WindowsElement> driverSession, string elementName, int waitTimeInMilliseconds) { var timeOutStopWatch = new Stopwatch();

        Task clickElementTask = new Task(() =>
        {
            timeOutStopWatch.Start();
            try
            {
              driverSession.FindElementByName(elementName).Click();
            }
            catch
            {

            }

            
        });

        clickElementTask.Start();

        while (waitTimeInMilliseconds > timeOutStopWatch.ElapsedMilliseconds)
        {
            Thread.Sleep(500);
            if (clickElementTask.Status == TaskStatus.RanToCompletion)
                break;
        }

    }

ritusenleo avatar Sep 14 '22 14:09 ritusenleo

Exactly what you have, but use FindElements and Actions to click the location.

liljohnak avatar Sep 14 '22 14:09 liljohnak

used this... element not found... it failed at var count.

timeOutStopWatch.Start(); try { var count = driverSession.FindElementsByName(elementName).Count; Actions action = new Actions(driverSession); action.MoveToElement(driverSession.FindElementByName(elementName)); action.Click(); action.Perform();

            }
            catch
            {

            }

ritusenleo avatar Sep 14 '22 14:09 ritusenleo

I don't have my computer at the moment but something more like this.

public static void ClickElement(this WindowsDriver driverSession, string elementName, int waitTimeInMilliseconds)
{
var timeOutStopWatch = new Stopwatch();

        Task clickElementTask = new Task(() =>
        {
            timeOutStopWatch.Start();
            try
{
Actions action = new Actions(driverSession);
action.MoveToElement(driverSession.FindElementsByName(elementName)[0].Location);
action.Click();
action.Perform();
            }
            catch
            {

            }

            
        });

        clickElementTask.Start();

        while (waitTimeInMilliseconds > timeOutStopWatch.ElapsedMilliseconds)
        {
            Thread.Sleep(500);
            if (clickElementTask.Status == TaskStatus.RanToCompletion)
                break;
        }

    }

liljohnak avatar Sep 14 '22 16:09 liljohnak

action.MoveToElement(driverSession.FindElementsByName(elementName)[0].Location); - provideing error (Cannot convert System.Drawing.Point to OpenQA.Selenium.IWebElement) It doesn't support in the my solution

ritusenleo avatar Sep 15 '22 08:09 ritusenleo

When I am trying to create a new task and click the element its unable to find the element. Its unable to find the element if i use findelements() but when i m using _driver.Current.FindElementByName("XXXXXXXXXX").Click(); its taking >30 sec but the operation occurs. help from the team please

ritusenleo avatar Sep 19 '22 09:09 ritusenleo

How many times in a test run do you need to find this element, if it's umpteen times then please use cache mechanism as suggested by @liljohnak & @Shakevg Please send a teams call request as i suspect issue in your code as was the case last time.

anunay1 avatar Sep 20 '22 10:09 anunay1

@anunay1 i sent you a zoom request

ritusenleo avatar Sep 20 '22 11:09 ritusenleo