1 // Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
2 // (c) 2005 Jon Tirsen (http://www.tirsen.com)
3 // (c) 2005 Michael Schuerig (http://www.schuerig.de/michael/)
5 // See scriptaculous.js for full license.
7 // experimental, Firefox-only
8 Event.simulateMouse = function(element, eventName) {
9 var options = Object.extend({
13 }, arguments[2] || {});
14 var oEvent = document.createEvent("MouseEvents");
15 oEvent.initMouseEvent(eventName, true, true, document.defaultView,
16 options.buttons, options.pointerX, options.pointerY, options.pointerX, options.pointerY,
17 false, false, false, false, 0, $(element));
19 if(this.mark) Element.remove(this.mark);
20 this.mark = document.createElement('div');
21 this.mark.appendChild(document.createTextNode(" "));
22 document.body.appendChild(this.mark);
23 this.mark.style.position = 'absolute';
24 this.mark.style.top = options.pointerY + "px";
25 this.mark.style.left = options.pointerX + "px";
26 this.mark.style.width = "5px";
27 this.mark.style.height = "5px;";
28 this.mark.style.borderTop = "1px solid red;"
29 this.mark.style.borderLeft = "1px solid red;"
32 alert('['+new Date().getTime().toString()+'] '+eventName+'/'+Test.Unit.inspect(options));
34 $(element).dispatchEvent(oEvent);
37 // 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.
38 // You need to downgrade to 1.0.4 for now to get this working
39 // See https://bugzilla.mozilla.org/show_bug.cgi?id=289940 for the fix that fixed too much
40 Event.simulateKey = function(element, eventName) {
41 var options = Object.extend({
48 }, arguments[2] || {});
50 var oEvent = document.createEvent("KeyEvents");
51 oEvent.initKeyEvent(eventName, true, true, window,
52 options.ctrlKey, options.altKey, options.shiftKey, options.metaKey,
53 options.keyCode, options.charCode );
54 $(element).dispatchEvent(oEvent);
57 Event.simulateKeys = function(element, command) {
58 for(var i=0; i<command.length; i++) {
59 Event.simulateKey(element,'keypress',{charCode:command.charCodeAt(i)});
66 // security exception workaround
67 Test.Unit.inspect = function(obj) {
70 if(typeof obj=="string" ||
71 typeof obj=="number") {
75 if(typeof obj[property]!="function")
76 info.push(property + ' => ' +
77 (typeof obj[property] == "string" ?
78 '"' + obj[property] + '"' :
82 return ("'" + obj + "' #" + typeof obj +
83 ": {" + info.join(", ") + "}");
86 Test.Unit.Logger = Class.create();
87 Test.Unit.Logger.prototype = {
88 initialize: function(log) {
91 this._createLogTable();
94 start: function(testName) {
95 if (!this.log) return;
96 this.testName = testName;
97 this.lastLogLine = document.createElement('tr');
98 this.statusCell = document.createElement('td');
99 this.nameCell = document.createElement('td');
100 this.nameCell.appendChild(document.createTextNode(testName));
101 this.messageCell = document.createElement('td');
102 this.lastLogLine.appendChild(this.statusCell);
103 this.lastLogLine.appendChild(this.nameCell);
104 this.lastLogLine.appendChild(this.messageCell);
105 this.loglines.appendChild(this.lastLogLine);
107 finish: function(status, summary) {
108 if (!this.log) return;
109 this.lastLogLine.className = status;
110 this.statusCell.innerHTML = status;
111 this.messageCell.innerHTML = this._toHTML(summary);
113 message: function(message) {
114 if (!this.log) return;
115 this.messageCell.innerHTML = this._toHTML(message);
117 summary: function(summary) {
118 if (!this.log) return;
119 this.logsummary.innerHTML = this._toHTML(summary);
121 _createLogTable: function() {
123 '<div id="logsummary"></div>' +
124 '<table id="logtable">' +
125 '<thead><tr><th>Status</th><th>Test</th><th>Message</th></tr></thead>' +
126 '<tbody id="loglines"></tbody>' +
128 this.logsummary = $('logsummary')
129 this.loglines = $('loglines');
131 _toHTML: function(txt) {
132 return txt.escapeHTML().replace(/\n/g,"<br/>");
136 Test.Unit.Runner = Class.create();
137 Test.Unit.Runner.prototype = {
138 initialize: function(testcases) {
139 this.options = Object.extend({
141 }, arguments[1] || {});
142 this.options.resultsURL = this.parseResultsURLQueryParameter();
143 if (this.options.testLog) {
144 this.options.testLog = $(this.options.testLog) || null;
146 if(this.options.tests) {
148 for(var i = 0; i < this.options.tests.length; i++) {
149 if(/^test/.test(this.options.tests[i])) {
150 this.tests.push(new Test.Unit.Testcase(this.options.tests[i], testcases[this.options.tests[i]], testcases["setup"], testcases["teardown"]));
154 if (this.options.test) {
155 this.tests = [new Test.Unit.Testcase(this.options.test, testcases[this.options.test], testcases["setup"], testcases["teardown"])];
158 for(var testcase in testcases) {
159 if(/^test/.test(testcase)) {
160 this.tests.push(new Test.Unit.Testcase(testcase, testcases[testcase], testcases["setup"], testcases["teardown"]));
165 this.currentTest = 0;
166 this.logger = new Test.Unit.Logger(this.options.testLog);
167 setTimeout(this.runTests.bind(this), 1000);
169 parseResultsURLQueryParameter: function() {
170 return window.location.search.parseQuery()["resultsURL"];
173 // "ERROR" if there was an error,
174 // "FAILURE" if there was a failure, or
175 // "SUCCESS" if there was neither
176 getResult: function() {
177 var hasFailure = false;
178 for(var i=0;i<this.tests.length;i++) {
179 if (this.tests[i].errors > 0) {
182 if (this.tests[i].failures > 0) {
192 postResults: function() {
193 if (this.options.resultsURL) {
194 new Ajax.Request(this.options.resultsURL,
195 { method: 'get', parameters: 'result=' + this.getResult(), asynchronous: false });
198 runTests: function() {
199 var test = this.tests[this.currentTest];
203 this.logger.summary(this.summary());
206 if(!test.isWaiting) {
207 this.logger.start(test.name);
211 this.logger.message("Waiting for " + test.timeToWait + "ms");
212 setTimeout(this.runTests.bind(this), test.timeToWait || 1000);
214 this.logger.finish(test.status(), test.summary());
216 // tail recursive, hopefully the browser will skip the stackframe
220 summary: function() {
225 for(var i=0;i<this.tests.length;i++) {
226 assertions += this.tests[i].assertions;
227 failures += this.tests[i].failures;
228 errors += this.tests[i].errors;
231 this.tests.length + " tests, " +
232 assertions + " assertions, " +
233 failures + " failures, " +
238 Test.Unit.Assertions = Class.create();
239 Test.Unit.Assertions.prototype = {
240 initialize: function() {
246 summary: function() {
248 this.assertions + " assertions, " +
249 this.failures + " failures, " +
250 this.errors + " errors" + "\n" +
251 this.messages.join("\n"));
256 fail: function(message) {
258 this.messages.push("Failure: " + message);
260 error: function(error) {
262 this.messages.push(error.name + ": "+ error.message + "(" + Test.Unit.inspect(error) +")");
265 if (this.failures > 0) return 'failed';
266 if (this.errors > 0) return 'error';
269 assert: function(expression) {
270 var message = arguments[1] || 'assert: got "' + Test.Unit.inspect(expression) + '"';
271 try { expression ? this.pass() :
272 this.fail(message); }
273 catch(e) { this.error(e); }
275 assertEqual: function(expected, actual) {
276 var message = arguments[2] || "assertEqual";
277 try { (expected == actual) ? this.pass() :
278 this.fail(message + ': expected "' + Test.Unit.inspect(expected) +
279 '", actual "' + Test.Unit.inspect(actual) + '"'); }
280 catch(e) { this.error(e); }
282 assertNotEqual: function(expected, actual) {
283 var message = arguments[2] || "assertNotEqual";
284 try { (expected != actual) ? this.pass() :
285 this.fail(message + ': got "' + Test.Unit.inspect(actual) + '"'); }
286 catch(e) { this.error(e); }
288 assertNull: function(obj) {
289 var message = arguments[1] || 'assertNull'
290 try { (obj==null) ? this.pass() :
291 this.fail(message + ': got "' + Test.Unit.inspect(obj) + '"'); }
292 catch(e) { this.error(e); }
294 assertHidden: function(element) {
295 var message = arguments[1] || 'assertHidden';
296 this.assertEqual("none", element.style.display, message);
298 assertNotNull: function(object) {
299 var message = arguments[1] || 'assertNotNull';
300 this.assert(object != null, message);
302 assertInstanceOf: function(expected, actual) {
303 var message = arguments[2] || 'assertInstanceOf';
305 (actual instanceof expected) ? this.pass() :
306 this.fail(message + ": object was not an instance of the expected type"); }
307 catch(e) { this.error(e); }
309 assertNotInstanceOf: function(expected, actual) {
310 var message = arguments[2] || 'assertNotInstanceOf';
312 !(actual instanceof expected) ? this.pass() :
313 this.fail(message + ": object was an instance of the not expected type"); }
314 catch(e) { this.error(e); }
316 _isVisible: function(element) {
317 element = $(element);
318 if(!element.parentNode) return true;
319 this.assertNotNull(element);
320 if(element.style && Element.getStyle(element, 'display') == 'none')
323 return this._isVisible(element.parentNode);
325 assertNotVisible: function(element) {
326 this.assert(!this._isVisible(element), Test.Unit.inspect(element) + " was not hidden and didn't have a hidden parent either. " + ("" || arguments[1]));
328 assertVisible: function(element) {
329 this.assert(this._isVisible(element), Test.Unit.inspect(element) + " was not visible. " + ("" || arguments[1]));
333 Test.Unit.Testcase = Class.create();
334 Object.extend(Object.extend(Test.Unit.Testcase.prototype, Test.Unit.Assertions.prototype), {
335 initialize: function(name, test, setup, teardown) {
336 Test.Unit.Assertions.prototype.initialize.bind(this)();
338 this.test = test || function() {};
339 this.setup = setup || function() {};
340 this.teardown = teardown || function() {};
341 this.isWaiting = false;
342 this.timeToWait = 1000;
344 wait: function(time, nextPart) {
345 this.isWaiting = true;
346 this.test = nextPart;
347 this.timeToWait = time;
352 if (!this.isWaiting) this.setup.bind(this)();
353 this.isWaiting = false;
354 this.test.bind(this)();
356 if(!this.isWaiting) {
357 this.teardown.bind(this)();
361 catch(e) { this.error(e); }