only-changed-jest-watch-plugin
Version:
Jest watch plugin for running either only the modified test (for TDD), or tests of dependant modules
105 lines (87 loc) • 3.62 kB
JavaScript
const fs = require('fs');
const path = require('path');
const glob = require("glob");
const dependencyTree = require('dependency-tree');
class OnlyChangedJestWatchPlugin {
constructor({config}) {
this.lastRun = new Date();
this.watchPathIgnoreGlobs = config.watchPathIgnoreGlobs || [];
}
onFileChange(rootDir, dependencies, modifiedFiles) {
const files = glob.sync(rootDir + "/**/*.js", { ignore: this.watchPathIgnoreGlobs });
files.forEach((file) => {
// Store whether has been modified
var stats = fs.statSync(file);
if (stats.mtime > this.lastRun) {
modifiedFiles.push(file);
}
// Get dependencies
const list = dependencyTree.toList({
filename: file,
directory: rootDir,
filter: path => path.indexOf('node_modules') === -1,
});
// Invert dependencies
list.forEach((dependency) => {
if (!(dependency in dependencies)) {
dependencies[dependency] = {};
}
if (!(file in dependencies[dependency])) {
dependencies[dependency][file] = {};
}
});
});
return { dependencies, modifiedFiles};
}
getModifiedDependencies(dependencies, modifiedFiles) {
const modifiedDependencies = {};
modifiedFiles.forEach((modifiedFile) => {
modifiedDependencies[modifiedFile] = dependencies[modifiedFile];
});
return modifiedDependencies;
}
getTestPaths(modifiedDependencies) {
const testPaths = [];
Object.keys(modifiedDependencies).forEach(key => {
// Loop over dependencies
Object.keys(modifiedDependencies[key]).forEach(filePath => {
// Remove file extension
const testPath = filePath.replace(/\.[^/.]+$/, '');
if (!testPaths.includes(testPath)) {
testPaths.push(testPath);
}
});
});
return testPaths;
}
apply(jestHooks) {
jestHooks.onFileChange(({projects}) => {
// A file change has been detected by jest
let dependencies = {};
let modifiedFiles = [];
// Build the inverted dependency tree and get the files that were modified
projects.forEach((project) => {
const result = this.onFileChange(project.config.rootDir, dependencies, modifiedFiles);
dependencies = result.dependencies;
modifiedFiles = result.modifiedFiles;
});
// Filter the dependencies down to files that were modified only
const modifiedDependencies = this.getModifiedDependencies(dependencies, modifiedFiles);
// Get a array of test paths that jest will check tests against to see if it should run the test
this.testPaths = this.getTestPaths(modifiedDependencies);
});
jestHooks.shouldRunTestSuite(({testPath}) => {
// Check to see if this test should be run
for (let i=0;i<this.testPaths.length;i++) {
if (testPath.includes(this.testPaths[i])) {
return true;
}
}
});
jestHooks.onTestRunComplete(results => {
// Store the last run date time
this.lastRun = new Date();
});
}
}
module.exports = OnlyChangedJestWatchPlugin;