Skip to content

Instantly share code, notes, and snippets.

@ef4
Created September 15, 2011 18:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ef4/1220137 to your computer and use it in GitHub Desktop.
Save ef4/1220137 to your computer and use it in GitHub Desktop.
Minimal Jasmine Setup for Browser & Console with Rails 3.1
//
// Jasmine Reporter for theubyracer on the console
//
// Originally adapted from https://github.com/mhevery/jasmine-node
//
// Helpers
//
(function(){
function noop() {}
printRunnerResults = function(runner){
var results = runner.results();
var suites = runner.suites();
var msg = '';
msg += suites.length + ' test' + ((suites.length === 1) ? '' : 's') + ', ';
msg += results.totalCount + ' assertion' + ((results.totalCount === 1) ? '' : 's') + ', ';
msg += results.failedCount + ' failure' + ((results.failedCount === 1) ? '' : 's') + '\n';
return msg;
};
ANSIColors = {
pass: function() { return '\033[32m'; }, // Green
fail: function() { return '\033[31m'; }, // Red
neutral: function() { return '\033[0m'; } // Normal
};
NoColors = {
pass: function() { return ''; },
fail: function() { return ''; },
neutral: function() { return ''; }
};
//
// Reporter implementation
//
TerminalReporter = function(config) {
this.print_ = config.print;
this.isVerbose_ = config.verbose || false;
this.onComplete_ = config.onComplete || noop;
this.color_ = config.color? ANSIColors: NoColors;
this.stackFilter = config.stackFilter || function(t) { return t; }
this.columnCounter_ = 0;
this.log_ = [];
this.start_ = 0;
};
TerminalReporter.prototype = {
// Public Methods //
log: noop,
reportSpecStarting: noop,
reportRunnerStarting: function(runner) {
this.printLine_('Started');
this.start_ = Number(new Date);
},
reportSuiteResults: function(suite) {
var specResults = suite.results();
var path = [];
while(suite) {
path.unshift(suite.description);
suite = suite.parentSuite;
}
var description = path.join(' ');
if (this.isVerbose_)
this.log_.push('Spec ' + description);
outerThis = this;
specResults.items_.forEach(function(spec){
if (spec.failedCount > 0 && spec.description) {
if (!outerThis.isVerbose_)
outerThis.log_.push(description);
outerThis.log_.push(' it ' + spec.description);
spec.items_.forEach(function(result){
if (!result.passed_)
outerThis.log_.push(' ' + outerThis.stackFilter(result.trace.stack) + '\n');
});
} else {
if (outerThis.isVerbose_)
outerThis.log_.push(' it ' + spec.description);
}
});
},
reportSpecResults: function(spec) {
var result = spec.results();
var msg = '';
if (result.passed()) {
msg = this.stringWithColor_('.', this.color_.pass());
// } else if (result.skipped) { TODO: Research why "result.skipped" returns false when "xit" is called on a spec?
// msg = (colors) ? (ansi.yellow + '*' + ansi.none) : '*';
} else {
msg = this.stringWithColor_('F', this.color_.fail());
}
this.print_(msg);
if (this.columnCounter_++ < 50) return;
this.columnCounter_ = 0;
this.print_('\n');
},
reportRunnerResults: function(runner) {
var elapsed = (Number(new Date) - this.start_) / 1000;
var owner = this;
this.printLine_('\n');
this.log_.forEach(function(entry) {
owner.printLine_(entry);
});
this.printLine_('Finished in ' + elapsed + ' seconds');
var summary = printRunnerResults(runner);
if(runner.results().failedCount === 0 ) {
this.printLine_(this.stringWithColor_(summary, this.color_.pass()));
}
else {
this.printLine_(this.stringWithColor_(summary, this.color_.fail()));
}
this.onComplete_(runner, this.log_);
},
// Helper Methods //
stringWithColor_: function(str, color) {
return (color || this.color_.neutral()) + str + this.color_.neutral();
},
printLine_: function(str) {
this.print_(str);
this.print_('\n');
}
};
window.TerminalReporter = TerminalReporter;
})();
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Jasmine Spec Runner</title>
<link rel="shortcut icon" type="image/png" href="/assets/jasmine-1.1.0/jasmine_favicon.png">
<link rel="stylesheet" type="text/css" href="/assets/jasmine-1.1.0/jasmine.css">
<script type="text/javascript" src="/assets/jasmine-1.1.0/jasmine.js"></script>
<script type="text/javascript" src="/assets/jasmine-1.1.0/jasmine-html.js"></script>
<script type="text/javascript" src="/assets/test"></script>
<script type="text/javascript">
(function() {
var jasmineEnv = jasmine.getEnv();
jasmineEnv.updateInterval = 1000;
var trivialReporter = new jasmine.TrivialReporter();
jasmineEnv.addReporter(trivialReporter);
jasmineEnv.specFilter = function(spec) {
return trivialReporter.specFilter(spec);
};
var currentWindowOnload = window.onload;
window.onload = function() {
if (currentWindowOnload) {
currentWindowOnload();
}
execJasmine();
};
function execJasmine() {
jasmineEnv.execute();
}
})();
</script>
</head>
<body>
</body>
</html>
require 'v8'
class JasmineContext
attr_reader :failed_count
def initialize
@waiting = []
@ctxt = V8::Context.new
# Jasmine just looks for this to exist, it doesn't need to do anything
@ctxt['window'] = @ctxt
# Expose methods to v8
@ctxt['setTimeout'] = method(:setTimeout)
@ctxt['puts'] = method(:puts)
@ctxt['exitStatus'] = method(:exitStatus)
# Jasmine tries to hook these, but doesn't really need them unless
# your code-under-test uses them.
@ctxt['clearTimeout'] = proc { raise Exception, 'unimplemented' }
@ctxt['setInterval'] = proc { raise Exception, 'unimplemented' }
@ctxt['clearInterval'] = proc { raise Exception, 'unimplemented' }
end
def load_asset(name)
@ctxt.eval(Rails.application.assets.find_asset(name).to_s)
end
def setTimeout(f, ms)
@waiting.push([Time.now + ms/1000.0, f])
# Re-sorting from scratch every time is wasteful, but doesn't
# really matter for a small number of pending timeouts. We could
# replace with a priority queue for much better efficiency.
@waiting.sort_by! {|time, func| time }
end
def runUntilDone
until @waiting.empty?
time, func = @waiting.shift
while time > Time.now
sleep(time - Time.now)
end
func.call()
end
end
def method_missing(name, *args)
@ctxt.send(name, *args)
end
def exitStatus(runner, log)
@failed_count = runner.results()['failedCount']
end
end
namespace :test do
task :javascript => ['environment'] do
context = JasmineContext.new
context.load_asset('jasmine-1.1.0/jasmine.js')
context.load_asset('jasmine-reporter.js')
context.load_asset('test')
context.eval <<-JS
jasmineEnv = jasmine.getEnv();
jasmineEnv.addReporter(new TerminalReporter({print: puts, color: true, onComplete: exitStatus}));
jasmineEnv.execute();
JS
context.runUntilDone
unless context.failed_count == 0
raise Exception, "#{context.failed_count} javascript tests failed"
end
end
end
task :test => ['test:javascript']
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment