show line numbers for spec failures, whoa nelly
This commit is contained in:
parent
05e7d07d40
commit
3c4e557517
@ -72,7 +72,7 @@ public:
|
|||||||
public slots:
|
public slots:
|
||||||
void log(const QString &msg);
|
void log(const QString &msg);
|
||||||
void specPassed();
|
void specPassed();
|
||||||
void specFailed();
|
void specFailed(const QString &specDetail);
|
||||||
void printName(const QString &name);
|
void printName(const QString &name);
|
||||||
void printResult(const QString &result);
|
void printResult(const QString &result);
|
||||||
void finishSuite(const QString &duration, const QString &total, const QString& failed);
|
void finishSuite(const QString &duration, const QString &total, const QString& failed);
|
||||||
@ -96,6 +96,7 @@ private:
|
|||||||
bool consoleNotUsedThisRun;
|
bool consoleNotUsedThisRun;
|
||||||
QQueue<QString> runnerFiles;
|
QQueue<QString> runnerFiles;
|
||||||
QString reportFilename;
|
QString reportFilename;
|
||||||
|
QStack<QString> failedSpecs;
|
||||||
|
|
||||||
void red();
|
void red();
|
||||||
void green();
|
void green();
|
||||||
@ -201,12 +202,13 @@ void HeadlessSpecRunner::specPassed()
|
|||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HeadlessSpecRunner::specFailed()
|
void HeadlessSpecRunner::specFailed(const QString &specDetail)
|
||||||
{
|
{
|
||||||
consoleNotUsedThisRun = true;
|
consoleNotUsedThisRun = true;
|
||||||
didFail = true;
|
didFail = true;
|
||||||
red();
|
red();
|
||||||
std::cout << 'F';
|
std::cout << 'F';
|
||||||
|
failedSpecs.push(specDetail);
|
||||||
clear();
|
clear();
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
@ -292,6 +294,14 @@ void HeadlessSpecRunner::finishSuite(const QString &duration, const QString &tot
|
|||||||
report << qPrintable(total) << "/" << qPrintable(failed) << "/";
|
report << qPrintable(total) << "/" << qPrintable(failed) << "/";
|
||||||
report << (usedConsole ? "T" : "F");
|
report << (usedConsole ? "T" : "F");
|
||||||
report << "/" << qPrintable(duration) << "\n";
|
report << "/" << qPrintable(duration) << "\n";
|
||||||
|
|
||||||
|
QString failedSpec;
|
||||||
|
|
||||||
|
while (!failedSpecs.isEmpty()) {
|
||||||
|
failedSpec = failedSpecs.pop();
|
||||||
|
report << qPrintable(failedSpec) << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
reportFH.close();
|
reportFH.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,4 +23,5 @@ Gem::Specification.new do |s|
|
|||||||
s.add_dependency 'jasmine', '~>1.1.beta'
|
s.add_dependency 'jasmine', '~>1.1.beta'
|
||||||
s.add_dependency 'coffee-script', '>= 2.2'
|
s.add_dependency 'coffee-script', '>= 2.2'
|
||||||
s.add_dependency 'rainbow'
|
s.add_dependency 'rainbow'
|
||||||
|
s.add_dependency 'multi_json'
|
||||||
end
|
end
|
||||||
|
@ -2,16 +2,42 @@ if !jasmine?
|
|||||||
throw new Error("jasmine not laoded!")
|
throw new Error("jasmine not laoded!")
|
||||||
|
|
||||||
class HeadlessReporterResult
|
class HeadlessReporterResult
|
||||||
constructor: (name) ->
|
constructor: (@name, @splitName) ->
|
||||||
@name = name
|
|
||||||
@results = []
|
@results = []
|
||||||
addResult: (message) ->
|
addResult: (message) ->
|
||||||
@results.push(message)
|
@results.push(message)
|
||||||
print: ->
|
print: ->
|
||||||
JHW.printName(@name)
|
output = @name
|
||||||
|
bestChoice = this._findSpecLine()
|
||||||
|
output += " (#{bestChoice.file}:#{bestChoice.lineNumber})" if bestChoice.file
|
||||||
|
|
||||||
|
JHW.printName(output)
|
||||||
for result in @results
|
for result in @results
|
||||||
do (result) =>
|
do (result) =>
|
||||||
JHW.printResult(result)
|
JHW.printResult(result)
|
||||||
|
_findSpecLine: ->
|
||||||
|
bestChoice = { accuracy: 0, file: null, lineNumber: null }
|
||||||
|
|
||||||
|
for file, lines of SPEC_LINE_NUMBERS
|
||||||
|
index = 0
|
||||||
|
while newLineNumber = lines[@splitName[index]]
|
||||||
|
index++
|
||||||
|
lineNumber = newLineNumber
|
||||||
|
|
||||||
|
if index > bestChoice.accuracy
|
||||||
|
bestChoice = { accuracy: index, file: file, lineNumber: lineNumber }
|
||||||
|
|
||||||
|
bestChoice
|
||||||
|
|
||||||
|
jasmine.Suite.prototype.getSuiteSplitName = ->
|
||||||
|
parts = if @parentSuite then @parentSuite.getSuiteSplitName() else []
|
||||||
|
parts.push(@description)
|
||||||
|
parts
|
||||||
|
|
||||||
|
jasmine.Spec.prototype.getSpecSplitName = ->
|
||||||
|
parts = @suite.getSuiteSplitName()
|
||||||
|
parts.push(@description)
|
||||||
|
parts
|
||||||
|
|
||||||
class jasmine.HeadlessReporter
|
class jasmine.HeadlessReporter
|
||||||
constructor: ->
|
constructor: ->
|
||||||
@ -32,9 +58,9 @@ class jasmine.HeadlessReporter
|
|||||||
if results.passed()
|
if results.passed()
|
||||||
JHW.specPassed()
|
JHW.specPassed()
|
||||||
else
|
else
|
||||||
JHW.specFailed()
|
JHW.specFailed(spec.getSpecSplitName().join('||'))
|
||||||
@failedCount++
|
@failedCount++
|
||||||
failureResult = new HeadlessReporterResult(spec.getFullName())
|
failureResult = new HeadlessReporterResult(spec.getFullName(), spec.getSpecSplitName())
|
||||||
for result in results.getItems()
|
for result in results.getItems()
|
||||||
do (result) =>
|
do (result) =>
|
||||||
if result.type == 'expect' and !result.passed_
|
if result.type == 'expect' and !result.passed_
|
||||||
|
@ -5,16 +5,22 @@
|
|||||||
throw new Error("jasmine not laoded!");
|
throw new Error("jasmine not laoded!");
|
||||||
}
|
}
|
||||||
HeadlessReporterResult = (function() {
|
HeadlessReporterResult = (function() {
|
||||||
function HeadlessReporterResult(name) {
|
function HeadlessReporterResult(name, splitName) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
this.splitName = splitName;
|
||||||
this.results = [];
|
this.results = [];
|
||||||
}
|
}
|
||||||
HeadlessReporterResult.prototype.addResult = function(message) {
|
HeadlessReporterResult.prototype.addResult = function(message) {
|
||||||
return this.results.push(message);
|
return this.results.push(message);
|
||||||
};
|
};
|
||||||
HeadlessReporterResult.prototype.print = function() {
|
HeadlessReporterResult.prototype.print = function() {
|
||||||
var result, _i, _len, _ref, _results;
|
var bestChoice, output, result, _i, _len, _ref, _results;
|
||||||
JHW.printName(this.name);
|
output = this.name;
|
||||||
|
bestChoice = this._findSpecLine();
|
||||||
|
if (bestChoice.file) {
|
||||||
|
output += " (" + bestChoice.file + ":" + bestChoice.lineNumber + ")";
|
||||||
|
}
|
||||||
|
JHW.printName(output);
|
||||||
_ref = this.results;
|
_ref = this.results;
|
||||||
_results = [];
|
_results = [];
|
||||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||||
@ -25,8 +31,44 @@
|
|||||||
}
|
}
|
||||||
return _results;
|
return _results;
|
||||||
};
|
};
|
||||||
|
HeadlessReporterResult.prototype._findSpecLine = function() {
|
||||||
|
var bestChoice, file, index, lineNumber, lines, newLineNumber;
|
||||||
|
bestChoice = {
|
||||||
|
accuracy: 0,
|
||||||
|
file: null,
|
||||||
|
lineNumber: null
|
||||||
|
};
|
||||||
|
for (file in SPEC_LINE_NUMBERS) {
|
||||||
|
lines = SPEC_LINE_NUMBERS[file];
|
||||||
|
index = 0;
|
||||||
|
while (newLineNumber = lines[this.splitName[index]]) {
|
||||||
|
index++;
|
||||||
|
lineNumber = newLineNumber;
|
||||||
|
}
|
||||||
|
if (index > bestChoice.accuracy) {
|
||||||
|
bestChoice = {
|
||||||
|
accuracy: index,
|
||||||
|
file: file,
|
||||||
|
lineNumber: lineNumber
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bestChoice;
|
||||||
|
};
|
||||||
return HeadlessReporterResult;
|
return HeadlessReporterResult;
|
||||||
})();
|
})();
|
||||||
|
jasmine.Suite.prototype.getSuiteSplitName = function() {
|
||||||
|
var parts;
|
||||||
|
parts = this.parentSuite ? this.parentSuite.getSuiteSplitName() : [];
|
||||||
|
parts.push(this.description);
|
||||||
|
return parts;
|
||||||
|
};
|
||||||
|
jasmine.Spec.prototype.getSpecSplitName = function() {
|
||||||
|
var parts;
|
||||||
|
parts = this.suite.getSuiteSplitName();
|
||||||
|
parts.push(this.description);
|
||||||
|
return parts;
|
||||||
|
};
|
||||||
jasmine.HeadlessReporter = (function() {
|
jasmine.HeadlessReporter = (function() {
|
||||||
function HeadlessReporter() {
|
function HeadlessReporter() {
|
||||||
this.results = [];
|
this.results = [];
|
||||||
@ -55,9 +97,9 @@
|
|||||||
if (results.passed()) {
|
if (results.passed()) {
|
||||||
return JHW.specPassed();
|
return JHW.specPassed();
|
||||||
} else {
|
} else {
|
||||||
JHW.specFailed();
|
JHW.specFailed(spec.getSpecSplitName().join('||'));
|
||||||
this.failedCount++;
|
this.failedCount++;
|
||||||
failureResult = new HeadlessReporterResult(spec.getFullName());
|
failureResult = new HeadlessReporterResult(spec.getFullName(), spec.getSpecSplitName());
|
||||||
_ref = results.getItems();
|
_ref = results.getItems();
|
||||||
_fn = __bind(function(result) {
|
_fn = __bind(function(result) {
|
||||||
if (result.type === 'expect' && !result.passed_) {
|
if (result.type === 'expect' && !result.passed_) {
|
||||||
|
@ -19,11 +19,22 @@ module Jasmine
|
|||||||
File.expand_path('../../../jasmine/jasmine.headless-reporter.js', __FILE__)
|
File.expand_path('../../../jasmine/jasmine.headless-reporter.js', __FILE__)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
class << self
|
||||||
|
def get_spec_line_numbers(file)
|
||||||
|
Hash[file.lines.each_with_index.collect { |line, index|
|
||||||
|
if description = line[%r{(describe|context|it)[( ]*(["'])(.*)\2}, 3]
|
||||||
|
[ description, index + 1 ]
|
||||||
|
end
|
||||||
|
}.compact]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def initialize(options = {})
|
def initialize(options = {})
|
||||||
@options = options
|
@options = options
|
||||||
@files = DEFAULT_FILES.dup
|
@files = DEFAULT_FILES.dup
|
||||||
@filtered_files = @files.dup
|
@filtered_files = @files.dup
|
||||||
@spec_outside_scope = false
|
@spec_outside_scope = false
|
||||||
|
@spec_files = []
|
||||||
use_config! if config?
|
use_config! if config?
|
||||||
|
|
||||||
@code_for_file = {}
|
@code_for_file = {}
|
||||||
@ -45,6 +56,18 @@ module Jasmine
|
|||||||
to_html(filtered_files)
|
to_html(filtered_files)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def spec_file_line_numbers
|
||||||
|
@spec_file_line_numbers ||= Hash[@spec_files.collect { |file|
|
||||||
|
if File.exist?(file)
|
||||||
|
if !(lines = self.class.get_spec_line_numbers(File.read(file))).empty?
|
||||||
|
[ file, lines ]
|
||||||
|
end
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
}.compact]
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def to_html(files)
|
def to_html(files)
|
||||||
coffeescript_run = []
|
coffeescript_run = []
|
||||||
@ -115,6 +138,10 @@ module Jasmine
|
|||||||
|
|
||||||
@files += found_files
|
@files += found_files
|
||||||
|
|
||||||
|
if searches == 'spec_files'
|
||||||
|
@spec_files = @files + spec_filter
|
||||||
|
end
|
||||||
|
|
||||||
@filtered_files += (if searches == 'spec_files'
|
@filtered_files += (if searches == 'spec_files'
|
||||||
@spec_outside_scope = ((spec_filter | found_files).sort != found_files.sort)
|
@spec_outside_scope = ((spec_filter | found_files).sort != found_files.sort)
|
||||||
spec_filter.empty? ? found_files : (spec_filter || found_files)
|
spec_filter.empty? ? found_files : (spec_filter || found_files)
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
require 'jasmine/files_list'
|
require 'jasmine/files_list'
|
||||||
|
require 'multi_json'
|
||||||
|
|
||||||
module Jasmine
|
module Jasmine
|
||||||
class TemplateWriter
|
class TemplateWriter
|
||||||
@ -11,14 +12,14 @@ module Jasmine
|
|||||||
output.unshift([ "specrunner.#{$$}.filter.html", files_list.filtered_files_to_html ]) if files_list.filtered?
|
output.unshift([ "specrunner.#{$$}.filter.html", files_list.filtered_files_to_html ]) if files_list.filtered?
|
||||||
|
|
||||||
output.each do |name, files|
|
output.each do |name, files|
|
||||||
File.open(name, 'w') { |fh| fh.print template_for(files) }
|
File.open(name, 'w') { |fh| fh.print template_for(files, files_list.spec_file_line_numbers) }
|
||||||
end
|
end
|
||||||
|
|
||||||
output.collect(&:first)
|
output.collect(&:first)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def template_for(files)
|
def template_for(files, spec_lines)
|
||||||
<<-HTML
|
<<-HTML
|
||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||||
<html>
|
<html>
|
||||||
@ -32,6 +33,9 @@ module Jasmine
|
|||||||
} };
|
} };
|
||||||
</script>
|
</script>
|
||||||
#{files.join("\n")}
|
#{files.join("\n")}
|
||||||
|
<script type="text/javascript">
|
||||||
|
SPEC_LINE_NUMBERS = #{MultiJson.encode(spec_lines)};
|
||||||
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
@ -206,5 +206,68 @@ describe Jasmine::FilesList do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '.get_spec_line_numbers' do
|
||||||
|
let(:line_numbers) do
|
||||||
|
described_class.get_spec_line_numbers(file)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'coffeescript' do
|
||||||
|
let(:file) do
|
||||||
|
<<-SPEC
|
||||||
|
describe 'test', ->
|
||||||
|
context 'yes', ->
|
||||||
|
it 'should do something', ->
|
||||||
|
"yes"
|
||||||
|
SPEC
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should get the line numbers' do
|
||||||
|
line_numbers['test'].should == 1
|
||||||
|
line_numbers['yes'].should == 2
|
||||||
|
line_numbers['should do something'].should == 3
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'javascript' do
|
||||||
|
let(:file) do
|
||||||
|
<<-SPEC
|
||||||
|
describe('test', function() {
|
||||||
|
context('yes', function() {
|
||||||
|
it('should do something', function() {
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
SPEC
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should get the line numbers' do
|
||||||
|
line_numbers['test'].should == 1
|
||||||
|
line_numbers['yes'].should == 2
|
||||||
|
line_numbers['should do something'].should == 3
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#spec_file_line_numbers' do
|
||||||
|
include FakeFS::SpecHelpers
|
||||||
|
|
||||||
|
before do
|
||||||
|
files_list.instance_variable_set(:@spec_files, [
|
||||||
|
'test.coffee',
|
||||||
|
'test2.coffee'
|
||||||
|
])
|
||||||
|
|
||||||
|
File.open('test.coffee', 'w') { |fh| fh.print "describe('cat')" }
|
||||||
|
File.open('test2.coffee', 'w') { |fh| fh.print "no matches" }
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should generate filenames and line number info' do
|
||||||
|
files_list.spec_file_line_numbers.should == {
|
||||||
|
'test.coffee' => { 'cat' => 1 }
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -68,5 +68,15 @@ describe Jasmine::Headless::Runner do
|
|||||||
it 'should succeed but with javascript error' do
|
it 'should succeed but with javascript error' do
|
||||||
Jasmine::Headless::Runner.run(:jasmine_config => 'spec/jasmine/success_with_error/success_with_error.yml').should == 1
|
Jasmine::Headless::Runner.run(:jasmine_config => 'spec/jasmine/success_with_error/success_with_error.yml').should == 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'should fail on one test' do
|
||||||
|
Jasmine::Headless::Runner.run(
|
||||||
|
:jasmine_config => 'spec/jasmine/failure/failure.yml',
|
||||||
|
:report => report
|
||||||
|
).should == 1
|
||||||
|
|
||||||
|
report.should be_a_report_containing(1, 1, false)
|
||||||
|
report.should contain_a_failing_spec(['failure', 'should fail with error code of 1'])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -25,7 +25,17 @@ RSpec::Matchers.define :be_a_report_containing do |total, fails, used_console|
|
|||||||
end
|
end
|
||||||
|
|
||||||
def parts(filename = nil)
|
def parts(filename = nil)
|
||||||
@parts ||= File.read(filename).strip.split('/')
|
@parts ||= File.readlines(filename).first.strip.split('/')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
RSpec::Matchers.define :contain_a_failing_spec do |*parts|
|
||||||
|
match do |filename|
|
||||||
|
report(filename).include?(parts.join("||")).should be_true
|
||||||
|
end
|
||||||
|
|
||||||
|
def report(filename)
|
||||||
|
@report ||= File.readlines(filename)[1..-1].collect(&:strip)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user