codeceptjs
Version:
Modern Era Acceptance Testing Framework for NodeJS
131 lines (115 loc) • 4.5 kB
JavaScript
const getConfig = require('../utils').getConfig;
const getTestRoot = require('../utils').getTestRoot;
const Codecept = require('../../codecept');
const container = require('../../container');
const output = require('../../output');
const { matchStep } = require('../../interfaces/bdd');
const { Parser } = require('gherkin');
const glob = require('glob');
const fsPath = require('path');
const fs = require('fs');
const escapeStringRegexp = require('escape-string-regexp');
const parser = new Parser();
parser.stopAtFirstError = false;
module.exports = function (genPath, options) {
const configFile = options.config || genPath;
const testsPath = getTestRoot(configFile);
const config = getConfig(configFile);
if (!config) return;
const codecept = new Codecept(config, {});
codecept.init(testsPath);
if (!config.gherkin) {
output.error('Gherkin is not enabled in config. Run `codecept gherkin:init` to enable it');
process.exit(1);
}
if (!config.gherkin.steps || !config.gherkin.steps[0]) {
output.error('No gherkin steps defined in config. Exiting');
process.exit(1);
}
if (!options.feature && !config.gherkin.features) {
output.error('No gherkin features defined in config. Exiting');
process.exit(1);
}
if (options.path && !config.gherkin.steps.includes(options.path)) {
output.error(`You must include ${options.path} to the gherkin steps in your config file`);
process.exit(1);
}
const files = [];
glob.sync(options.feature || config.gherkin.features, { cwd: options.feature ? '.' : global.codecept_dir }).forEach((file) => {
if (!fsPath.isAbsolute(file)) {
file = fsPath.join(global.codecept_dir, file);
}
files.push(fsPath.resolve(file));
});
output.print(`Loaded ${files.length} files`);
let newSteps = [];
const parseSteps = (steps) => {
const newSteps = [];
let currentKeyword = '';
for (const step of steps) {
if (step.keyword.trim() === 'And') {
if (!currentKeyword) throw new Error(`There is no active keyword for step '${step.text}'`);
step.keyword = currentKeyword;
}
currentKeyword = step.keyword;
try {
matchStep(step.text);
} catch (err) {
let stepLine;
if (/[{}()/]/.test(step.text)) {
stepLine = escapeStringRegexp(step.text)
.replace(/\//g, '\\/')
.replace(/\"(.*?)\"/g, '"(.*?)"')
.replace(/(\d+\\\.\d+)/, '(\\d+\\.\\d+)')
.replace(/ (\d+) /, ' (\\d+) ');
stepLine = Object.assign(stepLine, { type: step.keyword.trim(), location: step.location, regexp: true });
} else {
stepLine = step.text
.replace(/\"(.*?)\"/g, '{string}')
.replace(/(\d+\.\d+)/, '{float}')
.replace(/ (\d+) /, ' {int} ');
stepLine = Object.assign(stepLine, { type: step.keyword.trim(), location: step.location, regexp: false });
}
newSteps.push(stepLine);
}
}
return newSteps;
};
const parseFile = (file) => {
const ast = parser.parse(fs.readFileSync(file).toString());
for (const child of ast.feature.children) {
if (child.type === 'ScenarioOutline') continue; // skip scenario outline
newSteps = newSteps.concat(parseSteps(child.steps).map((step) => {
return Object.assign(step, { file: file.replace(global.codecept_dir, '').slice(1) });
}));
}
};
files.forEach(file => parseFile(file));
let stepFile = options.path || config.gherkin.steps[0];
if (!fs.existsSync(stepFile)) {
output.error('Please enter a valid step file path ', stepFile);
process.exit(1);
}
if (!fsPath.isAbsolute(stepFile)) {
stepFile = fsPath.join(global.codecept_dir, stepFile);
}
const snippets = newSteps
.filter((value, index, self) => self.indexOf(value) === index)
.map((step) => {
return `
${step.type}(${step.regexp ? '/^' : "'"}${step}${step.regexp ? '$/' : "'"}, () => {
// From "${step.file}" ${JSON.stringify(step.location)}
throw new Error('Not implemented yet');
});`;
});
if (!snippets.length) {
output.print('No new snippets found');
return;
}
output.success(`Snippets generated: ${snippets.length}`);
output.print(snippets.join('\n'));
if (!options.dryRun) {
output.success(`Snippets added to ${output.colors.bold(stepFile)}`);
fs.writeFileSync(stepFile, fs.readFileSync(stepFile).toString() + snippets.join('\n') + '\n'); // eslint-disable-line
}
};