2010-08-17 09:42:13 +02:00
|
|
|
/*
|
|
|
|
* File: unit_test.js
|
|
|
|
* Version: 0.0.1
|
|
|
|
* CVS: $Id$
|
|
|
|
* Description: Unit test framework
|
|
|
|
* Author: Allan Jardine (www.sprymedia.co.uk)
|
|
|
|
* Created: Sun Mar 8 22:02:49 GMT 2009
|
|
|
|
* Modified: $Date$ by $Author$
|
|
|
|
* Language: Javascript
|
|
|
|
* License: GPL v2 or BSD 3 point style
|
|
|
|
* Project: DataTables
|
|
|
|
* Contact: allan.jardine@sprymedia.co.uk
|
|
|
|
*
|
|
|
|
* Copyright 2009 Allan Jardine, all rights reserved.
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* This is a javascript library suitable for use as a unit testing framework. Employing a queuing
|
|
|
|
* mechanisim to take account of async events in javascript, this library will communicates with
|
|
|
|
* a controller frame (to report individual test status).
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
var oTest = {
|
|
|
|
/* Block further tests from occuring - might be end of tests or due to async wait */
|
|
|
|
bBlock: false,
|
|
|
|
|
|
|
|
/* Number of times to try retesting for a blocking test */
|
|
|
|
iReTestLimit: 20,
|
|
|
|
|
|
|
|
/* Amount of time to wait between trying for an async test */
|
2010-10-30 09:01:28 +02:00
|
|
|
iReTestDelay: 150,
|
2010-08-17 09:42:13 +02:00
|
|
|
|
|
|
|
/* End tests - external control */
|
|
|
|
bEnd: false,
|
|
|
|
|
|
|
|
/* Internal variables */
|
|
|
|
_aoQueue: [],
|
|
|
|
_iReTest: 0,
|
|
|
|
_bFinished: false,
|
|
|
|
|
|
|
|
|
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
|
|
* Recommened public functions
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Function: fnTest
|
|
|
|
* Purpose: Add a test to the queue
|
|
|
|
* Returns: -
|
|
|
|
* Inputs: string:sMessage - name of the test
|
|
|
|
* function:fnTest - function which will be evaludated to get the test result
|
|
|
|
*/
|
|
|
|
"fnTest": function ( sMessage, fnSetup, fnTest )
|
|
|
|
{
|
|
|
|
this._aoQueue.push( {
|
|
|
|
"sMessage": sMessage,
|
|
|
|
"fnSetup": fnSetup,
|
|
|
|
"fnTest": fnTest,
|
|
|
|
"bPoll": false
|
|
|
|
} );
|
|
|
|
this._fnNext();
|
|
|
|
},
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Function: fnWaitTest
|
|
|
|
* Purpose: Add a test to the queue which has a re-test cycle
|
|
|
|
* Returns: -
|
|
|
|
* Inputs: string:sMessage - name of the test
|
|
|
|
* function:fnTest - function which will be evaludated to get the test result
|
|
|
|
*/
|
|
|
|
"fnWaitTest": function ( sMessage, fnSetup, fnTest )
|
|
|
|
{
|
|
|
|
this._aoQueue.push( {
|
|
|
|
"sMessage": sMessage,
|
|
|
|
"fnSetup": fnSetup,
|
|
|
|
"fnTest": fnTest,
|
|
|
|
"bPoll": true
|
|
|
|
} );
|
|
|
|
this._fnNext();
|
|
|
|
},
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Function: fnStart
|
|
|
|
* Purpose: Indicate that this is a new unit and what it is testing (message to end user)
|
|
|
|
* Returns: -
|
|
|
|
* Inputs: string:sMessage - message to give to the user about this unit
|
|
|
|
*/
|
|
|
|
"fnStart": function ( sMessage )
|
|
|
|
{
|
|
|
|
window.parent.controller.fnStartMessage( sMessage );
|
|
|
|
},
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Function: fnComplete
|
|
|
|
* Purpose: Tell the controller that we are all done here
|
|
|
|
* Returns: -
|
|
|
|
* Inputs: -
|
|
|
|
*/
|
|
|
|
"fnComplete": function ()
|
|
|
|
{
|
|
|
|
this._bFinished = true;
|
|
|
|
this._fnNext();
|
|
|
|
},
|
|
|
|
|
2010-10-17 08:43:17 +02:00
|
|
|
/*
|
|
|
|
* Function: fnCookieDestroy
|
|
|
|
* Purpose: Destroy a cookie of a given name
|
|
|
|
* Returns: -
|
|
|
|
* Inputs: -
|
|
|
|
*/
|
|
|
|
"fnCookieDestroy": function ( oTable )
|
|
|
|
{
|
2012-10-31 19:12:22 +01:00
|
|
|
var s = oTable.fnSettings();
|
|
|
|
|
|
|
|
localStorage.setItem( 'DataTables_'+s.sInstance+'_'+window.location.pathname, null );
|
2010-10-17 08:43:17 +02:00
|
|
|
},
|
|
|
|
|
2010-08-17 09:42:13 +02:00
|
|
|
|
|
|
|
|
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
|
|
* Internal functions
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
"_fnReTest": function ( oTestInfo )
|
|
|
|
{
|
|
|
|
var bResult = oTestInfo.fnTest( );
|
|
|
|
if ( bResult )
|
|
|
|
{
|
|
|
|
/* Test passed on retry */
|
|
|
|
this._fnResult( true );
|
|
|
|
this._fnNext();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( this._iReTest < this.iReTestLimit )
|
|
|
|
{
|
|
|
|
this._iReTest++;
|
|
|
|
setTimeout( function() {
|
|
|
|
oTest._fnReTest( oTestInfo );
|
|
|
|
}, this.iReTestDelay );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
this._fnResult( false );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
"_fnNext": function ()
|
|
|
|
{
|
|
|
|
if ( this.bEnd )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !this.bBlock && this._aoQueue.length > 0 )
|
|
|
|
{
|
|
|
|
var oNextTest = this._aoQueue.shift();
|
|
|
|
window.parent.controller.fnTestStart( oNextTest.sMessage );
|
|
|
|
this.bBlock = true;
|
|
|
|
|
|
|
|
if ( typeof oNextTest.fnSetup == 'function' )
|
|
|
|
{
|
|
|
|
oNextTest.fnSetup( );
|
|
|
|
}
|
|
|
|
var bResult = oNextTest.fnTest( );
|
|
|
|
//bResult = false;
|
|
|
|
|
|
|
|
if ( oNextTest.bPoll )
|
|
|
|
{
|
|
|
|
if ( bResult )
|
|
|
|
{
|
|
|
|
this._fnResult( true );
|
|
|
|
this._fnNext();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_iReTest = 0;
|
|
|
|
setTimeout( function() {
|
|
|
|
oTest._fnReTest( oNextTest );
|
|
|
|
}, this.iReTestDelay );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
this._fnResult( bResult );
|
|
|
|
this._fnNext();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( !this.bBlock && this._aoQueue.length == 0 && this._bFinished )
|
|
|
|
{
|
|
|
|
window.parent.controller.fnUnitComplete( );
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
"_fnResult": function ( b )
|
|
|
|
{
|
|
|
|
window.parent.controller.fnTestResult( b );
|
|
|
|
this.bBlock = false;
|
|
|
|
if ( !b )
|
|
|
|
{
|
|
|
|
this.bEnd = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
var oDispacher = {
|
|
|
|
"click": function ( nNode, oSpecial )
|
|
|
|
{
|
|
|
|
var evt = this.fnCreateEvent( 'click', nNode, oSpecial );
|
|
|
|
if ( nNode.dispatchEvent )
|
|
|
|
nNode.dispatchEvent(evt);
|
|
|
|
else
|
|
|
|
nNode.fireEvent('onclick', evt);
|
|
|
|
},
|
|
|
|
|
|
|
|
"change": function ( nNode )
|
|
|
|
{
|
|
|
|
var evt = this.fnCreateEvent( 'change', nNode );
|
|
|
|
if ( nNode.dispatchEvent )
|
|
|
|
nNode.dispatchEvent(evt);
|
|
|
|
else
|
|
|
|
nNode.fireEvent('onchange', evt);
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Function: fnCreateEvent
|
|
|
|
* Purpose: Create an event oject based on the type to trigger an event - x-platform
|
|
|
|
* Returns: event:evt
|
|
|
|
* Inputs: string:sType - type of event
|
|
|
|
* node:nTarget - target node of the event
|
|
|
|
*/
|
|
|
|
fnCreateEvent: function( sType, nTarget, oSpecial )
|
|
|
|
{
|
|
|
|
var evt = null;
|
|
|
|
var oTargetPos = this._fnGetPos( nTarget );
|
|
|
|
var sTypeGroup = this._fnEventTypeGroup( sType );
|
|
|
|
if ( typeof oSpecial == 'undefined' )
|
|
|
|
{
|
|
|
|
oSpecial = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
var ctrlKey = false;
|
|
|
|
var altKey = false;
|
|
|
|
var shiftKey = (typeof oSpecial.shift != 'undefined') ? oSpecial.shift : false;
|
|
|
|
var metaKey = false;
|
|
|
|
var button = false;
|
|
|
|
|
|
|
|
if ( document.createEvent )
|
|
|
|
{
|
|
|
|
switch ( sTypeGroup )
|
|
|
|
{
|
|
|
|
case 'mouse':
|
|
|
|
evt = document.createEvent( "MouseEvents" );
|
|
|
|
evt.initMouseEvent( sType, true, true, window, 0, oTargetPos[0], oTargetPos[1],
|
|
|
|
oTargetPos[0], oTargetPos[1], ctrlKey, altKey, shiftKey,
|
|
|
|
metaKey, button, null );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'html':
|
|
|
|
evt = document.createEvent( "HTMLEvents" );
|
|
|
|
evt.initEvent( sType, true, true );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'ui':
|
|
|
|
evt = document.createEvent( "UIEvents" );
|
|
|
|
evt.initUIEvent( sType, true, true, window, 0 );
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( document.createEventObject )
|
|
|
|
{
|
|
|
|
switch ( sTypeGroup )
|
|
|
|
{
|
|
|
|
case 'mouse':
|
|
|
|
evt = document.createEventObject();
|
|
|
|
evt.screenX = oTargetPos[0];
|
|
|
|
evt.screenX = oTargetPos[1];
|
|
|
|
evt.clientX = oTargetPos[0];
|
|
|
|
evt.clientY = oTargetPos[1];
|
|
|
|
evt.ctrlKey = ctrlKey;
|
|
|
|
evt.altKey = altKey;
|
|
|
|
evt.shiftKey = shiftKey;
|
|
|
|
evt.metaKey = metaKey;
|
|
|
|
evt.button = button;
|
|
|
|
evt.relatedTarget = null;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'html':
|
|
|
|
/* fall through to basic event object */
|
|
|
|
|
|
|
|
case 'ui':
|
|
|
|
evt = document.createEventObject();
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return evt;
|
|
|
|
},
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Function: DesignCore.fnGetPos
|
|
|
|
* Purpose: Get the position of an element on the page
|
|
|
|
* Returns: array[ 0-int:left, 1-int:top ]
|
|
|
|
* Inputs: node:obj - node to analyse
|
|
|
|
*/
|
|
|
|
_fnGetPos: function ( obj )
|
|
|
|
{
|
|
|
|
var curleft = 0;
|
|
|
|
var curtop = 0;
|
|
|
|
|
|
|
|
if (obj.offsetParent)
|
|
|
|
{
|
|
|
|
curleft = obj.offsetLeft;
|
|
|
|
curtop = obj.offsetTop;
|
|
|
|
while (obj = obj.offsetParent )
|
|
|
|
{
|
|
|
|
curleft += obj.offsetLeft;
|
|
|
|
curtop += obj.offsetTop;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return [curleft,curtop];
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Function: _fnEventTypeGroup
|
|
|
|
* Purpose: Group the event types as per w3c groupings
|
|
|
|
* Returns: -
|
|
|
|
* Inputs: string:sType
|
|
|
|
*/
|
|
|
|
_fnEventTypeGroup: function ( sType )
|
|
|
|
{
|
|
|
|
switch ( sType )
|
|
|
|
{
|
|
|
|
case 'click':
|
|
|
|
case 'dblclick':
|
|
|
|
case 'mousedown':
|
|
|
|
case 'mousemove':
|
|
|
|
case 'mouseout':
|
|
|
|
case 'mouseover':
|
|
|
|
case 'mouseup':
|
|
|
|
return 'mouse';
|
|
|
|
|
|
|
|
case 'change':
|
|
|
|
case 'focus':
|
|
|
|
case 'blur':
|
|
|
|
case 'select':
|
|
|
|
case 'submit':
|
|
|
|
return 'html';
|
|
|
|
|
|
|
|
case 'keydown':
|
|
|
|
case 'keypress':
|
|
|
|
case 'keyup':
|
|
|
|
case 'load':
|
|
|
|
case 'unload':
|
|
|
|
return 'ui';
|
|
|
|
|
|
|
|
default:
|
|
|
|
return 'custom';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var oSession = {
|
|
|
|
nTable: null,
|
|
|
|
|
|
|
|
fnCache: function ()
|
|
|
|
{
|
|
|
|
this.nTable = document.getElementById('demo').cloneNode(true);
|
|
|
|
},
|
|
|
|
|
|
|
|
fnRestore: function ()
|
|
|
|
{
|
|
|
|
while( $.fn.dataTableSettings.length > 0 )
|
|
|
|
{
|
2012-02-01 09:16:49 +01:00
|
|
|
try {
|
|
|
|
$.fn.dataTableSettings[0].oInstance.fnDestroy();
|
|
|
|
} catch (e) {
|
|
|
|
$.fn.dataTableSettings.splice( 0, 1 );
|
|
|
|
}
|
2010-08-17 09:42:13 +02:00
|
|
|
}
|
|
|
|
//$.fn.dataTableSettings.splice( 0, $.fn.dataTableSettings.length );
|
|
|
|
var nDemo = document.getElementById('demo');
|
|
|
|
nDemo.innerHTML = "";
|
|
|
|
for ( var i=0, iLen=this.nTable.childNodes.length ; i<iLen ; i++ )
|
|
|
|
{
|
|
|
|
nDemo.appendChild( this.nTable.childNodes[0] );
|
|
|
|
}
|
|
|
|
this.fnCache();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$(document).ready( function () {
|
|
|
|
oSession.fnCache();
|
|
|
|
} );
|