Monday, March 14, 2011

Config Files

So for this post, I thought I would cover a pretty common problem people have with Selenium....how to get config files working! In my experience, most selenium coders don't have a developer's background, and may not know how to setup a standard App.config file.

When we compile our visual studio project, we end up getting a .dll we open with nUnit.  This is fine, we open the file, run the tests, and yell at the developers just like normal.  However, what if we want to change something about our tests?  Maybe we want to run them against a different environment, or we want to use a different username and password.  We normally would have to go back into visual studio, change the values, recompile, and run again.

However, nUnit automatically looks for a config file with our dll.  We can use this file to store our paramaters we want to change, and not have to recompile to modify our tests.  We could also have several different config files pre-generated, for different environments, users, browsers, languages, or whatever.   The file is saved as xml, so it is editable in any text editor.

Before we go into the file itself you should know that nUnit looks for a config file with your project name + .config.  So if our project is SeleniumTests.dll, it will look in the same directory for a file named SeleniumTests.dll.config.


So lets get started.  To add the config file, in Visual Studio right click on the project and select "Add New Item", and then select Application Configuration File.  Now that we have the file, we need to add our data into it.  So we want to add a new section called appSettings inside the <configuration> tag.  So it will look like this:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
</appSettings>
</configuration>

Now, all our variables can be stored inside the appSettings section, as follows:


<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
    <add key="envUrl" value="http://www.google.com/"/>
    <add key="browser" value="*firefox"/>
</appSettings>
</configuration>

We now have two variables created, one with our environment url, and the other with the browser to launch.

The last step is to be able to access our new variables.  The code itself is simple, however I would recommend creating a "Common" class that contains these global variables, that way all of your tests can access them.  In addition, the use of standard get/set commands allows you to use more complicated logic or setup permissions for your variables.

public static class Common
{
   public static int envUrl{ get ConfigurationManager.AppSettings["envUrl"]; set { envUrl= value; } }
 }

So at this point we have a Common.envUrl variable we can get/set.  We're done, right?  Technically yes, but it can be a pain to have to constantly be updating a config file.  Maybe you need to update five variables depending on what environment you are in.  The quickest way to solve this issue is to set sectionGroups.


In our example, we have added the ability to point our tests to different URL's through the Common.envUrl variable.  However, maybe there are other things that need to change as well when we change environments.  Using groups we can specify subsections to switch between without having to edit/delete values.

We define our sectionGroups in the configSections in our config file, then specify the data for each section later.  In the following example, I am defining a timeout value, and my username/password unique for two different environments.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <sectionGroup name="Environments">
      <section name="qa" type="System.Configuration.AppSettingsSection, System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
      <section name="prod" type="System.Configuration.AppSettingsSection, System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
    </sectionGroup>
  </configSections>
<Environments>
    <qa>
      <add key="timeout" value="120000"/>
      <add key="userName" value ="testuser1"/>
      <add key="password" value ="password1"/>
  </qa>
    <prod>
      <add key="timeout" value="60000"/>
      <add key="username" value ="produser1"/>
      <add key="password" value ="password2"/>
  </prod>
  </Environments>
</configuration>

We can now get the section and serialize it as a NameValueCollection. 

private static NameValueCollection envSettings = ConfigurationManager.GetSection("Environments") as NameValueCollection;

Now we can access our variables with the envSettings object like this:

envSettings.username, envSettings.password, envSettings.timeout.

Thursday, February 10, 2011

The Checkbox Quandary

So since I haven't posted in a month, and couldn't think of anything better to discuss, I'm going to share a neat little solution to what I call "The checkbox quandary".  It is summarized as follows:

Clicking on a checkbox only changes it's state.  Selenium doesn't know how to set it to a specific state.  This means that the value of the checkbox could potentially fluctuate each time we run our test.  To get around this we typically check the state of the checkbox before we check it.  Doing this each time is a pain, so here is a simple setCheckbox routine that does the logic for you. It takes standard locator and a boolean specifying if you want the checkbox checked or not.

 public void setCheckbox(string locator, bool isChecked)
        {
            selenium.waitForVisible(locator);
            if((isChecked==true)!=(selenium.IsChecked(locator)))
            {
                    click(locator);
            }

        }

The logic is pretty simple.  If our checkbox state isn't the specified state, we click the checkbox.  Otherwise, it's already in the correct state so we do nothing.  We put a waitForVisible command in there to make sure the element is fully rendered (and all javascript routines on the page are loaded) before we click on it.

Friday, January 7, 2011

Quick XPath For Dummies

So I had someone tell me they needed a more fundamental tutorial on xpath.  So lets start off with the basics:

What is Xpath?  It is a short way of referencing an element on a web page. 
What is it for?  In selenium it is used for identifying a html element that does not have an easy, unique identifier such as id, name, text.  
How does it work?  Well I don't really know.  But essentially it searches the web page, top to bottom, looking for elements that match the criteria. 

Let's talk about html.  Here is an example element: <a href=http://www.google.com>google link</a>.  This will show up on the page as a text link displaying the words "google link" and it will take you to www.google.com.  For each element there are three main parts:  the type, the attributes, and the text. 
Our element is of type a.  It has an attribute called href equal to http://www.google.com.  and it has text equal to "google link".  We can use all three of these things to search for our elements. 

The next concept to understand is the idea of nodes, and the familial relationship of html elements.  Look at this example code:

<div title="Section1">
   <td name="Search">
      <tr class="Yahoo">Yahoo Search</tr>
      <tr class="Google">Google Search</tr>
   </td>
</div>

Notice the </div> at the bottom? That means the td and tr elements are contained within the div.  These other elements are considered descendants of the div.  The td is a child, and the tr is a grandchild (and so on and so forth).  The two tr elements are considered siblings.  This is vital, as xpath uses these relationships to find your element

So suppose I wanted to find the google item.  Any of the following expressions will work:
//tr[@class='Google']
/div/td/tr[2]
//div[@title="Section1"]//tr[text()="Google Search"]

So lets analyze the expressions.  We start at the top element (also known as a node).  The // means to search all descendants, / means to just look at the current element's children.  So //div means look through all descendants for a div element.  The brackets [] specify something about that element.  So we can look for an attribute with the @ symbol, or look for text with the text() function.  We can chain as many of these together as we can. 

 Here is a quick reference:
// search all descendant elements
/ search all child elements
[] The predicate (specifies something about the element you are looking for)
@ Specifies an element attribute.  (For example, @title)
text() Gets the text of the element. 
. specifies the current node (useful when you want to look for an element's children in the predicate)
.. specifies the parent node
contains() Use this in the predicate if you can't do a full string match on an attribute or text() value.

waiting for a popup to close

I was having a problem yesterday where the popup I was working on didn't close by the time the next one was supposed to be open.  I looked through the selenium api and realized there was no good waitForPopUpToClose command, so I created a new function.  All it does is wait until the number of windows is 1.  This will obviously only work if you have 1 window open (besides the popup).

        public void waitForPopupToClose()
        {
            string[] titles;
            for (int second = 0; second<timeoutSeconds; second++)
            {
                try
                {
                    titles = selenium.GetAllWindowTitles();
                    if (titles.Length > 1)
                        sleep(1000);
                    else
                    {
                        break;
                    }
                }
                catch (Exception)
                {
                  
                }
                Thread.Sleep(1000);
            }
        }

Thursday, January 6, 2011

Xpath In All It's Glory

I thought it would be a good idea to write up a little bit about Xpath, why it rocks, and why you SHOULD use it.  I know many "experts" in selenium tell you that Xpath is bad, it's slow, and it needs to be avoided at all costs.  I disagree completely.  I will, of course, try to reference an item in the most clean and concise method possible.  So if an item has a unique id or name, you should use that and avoid an xpath expression.  However, there are so many times when the element you're trying to locate does not have a unique identifier, and you need to find it.

The problem with Xpath is the way most xpath generating programs work.  They generate a string of absolute locators a million miles long.  So something like this:  /body/td/tr[2]/div[3]/a.  This is NOT how you want to use Xpath.  This style of xpath expression should be your very LAST resort on locating an element.  But what is the alternative? Start with the parent.

First off, I strongly recommend the use of // instead of /.  It may be slightly slower locating an element, but it allows you to construct a much more transparent, and reliable xpath expression. 

So something like this would be a more appropriate xpath from the above example:  //div[@class='object1']/a  This looks through the entire page for a div with attribute "class" equal to "object1".  It then looks for a child <a> element.  This is fine as long as there is only one div with class=object1.  However, class is not a unique identifier, and it's quite possible there is more than one item on the page that matches our expression.  What is the solution?  Add another parent. 

//td[@title='Row1']//div[@class='object1']/a.  Neither title nor class are unique, but hopefully the combination of both is.  However, maybe not. 

If you can't find a parent or grandparent to start with that is unique, you can also try a sibling node.  Suppose we have a table where nothing has attributes.  We want to type into the text field in an adjacent row to a link.  We can find the link, because the link text is unique.  But we can't find the text field without resorting to some caveman xpath expression.  The easiest way i've found to do this is to start with the parent node, and in the predicate (the []) look for a child node, then select another node.  For example:
This expression select a row, looks for a descendant link with text "User1", then selects any descendant input.  You have to use the period inside to select the current node.

//tr[.//a[text()="User1"]]//input

Selenium and Selenium2 Visual Studio Templates

Here are some visual studio templates I created for selenium and selenium2.  All you should have to do is fix the references once you import them into visual studio 2010.

They feature:
Base class with Selenium1 api commands.
.config file usable by nUnit
PageObject design
Multi-project format
Automatically launches and closes selenium server.
Relative pathing
Sample Google Test

Selenium 1 Template

Selenium 2 Template