Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion api.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ Api.prototype._handleTeardown = function (data) {
};

Api.prototype._handleStats = function (stats) {
this.emit('stats', stats);

if (this.hasExclusive && !stats.hasExclusive) {
return;
}
Expand Down Expand Up @@ -165,10 +167,15 @@ Api.prototype._prefixTitle = function (file) {
return prefix;
};

Api.prototype.run = function (files) {
Api.prototype.run = function (files, options) {
var self = this;

this._reset();

if (options && options.runOnlyExclusive) {
this.hasExclusive = true;
}

return handlePaths(files, this.excludePatterns)
.map(function (file) {
return path.resolve(file);
Expand Down
49 changes: 41 additions & 8 deletions lib/watcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,29 @@ function Watcher(logger, api, files, sources) {
this.isTest = makeTestMatcher(files, api.excludePatterns);
this.run = function (specificFiles) {
logger.reset();
this.busy = api.run(specificFiles || files).then(function () {

var runOnlyExclusive = false;
if (specificFiles) {
var exclusiveFiles = specificFiles.filter(function (file) {
return this.filesWithExclusiveTests.indexOf(file) !== -1;
}, this);

runOnlyExclusive = exclusiveFiles.length !== this.filesWithExclusiveTests.length;
}

this.busy = api.run(specificFiles || files, {
runOnlyExclusive: runOnlyExclusive
}).then(function () {
logger.finish();
}, rethrowAsync);
};

this.testDependencies = [];
this.trackTestDependencies(api, sources);

this.filesWithExclusiveTests = [];
this.trackExclusivity(api);

this.dirtyStates = {};
this.watchFiles(files, sources);
this.rerunAll();
Expand Down Expand Up @@ -85,12 +100,6 @@ Watcher.prototype.trackTestDependencies = function (api, sources) {
});
};

Watcher.prototype.removeUnlinkedTestDependencies = function (unlinkedTests) {
unlinkedTests.forEach(function (testFile) {
this.updateTestDependencies(testFile, []);
}, this);
};

Watcher.prototype.updateTestDependencies = function (file, sources) {
if (sources.length === 0) {
this.testDependencies = this.testDependencies.filter(function (dep) {
Expand All @@ -113,6 +122,30 @@ Watcher.prototype.updateTestDependencies = function (file, sources) {
}
};

Watcher.prototype.trackExclusivity = function (api) {
var self = this;
api.on('stats', function (stats) {
self.updateExclusivity(stats.file, stats.hasExclusive);
});
};

Watcher.prototype.updateExclusivity = function (file, hasExclusiveTests) {
var index = this.filesWithExclusiveTests.indexOf(file);

if (hasExclusiveTests && index === -1) {
this.filesWithExclusiveTests.push(file);
} else if (!hasExclusiveTests && index !== -1) {
this.filesWithExclusiveTests.splice(index, 1);
}
};

Watcher.prototype.cleanUnlinkedTests = function (unlinkedTests) {
unlinkedTests.forEach(function (testFile) {
this.updateTestDependencies(testFile, []);
this.updateExclusivity(testFile, false);
}, this);
};

Watcher.prototype.observeStdin = function (stdin) {
var self = this;

Expand Down Expand Up @@ -153,7 +186,7 @@ Watcher.prototype.runAfterChanges = function () {
});
var unlinkedTests = diff(dirtyTests, addedOrChangedTests);

this.removeUnlinkedTestDependencies(unlinkedTests);
this.cleanUnlinkedTests(unlinkedTests);
// No need to rerun tests if the only change is that tests were deleted.
if (unlinkedTests.length === dirtyPaths.length) {
return;
Expand Down
35 changes: 35 additions & 0 deletions test/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,21 @@ test('test file with exclusive tests causes non-exclusive tests in other files t
});
});

test('test files can be forced to run in exclusive mode', function (t) {
t.plan(4);

var api = new Api();
return api.run(
[path.join(__dirname, 'fixture/es2015.js')],
{runOnlyExclusive: true}
).then(function () {
t.ok(api.hasExclusive);
t.is(api.testCount, 0);
t.is(api.passCount, 0);
t.is(api.failCount, 0);
});
});

test('resets state before running', function (t) {
t.plan(2);

Expand Down Expand Up @@ -666,6 +681,26 @@ test('emits dependencies for test files', function (t) {
result.catch(function () {});
});

test('emits stats for test files', function (t) {
t.plan(2);

var api = new Api();
api.on('stats', function (stats) {
if (stats.file === path.normalize('test/fixture/exclusive.js')) {
t.is(stats.hasExclusive, true);
} else if (stats.file === path.normalize('test/fixture/generators.js')) {
t.is(stats.hasExclusive, false);
} else {
t.ok(false);
}
});

return api.run([
'test/fixture/exclusive.js',
'test/fixture/generators.js'
]);
});

test('verify test count', function (t) {
t.plan(8);

Expand Down
Loading