- Overview
- Using The State Machine
- Laying Out Your Tests
- Helpers
- Frames Based Testing Framework
- Using Transition.js with Phantom.js for Headless Automated Testing
- Automating the Frames based testing Framework
Overview
Transition.js tests are implemented as state machines. This allows you to decouple the logic of waiting for the web site to complete an operation from the logic of what to do next.
NB: the following needs to be re-written for 2.0…
Using the state machine
There are four things that you must do in order to use the state machine:
1. Set your test’s name
2. Define your test’s states
3. Initialize the State Machine
4. Start the State Machine
When it runs, the state machine will poll the current state’s exit transitions until either the test times out, or one of the predicates returns true. The machine will progress until either the success or failure states have been reached.
1. Set The Test Name
To set your test’s name, assign to the name
parameter in the State Machine object:
Transition.Stm.name = "Login Test";
2. Defining A State
States can be defined by calling newState
:
Transition.Stm.newState('logout', self.doLogout, {start: true},
{to: 'viewLogin', pred: self.isLoggedOut }
);
newState
requires a state name (logout
), a function that will be invoked when the state is entered, a context, and a list of transitions.
Transitions contain the name of the target state: to
, and a boolean predicate: pred
. When the predicate returns true, the state machine will move to the target state.
Note that the first state in your test must be declared with the parameter start
in the context: {start: true}
.
The State Machine will define two states for you automatically: success
, and failure
. If your test throws an exeption, or times out (controlled by Transition.Stm.maxTestTimeout
, which defaults to 10s), it will enter the failure
state.
3. Initialize The State Machine
After declaring all of your states, you must call init()
:
Transition.Stm.init();
This allows the state machine to validate the graph, and create the success and failure states.
4. Start the State Machine
To begin executing the test, call start
:
Transition.Stm.start();
Helpers
A full list of the functions in Transition.js is available in the API Documentation.
Transition.log
Laying out your tests
Frames based testing framework.
The Frames based testing framework allwows you to interactively test your application, watch its progress, and single step your test. The Frames style tests can be run from any browser. I have found these tests to be valuable when testing mulitple devices. Being able to bring up the test on a mobile phone, a challenging environemnt in which to test, and step the test while watching the UI and the test log aids in troubleshooting.
To use the frames based testing framework, create an index.html
file with the following content:
index.html
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<frameset rows="67%,33%">
<frame name="main" />
<frame name="test" src="test.html" />
</frameset>
</html>
For the TODO example application, the tests are located at /test/
.
In the test.html
file, include jquery, the Transition.js testing framework, the APIs from the application you are testing (in this case, easy-api.js and todo.js), as well as the Transition test runner, transition-runner.js. Finally, include your test suite and call Transition.Runner.init()
which will process the test suite and build the test runner UI.
test.html
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=8" />
<title>Test Frame</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"></script>
<script src="/js/transition-1.0.0-SNAPSHOT.js" type="text/javascript"></script>
<script src="/js/easy-api.js" type="text/javascript"></script>
<script src="/js/todo.js" type="text/javascript"></script>
</head>
<body>
<script src="/js/transition-runner-1.0.0-SNAPSHOT.js" type="text/javascript"></script>
<script src="suite.js" type="text/javascript"></script>
<script type="text/javascript">
Transition.Runner.init();
</script>
</body>
</html>
suite.js
Use suite.js
to register your individual tests with a name, a uri and tags to help you organize your tests.
/*jslint browser: true, maxerr: 50, indent: 2, nomen: false */
/*global window, console, Transition */
"use strict";
Transition.Runner.addTests(
{name: "Login", uri: "suite/login.js", tags: ["login"] }
);
site/login.js
Finally, here is the login.js
test from the example application:
var LoginTest = LoginTest || (function () {
var self = {state: {}};
Transition.Stm.name = "Login Test";
self.doLogout = function () {
self.state.isLoggedOut = false;
Todo.logoutRequest()
.onStatus('OK', function (response) {
self.state.isLoggedOut = true;
})
.run();
};
self.doLogin = function () {
Transition.find('input[name=email]').val('kyle.burton@gmail.com');
Transition.find('input[name=password]').val('secret');
Transition.find('button#login').click();
};
Transition.Stm.newState('logout', self.doLogout, {start: true},
{to: 'viewLogin', pred: function () { return self.state.isLoggedOut; } }
);
Transition.Stm.newState('viewLogin', Transition.navigateTo_('/login'), {},
{to: 'doLogin', pred: Transition.elementExists_('input[name=email]') }
);
Transition.Stm.newState('doLogin', self.doLogin, {},
{to: 'success', pred: Transition.elementExists_('div#todo-list') }
);
Transition.Stm.init();
return self;
}());
Using Transtion.js with Phantom.js
The file phantom-runner.js can be used to execute your test suite using Phantom.js for automated, headless testing. The Rakefile
that is part of Transtion.js has an installer for Phantom.js:
$ rake phantom:install
Once installed you can invoke the Phantom runner, pointing it at your test suite:
$ ./software/phantomjs-1.5.0/bin/phantomjs examples/phantom-runner.js http://localhost:4567/tests/
>>>Thu Jun 07 2012 17:23:20 GMT-0400 (EDT): [logout]: Starting [Login Test]
[object Object]
[logout] trying pred[viewLogin] :true
>>>Thu Jun 07 2012 17:23:20 GMT-0400 (EDT): [logout]: transitioning to: viewLogin
[object Object]
[viewLogin] trying pred[doLogin] :true
>>>Thu Jun 07 2012 17:23:21 GMT-0400 (EDT): [viewLogin]: transitioning to: doLogin
ajax failure for GET, /todo
[object Object]
[doLogin] trying pred[success] :true
>>>Thu Jun 07 2012 17:23:21 GMT-0400 (EDT): [doLogin]: transitioning to: success
>>>Thu Jun 07 2012 17:23:21 GMT-0400 (EDT): [success]: TEST PASSED [Login Test]
>>>Thu Jun 07 2012 17:23:21 GMT-0400 (EDT): Full suite completed: 1 of 1 passed 100%.
1 passed, 0 failed, out of 1 100%
Automation of Frames Based Tests
This can be accomplished through invocation of the Transtion.Runner
’s runAll
method.
Using a Proxy to Separate your testing framework from your web application.
You may not want to expose your test suite with your public website (it may contain test user data that is either invalid or you do not want exposed). We often use Nginx and define a local server configuration that serves up our tests from local disk, and forwards all other requests to a staging or development server.