Search code examples
c#performancewatin

Slow iteration through elements in WatiN


I'm writing an application with Watin. Its great, but running a performance analysis on my program, over 50% of execution time is spent looping through lists of elements.

For example: foreach (TextField bT in browser.TextFields) {

Is very slow.

I seem to remember seeing somewhere there is a faster way of doing this in WatiN, but unfortunately I can't find the page again.

Accessing the number of elements also seems to be slow, eg; browser.CheckBoxes.Count

Thanks for any tips, Chris


Solution

  • I think I could answer you better if I had a better idea of what you were trying to do, but I can share some observations on what I've learned with WatiN so far.

    The more specific your selectors are, the faster things will go. Avoid using "browser.Elements" as that is really generic. I'm not sure that it saves much, but doing something like browser.Body.Elements throws the header elements out of the scope of things to check and may save a few calculations.

    When I say "scope", consider that WatiN always starts with the entire DOM. Can you think of ways to limit the scope of elements perhaps to the text fields within the main div on your page? WatiN returns Elements and ElementCollections, each of which may have its own ElementCollection. That div probably has a specific ID, so you can do something like

    var textFields = ie.Div("divId").TextFields;
    

    Look for opportunities to be more specific, and you can use LINQ to describe what you want more clearly. For example, can you write something like:

    ie.Body.TextFields.
      Where(tf => !string.IsNullOrWhiteSpace(tf.ClassName) && tf.ClassName.Contains("classname")).ToList().
      Foreach(tf => tf.Value = "Your Text");
    

    I would refine that further by reducing the number of times I scan the collection by doing something like:

    ie.Body.TextFields.ToList().
      Foreach(tf => {
        if(!string.IsNullOrWhiteSpace(tf.ClassName) && tf.ClassName.Contains("classname")) { 
          tf => tf.Value = "Your Text"
        }
      });
    

    The "Find.By*" specifiers also help WatiN operate on the collections you want faster and are a more elegant short-hand for what I wrote above:

    ie.Body.TextFields.Filter(Find.ByClass("class")).ToList().ForEach(tf => tf.Value = "Your Text");
    

    And as a last piece of advice, this project lets you find elements using jQuery/CSS style selectors.

    So, tl;dr: Narrow down the scope of what you're looking for, and be specific.

    Hope that helps. I'm looking for ways to speed up my own tests.