Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

root/spinoffs/scriptaculous/test/unittest.js

Revision 1966, 8.5 kB (checked in by madrobby, 5 years ago)

script.aculo.us: Souped-up Ajax.InPlaceEditor, added support for a form id and specifying all the texts through options [Jon Tirsen]

Line 
1 // Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
2 //           (c) 2005 Jon Tirsen
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
23 // small but works-for-me stuff for testing javascripts
24 // not ready for "production" use
25
26 Object.prototype.inspect = function(){
27   var info = [];
28   for(property in this)
29     if(typeof this[property]!="function")
30       info.push(property + ' => "' + this[property] + '"');
31   return ("'" + this + "' #" + typeof this +
32     ": {" + info.join(", ") + "}");
33 }
34
35 // overload inspect for Strings, very confusing output otherwise (comment out and you'll notice ;-) )
36 String.prototype.inspect = function() {
37   return this;
38 }
39
40 // experimental, Firefox-only
41 Event.simulateMouse = function(element, eventName) {
42   var oEvent = document.createEvent("MouseEvents");
43   oEvent.initMouseEvent(eventName, true, true, window, 1, 1, 1, 1, 1, false, false, false, false, 0, $(element));
44   $(element).dispatchEvent(oEvent);
45 };
46
47 Test = {}
48 Test.Unit = {};
49
50 Test.Unit.Logger = Class.create();
51 Test.Unit.Logger.prototype = {
52   initialize: function(log) {
53     this.log = $(log);
54     if (this.log) {
55       this._createLogTable();
56     }
57   },
58   start: function(testName) {
59     if (!this.log) return;
60     this.testName = testName;
61     this.lastLogLine = document.createElement('tr');
62     this.statusCell = document.createElement('td');
63     this.nameCell = document.createElement('td');
64     this.nameCell.appendChild(document.createTextNode(testName));
65     this.messageCell = document.createElement('td');
66     this.lastLogLine.appendChild(this.statusCell);
67     this.lastLogLine.appendChild(this.nameCell);
68     this.lastLogLine.appendChild(this.messageCell);
69     this.loglines.appendChild(this.lastLogLine);
70   },
71   finish: function(status, summary) {
72     if (!this.log) return;
73     this.lastLogLine.className = status;
74     this.statusCell.innerHTML = status;
75     this.messageCell.innerHTML = this._toHTML(summary);
76   },
77   message: function(message) {
78     if (!this.log) return;
79     this.messageCell.innerHTML = this._toHTML(message);
80   },
81   summary: function(summary) {
82     if (!this.log) return;
83     this.logsummary.innerHTML = this._toHTML(summary);
84   },
85   _createLogTable: function() {
86     this.log.innerHTML =
87     '<div id="logsummary"></div>' +
88     '<table id="logtable">' +
89     '<thead><tr><th>Status</th><th>Test</th><th>Message</th></tr></thead>' +
90     '<tbody id="loglines"></tbody>' +
91     '</table>';
92     this.logsummary = $('logsummary')
93     this.loglines = $('loglines');
94   },
95   _toHTML: function(txt) {
96     return txt.escapeHTML().replace(/\n/,"<br/>");
97   }
98 }
99
100 Test.Unit.Runner = Class.create();
101 Test.Unit.Runner.prototype = {
102   initialize: function(testcases, log) {
103     this.log = log;
104     this.tests = [];
105     for(var testcase in testcases) {
106       if(/^test/.test(testcase)) {
107         this.tests.push(new Test.Unit.Testcase(testcase, testcases[testcase], testcases["setup"], testcases["teardown"]));
108       }
109     }
110     this.currentTest = 0;
111     Event.observe(window, 'load', this._initialize.bindAsEventListener(this));
112   },
113   _initialize: function() {
114     this.logger = new Test.Unit.Logger(this.log);
115     setTimeout(this.runTests.bind(this), 1000);
116   },
117   runTests: function() {
118     var test = this.tests[this.currentTest];
119     if (!test) {
120       // finished!
121       this.logger.summary(this.summary());
122       return;
123     }
124     if(!test.isWaitingForAjax) {
125       this.logger.start(test.name);
126     }
127     test.run();
128     if(test.isWaitingForAjax) {
129       this.logger.message("Waiting for AJAX");
130       setTimeout(this.runTests.bind(this), test.ajaxTimeout);
131     } else {
132       this.logger.finish(test.status(), test.summary());
133       this.currentTest++;
134       // tail recursive, hopefully the browser will skip the stackframe
135       this.runTests();
136     }
137   },
138   summary: function() {
139     var assertions = 0;
140     var failures = 0;
141     var errors = 0;
142     var messages = [];
143     for(var i=0;i<this.tests.length;i++) {
144       assertions +=   this.tests[i].assertions;
145       failures   +=   this.tests[i].failures;
146       errors     +=   this.tests[i].errors;
147     }
148     return (
149       this.tests.length + " tests, " +
150       assertions + " assertions, " +
151       failures   + " failures, " +
152       errors     + " errors");
153   }
154 }
155
156 Test.Unit.Assertions = Class.create();
157 Test.Unit.Assertions.prototype = {
158   initialize: function() {
159     this.assertions = 0;
160     this.failures   = 0;
161     this.errors     = 0;
162     this.messages   = [];
163   },
164   summary: function() {
165     return (
166       this.assertions + " assertions, " +
167       this.failures   + " failures, " +
168       this.errors     + " errors" + "\n" +
169       this.messages.join("\n"));
170   },
171   pass: function() {
172     this.assertions++;
173   },
174   fail: function(message) {
175     this.failures++;
176     this.messages.push("Failure: " + message);
177   },
178   error: function(error) {
179     this.errors++;
180     this.messages.push(error.name + ": "+ error.message + "(" + error.inspect() +")");
181   },
182   status: function() {
183     if (this.failures > 0) return 'failed';
184     if (this.errors > 0) return 'error';
185     return 'passed';
186   },
187   assert: function(expression) {
188     var message = arguments[1] || 'assert: got "' + expression.inspect() + '"';
189     try { expression ? this.pass() :
190       this.fail(message); }
191     catch(e) { this.error(e); }
192   },
193   assertEqual: function(expected, actual) {
194     var message = arguments[2] || "assertEqual";
195     try { (expected == actual) ? this.pass() :
196       this.fail(message + ': expected "' + expected.inspect() +
197         '", actual "' + actual.inspect() + '"'); }
198     catch(e) { this.error(e); }
199   },
200   assertNotEqual: function(expected, actual) {
201     var message = arguments[2] || "assertNotEqual";
202     try { (expected != actual) ? this.pass() :
203       this.fail(message + ': got "' + actual.inspect() + '"'); }
204     catch(e) { this.error(e); }
205   },
206   assertNull: function(object) {
207     var message = arguments[1] || 'assertNull'
208     try { (object==null) ? this.pass() :
209       this.fail(message + ': got "' + object.inspect() + '"'); }
210     catch(e) { this.error(e); }
211   },
212   assertHidden: function(element) {
213     var message = arguments[1] || 'assertHidden';
214     this.assertEqual("none", element.style.display, message);
215   },
216   assertNotNull: function(object) {
217     var message = arguments[1] || 'assertNotNull';
218     this.assert(object != null);
219   },
220   assertVisible: function(element) {
221     if(element == document) return;
222     this.assertNotNull(element);
223     // if it's not an element (just check parent) may be a text node for example
224     if (element.style) {
225       this.assertNotEqual("none", element.style.display, element.inspect() + " should be visible");
226     }
227     this.assertVisible(element.parentNode);
228   }
229 }
230
231 Test.Unit.Testcase = Class.create();
232 Object.extend(Object.extend(Test.Unit.Testcase.prototype, Test.Unit.Assertions.prototype), {
233   initialize: function(name, test, setup, teardown) {
234     Test.Unit.Assertions.prototype.initialize.bind(this)();
235     this.name           = name;
236     this.test           = test || function() {};
237     this.setup          = setup || function() {};
238     this.teardown       = teardown || function() {};
239     this.isWaitingForAjax = false;
240     this.ajaxTimeout    = 1000;
241   },
242   waitForAjax: function(nextPart) {
243     this.isWaitingForAjax = true;
244     this.test = nextPart;
245   },
246   run: function() {
247     this.isWaitingForAjax = false;
248     try {
249       try {
250         this.setup.bind(this)();
251         this.test.bind(this)();
252       } finally {
253         if(!this.waitingForAjax) {
254           this.teardown.bind(this)();
255         }
256       }
257     }
258     catch(e) { this.error(e); }
259   }
260 });
Note: See TracBrowser for help on using the browser.