<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Gojko Adzic &#187; webtest</title>
	<atom:link href="http://gojko.net/tag/webtest/feed/" rel="self" type="application/rss+xml" />
	<link>http://gojko.net</link>
	<description>Building software that matters</description>
	<lastBuildDate>Thu, 18 Mar 2010 20:20:02 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Webtest now has a new mummy and daddy</title>
		<link>http://gojko.net/2009/11/20/webtest-now-has-a-new-mummy-and-daddy/</link>
		<comments>http://gojko.net/2009/11/20/webtest-now-has-a-new-mummy-and-daddy/#comments</comments>
		<pubDate>Fri, 20 Nov 2009 08:56:31 +0000</pubDate>
		<dc:creator>gojko</dc:creator>
				<category><![CDATA[articles]]></category>
		<category><![CDATA[fitnesse]]></category>
		<category><![CDATA[webtest]]></category>

		<guid isPermaLink="false">http://gojko.net/2009/11/20/webtest-now-has-a-new-mummy-and-daddy/</guid>
		<description><![CDATA[To my great surprise, someone has offered to take over my webtest fixtures project (fitnesse+selenium RC integration for java and .net), which I&#8217;ve discontinued over a year ago.
Chris McMahon and Marisa Seal are now the new mummy and daddy of the project. You can read what Chris had to say about it. Good luck!
]]></description>
			<content:encoded><![CDATA[<p>To my great surprise, someone has offered to take over my <a href="http://fitnesse.info/webtest">webtest fixtures project</a> (fitnesse+selenium RC integration for java and .net), which I&#8217;ve discontinued over a year ago.</p>
<p><a href="http://chrismcmahonsblog.blogspot.com">Chris McMahon</a> and <a href="http://thetestingblog.com/">Marisa Seal</a> are now the new mummy and daddy of the project. You can <a href="http://chrismcmahonsblog.blogspot.com/2009/11/ui-test-tool-search.html">read what Chris had to say about it</a>. Good luck!</p>
]]></content:encoded>
			<wfw:commentRss>http://gojko.net/2009/11/20/webtest-now-has-a-new-mummy-and-daddy/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to test AJAX sites with FitNesse and Selenium RC</title>
		<link>http://gojko.net/2008/02/14/ajax-selenium-fitnesse/</link>
		<comments>http://gojko.net/2008/02/14/ajax-selenium-fitnesse/#comments</comments>
		<pubDate>Thu, 14 Feb 2008 00:21:30 +0000</pubDate>
		<dc:creator>gojko</dc:creator>
				<category><![CDATA[fitnesse]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[selenium]]></category>
		<category><![CDATA[tdd]]></category>
		<category><![CDATA[webtest]]></category>

		<guid isPermaLink="false">http://gojko.net/2008/02/14/ajax-selenium-fitnesse/</guid>
		<description><![CDATA[It&#8217;s been almost a year since I wrote Automating web tests with FitNesse and Selenium, offering an idea how FitNesse can be used to implement a nice customer-friendly mini-language for user interface testing. Since then, that article has been one of the most popular, if not the single most popular, article on this web site. [...]]]></description>
			<content:encoded><![CDATA[<p><img src="/images/684719_test_me.jpg" style="border:1px solid black;margin:5px 5px 5px 5px; float:left" />It&#8217;s been almost a year since I wrote <a href="http://gojko.net/2007/05/20/automating-web-tests-with-fitnesse-and-selenium/">Automating web tests with FitNesse and Selenium</a>, offering an idea how FitNesse can be used to implement a nice customer-friendly mini-language for user interface testing. Since then, that article has been one of the most popular, if not the single most popular, article on this web site. I have helped several clients improve and integrate their UI testing based on the ideas in that article, expanding and improving the mini-language, especially for AJAX testing. Here is what I&#8217;ve learned about that in the last  year.<span id="more-101"></span></p>
<p><i>Quick note before we continue: FIT fixtures described in this article can be downloaded from <a href="http://fitnesse.info/webtest">fitnesse.info/webtest</a>. Both Java and .NET are supported and the fixtures are released under GPL. To learn how to set everything up, read the <a href="http://gojko.net/2007/05/20/automating-web-tests-with-fitnesse-and-selenium/">original article</a>.</i></p>
<h2>Effective AJAX testing with selenium.Wait</h2>
<p>In the original article, I have suggested using <i>WaitForCondition</i> and <i>selenium.browserbot.getCurrentWindow()</i> to dynamically evaluate JavaScript expressions and block until they become fulfilled. Although this did the trick, the code was very ugly and error-prone, mixing JavaScript evaluations with Java/.NET expressions. <b>It turned out that it was much better to poll browser a few times per second through Selenium RC API.</b> This way, the code is much more consistent, and waiting conditions are much easier to write. Polling, in theory, causes unnecessary delay, but this case Selenium RC and UI testing itself introduce a lot of latency, so the polling does not really make things any worse. In fact, the Java version of Selenium Remote Control has API support for that: <i>Wait</i> class in <i>com.thoughtworks.selenium</i> package. The official <a href="http://release.openqa.org/selenium-remote-control/0.9.2/doc/java/">JavaDoc</a> for that class is a bit wrong and misleading, but with a bit of experimenting that class is very easy to use, and quite powerful. The official documentation suggests this usage pattern:</p>
<pre>
new Wait("Couldn't find close button!") {
    boolean until() {
        return selenium.isElementPresent("button_Close");
    }
};
</pre>
<p>Yet this code will not even compile with Selenium RC 9.2, because no such constructor exists. Instead, the error message should be passed while calling the blocking <i>wait</i> method later. Here is an example that blocks until some text appears on the page:</p>
<pre>
  // private class of WebTest fixture
  private class WaitForTextToAppear extends Wait{
    private String text;
    public  WaitForTextToAppear(String  text){
      this.text= text;
    }
    public boolean until(){
       return WebTest.this.pageContainsText(text);
    }
  }
 // method of WebTest Fixture
 public boolean waitSecondsForTextToAppear(int timeout, String text){
   Wait x=new WaitForTextToAppear(text);
   x.wait("Cannot find text " +text+ " after "+timeout+" seconds",timeout*1000);
   return true;
 }
</pre>
<h3>Waiting In mini-language</h3>
<p>In FitNesse, this would be used as:</p>
<pre>
|wait|5|seconds for text|Hello World|to appear|
</pre>
<p>This line would block the execution of the page up to five seconds, waiting for <i>Hello World</i> to appear anywhere in the page. If that text does not appear after five seconds, the test breaks. Using this pattern, it is very easy to implement any kind of asynchronous waiting without manually checking for JavaScript expressions and worrying about Selenium-to-application page DOM conversions. So far, I have implemented the following waiting methods for the testing mini-language:</p>
<pre>
|wait|5|seconds for element|username|to appear|

|wait|5|seconds for element|username|to disappear|

|wait|5|seconds for text|Hello World|to appear|

|wait|5|seconds for text|Hello World|to disappear|

|wait|5|seconds for field|username|to contain text|Hello World|

|wait|5|seconds for element|username_label|to contain text|Please enter username|
</pre>
<p>the difference between &#8220;wait for field to contain text&#8221; and &#8220;wait for elelement to contain text&#8221; is that the first method checks for the current value of an INPUT field (&lt;input type=&#8221;text&#8221; name=&#8221;username&#8221; value=&#8221;Hello World&#8221;/&gt;), and the second checks for text inside a dom element (&lt;span id=&#8221;username_label&#8221;&gt;Please enter username&lt;/span&gt;). .NET Selenium RC API does not have this class, but it was not hard to implement, so the .NET fixture also supports this in the mini-language.</p>
<h2>Locator lookup takes too long</h2>
<p>Selenium uses &#8220;locators&#8221; to point to DOM elements that you want to automate. In the original article, I suggested a complex scheme of mapping user-friendly descriptions to locators so that we can use button captions, labels and similar visible text and labels to point to page elements. Under this scheme, the FitNesse-Selenium glue code tried out locators from an array until it found a match. This turned out to be such a performance penalty that I no longer suggest it. Each attempt to discover whether an element was present or not went through the full cycle of FitNesse, Selenium Remote Console, Browser, Selenium and back. In average, that increased the time for a UI test to execute by 500-600 percent. It turned out that, with a bit of care in naming, DOM element IDs can be used in all cases so that test pages are still descriptive enough, and indirect locator lookup can be avoided. <b>So now I suggest using DOM element IDs directly, not using labels or captions.</b></p>
<h3>Effective locators in mini-language</h3>
<p>I have introduced a new parameter to control whether the lookup is performed or not. It is still on by default, but if you put this table into your page:</p>
<pre>
|set locator lookup|false|
</pre>
<p>tests will execute much much faster. This will require you, however, to use DOM element IDs exclusively to point to all page elements. Even with lookup turned on, tests should now run faster if you use DOM element IDs, because I&#8217;ve moved IDs to the top of lookup arrays for all element types.</p>
<h2>Element type safety is not really important</h2>
<p>In the original article, I suggested checking whether something is a button, input field or a link when doing methods like <i>click</i>, so that something like:</p>
<pre>
|user clicks on|save|button|
</pre>
<p>would fail if <i>save</i> was a link identifier. I thought that would introduce one more level of safety and avoid problems because of ambiguous definitions. Since trying out all those locators works really slow, I gave up on checking for the type of element, and use that only in special cases (such as radio buttons, which should be selectable by value as well as name). This did not, in practice, make tests any less effective. So I now suggest avoiding such complex checks.</p>
<h3>Direct element access in mini-language</h3>
<p>The WebFixture mini-language now supports a bunch of methods for generic elements, which are located using the DOM element ID or element name, without checking the exact type. So you can write something like:</p>
<pre>
|user clicks on|save|
</pre>
<p>and that is going to work for buttons, labels, text elements and anything you can click on.</p>
<h2>Don&#8217;t pause, wait for specific events</h2>
<p>In the original article, I introduced a few methods that blocked until the whole page loaded correctly. With AJAX testing, those methods are no longer applicable. To allow an asynchronous operation to complete before continuing with the test, lots of people used the &#8216;pause&#8217; function. This caused more harm than good, so I&#8217;m now thinking of effectively removing that function or throwing an exception on the end of the pause to print a warning that the test should be rewritten. Pause is makes tests error prone and very brittle. If, for example, you pause for 5 seconds to wait for a form to load, then when you run the tests on different hardware or over network, the test itself might break because of longer latency (so the code implementation is still correct, but the test fails, which is a very dangerous anti-pattern). This gets solved by extending the pause to be long enough, so your tests are no longer running for 10 seconds but a minute&#8230; once the test suite starts running for longer than a minute people are no longer running tests before committing, and that makes the feedback loop even longer, reducing the effectiveness of tests.</p>
<p><b>It&#8217;s much better, if you can, to block and wait for a specific event.</b> So instead of pausing, use one of the wait functions as described in the beginning of this article. Those functions still allow you to specify the ultimate timeout period, so that if the event does not happen after 10-15 seconds the test breaks. A very important difference is that, in normal case, the execution will continue straight after the event does happen. So you&#8217;ll wait exactly as long as you need to, and not a second longer.</p>
<h2>DOM events don&#8217;t always fire automatically</h2>
<p>When you type stuff in with Selenium, DOM elements such as <i>onFocus</i>, <i>onBlur</i> and <i>onChange</i> don&#8217;t fire automatically (not to mention <i>onKeyUp</i> and <i>onKeyDown</i>). Lots of AJAX code is built around those events, and tests fail if the code relies on events. Selenium allows you to triggers the events manually using <i>fireEvent</i> method. <b>So, if your site behaves differently under test and when you play with it manually, missing events should be your first suspect</b>. </p>
<h3>Firing events manually in the mini-language</h3>
<p>I have changed the <i>UserTypesIntoField</i> method to fire events as well, in the appropriate order. You can fire an event explicitly using the <i>fire event for</i> method:<br />
<code><br />
|fire event|blur|for|username|<br />
</code> </p>
<p>To fire events, don&#8217;t put the leading <i>on</i> &mdash; use <i>click</i> instead of <i>onclick</i>.</p>
<h2>Some people prefer click-and-record</h2>
<p>Although I&#8217;ve tried to introduce a customer-friendly mini-language for testing, some people liked the idea of using FitNesse to wrap Selenium tests more because it UI tests could then be integrated into automated integration testing and because they could prepare and verify their database during Selenium tests. But they still preferred using Selenium IDE to record tests, without having to manually write them. I have introduced a new fixture class, <i>webfixture.PlainSeleniumTest</i>, that more or less just forwards the commands to Selenium RC. So you can use a Selenium test table, paste it in FitNesse, change it just a bit, and run the test using Selenium Remote Control. The only changes required are deleting the test name (first row of the table) and optionally changing the <i>open</i> command to include a relative URL instead of an absolute one. That allows you to record tests using Selenium IDE, but still integrate them into Cruise Control and control the database or talk to your domain objects during tests.</p>
<p>Selenium tests can be stored as HTML files, and you can use HTML directly in FitNesse without converting it to the Wiki syntax. Just paste  the table anywhere in the page, but put the HTML code between <i>!-</i> and <i>-!</i> to tell FitNesse to display the contents raw, without special formatting.</p>
<p>Originally, I thought that I could just get away by wrapping a Selenium RC instance into a Sequence Fixture as the system under test, and pass all commands to it. But Selenium RC API and browser-based Selenium scripts differ in some parts, especially for the waiting methods and verification methods. For example, <i>verifyVisible</i> in Selenium is called <i>isVisible</i> in Selenium RC. So I wrote a bunch of wrappers for <i>verifyXXX</i> and <i>assertXXX</i> methods to make tests run without changing.</p>
<p>The next problem was that the resulting Selenium test tables may have one additional empty cell if the method only has one argument, such as <i>open url</i>. Because of that additional argument, FitNesse will try to map the row to the method <i>open(String, String)</i> and fail because it could not find such a method. Because of that, I also wrote a bunch of wrappers for single-parameter methods that have a second string argument, which is just ignored. For example:</p>
<pre>
public void open (String url, String ignore){
  open(url);
}
public void click(String what, String ignore){
  instance.click(what);
}
</pre>
<p>With that, Selenium tests started working more or less out of the box. I occasionally have to add another method for one of the reasons mentioned above, but that is fairly quick and straightforward.</p>
<p>There&#8217;s one more trick related to this. Selenium scripts, especially those recorded, can be quite lengthy. FitNesse will flush output after each table, so if you leave the test as one big table, it will look like FitNesse is not doing anything for a while and then you&#8217;ll get all results at once. I&#8217;ve found it much better to just split the big table into several smaller tables, so that I can track progress while the test is running.  </p>
<h2>Use browser names instead of browser codes</h2>
<p><a href="http://www.cornetdesign.com" target="_blank">Cory Foy</a> suggested that we should not use browser codes like <i>*iehta</i>, but make tests even more user friendly by using descriptive browser names. I like that idea very much, so the <i>start browser</i> now supports both codes and names like <i>IE</i> and <i>Firefox</i>. It will map the name to the appropriate browser code for you.</p>
<h2>Plenty of new methods</h2>
<p>I have also added quite a few new methods to the mini-language for UI tests that check alerts, click on confirmations, inspect options available in SELECT elements, check whether elements are enabled or disabled and work with checkboxes and radio buttons. See the full list of supported methods in <a href="http://fitnesse.info/webtest">fitnesse.info/webtest</a>.</p>
<h2>Summary</h2>
<p>On the end, here is a summary of lessons learned:</p>
<ul>
<li>Poll browser a few times per second through Selenium RC API using the <i>Wait</i> class to check for asynchronous events.</li>
<li>Use DOM element IDs directly, don&#8217;t look for elements using xpath locators, labels or captions.</li>
<li>Don&#8217;t use a generic pause. If you can, block and wait for a specific event.</li>
<li>If your site behaves differently under test and when you play with it manually, missing events should be your first suspect. Fire events manually in that case.</li>
</ul>
<p>FIT fixtures that implement the testing mini-language for .NET and Java can be downloaded from <a href="http://fitnesse.info/webtest">fitnesse.info/webtest</a>. The code is released under GPL, so you can edit and experiment with it. If you add any new useful methods, please send them so that they can be included in the next version of this library&#8230;</p>
<p>Image credits: <a href="http://www.sxc.hu/profile/cancsajn" target="_blank">Timi az en vaok</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://gojko.net/2008/02/14/ajax-selenium-fitnesse/feed/</wfw:commentRss>
		<slash:comments>31</slash:comments>
		</item>
		<item>
		<title>Automating web tests with FitNesse and Selenium</title>
		<link>http://gojko.net/2007/05/20/automating-web-tests-with-fitnesse-and-selenium/</link>
		<comments>http://gojko.net/2007/05/20/automating-web-tests-with-fitnesse-and-selenium/#comments</comments>
		<pubDate>Sun, 20 May 2007 21:03:39 +0000</pubDate>
		<dc:creator>gojko</dc:creator>
				<category><![CDATA[articles]]></category>
		<category><![CDATA[fitnesse]]></category>
		<category><![CDATA[acceptance testing]]></category>
		<category><![CDATA[automation]]></category>
		<category><![CDATA[selenium]]></category>
		<category><![CDATA[tdd]]></category>
		<category><![CDATA[UI]]></category>
		<category><![CDATA[webtest]]></category>

		<guid isPermaLink="false">http://gojko.net/2007/05/20/automating-web-tests-with-fitnesse-and-selenium/</guid>
		<description><![CDATA[Web user interfaces have traditionally been hard to integrate into an automated test process.  Selenium+FitNesse combination, with just a bit of coding, solves this task incredibly well.
Selenium is a free browser automation and testing library, written by folks at ThoughtWorks. It can simulate text input, mouse events and execute various tests on page content. [...]]]></description>
			<content:encoded><![CDATA[<p><img src="/images/731545_check_it_2.jpg" style="border:1px solid black; margin:5px 5px 5px 5px" align="left"/>Web user interfaces have traditionally been hard to integrate into an automated test process.  Selenium+FitNesse combination, with just a bit of coding, solves this task incredibly well.</p>
<p><a href="http://www.openqa.org/selenium-core/" target="_blank">Selenium</a> is a free browser automation and testing library, written by folks at ThoughtWorks. It can simulate text input, mouse events and execute various tests on page content. It&#8217;s written in JavaScript, and is compatible with all major browsers and platforms.</p>
<p><a href="http://www.fitnesse.org" target="_blank">FitNesse</a> is an open-source test and collaboration server, based on the <a target="_blank" href="http://fit.c2.com/">Framework for integrated tests (FIT)</a>, and supports testing Java, .Net, Python and even some other code. I think that it is a good choice for the second side of the web UI testing coin, because it enables tests to be written almost like in English language. As the UI is very close to clients&#8217; eyes, tests can and should be written so that clients can verify them (and if you are really lucky, even help with writing and maintaining the tests). <span id="more-53"></span></p>
<p><br clear="all"/></p>
<p><b>UPDATE: I wrote a follow-up to this article in Feb. 2008, focusing on testing AJAX applications. Read it on <a href="http://gojko.net/2008/02/14/ajax-selenium-fitnesse/">http://gojko.net/2008/02/14/ajax-selenium-fitnesse</a></b></p>
<h2>Installing Selenium</h2>
<p>The core of Selenium is written in JavaScript, and is compatible with all major browsers. The Selenium Remote Console provides the glue between a test browser and .Net, Java or Python code, and enables us to write and run Selenium tests from almost all popular test frameworks.</p>
<p>Just download Selenium Remote Console from <a target="_blank" href="http://www.openqa.org/selenium-rc">http://www.openqa.org/selenium-rc</a>. Unpack the files somewhere on your disk, and then start the server from the server folder of the package, by executing <em>java -jar selenium-server.jar</em>. The server starts on port 4444 by default, if that port is taken you can change it by adding <em> -port <b>number</b></em> to the command line. </p>
<p>Selenium works by embedding the test site, along with some control scripts, in a frameset web page. The control scripts are then used to automate the test page in the main frame, and execute various tests. That method of work will clash with browser security rules if both frames do not come from the same domain. Remote console can open Internet Explorer and Firefox with a security tweak to allow cross-domain scripting, but if you don&#8217;t want that, or want to use a different browser, then put Selenium JavaScript files into your web site. Download them from <a href="http://www.openqa.org/selenium-core/" target="_blank">http://www.openqa.org/selenium-core/</a>, and put the files from core folder in the archive into the selenium-server folder of your web site (so that RemoteRunner.html is available on /selenium-server/RemoteRunner.html).</p>
<h2>A quick test</h2>
<p>Let&#8217;s first do a quick test to make sure that Selenium RC is running correctly. We&#8217;ll start a browser window, go to Google, enter a search phrase and click on the Search button. I&#8217;ll do the examples in C#, but you can also use Java &#8211; interfaces are very similar. Create a new .Net project, add thoughtworks.selenium.core.dll as a reference (it&#8217;s in the dotnet folder of Remote Control installation), and then create this class:</p>
<pre>
using System;
using Selenium;
namespace SeleniumTest
{
    class Console
    {
        static void Main(string[] args)
        {
            ISelenium sel = new DefaultSelenium(
              "localhost", 4444, "*iehta", "http://www.google.com");
            sel.Start();
            sel.Open("http://www.google.com/");
            sel.Type("q", "FitNesse");
            sel.Click("btnG");
            sel.WaitForPageToLoad("3000");
        }
    }
}
</pre>
<p>Make sure that Selenium RC is running, close all open Internet explorer windows, and then execute the program. Selenium RC will open a new IE window (it may be minimised on start, but you will see a new button in the task bar), and then go to Google and execute a search.<br />
<center><br />
<a href="/images/webtest-s1.png" border="0" target="_blank"><img src="/images/webtest-s1.png" width="600" /><br />click for full-size image</a><br />
</center></p>
<p>Selenium window has three frames. Top-left enables the user to display the log and debug the execution by examining the DOM tree. Top-right frame displays the last four executed Selenium commands, which comes useful when troubleshooting tests. The page under test is displayed in the central frame.</p>
<p>The first line initialises a selenium console instance, connecting it to a remote console on localhost port 4444. </p>
<pre>
ISelenium sel = new DefaultSelenium(
"localhost", 4444, "*iehta", "http://www.google.com");
</pre>
<p>The third argument is a browser string, and *iehta is the code for security-tweaked Internet Explorer which allows cross-domain scripting.  Use *chrome for firefox with cross-domain scripting, or *iexplore, *firefox and *opera for Internet Explorer, Firefox and Opera without cross-domain security tweaks. You can also specify a full path to the executable instead of these special keywords. </p>
<p>The fourth argument is the URL to the selenium test site, and is really important only if you do not use cross-domain scripting, but want Selenium to run the scripts from the local domain. In this case, it will try to get the remote runner from http://www.google.com/selenium-server/RemoteRunner.html, but since Google is not hosting a Selenium installation, it will run the local scripts instead. In any case, this argument needs to be specified, so just set it to some live site even if you use cross-domain scripting (like in this case).</p>
<p>As you can guess from the names, method Type will simulate entering data from keyboard into a text field, and Click will simulate a mouse click.  We accessed the text field and the button by their names, q and btnG.  Selenium can also find elements by their ID (prefix it with “identifier=&#8221;), XPath expression (prefix it with &#8220;xpath=&#8221;), DOM path or a CSS property. See <a target="_blank" href="http://www.openqa.org/selenium-core/reference.html">http://www.openqa.org/selenium-core/reference.html</a> for more information on locators.</p>
<h2>Connecting from FitNesse</h2>
<p>FitNesse is really great for automating acceptance tests, and if you have not had a chance to play with it yet, I suggest reading through the <a href="http://www.fitnesse.org/FitNesse.UserGuide" target="_blank">online user guide</a> for testing Java code, or my tutorial <a href="http://gojko.net/FitNesse/fitnesse.pdf" target="_blank">Getting fit with .Net</a> for working in the .Net environment. </p>
<p>Instead of writing a new fixture type for every page or web site, we use a generic <a href="/fitnesse/webtest">WebTest</a> fixture. It extends DoFixture, so that other fixtures can be easily embedded into it (for checking the back-end data after a web script, or preparing the stage for the web test). Web test fixture allows the scripts to be described almost like English prose, like this:</p>
<blockquote><p>
User opens URL http://localhost:7711/login.aspx<br />
User types testuser into username field<br />
User types testpassword into password field<br />
User clicks on Log In<br />
Page reloads in less than 3 seconds<br />
Page contains text You have logged in
</p></blockquote>
<p>To achieve the best effect, the script must relate to what users see on the screen. However, that is easier said than done. Text fields, check boxes and buttons are all instances of the &#8220;input&#8221; element, and although text fields are mostly distinguished by name, buttons names are typically not important, and users only see the &#8220;value&#8221; attribute of a button. WebTest fixture looks for various combinations of attributes: for example, when searching for a button, it first looks for an input element with type equal to submit or button, and the name attribute matching the query. If no such element is found, it looks for similar elements, with value attribute matching the query. On the end, it looks for a button with matching ID. All these combinations are listed in the buttonLocators array in the code:</p>
<pre>
 public static readonly string[] buttonLocators = new String[] {
	"xpath=//input[@type='submit' and @name='{0}']",
	"xpath=//input[@type='button' and @name='{0}']",
	"xpath=//input[@type='submit' and @value='{0}']",
	"xpath=//input[@type='button' and @value='{0}']",
	"xpath=//input[@type='submit' and @id='{0}']",
	"xpath=//input[@type='button' and @id='{0}']"};
</pre>
<p>Although looking for an element by ID or name would be quicker, we intentionally use Xpath and add extra information, to catch errors caused by wrong element types. GetLocator method checks a list of XPath expressions and returns the first matching element from the active document, so UserClicksOn method is very simple:</p>
<pre>
public void UserClicksOn(String buttonCaption){
            instance.Click(GetLocator(buttonCaption, buttonLocators));
}
</pre>
<p>We use the same technique to put text into text fields, areas and password fields. An array of Xpath expressions is used to check for various combinations of valid element types and attribute values, and the first matching element is then passed to Selenium Type method. </p>
<pre>
public void UserTypesIntoField(String what, String where){
      instance.Type(GetLocator(where.Replace(" ", ""), textFieldLocators), what);
}
</pre>
<p>Because text fields will mostly be referenced by a name or ID, but users will see the text before the field on the page (and probably try to reference it with that), we also strip the blanks from the name. So the test script line:</p>
<blockquote><p>User types 10109 into security number field</p></blockquote>
<p>will correctly map into an element named “securitynumber&#8221;.</p>
<p>With web tests, we typically want to check if the result was correct and if the site was responsive enough, and Selenium method WaitForPageToLoad can be used to check if a page loads in any given amount of time. The API is a bit weird, as it expects a string containing the number of milliseconds. We wrapped that into this WebTest fixture call:</p>
<pre>
public void PageReloadsInLessThanSeconds(String sec){
            instance.WaitForPageToLoad(sec + "000");
}
</pre>
<p>On the end, we need a method to verify that page contents are correct. Selenium method  IsTextPresent can help with that:</p>
<pre>
public bool PageContainsText(String s){
            return instance.IsTextPresent(s);
}
</pre>
<p>We&#8217;ll also need to open a browser and set up the Selenium environment from the test fixture. To keep the test script format in english-like prose, we&#8217;ll use the following syntax:</p>
<blockquote><p>Start Browser *iehta with selenium console on localhost at port 4444 and scripts at http://localhost:7711</p></blockquote>
<p>In WebTest fixture, that is covered by the following method:</p>
<pre>
public void StartBrowserWithSeleniumConsoleOnAtPortAndScriptsAt
   (String browser, String rcServer, int rcPort, String seleniumURL){
            instance = new DefaultSelenium(
                 rcServer, rcPort, browser, seleniumURL);
            instance.Start();
}
</pre>
<p>On the end of each test, we need to shut down the browser, so that remote console does not run out of resources. For that, we&#8217;ll use the following method:</p>
<pre>
public void ShutdownBrowser(){
            instance.Stop();
}
</pre>
<p>With all that, the web test can be easily described with this FitSesse script:</p>
<p><center></p>
<div style="overflow-x:scroll;width:600px;border:1px solid black;text-align:left">
<pre>

!|webfixture.WebTest|

!|Start Browser|*iehta|With Selenium Console On| localhost| At Port |4444|And Scripts At|http://localhost:7711|

|User Opens URL|http://localhost:7711/login.aspx|
|User types|testuser|into|username|field|
|User types|testpassword|into|password|field|

|User clicks on|Log In|
|Page reloads in less than|3|seconds|
|Page contains text|You have logged in|

|Shutdown browser| 
</pre>
</div>
<p><a href="/images/webtest-s3.png" border="0" target="_blank"><img src="/images/webtest-s3.png" width="600" /><br />click for full-size image</a><br />
</center></p>
<h2>Ajax testing</h2>
<p>With web 2.0 pages, waiting for the page to reload before we continue testing is not the best choice. Selenium also supports<br />
waiting for a JavaScript condition. Remember that Selenium script is being executed in a different frame, so referencing DOM elements and JS functions in your test site page will not work straight away. Prefix the references with<br />
<em>selenium.browserbot.getCurrentWindow()</em> to get from the Selenium frame to your test page. Here&#8217;s an example: </p>
<pre>
instance.WaitForCondition(
  "(selenium.browserbot.getCurrentWindow().get_username()!=null)",
  timeout);
</pre>
<h2>Remote execution</h2>
<p>Selenium Remote Console will try to open a new browser session with different security settings, but under the profile of the current user (in fact, the user which started the remote console). This may cause problems when you already have an open browser on the same machine.  The workaround is to use a different browser for testing. For example, I use Firefox for normal browsing, so RC can start IE and play with it. But, there is a much better solution.</p>
<p>As the name suggests, Remote Console can run on a dedicated test server, and be accessed remotely. Any browsers that RC opens will run on that machine. That enables developers to work with browsers on their machines and run the tests, without clashing with test execution. It also enables us to re-use the same FitNesse scripts to check how various browsers are behaving, even on different platforms. Just separate the initialisation and browser shut-down into SetUp and TearDown scripts, and then create a couple of different test suites with different SetUps which will use various browsers and remote console installations. Then, use symbolic links to import scripts from one test suite into all others. You will maintain scripts in one place, and they will test multiple browsers and platforms.</p>
<h2>Extending WebTest</h2>
<p>WebTest currently supports two more interesting methods: PageURLIs(String s) and  UserSelectsFrom(String what, String where). The first allows you to verify the page URL (and test redirections). The second automates selecting an option from a drop-down menu (HTML select element), in the form of <em>User Selects NY from Countries</em>.</p>
<p>Feel free to modify and adjust WebTest to your needs. For start, see dotnet/doc/index.html in your remote control installation for more information on ISelenium interface. You can a add search by ID to the top of all locator arrays, so that tests run faster, but that will make them more error-prone. You will probably want to add a few different expressions to the textbox, button or select lists. If you add something which may be useful to others, please share it by writing a comment on the  <a href="/fitnesse/webtest/">WebTest</a> fixture page.</p>
<p>Photo credits:<a href="http://www.sxc.hu/profile/lusi" target="_blank">Sanja Gjenero/SXC</a></p>
]]></content:encoded>
			<wfw:commentRss>http://gojko.net/2007/05/20/automating-web-tests-with-fitnesse-and-selenium/feed/</wfw:commentRss>
		<slash:comments>49</slash:comments>
		</item>
	</channel>
</rss>
