unit_test.js 8.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. /*
  2. * File: unit_test.js
  3. * Version: 0.0.1
  4. * CVS: $Id$
  5. * Description: Unit test framework
  6. * Author: Allan Jardine (www.sprymedia.co.uk)
  7. * Created: Sun Mar 8 22:02:49 GMT 2009
  8. * Modified: $Date$ by $Author$
  9. * Language: Javascript
  10. * License: GPL v2 or BSD 3 point style
  11. * Project: DataTables
  12. * Contact: allan.jardine@sprymedia.co.uk
  13. *
  14. * Copyright 2009 Allan Jardine, all rights reserved.
  15. *
  16. * Description:
  17. * This is a javascript library suitable for use as a unit testing framework. Employing a queuing
  18. * mechanisim to take account of async events in javascript, this library will communicates with
  19. * a controller frame (to report individual test status).
  20. *
  21. */
  22. var oTest = {
  23. /* Block further tests from occuring - might be end of tests or due to async wait */
  24. bBlock: false,
  25. /* Number of times to try retesting for a blocking test */
  26. iReTestLimit: 20,
  27. /* Amount of time to wait between trying for an async test */
  28. iReTestDelay: 150,
  29. /* End tests - external control */
  30. bEnd: false,
  31. /* Internal variables */
  32. _aoQueue: [],
  33. _iReTest: 0,
  34. _bFinished: false,
  35. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  36. * Recommened public functions
  37. */
  38. /*
  39. * Function: fnTest
  40. * Purpose: Add a test to the queue
  41. * Returns: -
  42. * Inputs: string:sMessage - name of the test
  43. * function:fnTest - function which will be evaludated to get the test result
  44. */
  45. "fnTest": function ( sMessage, fnSetup, fnTest )
  46. {
  47. this._aoQueue.push( {
  48. "sMessage": sMessage,
  49. "fnSetup": fnSetup,
  50. "fnTest": fnTest,
  51. "bPoll": false
  52. } );
  53. this._fnNext();
  54. },
  55. /*
  56. * Function: fnWaitTest
  57. * Purpose: Add a test to the queue which has a re-test cycle
  58. * Returns: -
  59. * Inputs: string:sMessage - name of the test
  60. * function:fnTest - function which will be evaludated to get the test result
  61. */
  62. "fnWaitTest": function ( sMessage, fnSetup, fnTest )
  63. {
  64. this._aoQueue.push( {
  65. "sMessage": sMessage,
  66. "fnSetup": fnSetup,
  67. "fnTest": fnTest,
  68. "bPoll": true
  69. } );
  70. this._fnNext();
  71. },
  72. /*
  73. * Function: fnStart
  74. * Purpose: Indicate that this is a new unit and what it is testing (message to end user)
  75. * Returns: -
  76. * Inputs: string:sMessage - message to give to the user about this unit
  77. */
  78. "fnStart": function ( sMessage )
  79. {
  80. window.parent.controller.fnStartMessage( sMessage );
  81. },
  82. /*
  83. * Function: fnComplete
  84. * Purpose: Tell the controller that we are all done here
  85. * Returns: -
  86. * Inputs: -
  87. */
  88. "fnComplete": function ()
  89. {
  90. this._bFinished = true;
  91. this._fnNext();
  92. },
  93. /*
  94. * Function: fnCookieDestroy
  95. * Purpose: Destroy a cookie of a given name
  96. * Returns: -
  97. * Inputs: -
  98. */
  99. "fnCookieDestroy": function ( oTable )
  100. {
  101. var s = oTable.fnSettings();
  102. localStorage.setItem( 'DataTables_'+s.sInstance+'_'+window.location.pathname, null );
  103. },
  104. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  105. * Internal functions
  106. */
  107. "_fnReTest": function ( oTestInfo )
  108. {
  109. var bResult = oTestInfo.fnTest( );
  110. if ( bResult )
  111. {
  112. /* Test passed on retry */
  113. this._fnResult( true );
  114. this._fnNext();
  115. }
  116. else
  117. {
  118. if ( this._iReTest < this.iReTestLimit )
  119. {
  120. this._iReTest++;
  121. setTimeout( function() {
  122. oTest._fnReTest( oTestInfo );
  123. }, this.iReTestDelay );
  124. }
  125. else
  126. {
  127. this._fnResult( false );
  128. }
  129. }
  130. },
  131. "_fnNext": function ()
  132. {
  133. if ( this.bEnd )
  134. {
  135. return;
  136. }
  137. if ( !this.bBlock && this._aoQueue.length > 0 )
  138. {
  139. var oNextTest = this._aoQueue.shift();
  140. window.parent.controller.fnTestStart( oNextTest.sMessage );
  141. this.bBlock = true;
  142. if ( typeof oNextTest.fnSetup == 'function' )
  143. {
  144. oNextTest.fnSetup( );
  145. }
  146. var bResult = oNextTest.fnTest( );
  147. //bResult = false;
  148. if ( oNextTest.bPoll )
  149. {
  150. if ( bResult )
  151. {
  152. this._fnResult( true );
  153. this._fnNext();
  154. }
  155. else
  156. {
  157. _iReTest = 0;
  158. setTimeout( function() {
  159. oTest._fnReTest( oNextTest );
  160. }, this.iReTestDelay );
  161. }
  162. }
  163. else
  164. {
  165. this._fnResult( bResult );
  166. this._fnNext();
  167. }
  168. }
  169. else if ( !this.bBlock && this._aoQueue.length == 0 && this._bFinished )
  170. {
  171. window.parent.controller.fnUnitComplete( );
  172. }
  173. },
  174. "_fnResult": function ( b )
  175. {
  176. window.parent.controller.fnTestResult( b );
  177. this.bBlock = false;
  178. if ( !b )
  179. {
  180. this.bEnd = true;
  181. }
  182. }
  183. };
  184. var oDispacher = {
  185. "click": function ( nNode, oSpecial )
  186. {
  187. var evt = this.fnCreateEvent( 'click', nNode, oSpecial );
  188. if ( nNode.dispatchEvent )
  189. nNode.dispatchEvent(evt);
  190. else
  191. nNode.fireEvent('onclick', evt);
  192. },
  193. "change": function ( nNode )
  194. {
  195. var evt = this.fnCreateEvent( 'change', nNode );
  196. if ( nNode.dispatchEvent )
  197. nNode.dispatchEvent(evt);
  198. else
  199. nNode.fireEvent('onchange', evt);
  200. },
  201. /*
  202. * Function: fnCreateEvent
  203. * Purpose: Create an event oject based on the type to trigger an event - x-platform
  204. * Returns: event:evt
  205. * Inputs: string:sType - type of event
  206. * node:nTarget - target node of the event
  207. */
  208. fnCreateEvent: function( sType, nTarget, oSpecial )
  209. {
  210. var evt = null;
  211. var oTargetPos = this._fnGetPos( nTarget );
  212. var sTypeGroup = this._fnEventTypeGroup( sType );
  213. if ( typeof oSpecial == 'undefined' )
  214. {
  215. oSpecial = {};
  216. }
  217. var ctrlKey = false;
  218. var altKey = false;
  219. var shiftKey = (typeof oSpecial.shift != 'undefined') ? oSpecial.shift : false;
  220. var metaKey = false;
  221. var button = false;
  222. if ( document.createEvent )
  223. {
  224. switch ( sTypeGroup )
  225. {
  226. case 'mouse':
  227. evt = document.createEvent( "MouseEvents" );
  228. evt.initMouseEvent( sType, true, true, window, 0, oTargetPos[0], oTargetPos[1],
  229. oTargetPos[0], oTargetPos[1], ctrlKey, altKey, shiftKey,
  230. metaKey, button, null );
  231. break;
  232. case 'html':
  233. evt = document.createEvent( "HTMLEvents" );
  234. evt.initEvent( sType, true, true );
  235. break;
  236. case 'ui':
  237. evt = document.createEvent( "UIEvents" );
  238. evt.initUIEvent( sType, true, true, window, 0 );
  239. break;
  240. default:
  241. break;
  242. }
  243. }
  244. else if ( document.createEventObject )
  245. {
  246. switch ( sTypeGroup )
  247. {
  248. case 'mouse':
  249. evt = document.createEventObject();
  250. evt.screenX = oTargetPos[0];
  251. evt.screenX = oTargetPos[1];
  252. evt.clientX = oTargetPos[0];
  253. evt.clientY = oTargetPos[1];
  254. evt.ctrlKey = ctrlKey;
  255. evt.altKey = altKey;
  256. evt.shiftKey = shiftKey;
  257. evt.metaKey = metaKey;
  258. evt.button = button;
  259. evt.relatedTarget = null;
  260. break;
  261. case 'html':
  262. /* fall through to basic event object */
  263. case 'ui':
  264. evt = document.createEventObject();
  265. break;
  266. default:
  267. break;
  268. }
  269. }
  270. return evt;
  271. },
  272. /*
  273. * Function: DesignCore.fnGetPos
  274. * Purpose: Get the position of an element on the page
  275. * Returns: array[ 0-int:left, 1-int:top ]
  276. * Inputs: node:obj - node to analyse
  277. */
  278. _fnGetPos: function ( obj )
  279. {
  280. var curleft = 0;
  281. var curtop = 0;
  282. if (obj.offsetParent)
  283. {
  284. curleft = obj.offsetLeft;
  285. curtop = obj.offsetTop;
  286. while (obj = obj.offsetParent )
  287. {
  288. curleft += obj.offsetLeft;
  289. curtop += obj.offsetTop;
  290. }
  291. }
  292. return [curleft,curtop];
  293. },
  294. /*
  295. * Function: _fnEventTypeGroup
  296. * Purpose: Group the event types as per w3c groupings
  297. * Returns: -
  298. * Inputs: string:sType
  299. */
  300. _fnEventTypeGroup: function ( sType )
  301. {
  302. switch ( sType )
  303. {
  304. case 'click':
  305. case 'dblclick':
  306. case 'mousedown':
  307. case 'mousemove':
  308. case 'mouseout':
  309. case 'mouseover':
  310. case 'mouseup':
  311. return 'mouse';
  312. case 'change':
  313. case 'focus':
  314. case 'blur':
  315. case 'select':
  316. case 'submit':
  317. return 'html';
  318. case 'keydown':
  319. case 'keypress':
  320. case 'keyup':
  321. case 'load':
  322. case 'unload':
  323. return 'ui';
  324. default:
  325. return 'custom';
  326. }
  327. }
  328. }
  329. var oSession = {
  330. nTable: null,
  331. fnCache: function ()
  332. {
  333. this.nTable = document.getElementById('demo').cloneNode(true);
  334. },
  335. fnRestore: function ()
  336. {
  337. while( $.fn.dataTableSettings.length > 0 )
  338. {
  339. try {
  340. $.fn.dataTableSettings[0].oInstance.fnDestroy();
  341. } catch (e) {
  342. $.fn.dataTableSettings.splice( 0, 1 );
  343. }
  344. }
  345. //$.fn.dataTableSettings.splice( 0, $.fn.dataTableSettings.length );
  346. var nDemo = document.getElementById('demo');
  347. nDemo.innerHTML = "";
  348. for ( var i=0, iLen=this.nTable.childNodes.length ; i<iLen ; i++ )
  349. {
  350. nDemo.appendChild( this.nTable.childNodes[0] );
  351. }
  352. this.fnCache();
  353. }
  354. }
  355. $(document).ready( function () {
  356. oSession.fnCache();
  357. } );