The Controller API
Every test authoring library and markup implements the Windmill Controller API. This API is used to simulate browser interactions, asserting elements and text exist, conditionally wait for elements to appear, and to store dynamic values for use in later tests.
Locators
Most of the controller API can take any of the locator keyword params. A locator tells windmill how to lookup a node to simulate a browser action on.
The available locators are:
- xpath
- An xpath expression that should return a single node.
- link
- The link name.
- name
- The display name of the node.
- id
- The element id.
- jsid
- A javascript expression that after evaluated returns an element DOM ID. If you don't specify a scope by including windmill.testWindow, or _w, this will assume you would like the window scope prepended. If you do specify the scope, this will directly evaluate the JavaScript you passed. This was done this way so that if you want to keep things clean, you can just pass the path within the test window. If you would like to prepend or append text to the ID that is returned you will want to specify the test window and include valid JavaScript to be evaluated to return the ID you wanted.
Ex. {"method":"click", "params":{"jsid":"document.variable.id"}}
(Appends the scope for you, becomes _w.document.variable.id)
Ex. {"method":"click", "params":{"jsid":"'mystring'+_w.document.variable.id"}}
Available Methods
- open
- Open a given url for testing. Takes a single param; url.
- click
- Click on the given node. Takes all locator params.
- doubleClick
- Double click on a given node. Takes all locator params.
- select
- Select an option from a given drop down or list. Takes all locator params, and a param; option.
- mousedown
- Fire the mousedown event on a given node. Takes all locator params.
- mouseup
- Fire a mouseup event on a given node. Takes all locator params.
- mouseover
- Fire a mouseover event on a given node. Takes all locator params.
- mouseout
- Fire a mouseout event on a given node. Takes all locator params. Note in most cases you should pair a mouseover with a mouseout to more accurately reflect normal mouse function
- reWriteAlert
- Override the window.alert function to send the alert content to the output tab. Used mostly when running in an integrated testing environment and alerts get in the way of the continuous test runs.
- check
- Toggle a given checkbox. Takes all locator params.
- radio
- Select a given radio button. Takes all locator params.
- type
- Enter data into any form text input field. Takes all locator params, and a text param.
- storeURL
- Store a URL in the Javascript variable registry to access later with the provided variable. Requires a param; link which is the element that will be used to get the URL. See Javascript Variable Registry for more details.
- storeVarFromJS
- Takes a param called 'options', this is a pipe delimited string with two parts, example string: 'test|window.location.href', this will store a variable named {$test} with the testing windows url, that you can then access from any future test by simply putting the string {$test} in the options. Example of that: {method:"open", params: {url:"{$test}"}}.
- waits.sleep
- Make the browser sleep for a given number of seconds. Takes a single param; milliseconds.
- waits.forElement
- Waits for a DOM element to exist, or times out. Takes all locator params and an optional param; timeout.
- waits.forPageLoad
- Waits for a new page to load in the testing window. Takes all an optional param; timeout.
- waits.forNotTitle
- Waits for the testing window to NOT have the provided title. Requires a param; title, and has an optional param; timeout.
- asserts.assertText
- Validates the existence of text in a provided DOM node. Takes all locator params; Also takes a param; validator as the text to verify.
- asserts.assertNode
- Asserts that a node exists in the DOM in the testing window. Takes all locator params.
- asserts.assertValue
- Assert that a value exists in the provided form element. Takes all locator params; also takes a param; validator.
- asserts.assertSelected
- Assert that an option was selected in a drop down or list element. Takes all locator params; also takes a param; validator.
- asserts.assertChecked
- Assert that a selected checkbox was checked. Takes all locator params.
- asserts.assertProperty
- Assert the value of a provided DOM nodes property. Takes all locator params, also takes a param; validator. The validator param is constructed as follows: property|value ex. ( disabled|true or style.border|1px ).
- asserts.assertImageLoaded
- Assert that an image is loaded on the page. Takes all locator params.
- asserts.assertJS
- Assert a JavaScript expression, Takes a parameter js which needs to be valid JavaScript code to be executed.
Variable Registry
Although the language you're writing tests already has variables you can set and use later in tests it can sometimes be useful to set variables through the windmill controller that stay around during the entire duration of your test run in the browser.
When your test comes into the IDE, it is parsed for variables that have been defined in the registry. If they exist, the variable is replaced with the value. If you would like random value that you can use for this session, that is possible as well.
Syntax:
Basic Variable: {$sometext} ex. {$myurl}
Behavior:
If it exists, it will be replaced with the value in the registry
If it doesn't exist, the variable syntax will be used ie. you will actually be creating a user called {$tempUser}
Random Variable: {$random(anything you want)} ex. {$random1}
Behavior:
If the variable exists in the registry, it will be replaced with it's value
If it doesn't exist a random value will be created
Example: This is the JSON representation of a test that uses the variable registry, the storeURL function is in the controller and available in the IDE for storing a target links address to use later.
{"method": "storeURL", "params": {"link": "[Chandler]"}, "version": "0.1"}
{"method": "open", "params": {"url":"{$[Chandler]}"}}
More on Assertions
An important part of your tests is making sure what you wanted to happen actually did.
If you are working in the IDE you can add these by inserting a new action and then selection one of the assert functions from the drop down.
If you are manually building your tests you can call the assertions as well
Excerpt from the ControllerApi
windmill.controller.asserts.assertText
This allows you to check within one level of the DOM for a string (this method name will be changed when we get a value verification function).
{"method": "asserts.assertText", "params": {"id" : "modalDialogPrompt", "validator" : "You have successfully created your Cosmo account."}}
windmill.controller.asserts.assertNode
This simply validates if a node now exists in the testing applications DOM.
{"method": "asserts.assertNode", "params": {"id" : "modalDialogPrompt"}
windmill.controller.asserts.assertProperty
This allows you to assert on the contents of a DOM NODE property. To avoid adding another layer of inputs to the registry, I simply delimit the validator field with a pipe (|), so the following validates the style.background property of the element identified by the id 'triageButtonNow', and returns true if the string representation of that property contains the string '1px', if not it fails.
{"params": {"validator": "style.background|1px", "id": "triageButtonNow"}, "version": "0.1", "method": "asserts.assertProperty"}
windmill.controller.asserts.assertJS
This allows you to assert anything in your JavaScript code in the app. Very helpful for checking state. For the action to pass the comparison must return true.
{"params": {"js": "_w.closed == false;"}, "method": "asserts.assertJS"}
Adding your own assertion
If your assertion is very specific to your application, see the BookChapter-7-Extensions section of the WIKI.
If your assertion is relatively general and will benefit others:
Step 1: Adding the code to the windmill controller (windmill/js/controller/controller.js) If your controller is browser specific and needs to be completely different for each browser, Put the functions for each in the specific controller files, and the correct one will be loaded depending on the browser you are using (windmill/js/controller/(ie,moz,saf)Controller.js
Note: (windmill/js/controller/controller.js) is only for functions that work on all browsers.
Go ahead find the code where the assertions are and add your code:
//Please give a brief description of the assertion
//The param_object is passed to every controller function
this.assertSomething = function (param_object) {
//You usually need to look up a UI element, this will use any provided locator
//And return you an element
var element = this._lookupDispatch(param_object);
//If the element was found error
if (!element){
return false;
}
//--Your application Logic should probably go here--
//Else return true
return true;
};
Step 2: In wm/registry.js we keep track of what functions need what UI, so we can build the IDE dynamically
You will notice that we are keeping the assert functions together, add a line:
windmill.registry.methods['assertSomething'] = {'locator': true, 'option': true } ;
If your assertion needs to locate something in the DOM it will expect, an ID, Name, Link, XPath etc. If your assertion doesn't need more information you can turn 'option' to false
If you would like a different option than available in this list:
windmill.registry.option.push('text','url','option','validator','destination','stopOnFailure','showRemote', 'milliseconds');
Feel free to add it. Currently the standard is to use validator as the string you would like to use in validating the UI element.
Now give it a try by either building your assertion in the IDE, or with JSON: {"method": "assertSomething", "params": {"id" : "whatever", "validator" : "blah"}}
Then if you aren't a committer, go ahead and send me a patch at adam@…
Moving On
Now that you understand the Controller API you can move along to learning how to use it in your authoring markup or language of choice.
Move on to the JSON Test Markup Chapter
