diff --git a/bin/jasmine-headless-webkit b/bin/jasmine-headless-webkit index 6e7d154..3a181a3 100755 --- a/bin/jasmine-headless-webkit +++ b/bin/jasmine-headless-webkit @@ -63,6 +63,7 @@ end puts "Running Jasmine specs..." files = %w{jasmine jasmine-html}.collect { |name| File.join(Jasmine.root, "lib/#{name}.js") } +files << File.join(gem_dir, 'jasmine/jasmine.headless-reporter.js') files += [ [ 'src_files', 'src_dir' ], [ 'stylesheets', 'src_dir' ], [ 'helpers', 'spec_dir' ], [ 'spec_files', 'spec_dir' ] ].collect do |searches, root| data[searches] ||= DEFAULTS[searches] diff --git a/coffee.watchr b/coffee.watchr new file mode 100644 index 0000000..88d3123 --- /dev/null +++ b/coffee.watchr @@ -0,0 +1,18 @@ +require 'coffee-script' + +FILE = 'jasmine/jasmine.headless-reporter.coffee' if !self.class.const_defined?(:FILE) +TARGET = FILE.gsub('.coffee', '.js') if !self.class.const_defined?(:TARGET) + +watch(FILE) { coffee } + +def coffee + begin + File.open(TARGET, 'w') { |fh| fh.print CoffeeScript.compile File.open(FILE) } + puts "Wrote #{TARGET}" + rescue Exception => e + puts e.message + end +end + +coffee + diff --git a/ext/jasmine-webkit-specrunner/specrunner.cpp b/ext/jasmine-webkit-specrunner/specrunner.cpp index fb2307a..9f0ea4b 100644 --- a/ext/jasmine-webkit-specrunner/specrunner.cpp +++ b/ext/jasmine-webkit-specrunner/specrunner.cpp @@ -66,7 +66,11 @@ public: void setColors(bool colors); public slots: void log(const QString &msg); - void specLog(int indent, const QString &msg, const QString &clazz); + void specPassed(); + void specFailed(); + void printName(const QString &name); + void printResult(const QString &result); + void finishSuite(const QString &duration, const QString &total, const QString& failed); private slots: void watch(bool ok); void errorLog(const QString &msg, int lineNumber, const QString &sourceID); @@ -81,6 +85,8 @@ private: bool hasErrors; bool usedConsole; bool showColors; + bool isFinished; + bool didFail; void red(); void green(); @@ -94,6 +100,8 @@ HeadlessSpecRunner::HeadlessSpecRunner() , hasErrors(false) , usedConsole(false) , showColors(false) + , isFinished(false) + , didFail(false) { m_page.settings()->enablePersistentStorage(); connect(&m_page, SIGNAL(loadFinished(bool)), this, SLOT(watch(bool))); @@ -104,7 +112,7 @@ HeadlessSpecRunner::HeadlessSpecRunner() void HeadlessSpecRunner::load(const QString &spec) { m_ticker.stop(); - m_page.mainFrame()->addToJavaScriptWindowObject("debug", this); + m_page.mainFrame()->addToJavaScriptWindowObject("JHW", this); m_page.mainFrame()->load(spec); m_page.setPreferredContentsSize(QSize(1024, 600)); } @@ -152,6 +160,23 @@ void HeadlessSpecRunner::clear() if (showColors) std::cout << "\033[m"; } +void HeadlessSpecRunner::specPassed() +{ + green(); + std::cout << '.'; + clear(); + fflush(stdout); +} + +void HeadlessSpecRunner::specFailed() +{ + didFail = true; + red(); + std::cout << 'F'; + clear(); + fflush(stdout); +} + void HeadlessSpecRunner::errorLog(const QString &msg, int lineNumber, const QString &sourceID) { red(); @@ -183,33 +208,37 @@ void HeadlessSpecRunner::log(const QString &msg) std::cout << std::endl; } -void HeadlessSpecRunner::specLog(int indent, const QString &msg, const QString &clazz) +void HeadlessSpecRunner::printName(const QString &name) { - for (int i = 0; i < indent; ++i) - std::cout << " "; - if ( clazz.endsWith("fail") ) { - red(); - } else { - yellow(); - } - std::cout << qPrintable(msg); - clear(); - std::cout << std::endl; + std::cout << std::endl << std::endl; + red(); + std::cout << qPrintable(name) << std::endl; + clear(); } -#define DUMP_MSG "(function(n, i) { \ - if (n.toString() === '[object NodeList]') { \ - for (var c = 0; c < n.length; ++c) arguments.callee(n[c], i); return \ - }\ - if (n.className === 'description' || n.className == 'resultMessage fail') {\ - debug.specLog(i, n.textContent, n.className);\ - }\ - var e = n.firstElementChild;\ - while (e) {\ - arguments.callee(e, i + 1); e = e.nextElementSibling; \ - }\ - n.className = '';\ -})(document.getElementsByClassName('suite failed'), 0);" +void HeadlessSpecRunner::printResult(const QString &result) +{ + red(); + std::cout << " " << qPrintable(result) << std::endl; + clear(); +} + +void HeadlessSpecRunner::finishSuite(const QString &duration, const QString &total, const QString& failed) +{ + std::cout << std::endl; + if (didFail) { + red(); + std::cout << "FAIL: "; + } else { + green(); + std::cout << "PASS: "; + } + + std::cout << qPrintable(total) << " tests, " << qPrintable(failed) << " failures, " << qPrintable(duration) << " secs." << std::endl; + clear(); + + isFinished = true; +} void HeadlessSpecRunner::timerEvent(QTimerEvent *event) { @@ -222,28 +251,17 @@ void HeadlessSpecRunner::timerEvent(QTimerEvent *event) QApplication::instance()->exit(1); if (!hasErrors) { - if (!hasElement(".jasmine_reporter") && !hasElement(".runner.running")) - return; + if (isFinished) { + int exitCode = 0; + if (didFail) { + exitCode = 1; + } else { + if (usedConsole) { + exitCode = 2; + } + } - if (hasElement(".runner.passed")) { - QWebElement desc = m_page.mainFrame()->findFirstElement(".description"); - green(); - std::cout << "PASS: " << qPrintable(desc.toPlainText()); - clear(); - std::cout << std::endl; - QApplication::instance()->exit(usedConsole ? 2 : 0); - return; - } - - if (hasElement(".runner.failed")) { - QWebElement desc = m_page.mainFrame()->findFirstElement(".description"); - red(); - std::cout << "FAIL: " << qPrintable(desc.toPlainText()); - clear(); - std::cout << std::endl; - m_page.mainFrame()->evaluateJavaScript(DUMP_MSG); - QApplication::instance()->exit(1); - return; + QApplication::instance()->exit(exitCode); } if (m_runs > 30) { diff --git a/jasmine/jasmine.headless-reporter.coffee b/jasmine/jasmine.headless-reporter.coffee new file mode 100644 index 0000000..f03b71c --- /dev/null +++ b/jasmine/jasmine.headless-reporter.coffee @@ -0,0 +1,45 @@ +if !jasmine? + throw new Exception("jasmine not laoded!") + +class HeadlessReporterResult + constructor: (name) -> + @name = name + @results = [] + print: -> + JHW.printName(@name) + for result in @results + do (result) => + JHW.printResult(result) + +class jasmine.HeadlessReporter + constructor: -> + @results = [] + @failedCount = 0 + @totalDuration = 0.0 + @length = 0 + reportRunnerResults: (runner) -> + for result in @results + do (result) => + result.print() + + JHW.finishSuite(@totalDuration, @length, @failedCount) + reportRunnerStarting: (runner) -> + reportSpecResults: (spec) -> + if spec.results().passed() + JHW.specPassed() + else + JHW.specFailed() + failureResult = new HeadlessReporterResult(spec.getFullName()) + for result in spec.results().getItems() + do (result) => + if result.type == 'expect' and !result.passed_ + @failedCount += 1 + failureResult.results.push(result.message) + @results.push(failureResult) + reportSpecStarting: (spec) -> + # something here + reportSuiteResults: (suite) -> + suite.startTime ?= new Date() + @totalDuration += (new Date() - suite.startTime) / 1000.0; + + @length += suite.specs().length diff --git a/jasmine/jasmine.headless-reporter.js b/jasmine/jasmine.headless-reporter.js new file mode 100644 index 0000000..60bf70d --- /dev/null +++ b/jasmine/jasmine.headless-reporter.js @@ -0,0 +1,81 @@ +(function() { + var HeadlessReporterResult; + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + if (!(typeof jasmine !== "undefined" && jasmine !== null)) { + throw new Exception("jasmine not laoded!"); + } + HeadlessReporterResult = (function() { + function HeadlessReporterResult(name) { + this.name = name; + this.results = []; + } + HeadlessReporterResult.prototype.print = function() { + var result, _i, _len, _ref, _results; + JHW.printName(this.name); + _ref = this.results; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + result = _ref[_i]; + _results.push(__bind(function(result) { + return JHW.printResult(result); + }, this)(result)); + } + return _results; + }; + return HeadlessReporterResult; + })(); + jasmine.HeadlessReporter = (function() { + function HeadlessReporter() { + this.results = []; + this.failedCount = 0; + this.totalDuration = 0.0; + this.length = 0; + } + HeadlessReporter.prototype.reportRunnerResults = function(runner) { + var result, _fn, _i, _len, _ref; + _ref = this.results; + _fn = __bind(function(result) { + return result.print(); + }, this); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + result = _ref[_i]; + _fn(result); + } + return JHW.finishSuite(this.totalDuration, this.length, this.failedCount); + }; + HeadlessReporter.prototype.reportRunnerStarting = function(runner) {}; + HeadlessReporter.prototype.reportSpecResults = function(spec) { + var failureResult, result, _fn, _i, _len, _ref; + if (spec.results().passed()) { + return JHW.specPassed(); + } else { + JHW.specFailed(); + failureResult = new HeadlessReporterResult(spec.getFullName()); + _ref = spec.results().getItems(); + _fn = __bind(function(result) { + if (result.type === 'expect' && !result.passed_) { + this.failedCount += 1; + return failureResult.results.push(result.message); + } + }, this); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + result = _ref[_i]; + _fn(result); + } + return this.results.push(failureResult); + } + }; + HeadlessReporter.prototype.reportSpecStarting = function(spec) {}; + HeadlessReporter.prototype.reportSuiteResults = function(suite) { + var _ref; + if ((_ref = suite.startTime) != null) { + _ref; + } else { + suite.startTime = new Date(); + }; + this.totalDuration += (new Date() - suite.startTime) / 1000.0; + return this.length += suite.specs().length; + }; + return HeadlessReporter; + })(); +}).call(this); diff --git a/lib/jasmine/cli.rb b/lib/jasmine/cli.rb index 95d688d..9e74db2 100644 --- a/lib/jasmine/cli.rb +++ b/lib/jasmine/cli.rb @@ -35,14 +35,15 @@ module Jasmine