Author: jmorliaguet Date: Sun Dec 25 16:42:56 2005 New Revision: 2076 Added: cpsskins/branches/jmo-perspectives/ui/framework/tests/ cpsskins/branches/jmo-perspectives/ui/framework/tests/test.css (contents, props changed) cpsskins/branches/jmo-perspectives/ui/framework/tests/unit/ cpsskins/branches/jmo-perspectives/ui/framework/tests/unit/cpsskins_test.html (contents, props changed) cpsskins/branches/jmo-perspectives/ui/framework/tests/unittest.js (contents, props changed) Log:
- added the javascript unittest framework from script.aculo.us (unittest.js) - added unit tests for cpsskins.js (for the Identifiable API so far) Added: cpsskins/branches/jmo-perspectives/ui/framework/tests/test.css ============================================================================== --- (empty file) +++ cpsskins/branches/jmo-perspectives/ui/framework/tests/test.css Sun Dec 25 16:42:56 2005 @@ -0,0 +1,40 @@ +body, div, p, h1, h2, h3, ul, ol, span, a, table, td, form, img, li { + font-family: sans-serif; +} + +body { + font-size:0.8em; +} + +#log { + padding-bottom: 1em; + border-bottom: 2px solid #000; + margin-bottom: 2em; +} + +#logsummary { + margin-bottom: 1em; + padding: 1ex; + border: 1px solid #000; + font-weight: bold; +} + +#logtable { + width:100%; + border-collapse: collapse; + border: 1px dotted #666; +} + +#logtable td, #logtable th { + text-align: left; + padding: 3px 8px; + border: 1px dotted #666; +} + +#logtable .passed { + background-color: #cfc; +} + +#logtable .failed, #logtable .error { + background-color: #fcc; +} \ No newline at end of file Added: cpsskins/branches/jmo-perspectives/ui/framework/tests/unit/cpsskins_test.html ============================================================================== --- (empty file) +++ cpsskins/branches/jmo-perspectives/ui/framework/tests/unit/cpsskins_test.html Sun Dec 25 16:42:56 2005 @@ -0,0 +1,115 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> + <title>CPSSkins Unit test file</title> + <meta http-equiv="content-type" content="text/html; charset=utf-8" /> + <script src="../../prototype.js" type="text/javascript"></script> + <script src="../../cpsskins.js" type="text/javascript"></script> + <script src="../unittest.js" type="text/javascript"></script> + <link rel="stylesheet" href="../test.css" type="text/css" /> +</head> +<body> +<h1>CPSSkins Unit test file</h1> +<p> + Tests for CPSSkins javascript library. +</p> + +<!-- Log output --> +<div id="testlog"> </div> + +<!-- Testing area --> + +<div id="e0"> + <div> + <div id="e1"></div> + <div> + <div id="e2"></div> + <div id="e3"></div> + <div id="e4"> + <div id="e5"></div> + </div> + </div> + <div></div> + <div id="e6"></div> + </div> +</div> + +<!-- Tests follow --> +<script type="text/javascript" language="javascript" charset="utf-8"> +// <![CDATA[ + + var e0 = $('e0'); + var e1 = $('e1'); + var e2 = $('e2'); + var e3 = $('e3'); + var e4 = $('e4'); + var e5 = $('e5'); + var e6 = $('e6'); + + new Test.Unit.Runner({ + + testIsIdentifiable: function() { with(this) { + assertEqual(Identifiable.isIdentifiable(e1), true); + assertEqual(Identifiable.isIdentifiable(e1.parentNode), false); + }}, + + testGetOrder: function() { with(this) { + assertEqual(Identifiable.getOrder(e1), 0); + assertEqual(Identifiable.getOrder(e2), 0); + assertEqual(Identifiable.getOrder(e3), 1); + assertEqual(Identifiable.getOrder(e4), 2); + assertEqual(Identifiable.getOrder(e5), 0); + assertEqual(Identifiable.getOrder(e6), 1); + }}, + + testGetNext: function() { with(this) { + assertEqual(Identifiable.getNext(e1), e6); + assertEqual(Identifiable.getNext(e2), e3); + assertEqual(Identifiable.getNext(e3), e4); + assertEqual(Identifiable.getNext(e4), null); + assertEqual(Identifiable.getNext(e5), null); + assertEqual(Identifiable.getNext(e6), null); + }}, + + testGetPrevious: function() { with(this) { + assertEqual(Identifiable.getPrevious(e6), e1); + assertEqual(Identifiable.getPrevious(e3), e2); + assertEqual(Identifiable.getPrevious(e4), e3); + assertEqual(Identifiable.getPrevious(e5), null); + assertEqual(Identifiable.getPrevious(e2), null); + assertEqual(Identifiable.getPrevious(e1), null); + }}, + + testGetParent: function() { with(this) { + assertEqual(Identifiable.getParent(e1), e0); + assertEqual(Identifiable.getParent(e2), e0); + assertEqual(Identifiable.getParent(e3), e0); + assertEqual(Identifiable.getParent(e4), e0); + assertEqual(Identifiable.getParent(e5), e4); + assertEqual(Identifiable.getParent(e6), e0); + }}, + + testGetIdentifiable: function() { with(this) { + assertEqual(Identifiable.getIdentifiable(e1), e1); + assertEqual(Identifiable.getIdentifiable(e2), e2); + assertEqual(Identifiable.getIdentifiable(e1.parentNode), + e0); + }}, + + testIsEmpty: function() { with(this) { + assertEqual(Identifiable.isEmpty(e0), false); + assertEqual(Identifiable.isEmpty(e1), true); + assertEqual(Identifiable.isEmpty(e2), true); + assertEqual(Identifiable.isEmpty(e3), true); + assertEqual(Identifiable.isEmpty(e4), false); + assertEqual(Identifiable.isEmpty(e5), true); + assertEqual(Identifiable.isEmpty(e6), true); + }} + + }); + +// ]]> +</script> +</body> +</html> Added: cpsskins/branches/jmo-perspectives/ui/framework/tests/unittest.js ============================================================================== --- (empty file) +++ cpsskins/branches/jmo-perspectives/ui/framework/tests/unittest.js Sun Dec 25 16:42:56 2005 @@ -0,0 +1,363 @@ +// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// (c) 2005 Jon Tirsen (http://www.tirsen.com) +// (c) 2005 Michael Schuerig (http://www.schuerig.de/michael/) +// +// See scriptaculous.js for full license. + +// experimental, Firefox-only +Event.simulateMouse = function(element, eventName) { + var options = Object.extend({ + pointerX: 0, + pointerY: 0, + buttons: 0 + }, arguments[2] || {}); + var oEvent = document.createEvent("MouseEvents"); + oEvent.initMouseEvent(eventName, true, true, document.defaultView, + options.buttons, options.pointerX, options.pointerY, options.pointerX, options.pointerY, + false, false, false, false, 0, $(element)); + + if(this.mark) Element.remove(this.mark); + this.mark = document.createElement('div'); + this.mark.appendChild(document.createTextNode(" ")); + document.body.appendChild(this.mark); + this.mark.style.position = 'absolute'; + this.mark.style.top = options.pointerY + "px"; + this.mark.style.left = options.pointerX + "px"; + this.mark.style.width = "5px"; + this.mark.style.height = "5px;"; + this.mark.style.borderTop = "1px solid red;" + this.mark.style.borderLeft = "1px solid red;" + + if(this.step) + alert('['+new Date().getTime().toString()+'] '+eventName+'/'+Test.Unit.inspect(options)); + + $(element).dispatchEvent(oEvent); +}; + +// Note: Due to a fix in Firefox 1.0.5/6 that probably fixed "too much", this doesn't work in 1.0.6 or DP2. +// You need to downgrade to 1.0.4 for now to get this working +// See https://bugzilla.mozilla.org/show_bug.cgi?id=289940 for the fix that fixed too much +Event.simulateKey = function(element, eventName) { + var options = Object.extend({ + ctrlKey: false, + altKey: false, + shiftKey: false, + metaKey: false, + keyCode: 0, + charCode: 0 + }, arguments[2] || {}); + + var oEvent = document.createEvent("KeyEvents"); + oEvent.initKeyEvent(eventName, true, true, window, + options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, + options.keyCode, options.charCode ); + $(element).dispatchEvent(oEvent); +}; + +Event.simulateKeys = function(element, command) { + for(var i=0; i<command.length; i++) { + Event.simulateKey(element,'keypress',{charCode:command.charCodeAt(i)}); + } +}; + +var Test = {} +Test.Unit = {}; + +// security exception workaround +Test.Unit.inspect = function(obj) { + var info = []; + + if(typeof obj=="string" || + typeof obj=="number") { + return obj; + } else { + for(property in obj) + if(typeof obj[property]!="function") + info.push(property + ' => ' + + (typeof obj[property] == "string" ? + '"' + obj[property] + '"' : + obj[property])); + } + + return ("'" + obj + "' #" + typeof obj + + ": {" + info.join(", ") + "}"); +} + +Test.Unit.Logger = Class.create(); +Test.Unit.Logger.prototype = { + initialize: function(log) { + this.log = $(log); + if (this.log) { + this._createLogTable(); + } + }, + start: function(testName) { + if (!this.log) return; + this.testName = testName; + this.lastLogLine = document.createElement('tr'); + this.statusCell = document.createElement('td'); + this.nameCell = document.createElement('td'); + this.nameCell.appendChild(document.createTextNode(testName)); + this.messageCell = document.createElement('td'); + this.lastLogLine.appendChild(this.statusCell); + this.lastLogLine.appendChild(this.nameCell); + this.lastLogLine.appendChild(this.messageCell); + this.loglines.appendChild(this.lastLogLine); + }, + finish: function(status, summary) { + if (!this.log) return; + this.lastLogLine.className = status; + this.statusCell.innerHTML = status; + this.messageCell.innerHTML = this._toHTML(summary); + }, + message: function(message) { + if (!this.log) return; + this.messageCell.innerHTML = this._toHTML(message); + }, + summary: function(summary) { + if (!this.log) return; + this.logsummary.innerHTML = this._toHTML(summary); + }, + _createLogTable: function() { + this.log.innerHTML = + '<div id="logsummary"></div>' + + '<table id="logtable">' + + '<thead><tr><th>Status</th><th>Test</th><th>Message</th></tr></thead>' + + '<tbody id="loglines"></tbody>' + + '</table>'; + this.logsummary = $('logsummary') + this.loglines = $('loglines'); + }, + _toHTML: function(txt) { + return txt.escapeHTML().replace(/\n/g,"<br/>"); + } +} + +Test.Unit.Runner = Class.create(); +Test.Unit.Runner.prototype = { + initialize: function(testcases) { + this.options = Object.extend({ + testLog: 'testlog' + }, arguments[1] || {}); + this.options.resultsURL = this.parseResultsURLQueryParameter(); + if (this.options.testLog) { + this.options.testLog = $(this.options.testLog) || null; + } + if(this.options.tests) { + this.tests = []; + for(var i = 0; i < this.options.tests.length; i++) { + if(/^test/.test(this.options.tests[i])) { + this.tests.push(new Test.Unit.Testcase(this.options.tests[i], testcases[this.options.tests[i]], testcases["setup"], testcases["teardown"])); + } + } + } else { + if (this.options.test) { + this.tests = [new Test.Unit.Testcase(this.options.test, testcases[this.options.test], testcases["setup"], testcases["teardown"])]; + } else { + this.tests = []; + for(var testcase in testcases) { + if(/^test/.test(testcase)) { + this.tests.push(new Test.Unit.Testcase(testcase, testcases[testcase], testcases["setup"], testcases["teardown"])); + } + } + } + } + this.currentTest = 0; + this.logger = new Test.Unit.Logger(this.options.testLog); + setTimeout(this.runTests.bind(this), 1000); + }, + parseResultsURLQueryParameter: function() { + return window.location.search.parseQuery()["resultsURL"]; + }, + // Returns: + // "ERROR" if there was an error, + // "FAILURE" if there was a failure, or + // "SUCCESS" if there was neither + getResult: function() { + var hasFailure = false; + for(var i=0;i<this.tests.length;i++) { + if (this.tests[i].errors > 0) { + return "ERROR"; + } + if (this.tests[i].failures > 0) { + hasFailure = true; + } + } + if (hasFailure) { + return "FAILURE"; + } else { + return "SUCCESS"; + } + }, + postResults: function() { + if (this.options.resultsURL) { + new Ajax.Request(this.options.resultsURL, + { method: 'get', parameters: 'result=' + this.getResult(), asynchronous: false }); + } + }, + runTests: function() { + var test = this.tests[this.currentTest]; + if (!test) { + // finished! + this.postResults(); + this.logger.summary(this.summary()); + return; + } + if(!test.isWaiting) { + this.logger.start(test.name); + } + test.run(); + if(test.isWaiting) { + this.logger.message("Waiting for " + test.timeToWait + "ms"); + setTimeout(this.runTests.bind(this), test.timeToWait || 1000); + } else { + this.logger.finish(test.status(), test.summary()); + this.currentTest++; + // tail recursive, hopefully the browser will skip the stackframe + this.runTests(); + } + }, + summary: function() { + var assertions = 0; + var failures = 0; + var errors = 0; + var messages = []; + for(var i=0;i<this.tests.length;i++) { + assertions += this.tests[i].assertions; + failures += this.tests[i].failures; + errors += this.tests[i].errors; + } + return ( + this.tests.length + " tests, " + + assertions + " assertions, " + + failures + " failures, " + + errors + " errors"); + } +} + +Test.Unit.Assertions = Class.create(); +Test.Unit.Assertions.prototype = { + initialize: function() { + this.assertions = 0; + this.failures = 0; + this.errors = 0; + this.messages = []; + }, + summary: function() { + return ( + this.assertions + " assertions, " + + this.failures + " failures, " + + this.errors + " errors" + "\n" + + this.messages.join("\n")); + }, + pass: function() { + this.assertions++; + }, + fail: function(message) { + this.failures++; + this.messages.push("Failure: " + message); + }, + error: function(error) { + this.errors++; + this.messages.push(error.name + ": "+ error.message + "(" + Test.Unit.inspect(error) +")"); + }, + status: function() { + if (this.failures > 0) return 'failed'; + if (this.errors > 0) return 'error'; + return 'passed'; + }, + assert: function(expression) { + var message = arguments[1] || 'assert: got "' + Test.Unit.inspect(expression) + '"'; + try { expression ? this.pass() : + this.fail(message); } + catch(e) { this.error(e); } + }, + assertEqual: function(expected, actual) { + var message = arguments[2] || "assertEqual"; + try { (expected == actual) ? this.pass() : + this.fail(message + ': expected "' + Test.Unit.inspect(expected) + + '", actual "' + Test.Unit.inspect(actual) + '"'); } + catch(e) { this.error(e); } + }, + assertNotEqual: function(expected, actual) { + var message = arguments[2] || "assertNotEqual"; + try { (expected != actual) ? this.pass() : + this.fail(message + ': got "' + Test.Unit.inspect(actual) + '"'); } + catch(e) { this.error(e); } + }, + assertNull: function(obj) { + var message = arguments[1] || 'assertNull' + try { (obj==null) ? this.pass() : + this.fail(message + ': got "' + Test.Unit.inspect(obj) + '"'); } + catch(e) { this.error(e); } + }, + assertHidden: function(element) { + var message = arguments[1] || 'assertHidden'; + this.assertEqual("none", element.style.display, message); + }, + assertNotNull: function(object) { + var message = arguments[1] || 'assertNotNull'; + this.assert(object != null, message); + }, + assertInstanceOf: function(expected, actual) { + var message = arguments[2] || 'assertInstanceOf'; + try { + (actual instanceof expected) ? this.pass() : + this.fail(message + ": object was not an instance of the expected type"); } + catch(e) { this.error(e); } + }, + assertNotInstanceOf: function(expected, actual) { + var message = arguments[2] || 'assertNotInstanceOf'; + try { + !(actual instanceof expected) ? this.pass() : + this.fail(message + ": object was an instance of the not expected type"); } + catch(e) { this.error(e); } + }, + _isVisible: function(element) { + element = $(element); + if(!element.parentNode) return true; + this.assertNotNull(element); + if(element.style && Element.getStyle(element, 'display') == 'none') + return false; + + return this._isVisible(element.parentNode); + }, + assertNotVisible: function(element) { + this.assert(!this._isVisible(element), Test.Unit.inspect(element) + " was not hidden and didn't have a hidden parent either. " + ("" || arguments[1])); + }, + assertVisible: function(element) { + this.assert(this._isVisible(element), Test.Unit.inspect(element) + " was not visible. " + ("" || arguments[1])); + } +} + +Test.Unit.Testcase = Class.create(); +Object.extend(Object.extend(Test.Unit.Testcase.prototype, Test.Unit.Assertions.prototype), { + initialize: function(name, test, setup, teardown) { + Test.Unit.Assertions.prototype.initialize.bind(this)(); + this.name = name; + this.test = test || function() {}; + this.setup = setup || function() {}; + this.teardown = teardown || function() {}; + this.isWaiting = false; + this.timeToWait = 1000; + }, + wait: function(time, nextPart) { + this.isWaiting = true; + this.test = nextPart; + this.timeToWait = time; + }, + run: function() { + try { + try { + if (!this.isWaiting) this.setup.bind(this)(); + this.isWaiting = false; + this.test.bind(this)(); + } finally { + if(!this.isWaiting) { + this.teardown.bind(this)(); + } + } + } + catch(e) { this.error(e); } + } +}); \ No newline at end of file -- http://lists.nuxeo.com/mailman/listinfo/z3lab-checkins