@nielse63/generate-tests
Version:
Automatically generate jest specs for uncovered source files
113 lines (111 loc) • 4.47 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.GenerateTests = exports.defaults = void 0;
const fast_glob_1 = __importDefault(require("fast-glob"));
const fs_extra_1 = __importDefault(require("fs-extra"));
const ignore_1 = __importDefault(require("ignore"));
const camelCase_1 = __importDefault(require("lodash/camelCase"));
const npmlog_1 = __importDefault(require("npmlog"));
const os_1 = __importDefault(require("os"));
const path_1 = __importDefault(require("path"));
npmlog_1.default.enableColor();
exports.defaults = {
glob: '**/src/**.{js,ts}',
};
class GenerateTests {
constructor(options) {
const config = typeof options === 'string'
? {
...exports.defaults,
glob: options,
}
: {
...exports.defaults,
...options,
};
this.cwd = config.cwd || process.cwd();
this.glob = config.glob;
this.fileobjects = [];
this.ignoredPatterns = [];
this.ignore = (0, ignore_1.default)();
}
async run() {
const files = await this.findFiles();
this.fileobjects = this.createFileObjects(files);
await this.ensureFiles();
await this.writeFiles();
return this.fileobjects;
}
async findGitignoreFiles(filepath = this.cwd) {
const gitignoreFile = path_1.default.join(filepath, '.gitignore');
if (fs_extra_1.default.existsSync(gitignoreFile)) {
const content = await fs_extra_1.default.readFile(gitignoreFile, 'utf-8');
const lines = content.split('\n').filter((line) => {
return line && !line.startsWith('#') && ignore_1.default.isPathValid(line);
});
this.ignore.add(lines);
this.ignoredPatterns.push(...lines);
}
if (filepath === '/' || filepath === os_1.default.homedir()) {
return this.ignoredPatterns;
}
return this.findGitignoreFiles(path_1.default.dirname(filepath));
}
async findFiles() {
await this.findGitignoreFiles();
const files = await (0, fast_glob_1.default)([this.glob], {
cwd: this.cwd,
ignore: ['**/node_modules', '**/flow-typed', '**/coverage', '**/.git'],
});
const filteredFiles = files.filter((file) => !this.ignore.ignores(file));
return filteredFiles;
}
createFileObjects(files) {
const fileobjects = files
.map((file) => {
const abspath = path_1.default.resolve(this.cwd, file);
const basename = path_1.default.basename(abspath);
const dirname = path_1.default.dirname(abspath);
const extension = path_1.default.extname(abspath);
const extrgx = new RegExp(`${extension}$`);
const classname = basename.replace(extrgx, '');
const testpath = path_1.default
.join(dirname, '__tests__', basename)
.replace(extrgx, `.spec${extension}`);
return { file, abspath, testpath, basename, classname };
})
.filter(({ testpath, classname }) => !fs_extra_1.default.existsSync(testpath) && classname !== 'index');
if (!fileobjects.length) {
npmlog_1.default.warn('generate-tests', 'No tests to generate');
return [];
}
return fileobjects;
}
async ensureFiles() {
const promises = this.fileobjects.map(async ({ testpath }) => fs_extra_1.default.ensureFile(testpath));
await Promise.all(promises);
}
async writeFiles() {
const promises = this.fileobjects.map(async ({ classname, testpath }) => {
const template = GenerateTests.createTestTemplate(classname);
return fs_extra_1.default.writeFile(testpath, template, 'utf8');
});
await Promise.all(promises);
}
static createTestTemplate(classname) {
const importName = classname.includes('-')
? (0, camelCase_1.default)(classname)
: classname;
return `import ${importName} from '../${classname}';
describe('${classname}', () => {
it('needs tests', () => {
expect(${importName}).toBeDefined();
});
});
`;
}
}
exports.GenerateTests = GenerateTests;