work towards allowing you to solo groups of tests easily

This commit is contained in:
Naomi Seyfer
2013-02-17 17:29:03 -08:00
parent 76162f9b06
commit aefe645f6c
6 changed files with 124 additions and 55 deletions

View File

@@ -35,6 +35,7 @@
</div>
</div>
</div>
{{> groupNav}}
<div class="row-fluid"><div class="span11 offset1">
<ul class="failedTests">
{{#each failedTests}}
@@ -51,15 +52,27 @@
</template>
<template name="progressBar">
<div id="testProgressBar" class="progress {{#if running}}progress-striped active{{/if}}">
<div id="testProgressBar" class="progress {{#if running}}progress-striped{{/if}}">
<div class="bar bar-danger" style="width: {{percentFail}}%;"></div>
<div class="bar {{#if anyFail}}bar-warning{{else}}bar-success{{/if}}" style="width: {{percentPass}}%;"></div>
</div>
</template>
<template name="groupNav">
<div class="navbar navbar-fixed-bottom navbar-inverse">
<div class="navbar-inner">
<ul class="nav">
{{#each groupPaths}}
<li><a class="group" href="#">{{name}}</a></li>
{{/each}}
</ul>
</div>
</div>
</template>
<template name="test_group">
<div class="group">
<div class="groupname">{{name}}</div>
<div class="groupname"><a>{{name}}</a></div>
{{#each tests}}
{{> test}}
{{/each}}

View File

@@ -1,15 +1,42 @@
var running = true;
var running;
var groupPathDeps;
var groupPath;
var resultTree;
var failedTests;
var resultDeps;
var countDeps;
var totalCount;
var passedCount;
var failedCount;
var resetTests = function () {
if (!Session.get("groupPath"))
Session.set("groupPath", []);
resultTree = [];
failedTests = [];
resultDeps = new Meteor.deps._ContextSet;
countDeps = new Meteor.deps._ContextSet;
totalCount = 0;
passedCount = 0;
failedCount = 0;
running = true;
};
resetTests();
Meteor.startup(function () {
rerunTests();
});
var rerunTests = function () {
countDeps.invalidateAll();
_resultsChanged();
Meteor._runTestsEverywhere(reportResults, function () {
running = false;
Meteor.onTestsComplete && Meteor.onTestsComplete();
_resultsChanged();
Meteor.flush();
// scroll to top so we can see global pass/fail
$("html, body").scrollTop(0);
});
});
}, Session.get("groupPath"));
};
Template.progressBar.running = function () {
countDeps.addCurrentContext();
@@ -20,14 +47,14 @@ Template.progressBar.percentPass = function () {
countDeps.addCurrentContext();
if (totalCount === 0)
return 0;
return Math.floor(100*passedCount/totalCount);
return 100*passedCount/totalCount;
};
Template.progressBar.percentFail = function () {
countDeps.addCurrentContext();
if (totalCount === 0)
return 0;
return Math.ceil(100*failedCount/totalCount);
return 100*failedCount/totalCount;
};
Template.progressBar.anyFail = function () {
@@ -35,6 +62,28 @@ Template.progressBar.anyFail = function () {
return failedCount > 0;
};
Template.groupNav.groupPaths = function () {
var groupPath = Session.get("groupPath");
var ret = [];
for (var i = 1; i <= groupPath.length; i++) {
ret.push({path: groupPath.slice(0,i), name: groupPath[i-1]});
}
return ret;
};
Template.groupNav.events({
"click .group": function () {
console.log("clicked", this);
Session.set("groupPath", this.path);
}
});
Template.test_group.events({
"click .groupname": function () {
Session.set("groupPath", this.path);
}
});
Template.test_table.running = function() {
resultDeps.addCurrentContext();
return running;
@@ -227,14 +276,6 @@ Template.event.is_debuggable = function() {
};
var resultTree = [];
var failedTests = [];
var resultDeps = new Meteor.deps._ContextSet;
var countDeps = new Meteor.deps._ContextSet;
var totalCount = 0;
var passedCount = 0;
var failedCount = 0;
var _resultsChanged = function() {
resultDeps.invalidateAll();
};
@@ -275,7 +316,6 @@ var _testStatus = function(t) {
// possibly 'events'.
var _findTestForResults = function (results) {
var groupPath = results.groupPath; // array
if ((! _.isArray(groupPath)) || (groupPath.length < 1)) {
throw new Error("Test must be part of a group");
}
@@ -286,7 +326,7 @@ var _findTestForResults = function (results) {
: resultTree);
var newGroup = _.find(array, function(g) { return g.name === gname; });
if (! newGroup) {
newGroup = {name: gname, parent: (group || null)}; // create group
newGroup = {name: gname, parent: (group || null), path: groupPath}; // create group
array.push(newGroup);
}
group = newGroup;

View File

@@ -10,6 +10,8 @@ Package.on_use(function (api) {
api.use('tinytest');
api.use('bootstrap');
api.use('session');
api.use(['spark', 'livedata', 'templating'], 'client');
api.add_files([

View File

@@ -331,9 +331,9 @@ _.extend(TestManager.prototype, {
self.ordered_tests.push(test);
},
createRun: function (onReport) {
createRun: function (onReport, pathPrefix) {
var self = this;
return new TestRun(self, onReport);
return new TestRun(self, onReport, pathPrefix);
}
});
@@ -344,46 +344,60 @@ TestManager = new TestManager;
/* TestRun */
/******************************************************************************/
TestRun = function (manager, onReport) {
TestRun = function (manager, onReport, pathPrefix) {
var self = this;
self.manager = manager;
self.onReport = onReport;
self.next_sequence_number = 0;
self._pathPrefix = pathPrefix || [];
_.each(self.manager.ordered_tests, function (test) {
self._report(test);
if (self._prefixMatch(test.groupPath))
self._report(test);
});
};
_.extend(TestRun.prototype, {
_prefixMatch: function (testPath) {
var self = this;
for (var i = 0; i < self._pathPrefix.length; i++) {
if (!testPath[i] || self._pathPrefix[i] !== testPath[i]) {
return false;
}
}
return true;
},
_runOne: function (test, onComplete, stop_at_offset) {
var self = this;
var startTime = (+new Date);
if (self._prefixMatch(test.groupPath)) {
test.run(function (event) {
/* onEvent */
self._report(test, event);
}, function () {
/* onComplete */
var totalTime = (+new Date) - startTime;
self._report(test, {type: "finish", timeMs: totalTime});
onComplete && onComplete();
}, function (exception) {
/* onException */
test.run(function (event) {
/* onEvent */
self._report(test, event);
}, function () {
/* onComplete */
var totalTime = (+new Date) - startTime;
self._report(test, {type: "finish", timeMs: totalTime});
// XXX you want the "name" and "message" fields on the
// exception, to start with..
self._report(test, {
type: "exception",
details: {
message: exception.message, // XXX empty???
stack: exception.stack // XXX portability
}
});
onComplete && onComplete();
}, stop_at_offset);
} else {
onComplete && onComplete();
}, function (exception) {
/* onException */
// XXX you want the "name" and "message" fields on the
// exception, to start with..
self._report(test, {
type: "exception",
details: {
message: exception.message, // XXX empty???
stack: exception.stack // XXX portability
}
});
onComplete && onComplete();
}, stop_at_offset);
}
},
run: function (onComplete) {
@@ -467,8 +481,8 @@ globals.Tinytest = {
// process only (if called on the server, runs the tests on the
// server, and likewise for the client.) Report results via
// onReport. Call onComplete when it's done.
Meteor._runTests = function (onReport, onComplete) {
var testRun = TestManager.createRun(onReport);
Meteor._runTests = function (onReport, onComplete, pathPrefix) {
var testRun = TestManager.createRun(onReport, pathPrefix);
testRun.run(onComplete);
};

View File

@@ -1,7 +1,7 @@
// Like Meteor._runTests, but runs the tests on both the client and
// the server. Sets a 'server' flag on test results that came from the
// server.
Meteor._runTestsEverywhere = function (onReport, onComplete) {
Meteor._runTestsEverywhere = function (onReport, onComplete, pathPrefix) {
var runId = Random.id();
var localComplete = false;
var remoteComplete = false;
@@ -17,7 +17,7 @@ Meteor._runTestsEverywhere = function (onReport, onComplete) {
Meteor._runTests(onReport, function () {
localComplete = true;
maybeDone();
});
}, pathPrefix);
Meteor.default_connection.registerStore(Meteor._ServerTestResultsCollection, {
update: function (msg) {
@@ -34,12 +34,12 @@ Meteor._runTestsEverywhere = function (onReport, onComplete) {
report.server = true;
onReport(report);
});
}
}
});
var handle = Meteor.subscribe(Meteor._ServerTestResultsSubscription, runId);
Meteor.call('tinytest/run', runId, function (error, result) {
Meteor.call('tinytest/run', runId, pathPrefix, function (error, result) {
if (error)
// XXX better report error
throw new Error("Test server returned an error");

View File

@@ -22,7 +22,7 @@
});
Meteor.methods({
'tinytest/run': function (runId) {
'tinytest/run': function (runId, pathPrefix) {
this.unblock();
// XXX using private API === lame
@@ -52,7 +52,7 @@
future.ret();
};
Meteor._runTests(onReport, onComplete);
Meteor._runTests(onReport, onComplete, pathPrefix);
future.wait();
},