Testing.js is a very simple testing framework that has no external dependencies. It is very lightweight. It can run in browser or non-browser JavaScript environments. Use it to test your JavaScript code.
Testing.js has several classes:
- Runner: Logs test failures and successes with its registered listeners
- Suite: Organizes related tests, runs setUp and tearDown functions before and after each test run, and reports to a Runner.
- Test: Consists of a message and a test. Calls Asserts in order to test your code.
- Assert: Throws failure errors when code doesn’t work as expected. These errors are caught and passed to the Runner, which logs them.
// Testing.js is stored at a fully qualified location in the dom // Run this function like this to pollute the global namespace with Testing.js functions. // See Details for instructions on using the library namespaced this['git://github.com/oatkiller/testingjs.git']();
// A Runner is required. // Runners create a default listener that reports to console.log, to override this, pass false when creating your Runner var runner = new Runner();
// A Suite contains multiple tests // A Suite config must specify a runner to report to // A Suite config may specify any number of tests. The assertion should be in the property name, and the test is the function, like this: var suite = new Suite({ runner : runner, '1+1 should not equal 3' : function () { // Use the Assert function, pass it true when a test has passed, or false otherwise. The second param is a message to send when a failure happens Assert(1+1!==3,'they did equal 3'); }, // This should fail '1+1 should equal 3' : function () { // 'they didnt equal 3' will be reported as the reason this test has failed Assert(1+1===3,'they didnt equal 3'); } });
// Call run() on a suite to run all of its tests suite.run();
If passed to a Suite, the optional setUp method will run before each test is run. If the optional tearDown method is passed, it will be run after each test is run. The setUp method, tearDown method, and each test, will be run in the scope of their Suite. Since setUp, tearDown and your tests are all run in the same scope, they can assign properties to the Suite in order to pass a payload between each other.
// In this example, I'll test the methods of a class
// A Widget class that has children var Widget = function () { this.children = []; };
// A hasChildren method that will return true if the widget has children Widget.prototype.hasChildren = function () { return this.children.length > 0; };
this['git://github.com/oatkiller/testingjs.git']();
var runner = new Runner();
var suite = new Suite({ runner : runner,
// Define the optional setUp method // This will be run before each test setUp : function () { // We will use a new widget for each test this.widget = new Widget(); },
// Define the optional tearDown method // This will be run after each test tearDown : function () { // Destroy the widget that we just used delete this.widget; }, 'hasChildren should return true if a widget has 1 child' : function () {
// Add a child this.widget.children.push({});
// Test the method Assert(this.widget.hasChildren() === true,'hasChildren did not return true when widget had 1 child'); }, 'hasChildren should return false if a widget has 0 children' : function () { // Test the method Assert(this.widget.hasChildren() === false,'hasChildren returned true when widget had 0 children'); } }); suite.run();
In order to prevent identifier collisons, Testing.js is stored in a fully qualified location. If you’d like to pollute your global namespace with Testing.js, just run the setup function without passing any parameters. If you’d rather namespace Testing.js, just pass the setup function a namespace object.
// Create an object to be a namespace var testing = {};
// Pass that object when you call the setup function this['git://github.com/oatkiller/testingjs.git'](testing);
// Now the classes in Testing are stored on your namespace object
// Access the Runner class at testing.Runner var runner = new testing.Runner();
// Access the Suite class at testing.Suite // If the namespace object was stored at ns, you'd use ns.Suite var suite = new testing.Suite({ runner : runner, '1+1 should not equal 3' : function () { // Assert is also now stored on the namespace testing.Assert(1+1!==3,'they did equal 3'); }, // This should fail '1+1 should equal 3' : function () { testing.Assert(1+1===3,'they didnt equal 3'); } }); suite.run();
The setup function is located on the global object (window, if run in a web browser). The property it is stored under is : ‘git://github.com/oatkiller/testingjs.git’.
Params
Param | Type | Optional? | Desc. |
exportObj | Object | Optional | If passed, export the public classes into exportObj. If not passed, public classes will be exported into the global |
The Runner class has listeners. Suite’s keep a reference to a runner. A runner instance is required to use testing.js
Constructor
Param | Type | Optional? | Desc. |
addDefaultListener | Boolean | Optional | If false, the default listener that writes to console.log will not be added. Otherwise, the default listener will be added |
Properties
Property | Type | Desc. |
listeners | Array | Holds a reference to each listener added to a Runner instance |
successCount | Number | The number of tests that have been run with success |
failureCount | Number | The number of tests that have been run that failed |
Param | Type | Optional? | Desc. |
handler | Function | Required | The handler that will be called when a test is run, or when a report is run. |
scope | Object | Optional | The scope to run handler in |
addListener registers a handler to a Runner. When the Runner logs a success, failure, or a report, the handler will be called with the type of message, and the payload.
this.addListener(function (messageType,payload) { // messageType will be 'report', 'success', or 'failure' if (messageType !== 'report') { // Successes and failures will have a assertionText and testFn property. // The assertionText property is the Assert text that the code failed // Failures will have an error property that is the Error that the Assert threw console.log(messageType,':',payload.assertionText,payload.error ? payload.error : ''); } else { console.log(messageType,': success: ',payload.successCount,' failure: ',payload.failureCount); } })
Param | Type | Optional? | Desc. |
messageType | String | Required | The type of message being handled. ‘success’ if a test has passed without failing. ‘failure’ if a test failed when run. Or ‘report’ when the Runner is running a report on how many tests failed vs. passed |
payload | Object | Required | An object with properties about the message being handled |
success
testFn | Test fn that ran successfully |
assertionText | The assertion the test makes |
failure
testFn | Test fn that ran successfully |
assertionText | The assertion the test makes |
error | The error that the failing Assert threw |
report
successCount | The number of successful tests |
failureCount | The number of failed tests |
private
This method fires listeners with a message. This is called when a Suite runs tests
private
This method fires listeners with a message about how many tests have passed or failed
The Assert function throws an Error if passed false for its first param. Use Assert in tests to check that your code works
Param | Type | Optional? | Desc. |
passed | Boolean | Required | True to pass, false to fail |
message | String | Optional | The message to log that explains why this code failed the test |
// This should fail '1+1 should equal 3' : function () { testing.Assert(1+1===3,'they didnt equal 3'); }
The Equals function throws an Error if its first two parameters evaluate to false when compared with ====’. The error message will include information about the actual value and the expected value. An additional error message is optional.
Param | Type | Optional? | Desc. |
actual | Anything | Required | A value generated by a test |
expected | Anything | Required | The value you expect `actual` to point to |
message | String | Optional | An additional error message to include along with the automatically generated one |
// This should fail '1+1 should equal 3' : function () { testing.Equals(1+1,3,'I am not good at math.'); } // Produces an error like: failure : 1+1 should equal 3 : "I am not good at math. : 2 was not 3 (expected)"
The Wait and Resume functions are used to test asynchronous code. Call Wait with a timeout handler and a wait duration. When your asynchronous code completes, call Resume. If the wait duration expires before Resume is called, an error will occur and the timeout handler will be called.
Equals
|Param|Type|Optional?|Desc.|
|timeoutHandler|Function or Number|Required|A function to call if the wait duration expires. Optionally pass the retuned value from setTimeout|
|waitDuration|Number|Required|Milliseconds before timing out|
Resume
|Param|Type|Optional?|Desc.|
None
// Wait one second for an ajax call to complete before asserting its value
// Note: The ajax methods here are made-up.
var ajaxRequest = new Request('test.html');
Wait(function () { // one second passed without the ajax call completing. An error will occur. Clean up the ajax request by cancelling it. ajaxRequest.cancel(); },1000);
// start the ajaxRequest ajaxRequest.happen({ // the call completed success : function (response) { Equals(response.code,301);
// the ajax request is done. Continue running the test suite. Resume(); } });
The Test class can be created directly, or by passing a test config to your Suite
Constructor
Param | Type | Optional? | Desc. |
assertionText | String | Required | The assertion that you are making with this test |
testFn | Function | Required | The test function |
Properties
Property | Type | Optional? | Desc. |
assertionText | String | The assertion that you are making with this test | |
testFn | Function | The test function |
Defining Tests with the Suites Config
You should probably define Tests with the Suites config
var suite = new Suite({ runner : runner, // any non-special property name is evaluated as an assertionText with the function is points to evaluated as a testFn // this creates a test just as if you'd called new Test('1+1 should not equal 3',function () { ... }); '1+1 should not equal 3' : function () { Assert(1+1!==3,'they did equal 3'); } });
*Defining Tests with the new keyword*
var test = new Test('1+1 evaluates to 2',function () { Assert(1+1 === 2,'1+1 did not evaluate to 2'); });
private
This method is called internally when a Suite runs its tests
The Suite class has Test instances, a Runner instance, and an optional setUp and optional tearDown method.