A Template test case allows to test an entire template (or module) in the DOM. A template is loaded into the page just as if it was loaded in a whole applcation, the test class however provides methods to check what is displayed in the page and to interact with it simulating user behavior.
It makes use of the class aria.jsunit.helpers.OutObj
to mock a TemplateCtxt
and provide a test area in the DOM. OutObj
is available as the property this.outObj
of the test class.
The structure of a Template test case is different from other unit tests. Due to the test complexity, a single TemplateTestCase
class should be used only for one asynchronous test (usually corresponding to one template).
The skeleton is as follow:
Aria.classDefinition({
$classpath : "MyTemplateTest",
$extends : "aria.jsunit.TemplateTestCase",
$prototype : {
runTemplateTest : function () {
// Do some assertions
this.end();
}
}
});
There's only one entry point, runTemplateTest
and the test can only be asynchronous, for this reason it's necessary to call this.end();
at the end of testing.
If the test class is called MyTemplateTest
, by default, the test runner will load the template MyTemplateTestTpl
inside the page and initialize it with an empty data-model. It is possible to change this behavior by configuring the environment as explained in the paragraph below.
The environment configuration allows to change the default Template test case behavior.
Aria.classDefinition({
$classpath : "MyTemplateTest",
$extends : "aria.jsunit.TemplateTestCase",
$constructor : function () {
this.$TemplateTestCase.constructor.call(this);
this.setTestEnv({
template : "another.path.TemplateToTest"
});
},
$prototype : {
runTemplateTest : function () {
// Do some assertions
this.end();
}
}
});
The environment can be changed in the test constructor calling this.setTestEnv();
, this method takes a configuration object with the following properties:
template
Template classpath, defaults to this.$classpath + "Tpl"
moduleCtrl
Module controller description. It should match the ModuleCtrl bean, defaults to null
data
Initial data model, default to an empty objectiframe
Whether the template should be loaded inside an iframe or directly in the test page. Using an iframe gives more isolation but makes the test slower as the framework must be loaded twice. Defaults to false
css
and baseCss
CSS text around the test area or iframe. It is useful to change for instance the window size and assert what happens on viewport resize. Use css
if you want to append to default CSS text, or baseCss
to change it completely.As the test might run in different environments (in the test page or inside an iframe) TemplateTestCase
class provide shortcuts to useful these objects:
this.templateCtxt
Reference to the template contextthis.testWindow
Reference to the window
object containing the template under test.this.testDocument
Reference to the document
object containing the template under testthis.testDiv
Element containing the template outputThe template context is particularly useful to test the internals of the template. It is an instance of aria.templates.TemplateCtxt so it has the interesting properties:
this.templateCtxt.data
Template's data model.this.templateCtxt.moduleCtrl
Public interface of the module controller.this.templateCtxt.moduleCtrlPrivate
Private instance of the module controller.this.templateCtxt._tpl
Template instance, it has all the methods defined in the template script.Through the templateCtxt
is possible to call the methods (among many others):
this.templateCtxt.$refresh()
Refresh the whole template of a specific section.this.templateCtxt.$focus(id)
Give focus to the element with the specified id.this.templateCtxt.$getElementById(id)
Returns an HTMLElement wrapped in DomElementWrapper.Usual assertion for this type of test case are the presence of DOM elements on the page, their attributes or properties when the template is loaded or after user interaction or template refresh.
The following utilities might be of help when asserting DOM element properties:
calculatePosition
, getGeometry
and getStyle
getZIndexForPopup
The above utilities are useful once you have a DOM element, to retrieve it you can use any of the following methods of the test class.
getElementById(id)
Return the DOM element in the current template with the specified id (the id should have been given with the {id .../}
statement).getElementsByClassName(dom, classname)
Get the element with the given class, child of a dom element.getWidgetInstance(id)
Get the instance of a widget from the template, given its ID.getWidgetDomElement(id, tagName)
Get the first DOM element with the given tag name from the given widget in the template.getInputField(id)
Get the input
DOM element of an input based widget.getWidgetDropDownPopup(id)
Get the DOM element of the dropdown popup associated to a DropDownTrait widget (MultiSelect, AutoComplete, ...).getExpandButton(id)
Get the expand button of a dropdown-based widget (MultiSelect, AutoComplete, ...).getLink(id)
Get the a
DOM element of a Link widget.This test class provides also methods to retrieve information of DOM elements:
computeZIndex(element)
Compute the z-index of an element.The greatest advantage of TemplateTestCase
class is the ability to simulate user behavior like click, type, mouse move and so on.
The class provides the following methods:
this.clickAndType(id, text, callback, blur)
Calling this method will click on the element with id id
, type the text in text
, blur the field if blur
is true
(default value) and execute the callback after.clickAndType
is convenient shortcut for a common user action, the implementation of this method use the utility class aria.utils.SynEvents
that is a wrapper around syn, the Standalone Synthetic Event Library by bitovi and available as shortcut on this.synEvent
.
this.synEvent.click(element, callback)
Emulates a click event on a specific DOM element, it'll also fire in the correct order the events mosedown
, mousemove
and mouseup
.this.synEvent.move(options, from, callback)
Emulates a mouse move from a given element from
or a point in the screen to another point as described in options
. It'll fire the eventsmouseover
and mouseout
as well as mouseenter
and mouseleave
on Internet Explorer.this.synEvent.type(element, text, callback)
Emulates typing in a specific DOM element. It fires the events keydown
, keypress
and keyup
on the given target.It is recommended to use the shortcut this.synEvent
over the full classpath because the shortcut fires the events in the correct environment, even when the test runs inside an iframe.
For more flexibility it's also possible to use the Syn
object directly using this.testWindow.Syn
. This allows to call any method provided by Syn, the drawback is that the callback must be a plain function and cannot be Aria Templates callback.
Syn
provides the following actions:
Syn.click(options, element, callback)
Syn.dblclick(options, element, callback)
Syn.rightClick(options, element, callback)
Syn.move(options, element, callback)
Syn.drag(options, element, callback)
Syn.key(options, element, callback)
Syn.type(options, element, callback)
The actions provided by Syn are always more complex than simply raising an event, in most cases they fire multiple events or simply require different implementation depending on the browser.
A lower level API is exposed by:
Syn.trigger(type, options, element)
This method allows to create a synthetic event and dispatch it on the element. It also runs any default actions for that element (like following a link on <a>
tags).aria.utils.FireDomEvent.fireEvent(type, element, options)
Fire any event on a target HTML element. It supports mouse, keyboard and generic HTML events. It can be used as well to simulate touch events.aria.utils.Delegate.delegate(event)
Use the internal delegate mechanism to fire any event, even non-standard ones. Events can be created calling aria.DomEvent.getFakeEvent(type, element)
and then adding properties on it. This is the lowest level API and only works for framework parts that rely on event delegation.The following example shows how to use a module controller in a template test. Currently it is necessary to set the data object inside the Environment explicitly to null
to access the same object from the template/template script and the module controller.
Aria.classDefinition({
$classpath : "MyTemplateTest",
$extends : "aria.jsunit.TemplateTestCase",
$constructor : function() {
this.$TemplateTestCase.constructor.call(this);
this.setTestEnv({
moduleCtrl : {
classpath : "controller.MyController"
},
data: null //necessary to have the same object inside the template/template script and the module controller
});
},
$prototype : {
runTemplateTest : function() {
//call module controller
this.templateCtxt.moduleCtrl.doRequest( //method setting something in the data object.
"ABC", {
fn : this.assertModuleCtrlCall,
scope: this
});
},
assertModuleCtrlCall : function () {
// Do some assertions
this.assertTrue(this.templateCtxt.data.value !== null);
this.end();
}
}
});
.