WUnit : unit tests for Web applications

WUnit aims to design unit tests for Web applications thanks to :

  • a client emulator (a non-visual browser) with operations for filling HTML forms, clicking on links and buttons, managing cookies, sending URLs to a target server,
  • a server emulator, that can be used for Web applications made with servlets or with the Active Tags Web module available in RefleX (which is accessible with a servlet too).
Quick start

A step by step tutorial is available here.

Say 3Unit

Don't say "double-u-u-nit", say "triple-u-nit".

Mathematical demonstration : 2u+u=3u

WUnit at a glance

Jump and start reading from this point.

AJAX support

WUnit support AJAX ! WUnit can be used to test your Rich Internet Applications !

The server emulator is an optional component that allows to test Web applications without running a Web server. Additionally, it offers means to examine the server internals (application settings, servlet, sessions...) and allows to act on them.

When combined with a framework such as XUnit, it is fairly easy to write tests that very quickly verify the well-functioning of a web site. WUnit supplies convenient means for designing Web scenarii along multiple HTML pages, for example with the image gallery application one can check various informations (HTML fragments, HTTP headers, object stored in sessions server-side, etc) all along a given scenario :

  • getting a welcome page and clicking on the "upload" page,
  • filling a form and upload images to the server,
  • getting an image gallery,
  • selecting an item supplied by a Javascript autocompleter,
  • etc

If you want to learn more about this example scenario, please visit WUnit quick start.

WUnit is different from other Web testing framework in several ways :

  • it browses Web pages as a chameleon : it can mimic the behaviour of your favorite browser without needing complex installations and patch on the system where the tests will run.
  • the tests are written in XML/XPath : if you already know XSLT, diving into WUnit and Active Tags is straightforward. You don't have to write C or Java or other low-level code.
  • it can act on the server directly : you will have more controls on your tests by acting both on the UI and the server.

The next section indicates how to get, install, and run WUnit ; the following sections will show you various facets of WUnit. The last section is the reference of this module.

Downloading, installing and running

As an Active Tags module, WUnit must run within the RefleX engine that you can download here. You can either :

  • get it with the full distribution or the source distribution (which is much more simple since all the third-party libraries expected are also supplied),
  • or get it separately in the xunit-0.4.0.jar file (XUnit and WUnit are packed together) ; in this case, you will also have to get the light distribution of RefleX, and download the third-party libraries required.

In both cases, unzip and install the distribution of RefleX you chose as indicated, and ensure that all the expected classes are in the CLASSPATH when running a test suite.

A WUnit test suite is runnable like any other test suite made with XUnit (you can have a look at XUnit before). In short, RefleX need to know where are the XUnit and WUnit modules, and this is done thanks to predefined catalog which is added automatically to the engine if the xunit-0.4.0.jar file is found in the classpath.

A WUnit test suite can be run with the following command :

 $ java -cp reflex-0.4.0.jar:xunit-0.4.0.jar (line cut)
     org.inria.ns.reflex.ReflexCLI run file:///path/to/test-suite-launcher.xcl

For a step by step installation, please refer to the WUnit quick start page.

Getting a Web page

In the following snippet code, a Web conversation is started with an hypothetic real Web server.

After submitting an HTTP request, we assert that the HTTP response gives the right return code and MIME type. To send an HTTP request we can use <wunit:submit> but <wunit:GET> can be used as a shortcut for HTTP GET.

The $wunit:document property that refer to the HTML document of the current frame is then compared with the result expected (an HTML file parsed with <xcl:parse-html>). Notice that an ill-formed HTML result is automatically extracted from the frame window to a well-formed XML document if necessary. <xcl:parse-html> works in the same way.

  <!--set the boundary of our test case-->
  <xunit:test-case label="[Web] Hello world !" name="report/whello">
      <!--start a Web conversation-->
      <wunit:conversation>
          <!--submit an HTTP GET request -->
          <wunit:GET url="http://www.example.com/myApp/index.html?who=John Doe"/>
          <!--we expect that the HTTP response code and the MIME type are those specified-->
          <xunit:assert-number-equals expected="200" result="{ value( $wunit:frame/@wunit:response-code ) }"/>
          <xunit:assert-string-equals expected="text/html" result="{ string( $wunit:frame/@wunit:mime-type ) }"/>
          <!--parse the HTML output expected
              ensure that the elements name are in lower case
              because the default WUnit client supply them in lower case too-->
          <xcl:parse-html elems-name="lower" name="output-expected" source="result/hello.html"/>
          <!--assert that the result of the HTTP response get by the client
              is the same than the output expected-->
          <xunit:assert-node-equals expected="{ $output-expected }" result="{ $wunit:document }"/>
      </wunit:conversation>
  </xunit:test-case>

The last active tag, <xunit:assert-node-equals>, comes from the XUnit module and will report a success if both documents are equals, an error (or several) if they are different, or a failure if the comparison can't be performed. Several assertions can be made within a single <xunit:test-case> that will generate a report in a file which name is derived from its @name attribute. In our case, the report file name is report/whello-err.xml. Please refer to XUnit for more informations.

Test-driven development

In the previous section, the complete HTML document was compared to the output expected. However, in most cases, the data structure obtained might vary all along the development process, breaking the tests written. Two techniques that can be combined can be considered for designing robust tests.

Focusing on atomic datas

Instead of comparing globally the result get with the output expected, it may be preferable to select explicitely the relevant datas of the result get, leaving the surrounding structure unchecked. With XPath, getting a fragment is straightforward, and arbitrary complex expressions can be considered for extracting datas.

For example, instead of writing :

  <xunit:assert-node-equals expected="{ $output-expected }" result="{ $wunit:document }"/>

...it might be better to write :

  <xunit:assert-string-equals expected="Hello John Doe !"
result="{ string( $wunit:document//div[@class='content'] ) }"/>

This way, if the structure is modified for example by adding a surrounding <DIV> element around the content, or by setting the name in bold, the test remains appliable.

Cleaning the datas with XSLT

Rather than checking the raw HTML datas, it can be advantageous to clean them by passing through an XSLT filter that removes unwanted elements and attributes but leaves the text content :

  <!--clean the HTML document obtained with XSLT-->
  <xcl:transform name="clean-result" source="{ $wunit:document }"
stylesheet="file:///path/to/cleaning.xsl"/> <!--parse the XML output expected--> <xcl:parse-html elems-name="lower" name="output-expected" source="result/hello.html"/> <!--assert that the cleaned result is the same than the output expected--> <xunit:assert-node-equals expected="{ $output-expected }" result="{ $clean-result }"/>

The following stylesheet consist on removing all elements, except the <DIV> and <A> elements ; only their relevant attributes are preserved :

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!--clean <a href="...">--> <xsl:template match="a[@href]"> <a href="{@href}"><xsl:apply-templates/></a> </xsl:template> <!--clean <div>--> <xsl:template match="div"> <div class="{@class}"><xsl:apply-templates/></div> </xsl:template> <!--remove the header <DIV> and the footer <DIV>--> <xsl:template match="div[@class='header' or @class='footer']"/> <!--remove other elements--> <xsl:template match="head | script | style"/> <!--strip leading and trailing whitespace and replace sequences of whitespaces by a single space--> <xsl:template match="text()"><xsl:value-of select="normalize-space(.)"/></xsl:template> </xsl:stylesheet>

Of course, more complex stylesheets could be considered for processing tables, lists, forms, medias, etc.

Finally, this method can be combined advantageously with the previous one for isolating the relevant datas.

How the DOM is altered

You must be aware that the documents handled might be slightly different according to how it has been processed:

  • First, the HTML parser will follow by default the HTML DOM specification that explicitly states that element and attribute names follow the semantics, including case-sensitivity, specified in the HTML 4 specification. In addition, section 1.2.1 of the HTML 4.01 specification states : "Element names are written in uppercase letters (e.g., BODY). Attribute names are written in lowercase letters (e.g., lang, onsubmit)."
  • Next, the Web client of WUnit emulates the behaviour of real-life clients (Firefox by default or Internet Explorer), that doesn't follow necessarily the specifications mentionned, and that sometimes fix arbitrarily some data.

Example:

A snippet HTML code as written in a file

  <table>
    <tr>
        <td>Foo</td>
    </tr>
  </table>
                   

The same code after HTML parsing (with element names set to lower case)

<table>
<tbody>
<tr>
<td>Foo</td>
</tr>
</tbody>
</table>
                   

The same code supplied by the Firefox client of WUnit

<table>
<tbody align="left">
<tr>
<td>Foo</td>
</tr>
</tbody>
</table>
                   

Consequently, in order to check the document load by the Web client against the document load from the file system by the HTML parser, you certainly have to set the elems-name option of the HTML parser, and perhaps to clean the DOM supplied by the Web client.

Example:

    <!-- GET an HTML page -->
    <wunit:submit method="GET" url="http://www.example.com/index.html"/>
    <!-- WUnit emulates Firefox (by default) that alters the DOM;
         we have to fix this with the styleseet
         prune.xsl remove align="left" in <tbody> -->
    <xcl:transform name="dom" source="{ $wunit:document }" style="tree"
stylesheet="wunit/prune.xsl"/> <!-- Ensure to specify that the HTML elements name have to be in lower case because this is what has done Firefox --> <xcl:parse-html elems-name="lower" name="oe" source="wunit/webapp1/index.html"/> <!-- Now, the "cleaned" DOM can be compared to our output expected --> <xunit:assert-node-equals expected="{ $oe }" result="{ $dom }"/>

If you don't specify the case of elements name, <xcl:parse-html> will supply conformant HTML documents. $wunit:document will supply documents conformant to the Web client emulated (elements in Firefox are in lower case). But if the MIME type of the response specifies that the document is an XML document, then $wunit:document will give an XML document, and the output expected should be parsed with an XML parser rather than an HTML parser: use <xcl:parse> instead.

Test design and abstraction

It is preferable to address HTML structures without expressing their canonical path in XPath expressions, but rather to address them the most directly thanks to a unique ID set on HTML elements, or to a class attribute set on a family of elements. That is to say, prefer writing $clean-result//div[@class='content'] rather than $clean-result/html/body/div[3]/div[4], which will break as soon as a new <div> element will be added before the one to test.

To help identifying structures smartly within HTML documents, you are encouraged to qualify HTML elements for example with microformats or any appropriate mean. This will allow you to retrieve easily datas all over the place.

In XP (Extreme Programming) methodology, test-driven developments mean that the tests are written first. For HTML applications, it is a kind of challenge since the details of the templates can evolve during the development process. Thanks to XML, you will be able to write unit tests even before the web site is built. To reach this goal, you are encouraged to design your Web application by identifying the relevant informations in your (X)HTML pages with an appropriate mean.

Following links

XPath can be used to select elements in an HTML page such as links, forms and buttons. When a link is get, it is straightforward to click on it :

  <!--set the boundary of our test case-->
  <xunit:test-case label="[Web] Click on a link" name="report/whello">
      <!--start to discuss with the server-->
      <wunit:conversation>
          <!--submit an HTTP GET request-->
          <wunit:GET url="http://www.example.com/index.html"/>
          <!--click on the second link found in the page-->
          <wunit:click target="{ $wunit:document//a[@href][2] }"/>
          <!--
              etc
          -->
      </wunit:conversation>
  </xunit:test-case>

What you would have in your favorite Web navigator :

[www]
index.html - Web Navigator

Welcome !

Please click on one of the links below :

After clicking on a link, the $wunit:frame is updated with the new page, except if some Javascript code changes the normal behaviour of the link.

As you might guess, various events can be submitted to the elements in the page. For example, a click event or a mouseOver event can be submitted on a button as well.

Shortcuts

<wunit:GET> and <wunit:click> are simply convenient shortcuts for submission of requests and events. The following snippet code performs the same as above :

  <!--submit an HTTP GET request-->
  <wunit:submit method="GET" url="http://www.example.com/index.html"/>
  <!--click on the second link found in the page-->
  <wunit:submit event="click" target="{ $wunit:document//a[@href][2] }"/>

We'll see later that the most common XPath properties supplied are also shortcuts.

Filling forms

Forms can be filled thanks to the <wunit:fill-form> elements ; within that element, you can set individually the values of input elements with <xcl:param>.

  <!--set the boundary of our test case-->
  <xunit:test-case label="[Web] Fill the login form" name="report/whello">
      <!--start to discuss with the server-->
      <wunit:conversation>
          <!--submit an HTTP GET request-->
          <wunit:submit method="GET" url="http://www.example.com/login.html"/>
          <!--fill the login form-->
          <wunit:fill-form form="{ $wunit:document//form[@name='login'] }">
              <xcl:param name="user" value="Bill"/>
              <xcl:param name="password" value="Sesame"/>
          </wunit:fill-form>
          <!--
              etc
          -->
      </wunit:conversation>
  </xunit:test-case>

What you would have in your favorite Web navigator :

[www]
login.html - Web Navigator

Login

Please fill the following form :

User name :
Password :

While filling the form, you can of course use alternatives and loops or any other construct available in other modules if you want. Mutliple values can also be set on the same input element. After filling the form, it is submitted to the server but this behaviour can be changed.

If you don't have an HTML form but that you want to send POST datas to the server, you can also use the <wunit:POST> element, that also accept parameters.

Checkboxes

Within the form you can have checkboxes ; you just have to send a boolean in the parameter value :

  <xcl:param name="iHaveABike" value="{ true() }"/>

Files upload

Files to upload are not so different, just use the io:file() function :

  <xcl:param name="imageOfBike" value="{ io:file( 'file:///path/to/myBike.png' ) }"/>

Like with any module, don't miss to declare the namespace URI of the I/O module : xmlns:io="http://ns.inria.org/active-tags/io"

Dealing with frames and windows

In the previous examples, every elements handled were located on the current and unique frame. When the window is splitted on several frames, or when the application creates several windows, it is still possible to get the element expected by your test. You just have to navigate within the hierarchy of the current frame or window.

Some convenient properties are available within a Web conversation. They are just shortcut for accessing members of objects exposed as XML items.

Understanding properties

If you look at the reference documentation of the $wunit:frame property, you will see that its type is #wunit:x-frame, which itself indicates that the XML-tree view of the HTML page is bound to its @wunit:document attribute.

The XPath expression value( $wunit:frame/@wunit:document ) allows to extract this document (rather than the string value of the attribute, which is the reference of the object behind the document).

Thus, $wunit:frame is a reference to the current frame of the client ($wunit:client). It is of course possible to select another frame, by simply getting one from the children of the client (that are all the top-level windows) or from the children of another frame. For example, $wunit:client/myWindow/myFrame will select the appropriate frame. If a frame or window doesn't have a name or if its name isn't an XML name, you can get it anyway like this for example : $wunit:client/*[name()='my Window'/*[2] : "my Window" can't appear in an XPath step, and since the structure of the frames within that specific window are likely known, they can be addressed by index.

To get all the frames, simply use $wunit:client//*.

To create a new top level window, set a string in the @frame attribute of the <wunit:submit> element. If this attribute contains an XPath expression, it should be resolved to a single frame, such as $wunit:client/myWindow/myFrame.

Other properties such as $wunit:document allow to retrieve objects from the current frame, but can also be get from the attributes of a frame : $wunit:frame/@wunit:document or $wunit:client/myWindow/myFrame/@wunit:document.

Getting the title of an HTML page can be done like this : $wunit:client/myWindow/myFrame/@wunit:document/html/head/title ; this XPath expression is somewhat unusual, this is because the HTML document is bound to the @wunit:document attribute of a #wunit:x-frame (read more about that hereafter).

Checking HTTP headers and cookies

Understanding X-operable objects

You might notice that the XPath expressions used to get some HTTP headers are somewhat exotic, yet they are legal XPath expressions. In the XML data model, an attribute can't contain something else than a string, whereas in Active Tags, it is possible to bind an arbitrary object to an attribute, like for the @wunit:headers and @wunit:cookies attributes. If those objects are XML friendly, an XPath expression can be applied on them, this is why we can use such XPath expressions.

Such objects are called X-operable objects.

Most useful headers are available directly as attributes of an instance of #wunit:x-frame, but the complete list of headers are also available with a specific one that contains the list of named headers. Cookies can also be accessed separately.

  • $wunit:frame/@wunit:response-code
  • $wunit:frame/@wunit:mime-type
  • $wunit:frame/@wunit:headers/Date
  • $wunit:frame/@wunit:headers/Server
  • $wunit:frame/@wunit:headers/Last-Modified
  • $wunit:frame/@wunit:cookies/LOCALE_PREFERENCE

Notice that in the XPath expressions above, you get an attribute or element as an object. To extract its value, use the string() function or the value() function.

Status, alerts and prompts

Status, alerts and prompts are also available as attributes of a #wunit:x-frame instance :

  • $wunit:frame/@wunit:status : the status of a frame is always the more recent one.
  • $wunit:frame/@wunit:alerts[1] : each time a Javascript alert('message'); is performed, the client automatically click on the OK button of the alert popup, but the message is stored within this attribute. The more recent message is the first one. Each frame stores its own alerts independantly but discards the older ones.
  • $wunit:frame/@wunit:prompt : a prompt is a popup that either wait for the user input or for clicking on the "OK" or "CANCEL" buttons. Prompts are blocking operations in script, and to go on a value must be supplied. This can be done by setting the value to the attribute :
      <!--click "OK" on a confirm message-->
      <xcl:attribute name="wunit:prompt" referent="{ $wunit:frame }" value="{ true() }"/>
      <!--set an input value on a prompt-->
      <xcl:attribute name="wunit:prompt" referent="{ $wunit:frame }" value="John Doe"/>
    Notice that before setting the value, the prompt can be read and its value is the message ; after setting the value, the prompt is discarded.

Getting server-side components

A WUnit conversation can be made with :

  • any Web server
  • a servlet container
  • an Active Tags Web application (that uses the RefleXServlet)

The advantage of using one of the two lasts is that server-side components can be handled during the conversation. For this purpose, the Web application must be registered directly while initializing the conversation that will launch a servlet container emulator instead of discussing with a real Web server :

    <!--start to discuss with the server emulator-->
    <wunit:conversation application="file:///path/to/webapps/hello/WEB-INF/web.xml"
uri="http://www.example.com/myApp"> <!--submit an HTTP GET request if the target host name match those specified, the request will be handled by the server emulator --> <wunit:submit method="GET" url="http://www.example.com/myApp/index.xml?who=John Doe"/> <!-- etc --> </wunit:conversation>

On the opposite, a real server can be involved in a Web conversation if the <wunit:conversation> is used without attributes :

    <!--start to discuss with a real server-->
    <wunit:conversation>
        <!--submit an HTTP GET request,
            the target host must be a Web server in service before-->
        <wunit:submit method="GET" url="http://www.acme.org/myApp/index.xml?who=John Doe"/>
        <!--
            etc
        -->
    </wunit:conversation>

Of course, in this last case the Web server have to be started before the tests are launched.

With the servlet container emulator, the following properties are available ; they have the same types of their counterpart properties of the Web module :

PropertyType
$wunit:application#web:x-application
$wunit:service#web:x-service
$wunit:session#web:x-session
$wunit:request#web:x-request
$wunit:response#web:x-response

Note that those objects are also available for frames that has sent an HTTP request to the emulator.

During the conversation you can act on any of them, for example for creating a session server-side before sending the request (or after), for storing objects within the application, and many other things that allow to cheat as long as they have some sense in your tests...

    <!--start to discuss with the server emulator-->
    <wunit:conversation application="file:///path/to/webapps/hello/WEB-INF/web.xml"
uri="http://www.example.com/myApp"> <!--submit an HTTP GET request--> <wunit:submit method="GET" url="http://www.example.com/myApp/index.xml?who=John Doe"/> <!-- etc --> <!--get the request parameter, and assert that it is those passed--> <xunit:assert-equals expected="John Doe" result="{ string( $wunit:response/who ) }"/> </wunit:conversation>

The WUnit tutorial use this facility for storing authoritatively objects in the user session.

More on the server emulator

The servlet-container emulator of RefleX also support JSP pages and a default servlet for handling static resources.

  • If your application contains JSP pages, since the server emulator is configured to use Jasper (the JSP engine which is part of Tomcat), you will therefore need the Jasper jar in your classpath (not bundled in RefleX), along with any on which it depends. Once done, your JSPs should run, just as they would in Tomcat. You can get the relavant libraries from the standard Tomcat binary download location : add to the classpath jasper-compiler.jar, jasper-runtime.jar, ant.jar, jsp-api.jar for Jasper v1.x, and add also commons-el.jar for Jasper v2.x.
  • Finally, the servlet-container emulator of RefleX also supply a default servlet for retrieving static resources ; this servlet is auto-registered under the name "default" like in Tomcat and can be referred safely in the Web deployment descriptor like this :
      <servlet-mapping>
          <url-pattern>*.css</url-pattern>
          <servlet-name>default</servlet-name>
      </servlet-mapping>
    ...all URLs ending with .css will be sent to the client.

Tips

XHTML

If your pages are in XHTML, you'll have to specify the XHTML namespace in your XPath expressions ; for that purpose, you just have to declare the namespace on an ancestor element :

        <!--prepare to get an XHTML page-->
        <wunit:conversation
    xmlns:xhtml="http://www.w3.org/1999/xhtml">
            <wunit:submit method="GET" url="http://www.example.com/index.xhtml?who=John Doe"/>
            <!--use the prefix defined in the namespace declaration-->
            <xunit:assert-node-equals expected="John Doe"
result="{ $wunit:document//xhtml:div[@name='content']//xhtml:span[@name='user'] }"/> </wunit:conversation>

Page trace

When using WUnit, it may happen that you're not sure about the details of the result returned by the server since you don't have a Web renderer. Sometimes it may be useful to trace the (X)HTML get ; you can simply use XSLT for that purpose :

  <!--write an HTML trace to the standard output-->
  <xcl:transform output="{ $sys:out }" source="{ $wunit:document }"/>

...and you'll have the result in the <sysout> section of the test report. Of course, you can serialize the page in a separate file if you prefer. Note that if you refer to the $sys:out property you have of course to set its namespace URI as usual.

Timing

Sometimes, you might get a page that contains a Javascript code that will run after a given delay. If you don't get the expected result, it might be because you try to test something that didn't occur yet. To avoid this, the best way is to make a pause before going on :

  <!--let enough time (500ms) to the script to be triggerred-->
  <xcl:sleep value="500"/>

There is an example in the WUnit tutorial where a Javascript autocompleter accept a delay parameter before sending a request to the server. We have to wait for the request before examining its effects.

XUnit integration

Unit tests can be designed with XUnit in 2 flavours :

  • Begin a test case that start a Web conversation :
      <!--set the boundary of our test case-->
      <xunit:test-case label="[Web] Hello world !" name="report/whello">
          <!--start a Web conversation-->
          <wunit:conversation>
              <!--
                  etc
              -->
          </wunit:conversation>
      </xunit:test-case>
  • Start a Web conversation that contains test cases :
      <!--start a Web conversation-->
      <wunit:conversation>
          <!--set the boundary of our test case-->
          <xunit:test-case label="[Web] Hello world !" name="report/whello">
              <!--
                  etc
              -->
          </xunit:test-case>
      </wunit:conversation>

The WUnit tutorial contains both styles.

The description of the XUnit module is available here.

WUnit internal

WUnit relies on HtmlUnit and Winstone with the following enhancements :

  • high-level abstraction of unit tests for Web applications, without having to write a single line of Java code
  • servlets internal are exposed as XML typed items
  • XPath access to the elements of HTML pages
  • support of packed Web applications (.war files)
  • auto-loading of Java classes found in WEB-INF/lib/ and WEB-INF/classes/ without specifying them in the CLASSPATH
  • a default servlet is available for serving static resources (like in Tomcat)
  • fully integrated to Active Tags and the RefleX engine
  • consistent and coherent with the Web module

Few low-level features of HtmlUnit are not exposed in WUnit ; if you want to act on them, you'll have to write your own extension. Those features are : sending requests through a proxy server, certificate handling and SSL support.

WUnit reference

WUnit : WUnit module
WUnit namespace URI : http://reflex.gforge.inria.fr/wunit.html
Usual prefix : wunit
Elements Foreign attributes Predefined properties Data types
<wunit:conversation>
<wunit:submit>
<wunit:fill-form>
<wunit:GET>
<wunit:POST>
<wunit:click>
@wunit:version
$wunit:client
$wunit:frame
$wunit:document
$wunit:server
$wunit:application
$wunit:service
$wunit:request
$wunit:response
$wunit:session
#wunit:x-client
#wunit:x-frame
#wunit:server

Must be an adt:expression that computes an object of the type expected.
Must be a hard-coded value (litteral)
Can be either a hard-coded value or an adt:expression
This material may be missing
Denotes a value to use by default
Allows a read operation.
Allows a write operation.
Allows a rename operation.
Allows an update operation.
Allows a delete operation.

WUnit requirements

WUnit is bundled with XUnit. See XUnit requirements.

WUnit elements

<wunit:conversation>

Set the boundaries of a conversation between a user-agent (an emulation of a browser) and a servlet container (not necessary emulated).

An emulated servlet container offers means to examine and act on the server internals.

A servlet container can be emulated if a web deployment descriptor and an URI is supplied : each request in the scope of that URI will be forwarded to the emulator, other URLs will be processed normally.

Attributes runtime | hard-coded | both
 NameTypeValue optional | default value
bothapplicationoptional Refer to a Web application to emulate.
unspecifieddefault value The conversation is made with a real Web server.
#xs:anyURI The URI reference to the web application to emulate. Must refer to a local file or directory. The target can be either of the following :
  • a Web deployment descriptor (WEB-INF/web.xml)
  • a directory that contains WEB-INF/web.xml
  • a Web archive .war
hard-codedurioptional#xs:anyURI Specifies the host to emulate. The context path of the Web application can be specified in the URI : the server emulator will serve URLs that are pointing to this Web application, other URLs will cause an error. If the context path is missing, the Web application will be hosted on the server root.
hard-codeduser-agentoptional Indicates to the client that it has to behave like a specific user agent.
#xs:stringFirefox 3default value
Internet Explorer 6
Internet Explorer 7
Internet Explorer 8

<wunit:submit>

Submit an HTTP request to the server or an event in a frame. It can be specified either by an URL, or by a click on a link or a button, or by submitting a form.

Submit an URL

Attributes runtime | hard-coded | both
 NameTypeValue optional | default value
bothurl#xs:anyURI Specifies the target URL.
hard-codedmethodoptional Indicates the HTTP method.
#xs:stringGETdefault valueSubmit an HTTP GET request.
POSTSubmit an HTTP POST request.
HEADSubmit an HTTP HEAD request.
PUTSubmit an HTTP PUT request.
DELETESubmit an HTTP DELETE request. Currently NOT SUPPORTED.
runtimeframeoptional#wunit:x-frame Specifies the frame that will load the page. For example : $wunit:client/someWindow/someFrame
#xs:string Specifies a name for a new top level window that will be created.
unspecifieddefault value The page will be loaded to the current frame, given by the $wunit:frame property.

Submit an event

Attributes runtime | hard-coded | both
 NameTypeValue optional | default value
runtimetarget#xml:element The target element in some frame. Can be an HTML or XHTML element. For example : $wunit:document//DIV[@id='products']//A[@href][1].
runtimeevent The event to send to the target element. Various events are available depending on the target object. For example, links and buttons can accept "click".
#xs:stringright-clickMouse right click.
double-clickMouse double click.
typeType a character.
other values must be Javascript events valid for the target.
runtimevalueoptional An additional information for the event : actually, a character or a string for the "type" event.
#xs:integer The code of the character. The value MUST be explicitely converted to a number : value="{ number(123) }".
#xs:string A set of characters to send.

Submit a form

Attributes runtime | hard-coded | both
 NameTypeValue optional | default value
runtimeform#xml:element The form element in the frame selected. Can be an HTML or XHTML element. For example : $wunit:document//FORM[@name='myForm'].
hard-codedsubmitoptional Specifies whether to submit or not the form to the server after filling the fields. A form not send to the server can be completed in a later action.
#xs:booleantruedefault valueThe form is submitted to the server.
falseThe form is not submitted to the server.
runtimeframeoptional#wunit:x-frame Specifies the frame that will load the page. For example : $wunit:client/someWindow/someFrame
#xs:string Specifies a name for a new top level window that will be created.
unspecifieddefault value The page will be loaded to the current frame, given by the $wunit:frame property.

<wunit:fill-form>

Fill an HTML form.

This action only specifies the form to fill ; to set named values to the form, subactions have to be used (<xcl:param>).

Attributes runtime | hard-coded | both
 NameTypeValue optional | default value
runtimeform#xml:element The form element in the frame selected. Can be an HTML or XHTML element. For example : $wunit:document//FORM[@name='myForm'].
bothsubmitoptional Specifies whether to submit or not the form to the server after filling the fields. A form not send to the server can be completed in a later action.
#xs:booleantruedefault valueThe form is submitted to the server.
falseThe form is not submitted to the server.
runtimeframeoptional#wunit:x-frame Specifies the frame that will load the page. For example : $wunit:client/someWindow/someFrame
#xs:string Specifies a name for a new top level window that will be created.
unspecifieddefault value The page will be loaded to the current frame, given by the $wunit:frame property.

<wunit:GET>

A shortcut for <wunit:submit method="GET">

Submit a explicit HTTP GET request to the server. The response is loaded in the current frame.

Attributes runtime | hard-coded | both
 NameTypeValue optional | default value
bothurl#xs:anyURI Specifies the target URL.

<wunit:POST>

Submit a explicit HTTP POST request to the server.

Parameters (<xcl:param>) encountered in this element will set them in the request body. The encoding type of the request will be set to "multipart/form-data".

Attributes runtime | hard-coded | both
 NameTypeValue optional | default value
bothurl#xs:anyURI Specifies the target URL.
runtimeframeoptional#wunit:x-frame Specifies the frame that will load the page. For example : $wunit:client/someWindow/someFrame
#xs:string Specifies a name for a new top level window that will be created.
unspecifieddefault value The page will be loaded to the current frame, given by the $wunit:frame property.

<wunit:click>

A shortcut for <wunit:submit event="click">

Click on an element.

Attributes runtime | hard-coded | both
 NameTypeValue optional | default value
runtimetarget#xml:element The target element in some frame. Can be an HTML or XHTML element. For example : $wunit:document//DIV[@id='products']//A[@href][1].
#wunit:x-frame The frame that receives the click. A click on a frame make it become the current frame.

Foreign attributes

@wunit:version

  • Priority : 0

The version of the WUnit module to use. This attribute should be encountered before any WUnit element, but it takes precedence on the element inside which it is hosted.

Predefined properties

They are available exclusively within a Web conversation.

$wunit:client

$wunit:client is a reference to the Web client.


$wunit:frame

A shortcut for { value( $wunit:client/@wunit:current-frame ) }

$wunit:frame is a reference to the current frame.


$wunit:document

A shortcut for { value( $wunit:frame/@wunit:document ) }

$wunit:document is a reference to the HTML or XML document of the current page. For HTML documents, element names are in uppercase and attribute names are in lowercase, as specified in section 1.2.1 of the HTML 4.01 specification.

Properties set by the server emulator

The following properties are available only when the conversation is made with a server emulator : they are available if the current frame contains a page that was served by the server emulator.

The type of those properties are the same of the counterpart properties handled server-side by the Web module when a Web application is made with Active Tags. It is not necessary to design a Web application with the Web module, the properties will be available on any servlet.

$wunit:server

$wunit:server is a reference to the Web server emulator.


$wunit:application

A shortcut for { value( $wunit:frame/@wunit:application ) }

$wunit:application is a reference to the Web application.


$wunit:service

A shortcut for { value( $wunit:frame/@wunit:service ) }

$wunit:service is a reference to the HTTP service (the servlet).


$wunit:request

A shortcut for { value( $wunit:frame/@wunit:request ) }

$wunit:request is a reference to the HTTP request.


$wunit:response

A shortcut for { value( $wunit:frame/@wunit:response ) }

$wunit:response is a reference to the HTTP response.


$wunit:session

$wunit:session is a reference to the HTTP session. If no session exists, the session is created server-side. To check if a session already exists, use $wunit:request/@web:has-session. It can be useful to store the session in a user property in order to avoid loosing it after the server destroy it.

Data types

#wunit:x-client type

Represents the Web client that discuss with the Web server.

Operation read | write | rename | update | delete
TypeValueComment
type()
#xs:QName#wunit:x-clientThis type
child::
read#adt:list of #wunit:x-frame The windows that this client has opened.
attribute::
read#adt:map of #adt:NItem The set of attributes specified below (and that can't be removed).
@wunit:current-frame
read#wunit:x-frame Return the current frame. Can be altered by Javascript, click on links, etc.
write#wunit:x-frame Set the current frame.
@wunit:user-agent
read#xs:string The name of the user agent. See values below.
write#xs:stringFirefox 2default valueSet the name of the user agent.
write#xs:stringInternet Explorer 6Set the name of the user agent.
write#xs:stringInternet Explorer 7Set the name of the user agent.
@wunit:user
read#xs:string The name of the user to send when an authentication is required.
write#xs:string Set the name of the user to send when an authentication is required.
@wunit:password
read#xs:string The name of the password to send when an authentication is required.
write#xs:string Set the name of the password to send when an authentication is required.
@wunit:cookie-specification
read#xs:string Indicates how the client have to handle cookies. Default is "rfc2109". See values below.
write#xs:string Set the cookie specification that this client will use. See values below.
write#xs:stringrfc2109default valueAs specified in RFC 2109.
write#xs:stringrfc2965As specified in RFC 2965.
write#xs:stringnetscapeAs specified in the Netscape cookie draft.
write#xs:stringIgnore cookies.

#wunit:x-frame type

Represents a window frame or a frame in a window. A frame can receive HTTP responses.

Operation read | write | rename | update | delete
TypeValueComment
type()
#xs:QName#wunit:x-frameThis type
name()
read#xs:string The name of the frame. Can be the empty string.
write#xs:string The name of the frame. Can be the empty string.
parent::
read#wunit:x-client The client if this frame is a top-level window.
read#wunit:x-frame The frame that contains this frame, if this frame is in a frame.
child::
read#adt:list of #wunit:x-frame The frames within this frame. If a frame contains another frame, the subframe won't be in the direct child of this frame, but in its descendent.
attribute::
read#adt:map of #adt:NItem The set of attributes specified below (and that can't be removed).
@wunit:document
read#xml:document The document contained in this frame.
@wunit:encoding
read#xs:string The character encoding specified in the HTTP header.
@wunit:content-length
read#xs:integer The content length specified in the HTTP header.
@wunit:mime-type
read#xs:string The MIME type specified in the HTTP header.
@wunit:input
read#io:input The bytes or character stream received.
@wunit:cookies
read#adt:list of #web:cookie The list of cookies received. All the cookies hold by the client for the URL frame are returned here.
@wunit:response-code
read#xs:integer The HTTP response code.
@wunit:response-message
read#xs:string The HTTP response message.
@wunit:url
read#xs:anyURI The URL of that page.
@wunit:headers
read#adt:list of #adt:NItem The list of headers received.
@wunit:status
read#xs:string The current status message of this frame.
@wunit:alerts
read#adt:list of #xs:string An history of the Javascript alerts received by this frame. Retain a maximum of 20 alerts. The more recent is the first one.
@wunit:prompt
read#xs:string The prompt message.
write#xs:boolean The value to set to a confirm prompt.
write#xs:string The value to set for a prompt input.
@wunit:application
read#web:x-application The Web application that has served the page in this frame. This attribute is available if the conversation is made with an emulator and if this frame sent a request to the Web application emulated.
@wunit:service
read#web:x-service The service (servlet) that has served the page in this frame. This attribute is available if the conversation is made with an emulator and if this frame sent a request to the Web application emulated.
@wunit:session
read#web:x-session The session of the Web application that has served the page in this frame. This attribute is available if the conversation is made with an emulator and if this frame sent a request to the Web application emulated.
@wunit:request
read#web:x-request The request that was sent to get the page in this frame. This attribute is available if the conversation is made with an emulator and if this frame sent a request to the Web application emulated.
@wunit:response
read#web:x-response The response of the page in this frame. This attribute is available if the conversation is made with an emulator and if this frame sent a request to the Web application emulated.

#wunit:server type

A marker type that represents a server, when a Web conversation is emulated.