actiWATE is no longer supported

If you are interested in this product development, please contact rd@actimind.com

Tutorial

actiWATE Framework

Section contents

Overview

actiWATE Framework provides a set of objects used for interacting with web application.

The main object in actiWATE Framework is ActiwateTestCase. This is the base object for all actiWATE tests. All actiWATE tests are inherited from this class. In most cases this will be the only class you will need to write automated tests.

The next object of actiWATE Framework is Window. Window object is an abstraction of a window of real Internet browser.

Several windows that sharing the same HTTP session (same cookies) are joined into ActiwateSession. By default actiWATE test works with one session and one window. But test can create new sessions and windows using methods newSession() and newWindow(). New windows can also be created by web application itself. For example, new windows are created by JavaScript function open() or when the value _blank is used as the target of a link or a form.

Other actiWATE Framework objects represent particular HTML elements and used for reading and changing their state.

For complete list of classes and their methods see API reference.

Test context

actiWATE Framework utilizes the principle of context. Most methods of ActiwateTestCase execute in context of particular HTML page, which can be either Window or Frame or IFrame object. For example, when test searches for text field using the method textField(String nameOrId) actiWATE Framework searches for text field on the current HTML page.

The test can change the context using methods setSession() and switchTo().

In certain cases usage of context reduces size of test code and a number of required local variables, and improves readability of the test code. For example, instead of the code

Window window = session.window();
setText(window.frame("main").textField("username"), "someuser");
setText(window.frame("main").textField("password"), "somepassword");
click(window.frame("main").buttonByText("Login"));
one can use
switchTo(session.window().frame("main"))
setText(textField("username"), "someuser");
setText(textField("password"), "somepassword");
click(buttonByText("Login"));
For detailed information see API reference and samples Frames.java and Popups.java.

Text normalization

HTML pages usually contain redundant space and carriage return characters, which are not displayed by real Internet browsers. If browser encounters sequence of space and/or carriage return characters it displays only one space character.

actiWATE Framework performs similar procedure. Methods that work with text on HTML page such as assertTextPresent() or linkByText() normalize text before using it. The normalization procedure includes:

  1. Replacing carriage returns with space characters;
  2. Replacing   entities with space characters;
  3. Replacing sequences of spaces with a single space.
For detailed information see API reference.

Working with forms

actiWATE Framework provides a number of objects representing HTML form controls such as Button, RadioButton, Checkbox, SingleSelect, MultipleSelect, TextField, Textarea, etc. These objects are used for reading and changing state of HTML controls and thus interacting with web application being tested.

Classes ActiwateTestCase, ActiwateSession, Window, Frame, IFrame and TableCell contain a number of methods that can be used to find these objects by various criteria. Classes ActiwateTestCase and ActiwateSession provide a number of methods such as setText, setFileName, selectOption, click, etc, which can be used for interacting with these objects.

The following code demonstrates how to set the value of a text field with name "username". It uses method textField(String nameOrId) to find the text field by its name and method setText() to set its value.

setText(textField("username"), "jsmith");
For detailed information see API reference and samples Form.java, FileUpload.java, and LiveTestCase.java.

Working with frames

actiWATE Framework provides objects Frame and IFrame which represent FRAME and IFRAME HTML elements correspondingly. These objects are similar to the object Window at large. Frame and IFrame objects can be used as a context of a test (see Test context).

The following code switches the context of the test to the frame with name "main". It uses the method Window.frame(String name) to find the frame by name and the method switchTo() to change the context.

switchTo(window().frame("main"));
For detailed information see API reference and sample Frames.java.

Working with tables

actiWATE Framework provides classes Table, TableRow and TableCell for working with HTML tables. You can get table row by index and cell by row and cell indexes. Row and cell indexes are order numbers of TR and TD (TH) elements inside TABLE and TR elements correspondingly. Indexes do not depend on colspan and rowspan attributes. The following figure shows values of row and cell indexes in case when rowspans and colspans are used.

Picture 3 Table row and cell indexes

For detailed information see API reference and sample Tables.java.

Accessing image maps and areas

There are several classes and methods in actiWATE Framework, which simplify lookup of image maps and areas.

Image maps are represented by ImageMap class. You can find maps by index or by name / id attribute value. ImageMap class provides you with access to the areas. This class also allows to retrieve all images referencing this map.

Area class represents image areas. Image area properties, such as href, coords, shape, etc. are available via this class.

For detailed information see API reference and sample ImageMaps.java.

Working with pop-up windows

When a web application opens a new browser window, either using JavaScript function open() or using value _blank as a target for a link or a form, actiWATE Framework creates new Window object and adds it to the list of windows of a session. Later on, actiWATE test can get this window using method window(String name) or windowWithTitle(String windowTitle).

The following code verifies that clicking on the button opens a new window. When the window is no longer needed the code closes it.

click(buttonByText("Open Pop-Up"));
switchTo(windowWithTitle("This is pop-up window"));
click(buttonByText("Close Pop-Up"));
switchTo(window(0))
For detailed information see API reference and sample Popups.java.

Working with alerts, confirms, and prompts

In order to test whether application correctly uses JavaScript functions alert(), confirm() and prompt(), you need to perform the following actions:

  1. Before the action that displays alert, confirmation or prompt dialog call certain method, such as expectConfirm(). This will make actiWATE expect the appearance of appropriate dialog.
    expectConfirm("Do you really want to create user 'jsmith'?", PRESS_OK);
    
  2. Performs the action that shows dialog. If displayed dialog is not what actiWATE expected, the method throws UnexpectedUserDialogException.
    click(buttonWithText("Create"));
    
  3. Verify that expected dialog was shown.
    verifyUserDialogs();
    
actiWATE Framework offers some simple expectations for dialogs and provides an ability to setup your custom expectations for dialogs in order to verify them the way you need it.

For detailed information see API reference and sample AlertConfirmPrompt.java.

Working with asynchronous events (timers, intervals, META-refreshes, AJAX)

There are number of events that are executed asynchronously in browsers. These events include:

  • Execution of JavaScript code scheduled by the setTimeout() function
  • Execution of JavaScript code scheduled by the setInterval() function
  • Execution of JavaScript callbacks by the XmlHttpRequest object
  • HTML page reloads initiated by META tags.
actiWATE doesn't execute these events asynchronously because otherwise tests won't be deterministic. Since all the mentioned events get triggered after some period of time (relative to the moment when they were initiated), actiWATE utilizes the time-line concept that helps to transform asynchronous events to synchronous and thus make their execution manageable.

The time-line is represented in actiWATE by the container object that implements the com.actimind.actiwate.testing.events.AsyncEvents interface. Generally, this container is the order of events that allows to iterate over events and to execute them in different ways. When an event gets scheduled during a test, the corresponding event object is placed into this container (scheduled).

All event objects implement the com.actimind.actiwate.testing.events.AsyncEvent interface and has a time offset property that stores number of milliseconds after which the event will be triggered. All events in the AsyncEvents container are ordered by this time offset property.

The time flow can be emulated by number of methods of the AsyncEvents interface. If the time is moved by some delta using one of this methods, actiWATE executes all events in the container that have tine offset property less than the delta. Executed events are removed from the AsyncEvents. Time doesn't go until one of time flow emulation methods is called.

Consider the following example that illustrates the time-line concept:

Suppose at some point of time there are three asynchronous events that should be triggered:

If we call ActiwateTestCase.getAsyncEvents().executeByTimeOffset(15) in our test to emulate time flow the 1st event will be executed and time offset properties of other event will be reduced by 15 milliseconds:

Asynchronous event types

actiWATE supports four asynchronous events that are represented by the interfaces described below.

com.actimind.actiwate.testing.events.TimeoutAsyncEvent
This interface represents the event that was created by the JavaScript setTimeout() function. Suppose we have the following JS code on some page:

setTimeout("alert(location)", 10);

When this line is executed, the TimeoutAsyncEvent is added to the AsyncEvents container with the initial time offset equal to 10. According to the setTimeout() function this event should be executed only once, so when it gets executed it's removed from the order.

com.actimind.actiwate.testing.events.IntervalAsyncEvent
This interface represents the event that was created by the JavaScript setInterval() function. Suppose we have the following JS code on some page:

setInterval("i++", 5);

When this line is executed, the IntervalAsyncEvent is added to the AsyncEvents container with the initial time offset equal to 5. According to the setInterval() function this event should be executed periodically, so when it gets executed, the event object is removed from the container and a new IntervalAsyncEvent object is added with the time offset equal to 5.

com.actimind.actiwate.testing.events.MetaRefreshAsyncEvent
This interface represents the META-refresh event. Suppose our page contain the following tag:

<META http-equiv="refresh" content="2;url=http://www.actiwate.com">

Normally, after the page containing this tag is parsed by actiWATE, the new MetaRefreshAsyncEvent is added to the container with the time offset equal to 2000 (2 seconds). However, if actiWATE is configured to process META refreshes immediately (see Configuration file), MetaRefreshAsyncEvent objects don't appear in the events container.

com.actimind.actiwate.testing.events.XmlHttpRequestAsyncEvent
This interface represents state changes of XmlHttpRequest objects. When the XmlHttpRequest.send() method of some XmlHttpRequest object is called four events are added to the container one-by-one: the first one is the event that calls XmlHttpRequest.obreadystatechange handler when the XmlHttpRequest.readystate property is assigned the value 1 (LOADING). When this first event is executed and removed form the container, the second one is added that corresponds to the LOADED state (2). Other 2 events for the INTERACTIVE (3) and COMPLETED (4) states are added in the same way. Time offsets of these events are configured in the actiWATE configuration file or using ActiwateSession.setXmlHttpRequestConfig() method.

Processing of events

There are two ways of processing asynchronous events: manual and automatic. Manual processing is performed by calling of AsyncEvents's methods in a test. In automatic mode actiWATE triggers events that were scheduled within the specified interval (see Configuration file) after every action performed in a test. Below manual and automatic modes are explained in more detail.

Manual mode:

Manual processing of events is intended to check Web Application's state before and after some asynchronous event is triggered. For example you might want to check an HTML page content before an AJAX request is send from this page and then check the page once again after the AJAX response is processed.

AsyncEvents interface allows user to execute asynchronous events using the following methods:

executeTillLatestEventOffset() - Executes all events in the container. If execution of some event will lead to scheduling of a new event, the newly scheduled event will be executed if it's time offset is less or equal to the time offset of the latest event on the moment of this method call, otherwise newly scheduled event will be added to the container but not executed to prevent infinite execution of events.

executeAllUntilEmpty() - Executes all events in the container until the container is empty. Note that if some events produce new events (JavaScript interval, for example) this method can lead to infinite execution of events.

executeByTimeOffset(long offsetMillis) - Executes all events which have time offset property less or equal to the specified offsetMillis parameter. All other events' time offsets are reduced by the offsetMillis value.

executeNextEvent() - Executes event with the least time offset. All other events' time offsets are reduced by the executed event time offset.

Automatic mode:

Automatic mode can be used in tests that don't verify page behavior in details, i.e. results of every asynchronous event separately. In this mode actiWATE automatically executes events that appear in the time-line during testing. If a tested web application has many asynchronous events, this mode helps to avoid writing of numerous calls to AsyncEvents interface since the events are processed automatically after each action such as clicks or goTo() calls.

Automatic mode is configured in actiWATE configuration file using the following two properties:

autoExecAsyncEvents - defines whether the automatic mode is enabled.

autoExecAsyncEventsOffset - defines the maximum time offset for events. Events that have time offset value less or equal to the value of this property will be executed automatically.

There is also one peculiarity of this mode: If a subsequent action didn't lead to new events in the time-line, no events are executed independently on whether the time-line already contains events with time offset less than the specified maximum. This means that the automatic execution happens only if new events with time offset property less or equal to the autoExecAsyncEventsOffset value were added in result of an action. This behavior is intended to prevent numerous automatic executions of events on some page in case many actions are performed on the page but no new events are added.

For additional information see API reference and XmlHttpRequest.java and Timers.java samles.

Working with the Screen

Most browsers provide JavaScript 'screen' object (window.screen) that contains information about the client's screen and rendering capabilities. Microsoft Internet Explorer 6.0 provides the following screen properties:

PropertyDescription
availHeightRetrieves the height of the working area of the system's screen, excluding the Microsoft® Windows® taskbar.
availWidthRetrieves the width of the working area of the system's screen, excluding the Microsoft® Windows® taskbar.
bufferDepthSets or retrieves the number of bits per pixel used for colors in the off-screen bitmap buffer.
colorDepthRetrieves the number of bits per pixel used for colors on the destination device or buffer.
deviceXDPIRetrieves the actual number of horizontal dots per inch (DPI) of the system's screen.
deviceYDPIRetrieves the actual number of vertical dots per inch (DPI) of the system's screen.
fontSmoothingEnabledRetrieves whether the user has enabled font smoothing in the Display control panel.
heightRetrieves the vertical resolution of the screen.
logicalXDPIRetrieves the normal number of horizontal dots per inch (DPI) of the system's screen.
logicalYDPIRetrieves the normal number of vertical dots per inch (DPI) of the system's screen.
updateIntervalSets or retrieves the update interval for the screen.
widthRetrieves the horizontal resolution of the screen.

actiWATE supports the screen object with the above properties and allows one to change the following ones in a test:

PropertyMethodDefault Value
availHeightscreen().setAvailHeight( int availHeight )740
availWidthscreen().setAvailWidth( int availWidth )1024
colorDepthscreen().setColorDepth( int bitsPerPixel )32
heightscreen().setHeight( int height )768
widthscreen().setWidth( int width )1024

For the following read-only properties actiWATE returns constant values that cannot be changed:

PropertyValue
deviceXDPI96
deviceYDPI96
logicalXDPI96
logicalYDPI96
fontSmoothingEnabledfalse

Both bufferDepth and updateInterval properties have default value '0' and can be changed in JavaScript.

You can also override default values for availHeight, availWidth, colorDepth, height, and width properties in actiwate.properties file for all actiWATE sessions.

For detailed information see:

Accessing HTML DOM

In certain cases it can be useful to perform some non-standard actions, such as changing value of hidden input element. For such cases actiWATE Framework provides access to HTML DOM. You can use HTML DOM to find certain HTML elements, verify DOM state, read or change element attributes etc.

The following methods can be used to access HTML DOM:

  1. Method document() in objects Window, Frame and IFrame;
  2. Methods frameElement() and iframeElement() in objects Frame and IFrame correspondingly;
  3. Method element() in objects representing HTML elements, such as Table, Button, Link, TextField, etc.
For detailed information see API reference and sample DOM.java.

Accessing non-HTML content

actiWATE Framework provides interface for accessing HTTP response data. This can be useful when window or frame contains non-HTML content. In this case you can use the method response() of Window, Frame or IFrame object to receive information about HTTP response.

The following code verifies that window contains a GIF image.

HttpResponse response = window().response();
assertEquals("image/gif", response.getContentType());
For detailed information see API reference and sample NonHTMLContent.java.

Executing JavaScript

In certain cases it can be useful to execute JavaScript right from the test code, for example, to check the value of JavaScript variable declared in HTML page. actiWATE Framework gives an opportunity to do so. For example, in order to verify that value of JavaScript variable currentWizardPage equals to 3 you can use the following code:

assertEquals(new Integer(3), executeJavaScript("currentWizardPage"));
For detailed information see API reference and sample CustomJavaScript.java.

Emulating JavaScript events

Most of web pages intercept and process actions performed by a user working in a browser, such as mouse movement, click on a mouse button, keystrokes etc. These actions are converted to JavaScript events by the browser. actiWATE allows emulating of these events in order to verify reactions of tested web pages.

Currently actiWATE supports only click action for any HTML element. When the click action is performed the following sequence of event is fired: mousedown, focus, mouseup, click. For example, if you need to emulate click on a <div> HTML element, you can write code like this:

HTMLElement myDiv = ( HTMLElement ) page().document().getElementById( "myDiv" );
click( myDiv );
For detailed information see API reference and sample JavaScriptEvents.java.

Enabling/Disabling JavaScript Execution

actiWATE doesn't support all the client-side technologies of real Internet browser. If HTML page being tested uses the technology that is not yet supported, such as Dynamic HTML behaviors or Macromedia Flash, then automated test can fail. actiWATE provides work-around so that such HTML pages can be tested.

For example, suppose that tested page contains the following HTML code that uses getExpression method:

<span id="blueSpan" style="background-color:lightblue; width:200px">

    The width of this blue span is set inline at 200 pixels.

</span>

<span id="yellowSpan" style="background-color:lightyellow;width:400px">

    The width of this yelllow span is set inline at 400 pixels.

</span>

<span id="greenSpan" style="background-color:lightgreen;
 width:expression(blueSpan.style.pixelWidth + yellowSpan.style.pixelWidth)">

    Expression is used to set the width of this span.

</span>

<script>

  var widthExpr = greenSpan.style.getExpression("width");

  ...

</script>

Then in order to avoid JavaScript error, you should
  1. Disable execution of JavaScript;
  2. Open the HTML page;
  3. Declare function greenSpan.style.getExpression();
  4. Run page scripts;
  5. Enable execution of JavaScript.
disableJavaScript(false);
goTo("...");
page().executeJavaScript("greenSpan.style.getExpression = function(){ "+
                         "return 'mock getExpression result';};");
page().runPageScripts();
enableJavaScript();
For detailed information see API reference and sample DisableJavaScript.java.

Handling Basic Authorization

Basic authorization is used to restrict access to Web documents or CGI scripts by user name and password. When a user accesses the restricted content through a browser he is presented with a dialog requesting credentials (user name and password) to access the content.

actiWATE provides an ability to specify required credentials before a restricted content is reached. There are two ways to specify credentials:

  1. Specify default authentication credentials in actiwate.properties file:
    ...
    authCredentials.username=myusername
    authCredentials.password=mypassword
    authCredentials.host=www.myhost.com
    authCredentials.realm=secretPlace
    ...
    
    This option is useful when the whole system under testing (or its part) is protected with basic authorization and the credentials for testing are static.

    Authentication credentials specified in the actiwate.properties are automatically added for every actiWATE sessions.

    For detailed information see Configuration file section.

  2. Add authentication credentials from a test:
    addAuthCredentials( "host", "realm", "username", "password" );
    
    This option is useful when a test should expect credentials created dynamically, for example a test creates a new user and must authenticate it using basic authorization.

    Note, that this method adds the specified credentials to a current actiWATE session only.

    For detailed information see description for ActiwateSession and ActiwateTestCase classes in API reference. Also the BasicAuthorization.java sample is available.

Reusing test code

If you need to reuse test code within one test class simply extract the reusable code to separate method and call it whenever needed. This method can accept parameters if needed. If it is necessary to reuse same method from several test classes then there are two options.

The first option is making a superclass for a number of test classes and placing reusable method in it. Sometimes this approach is not applicable, for example, if test classes are so different that having common superclass is confusing. In this case you can use the second option.

The second option is putting reusable code into a static method, which accepts object ActiwateSession as one of its parameters. You can call this method from any test class. Methods of class ActiwateTestCase, being non-static, will not be available from the reusable code. This code will use methods of session object passed as parameter.

See also sample TestScriptReusing.java.