Scott Hanselman

Unit Testing Silverlight with Selenium

July 31, '07 Comments [9] Posted in Programming | Silverlight | Tools
Sponsored By

Selenium is a web testing tool that runs directly in the browser. That means it's all JavaScript. It'll run on the Three Major OSes and on the Three Major Browsers (and others!), so that's cool. There's even a recorder/playback IDE called Selenium IDE that takes the form of a Firefox plugin.

One of the things that's particularly interesting about Selenium is that it uses HTML Tables as its input Domain Specific Language. Go ahead and read that sentence again just to drink it in.

For example, if you had a page called "/default.html" and on that page there was a button called "myButton" here's the code to open the page and click that button. 

<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">SeleniumTest</td></tr>
</thead><tbody>
<tr>
    <td>open</td>
    <td>/Default.html</td>
    <td></td>
</tr>
<tr>
    <td>click</td>
    <td>myButton</td>
    <td></td>
</tr>
</tbody></table>

This would be a "test" page and you'll also need a master "Suite" that would contain many tests. A Suite is just a table of tests:

<table>
<tr><td><b>Suite Of Tests</b></td></tr>
<tr><td>
<
a href="./SeleniumTest.html">Test Suite</a>
</
td></tr> </table>

Because of cross-site scripting issues, you have to install Selenium (just download the zip and upload the contents to your website) on your server and visit the pages from there. For example, here's the Selenium Test Runner on my server here at Hanselman.com.

As Selenium is all JavaScript, I thought it'd be nice to make sure it can test Silverlight applications. I can see how a testing framework that could easily interact with Silverlight would be a useful thing, so I set off to prove the concept.

First, I made a super-simple XAML of a TextBlock and a Circle:

<Canvas
    xmlns="http://schemas.microsoft.com/client/2007"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:ButtonSharp="clr-namespace:ButtonSharp;assembly=ClientBin/ButtonSharp.dll"
    x:Class="ButtonSharp.Page;assembly=ClientBin/ButtonSharp.dll"
    Width="320" Height="240"
    Background="White"
    x:Name="rootCanvas"
    >
    <Ellipse Fill="#FFFFFFFF" Stroke="#FF000000" x:Name="Circle" 
Width="169" Height="169" Canvas.Left="81" Canvas.Top="32"/> <TextBlock x:Name="MyText" Text="Hello World from my Script Tag"/> </Canvas>

In the code-behind I made a few Scriptable methods. By marking them Scriptable, they are made available to the "outside world" - in this case, JavaScript.

[Scriptable]
    public partial class Page: Canvas
    {
        public Page()
        {
            Loaded += new EventHandler(Page_Loaded);
        }

        TextBlock tb = null;
        Ellipse el = null;

        void Page_Loaded(object o, EventArgs e)
        {
            WebApplication.Current.RegisterScriptableObject("scott", this);
            tb = (TextBlock)this.FindName("MyText");
            el = (Ellipse)this.FindName("Circle");
        }

        [Scriptable]
        public void SetCircleColor()
        {
            tb.Text = "Hello from C#";
            el.Fill = new SolidColorBrush(Color.FromRgb(0xFF, 0x00, 0x00));

        }

        [Scriptable]
        public string GetCircleColor()
        {
            SolidColorBrush b = el.Fill as SolidColorBrush;
            return b.Color.ToString();
        }
}

The code does two useful things. First, it registers the class with the WebApplication via RegisterScriptableObject and names it "scott."  You'll see later where we refer to "scott" in JavaScript and you'll know we mean this class. Second, it finds the TextBlock and the Ellipse and squirrels them away for later use.

Back over on the outside, in the HTML page's JavaScript, I make two silly functions:

<script type="text/javascript">
    function changeColor()
    {
        var control = document.getElementById("SilverlightControl");
        control.Content.scott.SetCircleColor();
    }
    function getColor()
    {
        var control = document.getElementById("SilverlightControl");
        thing = control.Content.scott.GetCircleColor();
        alert(thing);
    }
</script>

Notice where we call the two managed C# methods via our "scott" object. Then I add two regular HTML buttons:

<input type="button" name="changeColor" value="Change Color" onclick="changeColor()"/>
<input type="button" name="checkColor" value="Check Color" onclick="getColor()"/>

You click one button and it calls changeColor which should make make the Circle red, and the other will ask the Circle what color it is and display the result in a JavaScript alert. You're welcome to run this little thing here if you like.

Note that you WILL need the Silverlight 1.1 Alpha Refresh first.

Now I make a Selenium Test like this. You can also use the Selenium IDE to record, write manually, step through and save tests if you're not into the whole Notepad thing.

<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">SeleniumTest</td></tr>
</thead><tbody>
<tr>
    <td>open</td>
    <td>http://www.hanselman.com/silverlight/seleniumtest/ButtonSharp/Default.html</td>
    <td></td>
</tr>
<tr>
    <td>click</td>
    <td>changeColor</td>
    <td></td>
</tr>
<tr>
    <td>click</td>
    <td>checkColor</td>
    <td></td>
</tr>
<tr>
    <td>assertAlert</td>
    <td>#FFFF0000</td>
    <td></td>
</tr>
</tbody></table>

The Selenium Reference is excellent and contains all the commands you can use. Remember, each command is one line in  test table like:

command target value

And there's many you can use. You can also make your own by making a file called user-extensions.js, and there's lots of details on the Selenium site. You can also use actual JavaScript in the targets and values if you include 'javascript{ }' in the parameter.

I'm sure that if I knew JavaScript better I could better access the Silverlight object and test all kinds of things. I'll leave this exercise to the Smarter Than I Reader.

You can pass parameters to the Selenium Test Reader like the test file via ?test= etc. If you want to run my Silverlight App inside the Selenium Test Runner in your own browser, just go here. Do note the format of the URL. You can also just visit the runner and enter the URLs yourself. You can have as many tests as you like in the suite.

NOTE: When you startup the runner, change these settings for a more dramatic experience. Turn the speed down to Slow with the slider, and click Highlight elements Then click either of the Green Play Buttons.

Selenium Functional Test Runner v0.8.2 [1727] - Mozilla Firefox

It'd be interesting what kinds of community extensions to Silverlight could be created for Selenium to make it even easier. I also wonder how well Watir or Watin can interact with Silverlight.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. I am a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web
Tuesday, July 31, 2007 6:05:20 AM UTC
scott, at oscon, i learned of a new web automated ui test framework called Windmill...http://timheuer.com/blog/archive/2007/07/26/14164.aspx -- they don't have binaries for windows yet, but the source is there... it was pretty impressive where they've gotten to right now and there are definitely similarities to selenium and some advantages.
Tuesday, July 31, 2007 6:31:42 AM UTC
That's pretty cool. So far, I've been a fan of WATIN because I like being able to run my tests using MbUnit as it makes it easy to integrate them into our Continous Integration process. The only problem so far is I haven't figured out how to properly test the DOM. For example, if a page is supposed to document.write some text, how do I use WATIN to test that it occurred properly. It looks like Selenium might be better for that purpose.
Tuesday, July 31, 2007 8:33:50 AM UTC
Hey Scott,
I too just posted a write-up on using Selenium. Thanks for adding some "color" regarding using it with Sliverlight. I haven't yet had the opportunity to put Sliverlight to use though the time is coming so this post will come in handy.

Here's my post:
Automated testing of ASP.NET web applications using Selenium
Thursday, August 02, 2007 4:54:03 PM UTC
Scott, have you seen this? WebAii

We're evaluating it now. Integrates with NUnit, MSTest, etc... Supports javascript, Ajax testing, IE and Firefox. Also makes it easy to test using Cassini. Check out the feature list. It *looks* like it puts WATIN to shame. I'll let you know more as we try it out.

Oh, and it's FREE!
Sunday, August 05, 2007 1:27:18 PM UTC
For quick and easy web testing I find Selenium to cumbersome. I use iMacros for Firefox now https://addons.mozilla.org/en-US/firefox/addon/3863

Cheers
Harald
Harald Heinze
Sunday, August 12, 2007 6:12:32 AM UTC
Scott, thanks for the tutorial on Selenium and Silverlight. We use Selenium quite extensively at Learning.com. Something your readers might be interested in is Selenium RC (Remote Control): http://www.openqa.org/selenium-rc. Selenium RC enables you to "...write automated web application UI tests in any programming language against any HTTP website using any mainstream JavaScript-enabled browser." We write our tests in C# using MBUnit and run them against IE6, IE7, FF 1.5, FF 2.0, and Safari 2.0 on the Mac. We're currently doing a good bit of DHTML goodness that needs to run in all the platforms. Writing our tests once and running them on each of the platforms has been useful, although it does take a while for the tests to run. To compensate, we've taken to using the XP/IE6 platform for the continuous integration build, and we run the other environments at night.

We will very likely start using Silverlight in specific areas of our site over the next couple of years. We will use it for creating true Rich Internet Applications (RIAs), which means that the users (and our tests) will be interacting directly with the XAML DOM. One of the things I've yet to see is elegant support in any of the automated UI test tools for interacting with and asserting properties of elements on the canvas. While I haven't delved too deeply into this, I wonder if it wouldn't make sense to create an implementation of the ISelenium interface specifically for Silverlight (see http://release.openqa.org/selenium-remote-control/0.9.0/doc/dotnet/html/index.html, and drill down into the DefaultSelenium class, which is currently the only implementation of ISelenium).

Thanks again,

-=michael=-
Michael Kelly
Tuesday, August 14, 2007 6:39:03 PM UTC

Aside from documentation provided on Open QA forums. Are there any up and coming training classes to better understand Selenium (IDE/testrunner/RemoteControl).

Thank You,

Pardip
pardip nayyer
Wednesday, August 15, 2007 6:37:49 PM UTC
Great article and for blazing the trail. One comment though. Please stop calling it "cross-site scripting issues". It's not an issue, but a protection and it's there for your own good :-)
Mr.E
Wednesday, August 15, 2007 6:52:32 PM UTC
Valid point, Mr. E., my bad.
Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.