Browse files

javascript_test: update prototype/unittest.js to latest 1.6.0.1 versi…

…ons, generate public/javascripts/name.js file when using the generator, add option to use application-provided prototype.js file instead of the one that comes with the pluging. Fixes #10662, #10667, #10669, #10694, #10697 and #10732.
  • Loading branch information...
1 parent 2634e25 commit cbbe7d69aeab43a5538cf36def38b9936c1d77a0 @madrobby madrobby committed Jan 9, 2008
View
9 CHANGELOG
@@ -1,5 +1,14 @@
*SVN*
+* Update to prototype + unittest 1.6.0.1 [nicwilliams]
+ The prototype unittest.js had evolved away from scriptaculous's verision.
+ NOTE: this involves the removal of the trial BDD system. Its possible people
+ are actually using this.
+
+* Generates a public/javascripts/name.js library file when generating the test file [nicwilliams]
+
+* Add -A/--use-app-assets generator option to allow usage of app's own prototype lib. [nicwillams]
+
* Add JavaScriptTest namespace wrapper
* Added test for JavaScript test runner
View
3,997 assets/prototype.js
2,963 additions, 1,034 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
614 assets/unittest.js
@@ -35,16 +35,14 @@ Event.simulateMouse = function(element, eventName) {
false, false, false, false, 0, $(element));
if(this.mark) Element.remove(this.mark);
- this.mark = document.createElement('div');
+
+ var style = 'position: absolute; width: 5px; height: 5px;' +
+ 'top: #{pointerY}px; left: #{pointerX}px;'.interpolate(options) +
+ 'border-top: 1px solid red; border-left: 1px solid red;'
+
+ this.mark = new Element('div', { style: style });
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));
@@ -78,203 +76,164 @@ Event.simulateKeys = function(element, command) {
}
};
-var Test = {}
-Test.Unit = {};
-
-// security exception workaround
-Test.Unit.inspect = Object.inspect;
+var Test = {
+ Unit: {
+ inspect: Object.inspect // security exception workaround
+ }
+};
-Test.Unit.Logger = Class.create();
-Test.Unit.Logger.prototype = {
- initialize: function(log) {
- this.log = $(log);
- if (this.log) {
- this._createLogTable();
- }
+Test.Unit.Logger = Class.create({
+ initialize: function(element) {
+ this.element = $(element);
+ if (this.element) 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);
+ if (!this.element) return;
+ this.element.down('tbody').insert('<tr><td>' + testName + '</td><td></td><td></td></tr>');
},
+
+ setStatus: function(status) {
+ this.getLastLogLine().addClassName(status).down('td', 1).update(status);
+ },
+
finish: function(status, summary) {
- if (!this.log) return;
- this.lastLogLine.className = status;
- this.statusCell.innerHTML = status;
- this.messageCell.innerHTML = this._toHTML(summary);
+ if (!this.element) return;
+ this.setStatus(status);
+ this.message(summary);
},
+
message: function(message) {
- if (!this.log) return;
- this.messageCell.innerHTML = this._toHTML(message);
+ if (!this.element) return;
+ this.getMessageCell().update(this._toHTML(message));
},
+
summary: function(summary) {
- if (!this.log) return;
- this.logsummary.innerHTML = this._toHTML(summary);
+ if (!this.element) return;
+ this.element.down('div').update(this._toHTML(summary));
+ },
+
+ getLastLogLine: function() {
+ return this.element.select('tr').last()
},
+
+ getMessageCell: function() {
+ return this.getLastLogLine().down('td', 2);
+ },
+
_createLogTable: function() {
- this.log.innerHTML =
- '<div id="logsummary"></div>' +
- '<table id="logtable">' +
+ var html = '<div class="logsummary">running...</div>' +
+ '<table class="logtable">' +
'<thead><tr><th>Status</th><th>Test</th><th>Message</th></tr></thead>' +
- '<tbody id="loglines"></tbody>' +
+ '<tbody class="loglines"></tbody>' +
'</table>';
- this.logsummary = $('logsummary')
- this.loglines = $('loglines');
+ this.element.update(html);
+
},
+
+ appendActionButtons: function(actions) {
+ actions = $H(actions);
+ if (!actions.any()) return;
+ var div = new Element("div", {className: 'action_buttons'});
+ actions.inject(div, function(container, action) {
+ var button = new Element("input").setValue(action.key).observe("click", action.value);
+ button.type = "button";
+ return container.insert(button);
+ });
+ this.getMessageCell().insert(div);
+ },
+
_toHTML: function(txt) {
return txt.escapeHTML().replace(/\n/g,"<br/>");
}
-}
+});
-Test.Unit.Runner = Class.create();
-Test.Unit.Runner.prototype = {
+Test.Unit.Runner = Class.create({
initialize: function(testcases) {
- this.options = Object.extend({
+ var options = 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(
- this.options.context ? ' -> ' + this.options.titles[testcase] : testcase,
- testcases[testcase], testcases["setup"], testcases["teardown"]
- ));
- }
- }
- }
- }
+
+ options.resultsURL = this.queryParams.resultsURL;
+ options.testLog = $(options.testLog);
+
+ this.tests = this.getTests(testcases);
this.currentTest = 0;
- this.logger = new Test.Unit.Logger(this.options.testLog);
- setTimeout(this.runTests.bind(this), 1000);
+ this.logger = new Test.Unit.Logger(options.testLog);
+ Event.observe(window, "load", function() {
+ this.runTests.bind(this).delay(0.1);
+ }.bind(this));
},
- parseResultsURLQueryParameter: function() {
- return window.location.search.parseQuery()["resultsURL"];
+
+ queryParams: window.location.search.parseQuery(),
+
+ getTests: function(testcases) {
+ var tests, options = this.options;
+ if (this.queryParams.tests) tests = this.queryParams.tests.split(',');
+ else if (options.tests) tests = options.tests;
+ else if (options.test) tests = [option.test];
+ else tests = Object.keys(testcases).grep(/^test/);
+
+ return tests.map(function(test) {
+ if (testcases[test])
+ return new Test.Unit.Testcase(test, testcases[test], testcases.setup, testcases.teardown);
+ }).compact();
},
- // 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";
- }
+ var results = {
+ tests: this.tests.length,
+ assertions: 0,
+ failures: 0,
+ errors: 0
+ };
+
+ return this.tests.inject(results, function(results, test) {
+ results.assertions += test.assertions;
+ results.failures += test.failures;
+ results.errors += test.errors;
+ return results;
+ });
},
+
postResults: function() {
if (this.options.resultsURL) {
new Ajax.Request(this.options.resultsURL,
- { method: 'get', parameters: 'result=' + this.getResult(), asynchronous: false });
+ { method: 'get', parameters: 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);
- }
+ var test = this.tests[this.currentTest], actions;
+
+ if (!test) return this.finish();
+ 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();
+ return;
}
+
+ this.logger.finish(test.status(), test.summary());
+ if (actions = test.actions) this.logger.appendActionButtons(actions);
+ this.currentTest++;
+ // tail recursive, hopefully the browser will skip the stackframe
+ this.runTests();
},
+
+ finish: function() {
+ this.postResults();
+ this.logger.summary(this.summary());
+ },
+
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.options.context ? this.options.context + ': ': '') +
- this.tests.length + " tests, " +
- assertions + " assertions, " +
- failures + " failures, " +
- errors + " errors");
+ return '#{tests} tests, #{assertions} assertions, #{failures} failures, #{errors} errors'
+ .interpolate(this.getResult());
}
-}
+});
-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);
- },
- info: function(message) {
- this.messages.push("Info: " + 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';
- },
+Test.Unit.Assertions = {
assert: function(expression) {
var message = arguments[1] || 'assert: got "' + Test.Unit.inspect(expression) + '"';
try { expression ? this.pass() :
@@ -288,18 +247,60 @@ Test.Unit.Assertions.prototype = {
'", 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); }
+ },
assertEnumEqual: function(expected, actual) {
var message = arguments[2] || "assertEnumEqual";
- try { $A(expected).length == $A(actual).length &&
+ expected = $A(expected);
+ actual = $A(actual);
+ try { expected.length == actual.length &&
expected.zip(actual).all(function(pair) { return pair[0] == pair[1] }) ?
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) + '"'); }
+ assertEnumNotEqual: function(expected, actual) {
+ var message = arguments[2] || "assertEnumEqual";
+ expected = $A(expected);
+ actual = $A(actual);
+ try { expected.length != actual.length ||
+ expected.zip(actual).any(function(pair) { return pair[0] != pair[1] }) ?
+ this.pass() : this.fail(message + ': ' + Test.Unit.inspect(expected) +
+ ' was the same as ' + Test.Unit.inspect(actual)); }
+ catch(e) { this.error(e); }
+ },
+ assertHashEqual: function(expected, actual) {
+ var message = arguments[2] || "assertHashEqual";
+ expected = $H(expected);
+ actual = $H(actual);
+ var expected_array = expected.toArray().sort(), actual_array = actual.toArray().sort();
+ // from now we recursively zip & compare nested arrays
+ try { expected_array.length == actual_array.length &&
+ expected_array.zip(actual_array).all(function(pair) {
+ return pair.all(function(i){ return i && i.constructor == Array }) ?
+ pair[0].zip(pair[1]).all(arguments.callee) : pair[0] == pair[1];
+ }) ?
+ this.pass() : this.fail(message + ': expected ' + Test.Unit.inspect(expected) +
+ ', actual ' + Test.Unit.inspect(actual)); }
+ catch(e) { this.error(e); }
+ },
+ assertHashNotEqual: function(expected, actual) {
+ var message = arguments[2] || "assertHashEqual";
+ expected = $H(expected);
+ actual = $H(actual);
+ var expected_array = expected.toArray().sort(), actual_array = actual.toArray().sort();
+ // from now we recursively zip & compare nested arrays
+ try { !(expected_array.length == actual_array.length &&
+ expected_array.zip(actual_array).all(function(pair) {
+ return pair.all(function(i){ return i && i.constructor == Array }) ?
+ pair[0].zip(pair[1]).all(arguments.callee) : pair[0] == pair[1];
+ })) ?
+ this.pass() : this.fail(message + ': ' + Test.Unit.inspect(expected) +
+ ' was the same as ' + Test.Unit.inspect(actual)); }
catch(e) { this.error(e); }
},
assertIdentical: function(expected, actual) {
@@ -318,41 +319,58 @@ Test.Unit.Assertions.prototype = {
},
assertNull: function(obj) {
var message = arguments[1] || 'assertNull'
- try { (obj==null) ? this.pass() :
+ try { (obj===null) ? this.pass() :
+ this.fail(message + ': got "' + Test.Unit.inspect(obj) + '"'); }
+ catch(e) { this.error(e); }
+ },
+ assertNotNull: function(obj) {
+ var message = arguments[1] || 'assertNotNull'
+ try { (obj!==null) ? this.pass() :
+ this.fail(message + ': got "' + Test.Unit.inspect(obj) + '"'); }
+ catch(e) { this.error(e); }
+ },
+ assertUndefined: function(obj) {
+ var message = arguments[1] || 'assertUndefined'
+ try { (typeof obj=="undefined") ? this.pass() :
+ this.fail(message + ': got "' + Test.Unit.inspect(obj) + '"'); }
+ catch(e) { this.error(e); }
+ },
+ assertNotUndefined: function(obj) {
+ var message = arguments[1] || 'assertNotUndefined'
+ try { (typeof obj != "undefined") ? this.pass() :
+ this.fail(message + ': got "' + Test.Unit.inspect(obj) + '"'); }
+ catch(e) { this.error(e); }
+ },
+ assertNullOrUndefined: function(obj){
+ var message = arguments[1] || 'assertNullOrUndefined'
+ try { (obj==null) ? this.pass() :
+ this.fail(message + ': got "' + Test.Unit.inspect(obj) + '"'); }
+ catch(e) { this.error(e); }
+ },
+ assertNotNullOrUndefined: function(obj){
+ var message = arguments[1] || 'assertNotNullOrUndefined'
+ try { (obj!=null) ? this.pass() :
this.fail(message + ': got "' + Test.Unit.inspect(obj) + '"'); }
catch(e) { this.error(e); }
},
assertMatch: function(expected, actual) {
var message = arguments[2] || 'assertMatch';
var regex = new RegExp(expected);
- try { (regex.exec(actual)) ? this.pass() :
+ try { regex.exec(actual) ? this.pass() :
this.fail(message + ' : regex: "' + Test.Unit.inspect(expected) + ' did not match: ' + Test.Unit.inspect(actual) + '"'); }
catch(e) { this.error(e); }
},
+ assertNoMatch: function(expected, actual) {
+ var message = arguments[2] || 'assertMatch';
+ var regex = new RegExp(expected);
+ try { !regex.exec(actual) ? this.pass() :
+ this.fail(message + ' : regex: "' + Test.Unit.inspect(expected) + ' matched: ' + Test.Unit.inspect(actual) + '"'); }
+ 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);
- },
- assertType: function(expected, actual) {
- var message = arguments[2] || 'assertType';
- try {
- (actual.constructor == expected) ? this.pass() :
- this.fail(message + ': expected "' + Test.Unit.inspect(expected) +
- '", actual "' + (actual.constructor) + '"'); }
- catch(e) { this.error(e); }
- },
- assertNotOfType: function(expected, actual) {
- var message = arguments[2] || 'assertNotOfType';
- try {
- (actual.constructor != expected) ? this.pass() :
- this.fail(message + ': expected "' + Test.Unit.inspect(expected) +
- '", actual "' + (actual.constructor) + '"'); }
- catch(e) { this.error(e); }
- },
assertInstanceOf: function(expected, actual) {
var message = arguments[2] || 'assertInstanceOf';
try {
@@ -374,24 +392,6 @@ Test.Unit.Assertions.prototype = {
this.fail(message + ": object doesn't respond to [" + method + "]"); }
catch(e) { this.error(e); }
},
- assertReturnsTrue: function(method, obj) {
- var message = arguments[2] || 'assertReturnsTrue';
- try {
- var m = obj[method];
- if(!m) m = obj['is'+method.charAt(0).toUpperCase()+method.slice(1)];
- m() ? this.pass() :
- this.fail(message + ": method returned false"); }
- catch(e) { this.error(e); }
- },
- assertReturnsFalse: function(method, obj) {
- var message = arguments[2] || 'assertReturnsFalse';
- try {
- var m = obj[method];
- if(!m) m = obj['is'+method.charAt(0).toUpperCase()+method.slice(1)];
- !m() ? this.pass() :
- this.fail(message + ": method returned true"); }
- catch(e) { this.error(e); }
- },
assertRaise: function(exceptionName, method) {
var message = arguments[2] || 'assertRaise';
try {
@@ -401,28 +401,14 @@ Test.Unit.Assertions.prototype = {
(e.name==exceptionName) ? this.pass() : this.error(e);
}
},
- assertElementsMatch: function() {
- var expressions = $A(arguments), elements = $A(expressions.shift());
- if (elements.length != expressions.length) {
- this.fail('assertElementsMatch: size mismatch: ' + elements.length + ' elements, ' + expressions.length + ' expressions');
- return false;
+ assertNothingRaised: function(method) {
+ var message = arguments[1] || 'assertNothingRaised';
+ try {
+ method();
+ this.pass();
+ } catch (e) {
+ this.fail(message + ": " + e.toString());
}
- elements.zip(expressions).all(function(pair, index) {
- var element = $(pair.first()), expression = pair.last();
- if (element.match(expression)) return true;
- this.fail('assertElementsMatch: (in index ' + index + ') expected ' + expression.inspect() + ' but got ' + element.inspect());
- }.bind(this)) && this.pass();
- },
- assertElementMatches: function(element, expression) {
- this.assertElementsMatch([element], expression);
- },
- benchmark: function(operation, iterations) {
- var startAt = new Date();
- (iterations || 1).times(operation);
- var timeTaken = ((new Date())-startAt);
- this.info((arguments[2] || 'Operation') + ' finished ' +
- iterations + ' iterations in ' + (timeTaken/1000)+'s' );
- return timeTaken;
},
_isVisible: function(element) {
element = $(element);
@@ -439,112 +425,106 @@ Test.Unit.Assertions.prototype = {
assertVisible: function(element) {
this.assert(this._isVisible(element), Test.Unit.inspect(element) + " was not visible. " + ("" || arguments[1]));
},
- benchmark: function(operation, iterations) {
- var startAt = new Date();
- (iterations || 1).times(operation);
- var timeTaken = ((new Date())-startAt);
- this.info((arguments[2] || 'Operation') + ' finished ' +
- iterations + ' iterations in ' + (timeTaken/1000)+'s' );
- return timeTaken;
+ assertElementsMatch: function() {
+ var expressions = $A(arguments), elements = $A(expressions.shift());
+ if (elements.length != expressions.length) {
+ this.fail('assertElementsMatch: size mismatch: ' + elements.length + ' elements, ' + expressions.length + ' expressions (' + expressions.inspect() + ')');
+ return false;
+ }
+ elements.zip(expressions).all(function(pair, index) {
+ var element = $(pair.first()), expression = pair.last();
+ if (element.match(expression)) return true;
+ this.fail('assertElementsMatch: (in index ' + index + ') expected ' + expression.inspect() + ' but got ' + element.inspect());
+ }.bind(this)) && this.pass();
+ },
+ assertElementMatches: function(element, expression) {
+ this.assertElementsMatch([element], expression);
}
-}
+};
-Test.Unit.Testcase = Class.create();
-Object.extend(Object.extend(Test.Unit.Testcase.prototype, Test.Unit.Assertions.prototype), {
+Test.Unit.Testcase = Class.create(Test.Unit.Assertions, {
initialize: function(name, test, setup, teardown) {
- Test.Unit.Assertions.prototype.initialize.bind(this)();
this.name = name;
-
- if(typeof test == 'string') {
- test = test.gsub(/(\.should[^\(]+\()/,'#{0}this,');
- test = test.gsub(/(\.should[^\(]+)\(this,\)/,'#{1}(this)');
- this.test = function() {
- eval('with(this){'+test+'}');
- }
- } else {
- this.test = test || function() {};
- }
-
- this.setup = setup || function() {};
- this.teardown = teardown || function() {};
- this.isWaiting = false;
- this.timeToWait = 1000;
+ this.test = test || Prototype.emptyFunction;
+ this.setup = setup || Prototype.emptyFunction;
+ this.teardown = teardown || Prototype.emptyFunction;
+ this.messages = [];
+ this.actions = {};
},
+
+ isWaiting: false,
+ timeToWait: 1000,
+ assertions: 0,
+ failures: 0,
+ errors: 0,
+ isRunningFromRake: window.location.port == 4711,
+
wait: function(time, nextPart) {
this.isWaiting = true;
this.test = nextPart;
this.timeToWait = time;
},
- run: function() {
+
+ run: function(rethrow) {
try {
try {
- if (!this.isWaiting) this.setup.bind(this)();
+ if (!this.isWaiting) this.setup();
this.isWaiting = false;
- this.test.bind(this)();
+ this.test();
} finally {
if(!this.isWaiting) {
- this.teardown.bind(this)();
+ this.teardown();
}
}
}
- catch(e) { this.error(e); }
- }
-});
-
-// *EXPERIMENTAL* BDD-style testing to please non-technical folk
-// This draws many ideas from RSpec http://rspec.rubyforge.org/
-
-Test.setupBDDExtensionMethods = function(){
- var METHODMAP = {
- shouldEqual: 'assertEqual',
- shouldNotEqual: 'assertNotEqual',
- shouldEqualEnum: 'assertEnumEqual',
- shouldBeA: 'assertType',
- shouldNotBeA: 'assertNotOfType',
- shouldBeAn: 'assertType',
- shouldNotBeAn: 'assertNotOfType',
- shouldBeNull: 'assertNull',
- shouldNotBeNull: 'assertNotNull',
-
- shouldBe: 'assertReturnsTrue',
- shouldNotBe: 'assertReturnsFalse',
- shouldRespondTo: 'assertRespondsTo'
- };
- Test.BDDMethods = {};
- for(m in METHODMAP) {
- Test.BDDMethods[m] = eval(
- 'function(){'+
- 'var args = $A(arguments);'+
- 'var scope = args.shift();'+
- 'scope.'+METHODMAP[m]+'.apply(scope,(args || []).concat([this])); }');
- }
- [Array.prototype, String.prototype, Number.prototype].each(
- function(p){ Object.extend(p, Test.BDDMethods) }
- );
-}
+ catch(e) {
+ if (rethrow) throw e;
+ this.error(e, this);
+ }
+ },
+
+ summary: function() {
+ var msg = '#{assertions} assertions, #{failures} failures, #{errors} errors\n';
+ return msg.interpolate(this) + this.messages.join("\n");
+ },
-Test.context = function(name, spec, log){
- Test.setupBDDExtensionMethods();
+ pass: function() {
+ this.assertions++;
+ },
- var compiledSpec = {};
- var titles = {};
- for(specName in spec) {
- switch(specName){
- case "setup":
- case "teardown":
- compiledSpec[specName] = spec[specName];
- break;
- default:
- var testName = 'test'+specName.gsub(/\s+/,'-').camelize();
- var body = spec[specName].toString().split('\n').slice(1);
- if(/^\{/.test(body[0])) body = body.slice(1);
- body.pop();
- body = body.map(function(statement){
- return statement.strip()
- });
- compiledSpec[testName] = body.join('\n');
- titles[testName] = specName;
+ fail: function(message) {
+ this.failures++;
+ var line = "";
+ try {
+ throw new Error("stack");
+ } catch(e){
+ line = (/\.html:(\d+)/.exec(e.stack || '') || ['',''])[1];
}
+ this.messages.push("Failure: " + message + (line ? " Line #" + line : ""));
+ },
+
+ info: function(message) {
+ this.messages.push("Info: " + message);
+ },
+
+ error: function(error, test) {
+ this.errors++;
+ this.actions['retry with throw'] = function() { test.run(true) };
+ 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';
+ },
+
+ benchmark: function(operation, iterations) {
+ var startAt = new Date();
+ (iterations || 1).times(operation);
+ var timeTaken = ((new Date())-startAt);
+ this.info((arguments[2] || 'Operation') + ' finished ' +
+ iterations + ' iterations in ' + (timeTaken/1000)+'s' );
+ return timeTaken;
}
- new Test.Unit.Runner(compiledSpec, { titles: titles, testLog: log || 'testlog', context: name });
-};
+});
View
13 generators/javascript_test/javascript_test_generator.rb
@@ -1,9 +1,22 @@
class JavascriptTestGenerator < Rails::Generator::NamedBase
+ default_options :app_assets => false
def manifest
record do |m|
m.directory File.join("test","javascript")
m.template 'javascript_test.html', File.join('test/javascript', "#{name}_test.html")
end
end
+
+ protected
+ def banner
+ "Usage: #{$0} javascript_test libary_file [--use-app-assets]"
+ end
+
+ def add_options!(opt)
+ opt.separator ''
+ opt.separator 'Options:'
+ opt.on("-A", "--use-app-assets",
+ "Uses application's own version of prototype.js instead of the plugins") { |v| options[:app_assets] = v }
+ end
end
View
19 generators/javascript_test/templates/javascript_test.html
@@ -4,7 +4,11 @@
<head>
<title>JavaScript unit test file</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <% if options[:app_assets] -%>
+ <script src="../../public/javascripts/prototype.js" type="text/javascript"></script>
+ <% else -%>
<script src="assets/prototype.js" type="text/javascript"></script>
+ <% end -%>
<script src="assets/unittest.js" type="text/javascript"></script>
<script src="../../public/javascripts/<%= name %>.js" type="text/javascript"></script>
@@ -22,9 +26,11 @@
</p>
</div>
- <!-- Log output -->
- <div id="testlog"> </div>
-
+ <!-- Log output (one per Runner, via {testLog: "testlog"} option)-->
+ <div id="testlog"></div>
+
+ <!-- Put or load sample/test html here (load via sampleLoad(file) in setup() methods) -->
+ <div id="sample"></div>
</div>
<script type="text/javascript">
@@ -46,7 +52,12 @@
assert(true);
}}
- }, "testlog");
+ }, {testLog: "testlog"});
+ // For each Test.UnitRunner instance, specify the element id where results will be
+ // published; e.g. <div id="testlog"/> above.
+ // That is, you can have multiple "new Test.Unit.Runner() { ... }" on this page, just
+ // create more <div id="testlog2"></div> etc, and pass the element id to the hash above:
+ // e.g. {testLog: "testlog2"}
// ]]>
</script>
</body>

0 comments on commit cbbe7d6

Please sign in to comment.