mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
work towards allowing you to solo groups of tests easily
This commit is contained in:
@@ -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}}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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([
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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();
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user