0

I have a collection of records on a web page, and when a record is clicked, a 'Delete' link is displayed (actually 'unhidden' as its actually always there).

When trying to access this 'Delete' link, I am using its value.

When I use Driver.FindElement, it returns the first Delete link, even though it's hidden, and therefore can't click it (and shouldn't as it is not the right link).

So, what I basically want to do is find only non-hidden links. The code below works, but as it iterates through every Delete link I am afraid it may be inefficient.

Is there a better way?

public class DataPageModel : BasePageModel
{
    private static readonly By DeleteSelector = By.CssSelector("input[value=\"Delete\"]");

    private IWebElement DeleteElement
    {
        get
        {
            var elements = Driver.FindElements(DeleteSelector);
            foreach (var element in elements.Where(e => e.Displayed))
            {
                return element;
            }
            Assert.Fail("Could not locate a visible Delete Element");
            return null;
        }
    }
}
Alister Scott
  • 3,675
  • 24
  • 41
  • Selenium tests are slow, so this code will probably not increase the execution time by even 1%... I would be more worried about readability of your code: communication of intent. Are you looking for one specific link or any non-hidden delete link. If one specific, it would be better to find by Id. If any link I'd find a better name for the property. – Torbjörn Kalin Apr 17 '12 at 05:51
  • Even if it's only 1%, it creates a snowball effect when you call this multiple times. Next thing you know you have a build that takes hours instead of minutes. – Alister Scott Apr 17 '12 at 06:00
  • Even if you call this method 100 times in the same test it probably only takes a fraction of the time it takes for your server to render one page. To improve the build time, measure and optimize the parts that actually take a long time. This method won't be it. – Torbjörn Kalin Apr 17 '12 at 06:27

1 Answers1

1

While I agree with @Torbjorn that you should be weary about where you spend your time optimizing, I do think this code is a bit inefficient.

Basically what is slowing the code down is the back and forth checking of each element to see if its displayed. To speed up the code, you need to get the element you want in one go.

Two options (both involve javascript):

jQuery

Take a look at the different ways to bring jQuery selectors to Selenium (I wrote about it here). Once you have that, you can make use of jQuery's :visible selector.

Alternatively if you know for sure the page already has jQuery loaded and you don't want to do all the extra code, you can simply use ExecuteScript:

IWebElement element = (IWebElement)driver.ExecuteScript("return $('input[value=\"Delete\"]:visible').first().get(0)");

Javascript

If you want to avoid jQuery you can just write a javascript function to do the same thing you are doing now in C#: Get all the possible elements and return the first visible one.

Then you would do something similar:

string script = //your javascript
IWebElement element = (IWebElement)driver.ExecuteScript(script);

You trade of readability with different degrees depending on which option you pick but they should all be more efficient. Of course these all require that javascript be enabled in the browser.

prestomanifesto
  • 12,528
  • 5
  • 34
  • 50