diff --git a/ext/jasmine-webkit-specrunner/ConsoleOutput.cpp b/ext/jasmine-webkit-specrunner/ConsoleOutput.cpp index 3b92cff..2093d99 100644 --- a/ext/jasmine-webkit-specrunner/ConsoleOutput.cpp +++ b/ext/jasmine-webkit-specrunner/ConsoleOutput.cpp @@ -82,8 +82,15 @@ void ConsoleOutput::logSpecFilename(const QString &name) { } void ConsoleOutput::logSpecResult(const QString &result) { + QStringList lines = result.split("\n"); + QStringListIterator linesIterator(lines); + red(); - *outputIO << " " << qPrintable(result) << std::endl; + while (linesIterator.hasNext()) { + *outputIO << " " << qPrintable(linesIterator.next()) << std::endl; + yellow(); + } + clear(); } diff --git a/ext/jasmine-webkit-specrunner/ConsoleOutput.h b/ext/jasmine-webkit-specrunner/ConsoleOutput.h index 898e7e4..b15004b 100644 --- a/ext/jasmine-webkit-specrunner/ConsoleOutput.h +++ b/ext/jasmine-webkit-specrunner/ConsoleOutput.h @@ -4,6 +4,7 @@ #include #include #include +#include class ConsoleOutput : public QObject { public: diff --git a/ext/jasmine-webkit-specrunner/test.rb b/ext/jasmine-webkit-specrunner/test.rb index ca7f407..0caf700 100644 --- a/ext/jasmine-webkit-specrunner/test.rb +++ b/ext/jasmine-webkit-specrunner/test.rb @@ -7,6 +7,8 @@ system %{make clean} $: << File.expand_path("../../../lib", __FILE__) require 'qt/qmake' +result = 0 + Dir['*_test.pro'].each do |test| FileUtils.rm_f('jhw-test') @@ -15,10 +17,15 @@ Dir['*_test.pro'].each do |test| if File.file?('jhw-test') system %{./jhw-test} if $?.exitstatus != 0 - exit 1 + result = 1 + break end else - exit 1 + result = 1 + break end end +Qt::Qmake.make!('jasmine-headless-webkit', 'specrunner.pro') + +exit result diff --git a/jasmine/jasmine.headless-reporter.coffee b/jasmine/jasmine.headless-reporter.coffee index a98bdbc..8b6d383 100644 --- a/jasmine/jasmine.headless-reporter.coffee +++ b/jasmine/jasmine.headless-reporter.coffee @@ -24,6 +24,44 @@ jasmine.Spec.prototype.getJHWSpecInformation = -> parts.push('') parts.join("||") +jasmine.Spec.prototype.fail = (e) -> + if e and window.CoffeeScriptToFilename + filename = e.sourceURL.split('/').pop() + if realFilename = window.CoffeeScriptToFilename[filename] + e = { + name: e.name, + message: e.message, + lineNumber: "~" + String(e.line), + sourceURL: realFilename + } + + expectationResult = new jasmine.ExpectationResult({ + passed: false, + message: if e then jasmine.util.formatException(e) else 'Exception', + trace: { stack: e.stack } + }) + @results_.addResult(expectationResult) + +jasmine.NestedResults.isValidSpecLine = (line) -> + line.match(/^\s*expect/) != null || line.match(/^\s*return\s*expect/) != null + +jasmine.NestedResults.parseFunction = (func) -> + lines = [] + lineCount = 0 + for line in func.split("\n") + if jasmine.NestedResults.isValidSpecLine(line) + line = line.replace(/^\s*/, '').replace(/\s*$/, '').replace(/^return\s*/, '') + lines.push([line, lineCount]) + lineCount += 1 + lines + +jasmine.NestedResults.parseAndStore = (func) -> + if !jasmine.NestedResults.ParsedFunctions[func] + jasmine.NestedResults.ParsedFunctions[func] = jasmine.NestedResults.parseFunction(func) + jasmine.NestedResults.ParsedFunctions[func] + +jasmine.NestedResults.ParsedFunctions = [] + if !jasmine.WaitsBlock.prototype._execute jasmine.WaitsBlock.prototype._execute = jasmine.WaitsBlock.prototype.execute jasmine.WaitsForBlock.prototype._execute = jasmine.WaitsForBlock.prototype.execute @@ -37,6 +75,15 @@ if !jasmine.WaitsBlock.prototype._execute jasmine.WaitsBlock.prototype.execute = pauseAndRun jasmine.WaitsForBlock.prototype.execute = pauseAndRun + jasmine.NestedResults.prototype.addResult_ = jasmine.NestedResults.prototype.addResult + jasmine.NestedResults.prototype.addResult = (result) -> + result.expectations = [] + # always three up? + + result.expectations = jasmine.NestedResults.parseAndStore(arguments.callee.caller.caller.caller.toString()) + + this.addResult_(result) + # Try to get the line number of a failed spec class window.HeadlessReporterResult constructor: (@name, @splitName) -> @@ -50,7 +97,10 @@ class window.HeadlessReporterResult JHW.printName(output) for result in @results - JHW.printResult(result) + output = result.message + if result.lineNumber + output += " (line ~#{bestChoice.lineNumber + result.lineNumber})\n #{result.line}" + JHW.printResult(output) @findSpecLine: (splitName) -> bestChoice = { accuracy: 0, file: null, lineNumber: null } @@ -104,9 +154,13 @@ class jasmine.HeadlessReporter JHW.specFailed(spec.getJHWSpecInformation()) @failedCount++ failureResult = new HeadlessReporterResult(spec.getFullName(), spec.getSpecSplitName()) + testCount = 1 for result in results.getItems() if result.type == 'expect' and !result.passed_ - failureResult.addResult(result.message) + if foundLine = result.expectations[testCount - 1] + [ result.line, result.lineNumber ] = foundLine + failureResult.addResult(result) + testCount += 1 @results.push(failureResult) reportSpecStarting: (spec) -> diff --git a/jasmine/jasmine.headless-reporter.js b/jasmine/jasmine.headless-reporter.js index 04268e6..c77f219 100644 --- a/jasmine/jasmine.headless-reporter.js +++ b/jasmine/jasmine.headless-reporter.js @@ -26,6 +26,53 @@ } return parts.join("||"); }; + jasmine.Spec.prototype.fail = function(e) { + var expectationResult, filename, realFilename; + if (e && window.CoffeeScriptToFilename) { + filename = e.sourceURL.split('/').pop(); + if (realFilename = window.CoffeeScriptToFilename[filename]) { + e = { + name: e.name, + message: e.message, + lineNumber: "~" + String(e.line), + sourceURL: realFilename + }; + } + } + expectationResult = new jasmine.ExpectationResult({ + passed: false, + message: e ? jasmine.util.formatException(e) : 'Exception', + trace: { + stack: e.stack + } + }); + return this.results_.addResult(expectationResult); + }; + jasmine.NestedResults.isValidSpecLine = function(line) { + return line.match(/^\s*expect/) !== null || line.match(/^\s*return\s*expect/) !== null; + }; + jasmine.NestedResults.parseFunction = function(func) { + var line, lineCount, lines, _i, _len, _ref; + lines = []; + lineCount = 0; + _ref = func.split("\n"); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + line = _ref[_i]; + if (jasmine.NestedResults.isValidSpecLine(line)) { + line = line.replace(/^\s*/, '').replace(/\s*$/, '').replace(/^return\s*/, ''); + lines.push([line, lineCount]); + } + lineCount += 1; + } + return lines; + }; + jasmine.NestedResults.parseAndStore = function(func) { + if (!jasmine.NestedResults.ParsedFunctions[func]) { + jasmine.NestedResults.ParsedFunctions[func] = jasmine.NestedResults.parseFunction(func); + } + return jasmine.NestedResults.ParsedFunctions[func]; + }; + jasmine.NestedResults.ParsedFunctions = []; if (!jasmine.WaitsBlock.prototype._execute) { jasmine.WaitsBlock.prototype._execute = jasmine.WaitsBlock.prototype.execute; jasmine.WaitsForBlock.prototype._execute = jasmine.WaitsForBlock.prototype.execute; @@ -38,6 +85,12 @@ }; jasmine.WaitsBlock.prototype.execute = pauseAndRun; jasmine.WaitsForBlock.prototype.execute = pauseAndRun; + jasmine.NestedResults.prototype.addResult_ = jasmine.NestedResults.prototype.addResult; + jasmine.NestedResults.prototype.addResult = function(result) { + result.expectations = []; + result.expectations = jasmine.NestedResults.parseAndStore(arguments.callee.caller.caller.caller.toString()); + return this.addResult_(result); + }; } window.HeadlessReporterResult = (function() { function HeadlessReporterResult(name, splitName) { @@ -60,7 +113,11 @@ _results = []; for (_i = 0, _len = _ref.length; _i < _len; _i++) { result = _ref[_i]; - _results.push(JHW.printResult(result)); + output = result.message; + if (result.lineNumber) { + output += " (line ~" + (bestChoice.lineNumber + result.lineNumber) + ")\n " + result.line; + } + _results.push(JHW.printResult(output)); } return _results; }; @@ -130,7 +187,7 @@ return this.startTime = new Date(); }; HeadlessReporter.prototype.reportSpecResults = function(spec) { - var failureResult, result, results, _i, _len, _ref; + var failureResult, foundLine, result, results, testCount, _i, _len, _ref; if (this.hasError()) { return; } @@ -142,12 +199,17 @@ JHW.specFailed(spec.getJHWSpecInformation()); this.failedCount++; failureResult = new HeadlessReporterResult(spec.getFullName(), spec.getSpecSplitName()); + testCount = 1; _ref = results.getItems(); for (_i = 0, _len = _ref.length; _i < _len; _i++) { result = _ref[_i]; if (result.type === 'expect' && !result.passed_) { - failureResult.addResult(result.message); + if (foundLine = result.expectations[testCount - 1]) { + result.line = foundLine[0], result.lineNumber = foundLine[1]; + } + failureResult.addResult(result); } + testCount += 1; } return this.results.push(failureResult); } diff --git a/lib/jasmine/files_list.rb b/lib/jasmine/files_list.rb index 37beebe..2764b28 100644 --- a/lib/jasmine/files_list.rb +++ b/lib/jasmine/files_list.rb @@ -1,6 +1,7 @@ require 'jasmine-core' require 'iconv' require 'time' +require 'multi_json' module Jasmine class FilesList @@ -63,10 +64,25 @@ module Jasmine alert_time = nil end - case File.extname(file) + function_locations = {} + source = nil + + result = case File.extname(file) when '.coffee' begin - %{} + cache = Jasmine::Headless::CoffeeScriptCache.new(file) + source = cache.handle + if cache.cached? + %{ + S + + } + else + %{} + end rescue CoffeeScript::CompilationError => ne puts "[%s] %s: %s" % [ 'coffeescript'.color(:red), file.color(:yellow), ne.message.to_s.color(:white) ] raise ne @@ -79,6 +95,8 @@ module Jasmine when '.css' %{} end + + result }.flatten.compact.reject(&:empty?) end diff --git a/lib/jasmine/headless/cacheable_action.rb b/lib/jasmine/headless/cacheable_action.rb index 77c57c2..067cf27 100644 --- a/lib/jasmine/headless/cacheable_action.rb +++ b/lib/jasmine/headless/cacheable_action.rb @@ -60,7 +60,11 @@ module Jasmine::Headless end def fresh? - File.exist?(cache_file) && (File.mtime(file) < File.mtime(cache_file)) + cached? && (File.mtime(file) < File.mtime(cache_file)) + end + + def cached? + File.exist?(cache_file) end def action diff --git a/lib/jasmine/headless/runner.rb b/lib/jasmine/headless/runner.rb index 7791103..b032df7 100644 --- a/lib/jasmine/headless/runner.rb +++ b/lib/jasmine/headless/runner.rb @@ -14,7 +14,8 @@ module Jasmine 'spec_dir' => 'spec/javascripts', 'src_dir' => nil, 'stylesheets' => [], - 'src_files' => [] + 'src_files' => [], + 'backtrace' => [] } RUNNER_DIR = File.expand_path('../../../../ext/jasmine-webkit-specrunner', __FILE__) diff --git a/spec/javascripts/jasmine.headless-reporter_spec.coffee b/spec/javascripts/jasmine.headless-reporter_spec.coffee index 64e291b..f70203e 100644 --- a/spec/javascripts/jasmine.headless-reporter_spec.coffee +++ b/spec/javascripts/jasmine.headless-reporter_spec.coffee @@ -94,3 +94,22 @@ describe 'jasmine.WaitsBlock and jasmine.WaitsForBlock', -> runs -> expect(true).toEqual(true) +describe 'jasmine.NestedResults.isValidSpecLine', -> + it 'should check the lines', -> + expect(jasmine.NestedResults.isValidSpecLine('yes')).toEqual(false) + expect(jasmine.NestedResults.isValidSpecLine('expect')).toEqual(true) + expect(jasmine.NestedResults.isValidSpecLine(' expect')).toEqual(true) + expect(jasmine.NestedResults.isValidSpecLine('return expect')).toEqual(true) + expect(jasmine.NestedResults.isValidSpecLine(' return expect')).toEqual(true) + +describe 'jasmine.nestedResults.parseFunction', -> + it 'should parse the function', -> + expect(jasmine.NestedResults.parseFunction(""" +test +expect("cat") + return expect("dog") + """)).toEqual([ + [ 'expect("cat")', 1 ], + [ 'expect("dog")', 2 ] + ]) + diff --git a/spec/lib/jasmine/files_list_spec.rb b/spec/lib/jasmine/files_list_spec.rb index 1fe9f37..a5aa268 100644 --- a/spec/lib/jasmine/files_list_spec.rb +++ b/spec/lib/jasmine/files_list_spec.rb @@ -170,7 +170,8 @@ describe Jasmine::FilesList do 'test.coffee' ]) - Jasmine::Headless::CoffeeScriptCache.stubs(:for).with('test.coffee').returns("i compiled") + File.stubs(:read) + Jasmine::Headless::CoffeeScriptCache.any_instance.stubs(:handle).returns("i compiled") end context '#files_to_html' do diff --git a/spec/lib/jasmine/headless/cacheable_action_spec.rb b/spec/lib/jasmine/headless/cacheable_action_spec.rb index 01b006f..b168999 100644 --- a/spec/lib/jasmine/headless/cacheable_action_spec.rb +++ b/spec/lib/jasmine/headless/cacheable_action_spec.rb @@ -22,6 +22,8 @@ describe Jasmine::Headless::CacheableAction do let(:cache_file) { File.join(cache_dir, cache_type, Digest::SHA1.hexdigest(file)) } let(:cache_file_data) { YAML.load(File.read(cache_file)) } + let(:cache_object) { described_class.new(file) } + describe '.for' do context 'cache disabled' do before do @@ -32,6 +34,8 @@ describe Jasmine::Headless::CacheableAction do action_runs! described_class.for(file).should == compiled cache_file.should_not be_a_file + + cache_object.should_not be_cached end end @@ -52,6 +56,7 @@ describe Jasmine::Headless::CacheableAction do described_class.for(file).should == compiled cache_file_data.should == compiled + cache_object.should be_cached end end @@ -69,6 +74,7 @@ describe Jasmine::Headless::CacheableAction do described_class.for(file).should == compiled cache_file_data.should == compiled + cache_object.should be_cached end end @@ -81,6 +87,7 @@ describe Jasmine::Headless::CacheableAction do described_class.for(file).should == compiled cache_file_data.should == compiled + cache_object.should be_cached end end end diff --git a/spec/lib/jasmine/template_writer_spec.rb b/spec/lib/jasmine/template_writer_spec.rb index ad2a8f7..5783e0d 100644 --- a/spec/lib/jasmine/template_writer_spec.rb +++ b/spec/lib/jasmine/template_writer_spec.rb @@ -6,6 +6,10 @@ describe Jasmine::TemplateWriter do describe '.write!' do include FakeFS::SpecHelpers + before do + File.stubs(:read).returns(nil) + end + let(:files_list) { Jasmine::FilesList.new } before do