halfway in the middle of the reporting change

This commit is contained in:
John Bintz 2011-09-02 15:52:19 -04:00
parent 68a2888d35
commit e5510f13d0
13 changed files with 398 additions and 219 deletions

1
.gitignore vendored
View File

@ -11,3 +11,4 @@ moc_*.*
.DS_Store .DS_Store
hydra-runner.log hydra-runner.log
jhw-test jhw-test
.jhw-cache/

View File

@ -26,7 +26,8 @@ guard 'jasmine-headless-webkit', :all_on_start => false do
end end
def compile def compile
system %{cd ext/jasmine-webkit-specrunner && ruby test.rb && ruby extconf.rb} #system %{cd ext/jasmine-webkit-specrunner && ruby test.rb && ruby extconf.rb}
system %{cd ext/jasmine-webkit-specrunner && ruby extconf.rb}
end end
compile compile

View File

@ -1,10 +1,54 @@
#include "ReportFileOutput.h" #include "ReportFileOutput.h"
ReportFileOutput::ReportFileOutput() : QObject() { using namespace std;
ReportFileOutput::ReportFileOutput() : QObject() {
reset();
}
void ReportFileOutput::reset() {
buffer = new stringstream();
outputIO = buffer;
} }
void ReportFileOutput::passed(const QString &specDetail) { void ReportFileOutput::passed(const QString &specDetail) {
*outputIO << "PASS||" << qPrintable(specDetail) << std::endl; *outputIO << "PASS||" << qPrintable(specDetail) << std::endl;
successes.push(specDetail); successes.push(specDetail);
} }
void ReportFileOutput::failed(const QString &specDetail) {
*outputIO << "FAIL||" << qPrintable(specDetail) << std::endl;
failures.push(specDetail);
}
void ReportFileOutput::errorLog(const QString &msg, int lineNumber, const QString &sourceID) {
*outputIO << "ERROR||" << qPrintable(msg) << "||" << qPrintable(sourceID) << ":" << lineNumber << std::endl;
}
void ReportFileOutput::consoleLog(const QString &msg) {
*outputIO << "CONSOLE||" << qPrintable(msg) << std::endl;
}
void ReportFileOutput::internalLog(const QString &, const QString &) {}
void ReportFileOutput::logSpecFilename(const QString &) {}
void ReportFileOutput::logSpecResult(const QString &) {}
void ReportFileOutput::reportFailure(const QString &totalTests, const QString &failedTests, const QString &duration) {
reportTotals(totalTests, failedTests, duration, false);
}
void ReportFileOutput::reportSuccess(const QString &totalTests, const QString &failedTests, const QString &duration) {
reportTotals(totalTests, failedTests, duration, false);
}
void ReportFileOutput::reportSuccessWithJSErrors(const QString &totalTests, const QString &failedTests, const QString &duration) {
reportTotals(totalTests, failedTests, duration, true);
}
void ReportFileOutput::reportTotals(const QString &totalTests, const QString &failedTests, const QString &duration, bool hasJavaScriptError) {
*outputIO << "TOTAL||" << qPrintable(totalTests) << "||" << qPrintable(failedTests) << "||" << qPrintable(duration) << "||";
*outputIO << (hasJavaScriptError ? "T" : "F");
*outputIO << std::endl;
}

View File

@ -4,6 +4,9 @@
#include <QObject> #include <QObject>
#include <iostream> #include <iostream>
#include <QStack> #include <QStack>
#include <sstream>
using namespace std;
class ReportFileOutput : public QObject { class ReportFileOutput : public QObject {
public: public:
@ -21,9 +24,14 @@ class ReportFileOutput : public QObject {
void reportSuccess(const QString &totalTests, const QString &failedTests, const QString &duration); void reportSuccess(const QString &totalTests, const QString &failedTests, const QString &duration);
void reportSuccessWithJSErrors(const QString &totalTests, const QString &failedTests, const QString &duration); void reportSuccessWithJSErrors(const QString &totalTests, const QString &failedTests, const QString &duration);
std::ostream *outputIO; void reset();
stringstream *buffer;
stringstream *outputIO;
QStack<QString> successes; QStack<QString> successes;
QStack<QString> failures; QStack<QString> failures;
private:
void reportTotals(const QString &totalTests, const QString &failedTests, const QString &duration, bool hasJavaScriptError);
}; };
#endif #endif

View File

@ -23,11 +23,66 @@ void ReportFileOutputTest::testFailed() {
ReportFileOutput output; ReportFileOutput output;
output.outputIO = &buffer; output.outputIO = &buffer;
output.passed("test||done||file.js:23"); output.failed("test||done||file.js:23");
QVERIFY(buffer.str() == "FAIL||test||done||file.js:23\n"); QVERIFY(buffer.str() == "FAIL||test||done||file.js:23\n");
QVERIFY(output.successes.size() == 0); QVERIFY(output.successes.size() == 0);
QVERIFY(output.failures.size() == 1); QVERIFY(output.failures.size() == 1);
} }
void ReportFileOutputTest::testErrorLog() {
stringstream buffer;
ReportFileOutput output;
output.outputIO = &buffer;
output.errorLog("JS Error", 23, "file.js");
QVERIFY(buffer.str() == "ERROR||JS Error||file.js:23\n");
}
void ReportFileOutputTest::testConsoleLog() {
stringstream buffer;
ReportFileOutput output;
output.outputIO = &buffer;
output.consoleLog("Console");
QVERIFY(buffer.str() == "CONSOLE||Console\n");
}
void ReportFileOutputTest::testStubMethods() {
stringstream buffer;
ReportFileOutput output;
output.outputIO = &buffer;
output.internalLog("Internal", "Log");
output.logSpecFilename("Filename");
output.logSpecResult("REsult");
}
void ReportFileOutputTest::testReportFailure() {
stringstream buffer;
ReportFileOutput output;
output.outputIO = &buffer;
output.reportFailure("5", "2", "1.5");
QVERIFY(buffer.str() == "TOTAL||5||2||1.5||F\n");
}
void ReportFileOutputTest::testReportSuccess() {
stringstream buffer;
ReportFileOutput output;
output.outputIO = &buffer;
output.reportSuccess("5", "0", "1.5");
QVERIFY(buffer.str() == "TOTAL||5||0||1.5||F\n");
}
void ReportFileOutputTest::testReportSuccessWithJSErrors() {
stringstream buffer;
ReportFileOutput output;
output.outputIO = &buffer;
output.reportSuccessWithJSErrors("5", "0", "1.5");
QVERIFY(buffer.str() == "TOTAL||5||0||1.5||T\n");
}
QTEST_MAIN(ReportFileOutputTest); QTEST_MAIN(ReportFileOutputTest);

View File

@ -15,6 +15,12 @@ class ReportFileOutputTest : public QObject {
private slots: private slots:
void testPassed(); void testPassed();
void testFailed(); void testFailed();
void testErrorLog();
void testConsoleLog();
void testStubMethods();
void testReportFailure();
void testReportSuccess();
void testReportSuccessWithJSErrors();
}; };
#endif #endif

View File

@ -7,197 +7,195 @@
#include "Runner.h" #include "Runner.h"
Runner::Runner() : QObject() using namespace std;
, m_runs(0)
, hasErrors(false) Runner::Runner() : QObject()
, usedConsole(false) , m_runs(0)
, isFinished(false) , hasErrors(false)
, didFail(false) { , usedConsole(false)
m_page.settings()->enablePersistentStorage(); , isFinished(false)
connect(&m_page, SIGNAL(loadFinished(bool)), this, SLOT(watch(bool))); , didFail(false) {
connect(&m_page, SIGNAL(consoleLog(QString, int, QString)), this, SLOT(errorLog(QString, int, QString))); m_page.settings()->enablePersistentStorage();
connect(&m_page, SIGNAL(internalLog(QString, QString)), this, SLOT(internalLog(QString, QString))); connect(&m_page, SIGNAL(loadFinished(bool)), this, SLOT(watch(bool)));
connect(m_page.mainFrame(), SIGNAL(javaScriptWindowObjectCleared()), this, SLOT(addJHW())); connect(&m_page, SIGNAL(consoleLog(QString, int, QString)), this, SLOT(errorLog(QString, int, QString)));
connect(&m_page, SIGNAL(internalLog(QString, QString)), this, SLOT(internalLog(QString, QString)));
connect(m_page.mainFrame(), SIGNAL(javaScriptWindowObjectCleared()), this, SLOT(addJHW()));
}
void Runner::addFile(const QString &spec) {
runnerFiles.enqueue(spec);
}
void Runner::go()
{
m_ticker.stop();
m_page.setPreferredContentsSize(QSize(1024, 600));
addJHW();
loadSpec();
}
void Runner::addJHW()
{
m_page.mainFrame()->addToJavaScriptWindowObject("JHW", this);
}
void Runner::loadSpec()
{
m_page.mainFrame()->load(runnerFiles.dequeue());
m_ticker.start(200, this);
}
void Runner::watch(bool ok)
{
if (!ok) {
std::cerr << "Can't load " << qPrintable(m_page.mainFrame()->url().toString()) << ", the file may be broken." << std::endl;
std::cerr << "Out of curiosity, did your tests try to submit a form and you haven't prevented that?" << std::endl;
std::cerr << "Try running your tests in your browser with the Jasmine server and see what happens." << std::endl;
QApplication::instance()->exit(1);
return;
} }
void Runner::addFile(const QString &spec) { m_ticker.start(200, this);
runnerFiles.enqueue(spec); }
}
void Runner::go() bool Runner::hasElement(const char *select)
{ {
m_ticker.stop(); return !m_page.mainFrame()->findFirstElement(select).isNull();
m_page.setPreferredContentsSize(QSize(1024, 600)); }
addJHW();
loadSpec();
}
void Runner::addJHW()
{
m_page.mainFrame()->addToJavaScriptWindowObject("JHW", this);
}
void Runner::loadSpec() void Runner::setColors(bool colors) {
{ consoleOutput.showColors = colors;
m_page.mainFrame()->load(runnerFiles.dequeue()); }
m_ticker.start(200, this);
}
void Runner::watch(bool ok) void Runner::reportFile(const QString &file) {
{ reportFileName = file;
if (!ok) { }
std::cerr << "Can't load " << qPrintable(m_page.mainFrame()->url().toString()) << ", the file may be broken." << std::endl;
std::cerr << "Out of curiosity, did your tests try to submit a form and you haven't prevented that?" << std::endl;
std::cerr << "Try running your tests in your browser with the Jasmine server and see what happens." << std::endl;
QApplication::instance()->exit(1);
return;
}
m_ticker.start(200, this); bool Runner::hasError() {
} return hasErrors;
}
bool Runner::hasElement(const char *select) void Runner::specPassed(const QString &specDetail) {
{ consoleOutput.passed(specDetail);
return !m_page.mainFrame()->findFirstElement(select).isNull(); reportFileOutput.passed(specDetail);
} }
void Runner::setColors(bool colors) void Runner::specFailed(const QString &specDetail) {
{ consoleOutput.failed(specDetail);
consoleOutput.showColors = colors; reportFileOutput.failed(specDetail);
}
void Runner::reportFile(const QString &file) didFail = true;
{ failedSpecs.push(specDetail);
reportFilename = file; }
}
bool Runner::hasError() { void Runner::errorLog(const QString &msg, int lineNumber, const QString &sourceID)
return hasErrors; {
} consoleOutput.errorLog(msg, lineNumber, sourceID);
reportFileOutput.errorLog(msg, lineNumber, sourceID);
void Runner::specPassed() hasErrors = true;
{ m_runs = 0;
consoleOutput.passed(""); m_ticker.start(200, this);
} }
void Runner::specFailed(const QString &specDetail) void Runner::internalLog(const QString &note, const QString &msg) {
{ consoleOutput.internalLog(note, msg);
consoleOutput.failed(""); reportFileOutput.internalLog(note, msg);
didFail = true; }
failedSpecs.push(specDetail);
}
void Runner::errorLog(const QString &msg, int lineNumber, const QString &sourceID) void Runner::log(const QString &msg)
{ {
consoleOutput.errorLog(msg, lineNumber, sourceID); usedConsole = true;
consoleOutput.consoleLog(msg);
reportFileOutput.consoleLog(msg);
}
hasErrors = true; void Runner::leavePageAttempt(const QString &msg)
m_runs = 0; {
m_ticker.start(200, this); consoleOutput.internalLog("error", msg);
} m_page.oneFalseConfirm();
hasErrors = true;
}
void Runner::internalLog(const QString &note, const QString &msg) { void Runner::printName(const QString &name)
consoleOutput.internalLog(note, msg); {
} consoleOutput.logSpecFilename(name);
}
void Runner::log(const QString &msg) void Runner::printResult(const QString &result)
{ {
usedConsole = true; consoleOutput.logSpecResult(result);
consoleOutput.consoleLog(msg); }
}
void Runner::leavePageAttempt(const QString &msg) void Runner::finishSuite(const QString &duration, const QString &total, const QString& failed)
{ {
consoleOutput.internalLog("error", msg); if (didFail) {
m_page.oneFalseConfirm(); consoleOutput.reportFailure(total, failed, duration);
hasErrors = true; reportFileOutput.reportFailure(total, failed, duration);
} } else {
if (hasErrors) {
void Runner::printName(const QString &name) consoleOutput.reportSuccessWithJSErrors(total, failed, duration);
{ reportFileOutput.reportSuccessWithJSErrors(total, failed, duration);
consoleOutput.logSpecFilename(name);
}
void Runner::printResult(const QString &result)
{
consoleOutput.logSpecResult(result);
}
void Runner::finishSuite(const QString &duration, const QString &total, const QString& failed)
{
if (didFail) {
consoleOutput.reportFailure(total, failed, duration);
} else { } else {
if (hasErrors) { consoleOutput.reportSuccess(total, failed, duration);
consoleOutput.reportSuccessWithJSErrors(total, failed, duration); reportFileOutput.reportSuccess(total, failed, duration);
} else {
consoleOutput.reportSuccess(total, failed, duration);
}
} }
if (!reportFilename.isEmpty()) {
QFile reportFH(reportFilename);
if (reportFH.open(QFile::WriteOnly)) {
QTextStream report(&reportFH);
report << qPrintable(total) << "/" << qPrintable(failed) << "/";
report << (usedConsole ? "T" : "F");
report << "/" << qPrintable(duration) << "\n";
QString failedSpec;
while (!failedSpecs.isEmpty()) {
failedSpec = failedSpecs.pop();
report << qPrintable(failedSpec) << "\n";
}
reportFH.close();
}
}
isFinished = true;
} }
void Runner::timerEvent(QTimerEvent *event) if (!reportFileName.isEmpty()) {
{ QFile outputFile(reportFileName);
++m_runs; outputFile.open(QIODevice::WriteOnly);
if (event->timerId() != m_ticker.timerId()) QTextStream ts(&outputFile);
return;
if (hasErrors && m_runs > 2) ts << reportFileOutput.outputIO->str().c_str();
QApplication::instance()->exit(1);
if (isFinished) { outputFile.close();
int exitCode = 0; }
if (didFail || hasErrors) {
exitCode = 1; isFinished = true;
} else { }
if (usedConsole) {
exitCode = 2; void Runner::timerEvent(QTimerEvent *event)
} {
++m_runs;
if (event->timerId() != m_ticker.timerId())
return;
if (hasErrors && m_runs > 2)
QApplication::instance()->exit(1);
if (isFinished) {
int exitCode = 0;
if (didFail || hasErrors) {
exitCode = 1;
} else {
if (usedConsole) {
exitCode = 2;
} }
}
bool runAgain = true; bool runAgain = true;
if (runnerFiles.count() == 0) { if (runnerFiles.count() == 0) {
runAgain = false;
} else {
if (exitCode == 1) {
runAgain = false; runAgain = false;
} else {
if (exitCode == 1) {
runAgain = false;
}
}
if (runAgain) {
isFinished = false;
loadSpec();
} else {
QApplication::instance()->exit(exitCode);
} }
} }
if (m_runs > 30) { if (runAgain) {
std::cout << "WARNING: too many runs and the test is still not finished!" << std::endl; isFinished = false;
QApplication::instance()->exit(1); loadSpec();
} else {
QApplication::instance()->exit(exitCode);
} }
} }
if (m_runs > 30) {
std::cout << "WARNING: too many runs and the test is still not finished!" << std::endl;
QApplication::instance()->exit(1);
}
}

View File

@ -6,53 +6,57 @@
#include <QFile> #include <QFile>
#include <QTextStream> #include <QTextStream>
#include <iostream> #include <iostream>
#include <fstream>
#include <QQueue> #include <QQueue>
#include "Page.h" #include "Page.h"
#include "ConsoleOutput.h" #include "ConsoleOutput.h"
#include "ReportFileOutput.h" #include "ReportFileOutput.h"
class Runner: public QObject { using namespace std;
Q_OBJECT
public: class Runner: public QObject {
Runner(); Q_OBJECT
void setColors(bool colors); public:
void reportFile(const QString &file); Runner();
void addFile(const QString &spec); void setColors(bool colors);
void go(); void reportFile(const QString &file);
void addFile(const QString &spec);
void go();
public slots: public slots:
void log(const QString &msg); void log(const QString &msg);
bool hasError(); bool hasError();
void leavePageAttempt(const QString &msg); void leavePageAttempt(const QString &msg);
void specPassed(); void specPassed(const QString &specDetail);
void specFailed(const QString &specDetail); 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);
private slots: private slots:
void watch(bool ok); void watch(bool ok);
void errorLog(const QString &msg, int lineNumber, const QString &sourceID); void errorLog(const QString &msg, int lineNumber, const QString &sourceID);
void internalLog(const QString &note, const QString &msg); void internalLog(const QString &note, const QString &msg);
void addJHW(); void addJHW();
protected: protected:
bool hasElement(const char *select); bool hasElement(const char *select);
void timerEvent(QTimerEvent *event); void timerEvent(QTimerEvent *event);
private: private:
Page m_page; Page m_page;
QBasicTimer m_ticker; QBasicTimer m_ticker;
int m_runs; int m_runs;
bool hasErrors; bool hasErrors;
bool usedConsole; bool usedConsole;
bool isFinished; bool isFinished;
bool didFail; bool didFail;
QQueue<QString> runnerFiles; QQueue<QString> runnerFiles;
QString reportFilename; QStack<QString> failedSpecs;
QStack<QString> failedSpecs;
ConsoleOutput consoleOutput; ConsoleOutput consoleOutput;
ReportFileOutput reportFileOutput; ReportFileOutput reportFileOutput;
void loadSpec(); QString reportFileName;
};
void loadSpec();
};
#endif #endif

View File

@ -56,11 +56,13 @@ int main(int argc, char** argv)
app.setApplicationName("jasmine-headless-webkit"); app.setApplicationName("jasmine-headless-webkit");
Runner runner; Runner runner;
runner.setColors(showColors); runner.setColors(showColors);
runner.reportFile(reporter); runner.reportFile(reporter);
for (index = optind; index < argc; index++) { for (index = optind; index < argc; index++) {
runner.addFile(QString::fromLocal8Bit(argv[index])); runner.addFile(QString::fromLocal8Bit(argv[index]));
} }
runner.go(); runner.go();
return app.exec(); return app.exec();

View File

@ -8,19 +8,19 @@ class window.HeadlessReporterResult
@results.push(message) @results.push(message)
print: -> print: ->
output = @name output = @name
bestChoice = this._findSpecLine() bestChoice = HeadlessReporterResult.findSpecLine(@splitName)
output += " (#{bestChoice.file}:#{bestChoice.lineNumber})" if bestChoice.file output += " (#{bestChoice.file}:#{bestChoice.lineNumber})" if bestChoice.file
JHW.printName(output) JHW.printName(output)
for result in @results for result in @results
JHW.printResult(result) JHW.printResult(result)
_findSpecLine: -> @findSpecLine: (splitName) ->
bestChoice = { accuracy: 0, file: null, lineNumber: null } bestChoice = { accuracy: 0, file: null, lineNumber: null }
for file, lines of HeadlessReporterResult.specLineNumbers for file, lines of HeadlessReporterResult.specLineNumbers
index = 0 index = 0
lineNumber = 0 lineNumber = 0
while newLineNumberInfo = lines[@splitName[index]] while newLineNumberInfo = lines[splitName[index]]
if newLineNumberInfo.length == 0 if newLineNumberInfo.length == 0
lineNumber = newLineNumberInfo[0] lineNumber = newLineNumberInfo[0]
else else
@ -40,14 +40,20 @@ class window.HeadlessReporterResult
jasmine.Suite.prototype.getSuiteSplitName = -> jasmine.Suite.prototype.getSuiteSplitName = ->
parts = if @parentSuite then @parentSuite.getSuiteSplitName() else [] parts = if @parentSuite then @parentSuite.getSuiteSplitName() else []
parts.push(@description) parts.push(String(@description).replace(/[\n\r]/g, ' '))
parts parts
jasmine.Spec.prototype.getSpecSplitName = -> jasmine.Spec.prototype.getSpecSplitName = ->
parts = @suite.getSuiteSplitName() parts = @suite.getSuiteSplitName()
parts.push(@description) parts.push(String(@description).replace(/[\n\r]/g, ' '))
parts parts
jasmine.Spec.prototype.getJHWSpecInformation = ->
parts = this.getSpecSplitName()
specLineInfo = HeadlessReporterResult.findSpecLine(parts)
parts.push("#{specLineInfo.file}:#{specLineInfo.lineNumber}")
parts.join("||")
class jasmine.HeadlessReporter class jasmine.HeadlessReporter
constructor: (@callback = null) -> constructor: (@callback = null) ->
@results = [] @results = []
@ -61,27 +67,31 @@ class jasmine.HeadlessReporter
this.callback() if @callback this.callback() if @callback
JHW.finishSuite((new Date() - @startTime) / 1000.0, @length, @failedCount) JHW.finishSuite((new Date() - @startTime) / 1000.0, @length, @failedCount)
reportRunnerStarting: (runner) -> reportRunnerStarting: (runner) ->
@startTime = new Date() @startTime = new Date()
reportSpecResults: (spec) -> reportSpecResults: (spec) ->
return if this.hasError() return if this.hasError()
results = spec.results() results = spec.results()
@length++ @length++
if results.passed() if results.passed()
JHW.specPassed() JHW.specPassed(spec.getJHWSpecInformation())
else else
JHW.specFailed(spec.getSpecSplitName().join('||')) JHW.specFailed(spec.getJHWSpecInformation())
@failedCount++ @failedCount++
failureResult = new HeadlessReporterResult(spec.getFullName(), spec.getSpecSplitName()) failureResult = new HeadlessReporterResult(spec.getFullName(), spec.getSpecSplitName())
for result in results.getItems() for result in results.getItems()
if result.type == 'expect' and !result.passed_ if result.type == 'expect' and !result.passed_
failureResult.addResult(result.message) failureResult.addResult(result.message)
@results.push(failureResult) @results.push(failureResult)
reportSpecStarting: (spec) -> reportSpecStarting: (spec) ->
if this.hasError() if this.hasError()
spec.finish() spec.finish()
spec.suite.finish() spec.suite.finish()
reportSuiteResults: (suite) -> reportSuiteResults: (suite) ->
hasError: -> hasError: ->
JHW.hasError() JHW.hasError()

View File

@ -14,7 +14,7 @@
HeadlessReporterResult.prototype.print = function() { HeadlessReporterResult.prototype.print = function() {
var bestChoice, output, result, _i, _len, _ref, _results; var bestChoice, output, result, _i, _len, _ref, _results;
output = this.name; output = this.name;
bestChoice = this._findSpecLine(); bestChoice = HeadlessReporterResult.findSpecLine(this.splitName);
if (bestChoice.file) { if (bestChoice.file) {
output += " (" + bestChoice.file + ":" + bestChoice.lineNumber + ")"; output += " (" + bestChoice.file + ":" + bestChoice.lineNumber + ")";
} }
@ -27,7 +27,7 @@
} }
return _results; return _results;
}; };
HeadlessReporterResult.prototype._findSpecLine = function() { HeadlessReporterResult.findSpecLine = function(splitName) {
var bestChoice, file, index, lastLine, line, lineNumber, lines, newLineNumberInfo, _i, _len, _ref; var bestChoice, file, index, lastLine, line, lineNumber, lines, newLineNumberInfo, _i, _len, _ref;
bestChoice = { bestChoice = {
accuracy: 0, accuracy: 0,
@ -39,7 +39,7 @@
lines = _ref[file]; lines = _ref[file];
index = 0; index = 0;
lineNumber = 0; lineNumber = 0;
while (newLineNumberInfo = lines[this.splitName[index]]) { while (newLineNumberInfo = lines[splitName[index]]) {
if (newLineNumberInfo.length === 0) { if (newLineNumberInfo.length === 0) {
lineNumber = newLineNumberInfo[0]; lineNumber = newLineNumberInfo[0];
} else { } else {
@ -70,15 +70,22 @@
jasmine.Suite.prototype.getSuiteSplitName = function() { jasmine.Suite.prototype.getSuiteSplitName = function() {
var parts; var parts;
parts = this.parentSuite ? this.parentSuite.getSuiteSplitName() : []; parts = this.parentSuite ? this.parentSuite.getSuiteSplitName() : [];
parts.push(this.description); parts.push(String(this.description).replace(/[\n\r]/g, ' '));
return parts; return parts;
}; };
jasmine.Spec.prototype.getSpecSplitName = function() { jasmine.Spec.prototype.getSpecSplitName = function() {
var parts; var parts;
parts = this.suite.getSuiteSplitName(); parts = this.suite.getSuiteSplitName();
parts.push(this.description); parts.push(String(this.description).replace(/[\n\r]/g, ' '));
return parts; return parts;
}; };
jasmine.Spec.prototype.getJHWSpecInformation = function() {
var parts, specLineInfo;
parts = this.getSpecSplitName();
specLineInfo = HeadlessReporterResult.findSpecLine(parts);
parts.push("" + specLineInfo.file + ":" + specLineInfo.lineNumber);
return parts.join("||");
};
jasmine.HeadlessReporter = (function() { jasmine.HeadlessReporter = (function() {
function HeadlessReporter(callback) { function HeadlessReporter(callback) {
this.callback = callback != null ? callback : null; this.callback = callback != null ? callback : null;
@ -112,9 +119,9 @@
results = spec.results(); results = spec.results();
this.length++; this.length++;
if (results.passed()) { if (results.passed()) {
return JHW.specPassed(); return JHW.specPassed(spec.getJHWSpecInformation());
} else { } else {
JHW.specFailed(spec.getSpecSplitName().join('||')); JHW.specFailed(spec.getJHWSpecInformation());
this.failedCount++; this.failedCount++;
failureResult = new HeadlessReporterResult(spec.getFullName(), spec.getSpecSplitName()); failureResult = new HeadlessReporterResult(spec.getFullName(), spec.getSpecSplitName());
_ref = results.getItems(); _ref = results.getItems();

View File

@ -9,11 +9,8 @@ describe 'HeadlessReporterResult', ->
} }
} }
it 'should find the best spec lines', -> it 'should find the best spec lines', ->
result = new HeadlessReporterResult('test', [ 'name', 'of', 'test' ]) expect(HeadlessReporterResult.findSpecLine([ 'name', 'of', 'test' ]).lineNumber).toEqual(3)
expect(result._findSpecLine().lineNumber).toEqual(3) expect(HeadlessReporterResult.findSpecLine([ 'other', 'of', 'test' ]).lineNumber).toEqual(10)
result = new HeadlessReporterResult('test', [ 'other', 'of', 'test' ])
expect(result._findSpecLine().lineNumber).toEqual(10)
describe 'jasmine.HeadlessReporter', -> describe 'jasmine.HeadlessReporter', ->
reporter = null reporter = null
@ -36,3 +33,31 @@ describe 'jasmine.HeadlessReporter', ->
expect(spec.finish).toHaveBeenCalled() expect(spec.finish).toHaveBeenCalled()
expect(suite.finish).toHaveBeenCalled() expect(suite.finish).toHaveBeenCalled()
describe 'jasmine.Suite.prototype.getSuiteSplitName', ->
it 'should flatten the description', ->
suite = new jasmine.Suite({});
suite.description = "hello\ngoodbye\n";
expect(suite.getSuiteSplitName()).toEqual([ "hello goodbye " ])
it 'should not fail on missing description', ->
suite = new jasmine.Suite({});
suite.description = 1;
expect(suite.getSuiteSplitName()).toEqual([ "1" ])
describe 'jasmine.Spec.prototype.getSuiteSplitName', ->
it 'should flatten the description', ->
spec = new jasmine.Spec({}, {});
spec.suite = {
getSuiteSplitName: -> []
}
spec.description = "hello\ngoodbye\n";
expect(spec.getSpecSplitName()).toEqual([ "hello goodbye " ])
it 'should not fail on missing description', ->
spec = new jasmine.Spec({}, {});
spec.suite = {
getSuiteSplitName: -> []
}
spec.description = 1
expect(spec.getSpecSplitName()).toEqual([ "1" ])

View File

@ -0,0 +1,18 @@
require 'spec_helper'
describe Jasmine::Headless::Report do
include FakeFS::SpecHelpers
describe '.load' do
context 'no file' do
it 'should raise an exception' do
expect { described_class.load(file) }.to raise_error(Errno::ENOENT)
end
end
context 'file' do
end
end
end