Skip to content
This repository has been archived by the owner on Oct 11, 2024. It is now read-only.

Commit

Permalink
NODE - add only when watching
Browse files Browse the repository at this point in the history
This enables to only rerun tests that are affected by a file save
Saving a src file will rerun test files that are dependent of that
with the src file as input to coverage.
Saving a test file will rerun the test file with the dependent src file
as input to coverage
  • Loading branch information
stoffeastrom committed Nov 14, 2017
1 parent 2d61106 commit 1619a33
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 30 deletions.
53 changes: 39 additions & 14 deletions src/node/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,41 @@ const options = require('./options');
class Runner {
constructor(argv, libs) {
this.argv = argv;
this.files = [];
this.testFiles = [];
this.onlyTestFiles = [];
this.srcFiles = [];
this.onlySrcFiles = [];
this.mochaRunner = undefined;
this.mocha = undefined;
this.nyc = undefined;
this.isFirstRun = true;
this.libs = libs;
}
setFiles() {
this.files = globby.sync(this.argv.glob).map(f => path.resolve(f));
if (!this.files.length) {
setOnlyFilesFromTestFile(testFile) {
this.onlyTestFiles = [testFile];
const mod = require.cache[testFile];
this.onlySrcFiles = mod.children.filter(m => this.srcFiles.indexOf(m.id) !== -1).map(m => m.id);
}
setOnlyFilesFromSrcFile(srcFile) {
this.onlyTestFiles = this.testFiles.filter((f) => {
const mod = require.cache[f];
return mod
.children
.filter(m => m.id === srcFile).length !== 0;
});
this.onlySrcFiles = [srcFile];
}
setOnlyFiles(file) {
const isTestFile = this.testFiles.indexOf(file) !== -1;
if (isTestFile) {
this.setOnlyFilesFromTestFile(file);
} else {
this.setOnlyFilesFromSrcFile(file);
}
}
setTestFiles() {
this.testFiles = globby.sync(this.argv.glob).map(f => path.resolve(f));
if (!this.testFiles.length) {
console.log('No files found for:', this.argv.glob);
process.exit(1);
}
Expand Down Expand Up @@ -61,30 +85,30 @@ class Runner {
});
return this;
}
setup() {
setup(testFiles, srcFiles) {
if (this.argv.coverage) {
this.nyc.reset();
if (this.isFirstRun) {
this.nyc.wrap();
}
this.srcFiles.forEach((f) => {
srcFiles.forEach((f) => {
if (require.cache[f]) {
delete require.cache[f];
}
});
}
this.files.forEach((f) => {
testFiles.forEach((f) => {
if (require.cache[f]) {
delete require.cache[f];
}
this.mocha.addFile(f);
});
if (this.argv.coverage) {
this.srcFiles.forEach(f => require(`${f}`));
srcFiles.forEach(f => require(`${f}`));
}
return this;
}
setupAndRunTests() {
setupAndRunTests(testFiles, srcFiles) {
process.removeAllListeners();
if (this.mochaRunner) {
this.mochaRunner.removeAllListeners();
Expand All @@ -93,15 +117,16 @@ class Runner {
this.nyc = new this.libs.NYC(this.argv.nyc);
this
.deleteCoverage()
.setup()
.setup(testFiles, srcFiles)
.runTests();
}
run() {
this.setupAndRunTests();
this.setupAndRunTests(this.testFiles, this.srcFiles);
if (this.argv.watch) {
this.libs.chokidar.watch(this.argv.watchGlob).on('change', () => {
this.libs.chokidar.watch(this.argv.watchGlob).on('change', (f) => {
this.isFirstRun = false;
this.setupAndRunTests();
this.setOnlyFiles(path.resolve(f));
this.setupAndRunTests(this.onlyTestFiles, this.onlySrcFiles);
});
}
}
Expand Down Expand Up @@ -148,7 +173,7 @@ const node = {
handler(argv) {
const runner = new node.Runner(argv, { Mocha, NYC, importCwd, chokidar });
runner
.setFiles()
.setTestFiles()
.setSrcFiles()
.ensureBabelRequire()
.require()
Expand Down
34 changes: 18 additions & 16 deletions test/unit/node/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ describe('Node command', () => {
const argv = {};
const runner = new Runner(argv);
expect(runner.argv).to.equal(argv);
expect(runner.files).to.eql([]);
expect(runner.testFiles).to.eql([]);
expect(runner.srcFiles).to.eql([]);
expect(runner.mochaRunner).to.equal(undefined);
expect(runner.mocha).to.equal(undefined);
Expand All @@ -38,8 +38,8 @@ describe('Node command', () => {
const argv = {};
const runner = new Runner(argv);
sandbox.stub(globby, 'sync').returns(['foo.js']);
runner.setFiles();
expect(runner.files).to.eql([path.resolve('foo.js')]);
runner.setTestFiles();
expect(runner.testFiles).to.eql([path.resolve('foo.js')]);
});

it('should exit if no files found', () => {
Expand All @@ -48,7 +48,7 @@ describe('Node command', () => {
const runner = new Runner(argv);
sandbox.stub(globby, 'sync').returns([]);
sandbox.stub(console, 'log');
runner.setFiles();
runner.setTestFiles();
expect(exit).to.have.been.calledWithExactly(1);
});

Expand Down Expand Up @@ -116,7 +116,7 @@ describe('Node command', () => {
const wrap = sandbox.stub();
const runner = new Runner({ coverage: true });
runner.nyc = { reset, wrap };
runner.setup();
runner.setup([], []);
expect(reset).to.have.been.calledWithExactly();
expect(wrap).to.have.been.calledWithExactly();
});
Expand All @@ -127,7 +127,7 @@ describe('Node command', () => {
const runner = new Runner({ coverage: true });
runner.nyc = { reset, wrap };
runner.isFirstRun = false;
runner.setup();
runner.setup([], []);
expect(reset).to.have.been.calledWithExactly();
expect(wrap.callCount).to.equal(0);
});
Expand All @@ -140,11 +140,7 @@ describe('Node command', () => {
runner.nyc = { reset, wrap };
runner.mocha = { addFile };
const file = path.resolve('test/unit/node/index.spec.js');
const files = [file];
const srcFiles = [path.resolve('src/node/index.js')];
runner.files = files;
runner.srcFiles = srcFiles;
runner.setup();
runner.setup([file], []);
expect(addFile).to.have.been.calledWithExactly(file);
});
});
Expand Down Expand Up @@ -181,19 +177,25 @@ describe('Node command', () => {
it('should run without watching', () => {
const runner = new Runner({ watch: false });
runner.setupAndRunTests = sandbox.stub();
const testFiles = ['foo.spec.js'];
const srcFiles = ['foo.js'];
runner.testFiles = testFiles;
runner.srcFiles = srcFiles;
runner.run();
expect(runner.setupAndRunTests).to.have.been.calledWithExactly();
expect(runner.setupAndRunTests).to.have.been.calledWithExactly(testFiles, srcFiles);
});

it('should run with watching', () => {
sandbox.stub(console, 'log');
const watchGlob = ['foo.js'];
const on = sandbox.stub();
const watch = sandbox.stub().returns({ on });
const chokidar = { watch };
const runner = new Runner({ watch: true, watchGlob }, { chokidar });
runner.setupAndRunTests = sandbox.stub();
runner.findFiles = sandbox.stub();
runner.run();
on.callArg(1);
on.callArg(1, 'foo.js');
expect(runner.isFirstRun).to.equal(false);
expect(runner.setupAndRunTests.callCount).to.equal(2);
});
Expand Down Expand Up @@ -238,20 +240,20 @@ describe('Node command', () => {

it('should call the runner functions', () => {
const origRunner = cmd.Runner;
const setFiles = sandbox.stub().returnsThis();
const setTestFiles = sandbox.stub().returnsThis();
const setSrcFiles = sandbox.stub().returnsThis();
const ensureBabelRequire = sandbox.stub().returnsThis();
const req = sandbox.stub().returnsThis();
const run = sandbox.stub().returnsThis();
class Dummy { }
Dummy.prototype.setFiles = setFiles;
Dummy.prototype.setTestFiles = setTestFiles;
Dummy.prototype.setSrcFiles = setSrcFiles;
Dummy.prototype.ensureBabelRequire = ensureBabelRequire;
Dummy.prototype.require = req;
Dummy.prototype.run = run;
cmd.Runner = Dummy;
handler({});
expect(setFiles).to.have.been.calledImmediatelyBefore(setSrcFiles);
expect(setTestFiles).to.have.been.calledImmediatelyBefore(setSrcFiles);
expect(setSrcFiles).to.have.been.calledImmediatelyBefore(ensureBabelRequire);
expect(ensureBabelRequire).to.have.been.calledImmediatelyBefore(req);
expect(req).to.have.been.calledImmediatelyBefore(run);
Expand Down

0 comments on commit 1619a33

Please sign in to comment.