Skip to content

Commit 83ab1e4

Browse files
committed
Merge pull request #621 from sindresorhus/sticky-only
Make .only sticky in watch mode
2 parents e810ed4 + b4abee1 commit 83ab1e4

File tree

4 files changed

+213
-31
lines changed

4 files changed

+213
-31
lines changed

api.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ Api.prototype._handleTeardown = function (data) {
106106
};
107107

108108
Api.prototype._handleStats = function (stats) {
109+
this.emit('stats', stats);
110+
109111
if (this.hasExclusive && !stats.hasExclusive) {
110112
return;
111113
}
@@ -165,10 +167,15 @@ Api.prototype._prefixTitle = function (file) {
165167
return prefix;
166168
};
167169

168-
Api.prototype.run = function (files) {
170+
Api.prototype.run = function (files, options) {
169171
var self = this;
170172

171173
this._reset();
174+
175+
if (options && options.runOnlyExclusive) {
176+
this.hasExclusive = true;
177+
}
178+
172179
return handlePaths(files, this.excludePatterns)
173180
.map(function (file) {
174181
return path.resolve(file);

lib/watcher.js

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,29 @@ function Watcher(logger, api, files, sources) {
3939
this.isTest = makeTestMatcher(files, api.excludePatterns);
4040
this.run = function (specificFiles) {
4141
logger.reset();
42-
this.busy = api.run(specificFiles || files).then(function () {
42+
43+
var runOnlyExclusive = false;
44+
if (specificFiles) {
45+
var exclusiveFiles = specificFiles.filter(function (file) {
46+
return this.filesWithExclusiveTests.indexOf(file) !== -1;
47+
}, this);
48+
49+
runOnlyExclusive = exclusiveFiles.length !== this.filesWithExclusiveTests.length;
50+
}
51+
52+
this.busy = api.run(specificFiles || files, {
53+
runOnlyExclusive: runOnlyExclusive
54+
}).then(function () {
4355
logger.finish();
4456
}, rethrowAsync);
4557
};
4658

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

62+
this.filesWithExclusiveTests = [];
63+
this.trackExclusivity(api);
64+
5065
this.dirtyStates = {};
5166
this.watchFiles(files, sources);
5267
this.rerunAll();
@@ -85,12 +100,6 @@ Watcher.prototype.trackTestDependencies = function (api, sources) {
85100
});
86101
};
87102

88-
Watcher.prototype.removeUnlinkedTestDependencies = function (unlinkedTests) {
89-
unlinkedTests.forEach(function (testFile) {
90-
this.updateTestDependencies(testFile, []);
91-
}, this);
92-
};
93-
94103
Watcher.prototype.updateTestDependencies = function (file, sources) {
95104
if (sources.length === 0) {
96105
this.testDependencies = this.testDependencies.filter(function (dep) {
@@ -113,6 +122,30 @@ Watcher.prototype.updateTestDependencies = function (file, sources) {
113122
}
114123
};
115124

125+
Watcher.prototype.trackExclusivity = function (api) {
126+
var self = this;
127+
api.on('stats', function (stats) {
128+
self.updateExclusivity(stats.file, stats.hasExclusive);
129+
});
130+
};
131+
132+
Watcher.prototype.updateExclusivity = function (file, hasExclusiveTests) {
133+
var index = this.filesWithExclusiveTests.indexOf(file);
134+
135+
if (hasExclusiveTests && index === -1) {
136+
this.filesWithExclusiveTests.push(file);
137+
} else if (!hasExclusiveTests && index !== -1) {
138+
this.filesWithExclusiveTests.splice(index, 1);
139+
}
140+
};
141+
142+
Watcher.prototype.cleanUnlinkedTests = function (unlinkedTests) {
143+
unlinkedTests.forEach(function (testFile) {
144+
this.updateTestDependencies(testFile, []);
145+
this.updateExclusivity(testFile, false);
146+
}, this);
147+
};
148+
116149
Watcher.prototype.observeStdin = function (stdin) {
117150
var self = this;
118151

@@ -153,7 +186,7 @@ Watcher.prototype.runAfterChanges = function () {
153186
});
154187
var unlinkedTests = diff(dirtyTests, addedOrChangedTests);
155188

156-
this.removeUnlinkedTestDependencies(unlinkedTests);
189+
this.cleanUnlinkedTests(unlinkedTests);
157190
// No need to rerun tests if the only change is that tests were deleted.
158191
if (unlinkedTests.length === dirtyPaths.length) {
159192
return;

test/api.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,21 @@ test('test file with exclusive tests causes non-exclusive tests in other files t
621621
});
622622
});
623623

624+
test('test files can be forced to run in exclusive mode', function (t) {
625+
t.plan(4);
626+
627+
var api = new Api();
628+
return api.run(
629+
[path.join(__dirname, 'fixture/es2015.js')],
630+
{runOnlyExclusive: true}
631+
).then(function () {
632+
t.ok(api.hasExclusive);
633+
t.is(api.testCount, 0);
634+
t.is(api.passCount, 0);
635+
t.is(api.failCount, 0);
636+
});
637+
});
638+
624639
test('resets state before running', function (t) {
625640
t.plan(2);
626641

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

684+
test('emits stats for test files', function (t) {
685+
t.plan(2);
686+
687+
var api = new Api();
688+
api.on('stats', function (stats) {
689+
if (stats.file === path.normalize('test/fixture/exclusive.js')) {
690+
t.is(stats.hasExclusive, true);
691+
} else if (stats.file === path.normalize('test/fixture/generators.js')) {
692+
t.is(stats.hasExclusive, false);
693+
} else {
694+
t.ok(false);
695+
}
696+
});
697+
698+
return api.run([
699+
'test/fixture/exclusive.js',
700+
'test/fixture/generators.js'
701+
]);
702+
});
703+
669704
test('verify test count', function (t) {
670705
t.plan(8);
671706

0 commit comments

Comments
 (0)