User Extensions and Add-ons in Selenium 1.0 Testing Tools

Exclusive offer: get 50% off this eBook here
Selenium 1.0 Testing Tools: Beginner’s Guide

Selenium 1.0 Testing Tools: Beginner’s Guide — Save 50%

Test your web applications with multiple browsers using the Selenium Framework to ensure the quality of web applications

£14.99    £7.50
by David Burns | November 2010 | Beginner's Guides RAW Open Source

In this article, by David Burns, author of Selenium 1.0 Testing Tools, we are going to look at how we can expand Selenium. This is for those times when Selenium's API is not verbose enough.

Selenium has the ability to allow developers to create functions, in the same three-column format, to all tests to reuse snippets of code instead of evaluating them with getEval calls.

User extensions and add-ons are all written in JavaScript. This is due to Selenium's core being written in JavaScript. Let's now have a look at user extensions.

In this article, we shall discuss:

  • User extensions
  • Add-ons

So let's get on with it...

 

Selenium 1.0 Testing Tools: Beginner’s Guide

Selenium 1.0 Testing Tools: Beginner’s Guide

Test your web applications with multiple browsers using the Selenium Framework to ensure the quality of web applications

  • Save your valuable time by using Selenium to record, tweak and replay your test scripts
  • Get rid of any bugs deteriorating the quality of your web applications
  • Take your web applications one step closer to perfection using Selenium tests
  • Packed with detailed working examples that illustrate the techniques and tools for debugging
        Read more about this book      

(For more resources on this subject, see here.)

Important preliminary points

If you are creating an extension that can be used by all, make sure that it is stored in a central place, like a version control system. This will prevent any potential issues in the future when others in your team start to use it.

User extensions

Imagine that you wanted to use a snippet of code that is used in a number of different tests. You could use:

type | locator | javascript{ .... }

However, if you had a bug in the JavaScript you would need to go through all the tests that reused this snippet of code.

This, as we know from software development, is not good practice and is normally corrected with a refactoring of the code. In Selenium, we can create our own function that can then be used throughout the tests.

User extensions are stored in a separate file that we will tell Selenium IDE or Selenium RC to use. Inside there the new function will be written in JavaScript.

Because Selenium's core is developed in JavaScript, creating an extension follows the standard rules for prototypal languages. To create an extension, we create a function in the following design pattern.

Selenium.prototype.doFunctionName = function(){
.
.
.
}

The "do" in front of the function name tells Selenium that this function can be called as a command for a step instead of an internal or private function.

Now that we understand this, let's see this in action.

Time for action – installing a user extension

Now that you have a need for a user extension, let's have a look at installing an extension into Selenium IDE. This will make sure that we can use these functions in future Time for action sections throughout this article.

  1. Open your favorite text editor.
  2. Create an empty method with the following text:

    Selenium.prototype.doNothing = function(){
    .
    .
    .
    }

  3. Start Selenium IDE.
  4. Click on the Options menu and then click on Options.
  5. Place the path of the user-extension.js file in the textbox labeled Selenium IDE extensions.
  6. Click on OK.
  7. Restart Selenium IDE.
  8. Start typing in the Command textbox and your new command will be available, as seen in the next screenshot:

What just happened?

We have just seen how to create our first basic extension command and how to get this going in Selenium IDE. You will notice that you had to restart Selenium IDE for the changes to take effect. Selenium has a process that finds all the command functions available to it when it starts up, and does a few things to it to make sure that Selenium can use them without any issues.

Now that we understand how to create and install an extension command let's see what else we can do with it. In the next Time for action, we are going to have a look at creating a randomizer command that will store the result in a variable that we can use later in the test.

Time for action – using Selenium variables in extensions

Imagine that you are testing something that requires some form of random number entered into a textbox. You have a number of tests that require you to create a random number for the test so you can decide that you are going to create a user extension and then store the result in a variable.

To do this we will need to pass in arguments to our function that we saw earlier. The value in the target box will be passed in as the first argument and the value textbox will be the second argument. We will use this in a number of different examples throughout this article.

Let's now create this extension.

  1. Open your favorite text editor and open the user-extension.js file you created earlier.
  2. We are going to create a function called storeRandom. The function will look like the following:

    Selenium.prototype.doStoreRandom = function(variableName){
    random = Math.floor(Math.random()*10000000);
    storedVars[variableName] = random;
    }

  3. Save the file.
  4. Restart Selenium IDE.
  5. Create a new step with storeRandom and the variable that will hold the value will be called random.
  6. Create a step to echo the value in the random variable.

What just happened?

In the previous example, we saw how we can create an extension function that allows us to use variables that can be used throughout the rest of the test. It uses the storedVars dictionary that we saw in the previous chapter. As everything that comes from the Selenium IDE is interpreted as a string, we just needed to put the variable as the key in storedVars. It is then translated and will look like storedVars['random'] so that we can use it later.

As with normal Selenium commands, if you run the command a number of times, it will overwrite the value that is stored within that variable, as we can see in the previous screenshot.

Now that we know how to create an extension command that computes something and then stores the results in a variable, let's have a look at using that information with a locator.

Time for action – using locators in extensions

Imagine that you need to calculate today's date and then type that into a textbox. To do that you can use the type | locator | javascript{...} format, but sometimes it's just neater to have a command that looks like typeTodaysDate | locator. We do this by creating an extension and then calling the relevant Selenium command in the same way that we are creating our functions. To tell it to type in a locator, use:

this.doType(locator,text);

The this in front of the command text is to make sure that it used the doType function inside of the Selenium object and not one that may be in scope from the user extensions.

Let's see this in action:

  1. Use your favorite text editor to edit the user extensions that you were using in the previous examples.
  2. Create a new function called doTypeTodaysDate with the following snippet:

    Selenium.prototype.doTypeTodaysDate = function(locator){
    var dates = new Date();
    var day = dates.getDate();
    if (day < 10){
    day = '0' + day;
    }
    month = dates.getMonth() + 1;
    if (month < 10){
    month = '0' + month;
    }
    var year = dates.getFullYear();
    var prettyDay = day + '/' + month + '/' + year;
    this.doType(locator, prettyDay);
    }

  3. Save the file and restart Selenium IDE.
  4. Create a step in a test to type this in a textbox.
  5. Run your script. It should look similar to the next screenshot:

What just happened?

We have just seen that we can create extension commands that use locators. This means that we can create commands to simplify tests as in the previous example where we created our own Type command to always type today's date in the dd/mm/yyyy format. We also saw that we can call other commands from within our new command by calling its original function in Selenium. The original function has do in front of it.

Now that we have seen how we can use basic locators and variables, let's have a look at how we can access the page using browserbot from within an extension method.

Selenium 1.0 Testing Tools: Beginner’s Guide Test your web applications with multiple browsers using the Selenium Framework to ensure the quality of web applications
Published: November 2010
eBook Price: £14.99
Book Price: £24.99
See more
Select your format and quantity:
        Read more about this book      

(For more resources on this subject, see here.)

Time for action – using browserbot from within an extension

Imagine that you need to interact with an element on the page and the only way to do that is to access it is through a JavaScript API. This is quite common when trying to automate testing against web-based editor components that are becoming commonplace. One that I have seen is the Telerik RADEditor.

To do this we will need to access the same browserbot object. This is because the getEval command runs the snippet within the Selenium object.

Let's see this in action now:

  1. Open up your favorite text editor and open up the user extensions file that you created earlier.
  2. Create a new function and call it doCheckDate, as seen in the following snippet:

    Selenium.prototype.doCheckDate = function(){
    var dates = new Date();
    var day = dates.getDate();
    if (day < 10){
    day = '0' + day;
    }
    month = dates.getMonth() + 1;
    if (month < 10){
    month = '0' + month;
    }
    var year = dates.getFullYear();
    var prettyDay = day + '/' + month + '/' + year;
    this.browserbot.getUserWindow().checkDate(prettyDay);
    }

  3. Save the file and restart Selenium IDE.
  4. Create a new step using the new command.
  5. Create a new step with verifyText that checks whether the location with "Answer" has the word Correct.
  6. Run the script. It should look similar to the next screenshot:

What just happened?

We have just seen how we can create a user extension to access the page using browserbot. This can then allow our tests to manipulate the DOM or access JavaScript APIs that may be available. Creating an extension command allows you to re-use the code in a number of different tests instead of using the getEval command.

This code re-use can be very beneficial especially if the tests require you to add or remove things from the DOM at the beginning of the test or at the end of the test.

There will be times where we may need to create a new command that either verifies or asserts something for the test. For this we can use the same technique Selenium's Core commands use to fail a test.

To do this we need to use the Selenium CommandComplete object in our extension method to keep track of the step when Selenium is updating the asserts passed or failed. This object is populated and then passed to the commandComplete function within the Selenium Object.

Let's now see this in action.

Time for action – creating new commands to verify or assert

Imagine that in the previous example you wanted to have the extension method verify the text on the screen instead of having a separate step to do the verification or assertion. This can make tests a lot more compact and possibly easier to read.

We can see this in the next example:

  1. Open your favorite text editor and the user extensions file that you created earlier.
  2. Create a new function called doFireDateAndVerifyText with the following snippet:

    Selenium.prototype.doFireDateAndVerifyText =
    function(locator,value){
    var dates = new Date();
    var day = dates.getDate();
    if (day < 10){
    day = '0' + day;
    }
    month = dates.getMonth() + 1;
    if (month < 10){
    month = '0' + month;
    }
    var year = dates.getFullYear();
    var prettyDay = day + '/' + month + '/' + year;
    this.browserbot.getUserWindow().checkDate(prettyDay);

    var lastResult = new CommandResult();
    try{
    var realValue = this.getText(locator);

    if (realValue === value){
    lastResult.failed = false;
    } else {
    lastResult.failed = true;
    }
    } catch (e) {
    lastResult.failed = true;
    lastResult.message = e.message;
    }
    this.commandComplete(lastResult);
    }

  3. Save the file and restart Selenium IDE.
  4. Run the test. I have shown it being run against a page that will fail in order to show you that it can make the test fail.

What just happened?

We have just seen how we can create new commands for our tests that can verify or assert that something is on the page. In the new command we started to use the CommandResult object to store the result of the test. When the step had completed, it called the this.commandComplete command so that we could record if the step was successful or not.

The CommandComplete object keeps track of whether the step was successful or not as well as any message that we may want to output to the screen to say why the step failed. This is the same procedure that Selenium Core code uses to show if a test has passed or failed.

If you wanted your new command to act as an assert and fail the test when it does not meet the criteria, add the following to the catch part of the extension:

this.testComplete();

Pop quiz

  • How do you store variables to be used later in the test?
    • Use the storedVars dictionary
    • Create a new variable that has global scope
    • You cannot store variables using user extensions
  • Can your user extension call other commands such as type or click?
  • Can your user extension access the DOM programmatically?
  • How can a new command fail a test if it was doing a verify?

Have a go hero – doing more with user extensions

Try to create a new command that will take a string from a variable that is saved in a step before and then reverse it. You will need to use the storeText command to get the string. Then create a function called doReverse that stores the result in a different variable to the one you used before. This second variable can then be echoed out or can be typed into a textbox or textarea.

Selenium 1.0 Testing Tools: Beginner’s Guide Test your web applications with multiple browsers using the Selenium Framework to ensure the quality of web applications
Published: November 2010
eBook Price: £14.99
Book Price: £24.99
See more
Select your format and quantity:
        Read more about this book      

(For more resources on this subject, see here.)

Add-ons

Adam Goucher, one of the Selenium IDE maintainers, created a new API that allowed anyone to create new add-ons for Selenium IDE. These add-ons differ from the user extensions that we see all the time, in that they are Mozilla Firefox add-ons that Selenium can access. This is similar to the way that YSlow, a plugin from Yahoo! can access Firebug and give you all the information that is needed. We saw another add-on for Firebug called Firefinder.

Time for action – creating a basic add-on

In this section of the article, we are going to have a look at how we can make a basic add-on. The following steps can also be used to create a normal Firefox add-on.

Firstly, you will need to create a folder on your hard drive. Everything that follows will be done within that folder.

  1. Open your favorite text editor.
  2. Create a file called install.rdf and add the following snippet. This file tells Mozilla Firefox what is needed to install this add-on.

    <?xml version="1.0" encoding="UTF-8"?>
    <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:em="http://www.mozilla.org/2004/em-rdf#">
    <Description about="urn:mozilla:install-manifest">
    <!-- needs to be in the format of an email address,
    but should be an actual email address -->
    <em:id>your email address</em:id>
    <!-- has to be lowercase -->
    <em:name>name of addon</em:name>
    <em:version>1.0</em:version>
    <em:creator>Your Name</em:creator>
    <em:description>
    A quick plugin for Selenium IDE
    </em:description>
    <em:type>2</em:type>
    <!--Preferences -->
    <em:optionsURL>
    chrome://book/content/view/options.xul
    </em:optionsURL>

    <!-- its a firefox plugin -->
    <em:targetApplication>
    <Description>
    <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
    <em:minVersion>1.5</em:minVersion>
    <em:maxVersion>4.0.*</em:maxVersion>
    </Description>
    </em:targetApplication>

    <!-- this is an Se-IDE plugin,
    so we need to specify it as a requirement -->
    <em:requires>
    <Description>
    <em:id>{a6fd85ed-e919-4a43-a5af-8da18bda539f}</em:id>
    <em:minVersion>1.4</em:minVersion>
    <em:maxVersion>1.*</em:maxVersion>
    </Description>
    </em:requires>
    </Description>
    </RDF>

  3. Create a new file called chrome.manifest in the root folder. This file lets the Mozilla Firefox add-on know where all the different bits of information are.

    content book chrome/content/

    locale book en-US chrome/locale/en-US/

    overlay chrome://selenium-ide/content/selenium-ide-common.xul
    chrome://book/content/view/optionsOverlay.xul

  4. Now that we have created the call.
  5. Create a folder called content.
  6. Inside content create a folder called view.
  7. Inside the view folder we will need to create a file called optionsOverlay.xul as we saw in the previous step. This will tell Selenium IDE that it needs to add the following items to the drop-down menu. The next snippet will add Book Addon options to the Selenium:

    <?xml version="1.0"?>
    <?xml-stylesheet href="chrome://global/skin/" type="text/css"?>

    <overlay id="selenium_overlay"
    xmlns=
    "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

    <menupopup id="options-popup">
    <menuitem label="Book Addon options" accesskey="P"
    oncommand=
    "window.open('chrome://book/content/view/options.xul',
    'Book Options','chrome=yes,,centerscreen=yes');" />
    </menupopup>

    </overlay>

  8. Create a file called options.xul and place the following snippet in it:

    <?xml version="1.0"?>
    <?xml-stylesheet href="chrome://global/skin/" type="text/css"?>

    <prefwindow id="book-prefs"
    title="'Book Options"
    width="520"
    height="200"
    xmlns=
    "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

    <!-- Pref Pane -->
    <prefpane id="book-panel" label="'Book Options">

    <preferences>
    <preference id="pref_perform"
    name="extensions.selenium-ide.book.book-options"
    type="bool" />
    </preferences>
    <!—Window layout so we can see how it all works together -->
    <tabbox>
    <tabs>
    <tab label="General"/>
    </tabs>
    <tabpanels flex="1" >
    <tabpanel>
    <vbox flex="1">
    <hbox align="center">
    <!—if you use & at the beginning and ; at the end it will allow
    you to localize if you create a folder called locale in the root
    and place in it different languages -->
    <label control="name" value="A Checkbox"/>
    <checkbox preference="checkbox_perf"
    id="checkbox" />
    </hbox>
    <spacer height="100" />
    </vbox>
    </tabpanel>
    </tabpanels>
    </tabbox>
    </prefpane>
    </prefwindow>

  9. In the options.xul file, you can add JavaScript so that when something is clicked, it can run a snippet of code. This means that you do not need to make something run automatically. To reference JavaScript you would add:

    <!—- reference some javascript -->
    <script type="application/x-javascript"
    src='//dgdsbygo8mp3h.cloudfront.net/sites/default/files/blank.gif' data-original="chrome://selenium-ide/content/api.js"/>

    <html:script type="application/javascript">
    var ide_api = new API();
    ide_api.addPluginProvidedFormatter("CheckBox",
    "Friendlier Checkbox name",
    "chrome://book/content/code/file-holding-info.js");
    </html:script>

    This registers JavaScript to the item and then when it is clicked it will run that snippet of code.

  10. Create a folder called code in content.
  11. Create a file in code to hold your code snippet.
    To reference other JavaScript files, you will need to use the following syntax:

    load('chrome://book/content/code/other-javascript.js');

    The snippet will need to have a name of what it will be recognized as. In the previous snippet, we called it CheckBox. Adding this.name = 'Checkbox'; will do it. You can now add other functions that you may find useful.

  12. When you have created everything you want, zip up the root folder. Once this has been done, rename the file so that its file type is .xpi. The file type is normally the last three letters in the name that follows the last full stop.

Creating an add-on relies on understanding basic programming. You will need to understand how to develop using JavaScript because it is more than just creating the odd function.

What just happened?

We have just seen what it takes to create a new add-on that will attach to the Selenium IDE. This is a new bit of functionality that allows us to build onto IDE in a similar way to user extensions but can be a lot more powerful. This is because add-ons are not limited by the JavaScript sandbox.

Creating a new add-on requires programming knowledge that is slightly more intensive than creating extension methods.

Pop quiz

  • What is a Selenium IDE add-on?

Summary

We learned a lot in this article about how we can extend Selenium when it does not have all the commands that we would want. This can be from needing a simple random number generator to a way to interact with a JavaScript API that is available on the page under test.

Specifically, we covered the following topics:

  • User extensions: In this section of the article, we had a look at what is required to create a user extension. This gives us the ability to create new commands for our test steps. It gives us the ability to extend Selenium without having to rebuild Selenium from scratch.

    We had a look at how our extensions can use variables like we normally do within Selenium. This can be useful if you need to access an API and you only need to create the object once.

    We had a look at how we can call other commands from within our new command. This can be useful if we need to create a new a version of Click or Type.

    We briefly looked at how we can use the browserbot object within our extension and how this can benefit us if we need to create new commands to access JavaScript APIs on the page. And finally we had a look at how we can add verifications and assertions to our new commands so that if we are accessing an API, we can access it and verify in one command. This can make tests a lot more compact and easier to read.

  • Creating add-ons: In this we saw how we can create a Mozilla Firefox add-on that can couple onto Selenium IDE. This will allow us to create tests that can use custom selectors or allow Selenium to work against items that it never has before, such as Flex. As this uses basic Firefox add-on design patterns, you can do a lot with it that can then be used to create new add-ons that do not need to be attached to Selenium IDE.

We also discussed that when saving user extensions we need to make sure that we restart the IDE after each save to make sure that it is always using the latest version.


Further resources on this subject:


About the Author :


David Burns

David Burns is a Senior Developer in Test having worked with Selenium for quite a few years. He is a Selenium Core Committer and so he knows and understands what users and developers want from the framework.

Books From Packt


Python Testing: Beginner's Guide
Python Testing: Beginner's Guide

Software Testing with Visual Studio Team System 2008
Software Testing with Visual Studio Team System 2008

JavaScript Testing Beginner's Guide
JavaScript Testing Beginner's Guide

Django 1.1 Testing and Debugging
Django 1.1 Testing and Debugging

Software Testing using Visual Studio 2010
Software Testing using Visual Studio 2010

Moodle 1.9 Testing and Assessment
Moodle 1.9 Testing and Assessment

iReport 3.7
iReport 3.7

JasperReports 3.6 Development Cookbook
JasperReports 3.6 Development Cookbook


Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software