UNPKG

jest-bdd-generator

Version:

Jest code generator empowered with Gherkin and BDD

179 lines (178 loc) 8.9 kB
function _define_property(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } import { AstBuilder, GherkinClassicTokenMatcher, Parser } from "@cucumber/gherkin"; import { IdGenerator } from "@cucumber/messages"; import { JestToGherkin } from "../jest-to-gherkin/JestToGherkin"; export * from "../types"; const newId = IdGenerator.uuid(); const builder = new AstBuilder(newId); const matcher = new GherkinClassicTokenMatcher(); const parser = new Parser(builder, matcher); class TestGeneratorFromSource { /** * Read Gherkin source code and generate GherkinDocument object. * @param gherkinDoc string of Gherkin soucecode. * @returns GherkinDocument object. */ compileGherkinFromSource(gherkinDoc) { const gherkinDocument = parser.parse(gherkinDoc); return gherkinDocument; } /** * Get steps details from source code. Includes statements, position, accessed variables, defined indentifiers * @param source TypeScript source code in Jest * @returns Array of Steps extracted from the source code. */ compileKnownStepsFromSource(source) { this.source = source; const _piler = new JestToGherkin(); _piler.fileName = "pathTestInput.test.ts"; const o = _piler.transpile(source, { fileName: "pathTestInput.test.ts" }).outputText; this.transpiler = _piler; return _piler.output; } /** * @deprecated * Generate Jest testing. Use `generateJestFromGherkin` instead. * If a step is given source code `statements`, it will use it. * If there are same step definitions in other scenarios without source code, it will reference them with comments. * @param steps array of Steps extracted from source code. * @param gherkinSource source Gherkin text. * @returns Jest testing code in TypeScript, or undefined if cannot find the Feature definition. */ generateGherkinFromSource(steps, gherkinSource) { return this.generateJestFromGherkin(steps, gherkinSource); } /** * Generate Jest testing. * If a step is given source code `statements`, it will use it. * If there are same step definitions in other scenarios without source code, it will reference them with comments. * @param steps array of Steps extracted from source code. * @param gherkinSource source Gherkin text. * @returns Jest testing code in TypeScript, or undefined if cannot find the Feature definition. */ generateJestFromGherkin(steps, gherkinSource) { var _plan_feature, _feature_sourceCode; const plan = this.compileGherkinFromSource(gherkinSource); const statements = (_plan_feature = plan.feature) === null || _plan_feature === void 0 ? void 0 : _plan_feature.children.map((p) => { var _p_scenario, _p_scenario1, _p_scenario2; let lastKeyword; const sourceSteps = (_p_scenario = p.scenario) === null || _p_scenario === void 0 ? void 0 : _p_scenario.steps.map((pStep) => { const criteria = pStep.text; const keyword = pStep.keyword === "And " ? lastKeyword : pStep.keyword; lastKeyword = keyword; const source = steps.find((s) => { var _p_scenario3; return s.value === criteria && s.parent === ((_p_scenario3 = p.scenario) === null || _p_scenario3 === void 0 ? void 0 : _p_scenario3.name); }); if (source === null || source === void 0 ? void 0 : source.sourceCode) { var _source_sourceCode_statements; var _source_sourceCode_statements_map; return [ // `//@${source.key} ${source.value}`, // ` // import [${source.sourceCode?.imports}]`, // ` // export [${source.sourceCode?.exports}]`, ` ${((_source_sourceCode_statements_map = (_source_sourceCode_statements = source.sourceCode.statements) === null || _source_sourceCode_statements === void 0 ? void 0 : _source_sourceCode_statements.map((a) => a.getFullText())) !== null && _source_sourceCode_statements_map !== void 0 ? _source_sourceCode_statements_map : []).join("")}` ].join(""); } const sourceInOtherScenario = steps.find((s) => s.value === criteria); if (sourceInOtherScenario) { var _sourceInOtherScenario_sourceCode, _sourceInOtherScenario_sourceCode1, _sourceInOtherScenario_sourceCode_statements, _sourceInOtherScenario_sourceCode2; var _sourceInOtherScenario_sourceCode_statements_map; return [ `/**`, `* FOUND: @${keyword}${pStep.text}`, `* FROM: (Scenario)${sourceInOtherScenario.parent} - [Step]${sourceInOtherScenario.key} ${sourceInOtherScenario.value}`, `* referenced: [${(_sourceInOtherScenario_sourceCode = sourceInOtherScenario.sourceCode) === null || _sourceInOtherScenario_sourceCode === void 0 ? void 0 : _sourceInOtherScenario_sourceCode.imports}]`, `* declared: [${(_sourceInOtherScenario_sourceCode1 = sourceInOtherScenario.sourceCode) === null || _sourceInOtherScenario_sourceCode1 === void 0 ? void 0 : _sourceInOtherScenario_sourceCode1.exports}]`, `* (remove this comments block with: /^\\s*?\\/\\*\\*\\n\\*\\s*?FOUND: @.+\\n(\\*.+\\n)+/g )`, `${((_sourceInOtherScenario_sourceCode_statements_map = (_sourceInOtherScenario_sourceCode2 = sourceInOtherScenario.sourceCode) === null || _sourceInOtherScenario_sourceCode2 === void 0 ? void 0 : (_sourceInOtherScenario_sourceCode_statements = _sourceInOtherScenario_sourceCode2.statements) === null || _sourceInOtherScenario_sourceCode_statements === void 0 ? void 0 : _sourceInOtherScenario_sourceCode_statements.map((a) => a.getFullText())) !== null && _sourceInOtherScenario_sourceCode_statements_map !== void 0 ? _sourceInOtherScenario_sourceCode_statements_map : []).join("")}`, `*/` ].join("\n"); } return [ `//@${keyword}${pStep.text}`, ` // TODO: implement assertions here;`, ` return 'pending';`, `` ].join(" \n"); }).join("\n"); let fnTitle = "it"; let sourceParams = []; if ((_p_scenario1 = p.scenario) === null || _p_scenario1 === void 0 ? void 0 : _p_scenario1.examples) { const exp = p.scenario.examples.map((ex) => { var _ex_tableHeader; const ret = []; var _ex_tableHeader_cells_map; sourceParams = (_ex_tableHeader_cells_map = (_ex_tableHeader = ex.tableHeader) === null || _ex_tableHeader === void 0 ? void 0 : _ex_tableHeader.cells.map((cell) => cell.value)) !== null && _ex_tableHeader_cells_map !== void 0 ? _ex_tableHeader_cells_map : []; ex.tableBody.forEach((line) => { const row = {}; line.cells.forEach((v, i) => { row[sourceParams[i]] = JSON.parse(v.value); }); const lineExpression = Object.keys(row).map((k) => { const valueExpression = JSON.stringify(row[k]); if (k.match(/^[a-zA-Z][0-9a-zA-Z]*?$/)) { return `${k}: ${valueExpression}`; } else { return `"${k}": ${valueExpression}`; } }).join(", "); ret.push(`{${lineExpression}}`); }); return ret.join(",\n "); }).join(""); fnTitle = `test.each([ ${exp} ])`; sourceParams = sourceParams.map((strVariable) => { if (strVariable.match(/^[a-zA-Z][0-9a-zA-Z]*?$/)) { return strVariable; } else { return `'${strVariable}': ${strVariable.replace(/-(\w)/g, (x) => x[1].toUpperCase())}`; } }); } return `${fnTitle}('${(_p_scenario2 = p.scenario) === null || _p_scenario2 === void 0 ? void 0 : _p_scenario2.name}', async ({ ${sourceParams} }) => { ${sourceSteps} });`; }).flat().join("\n"); const feature = steps.find((s) => { var _plan_feature2; return s.key === "Feature" && s.value === ((_plan_feature2 = plan.feature) === null || _plan_feature2 === void 0 ? void 0 : _plan_feature2.name); }); if (feature === null || feature === void 0 ? void 0 : (_feature_sourceCode = feature.sourceCode) === null || _feature_sourceCode === void 0 ? void 0 : _feature_sourceCode.statements) { const contents = feature.sourceCode.statements; const head = this.source.substring(0, contents[0].getFullStart()); const tail = this.source.substring(contents[contents.length - 1].end); return [ head, statements, tail ].join("\n"); } else { return statements; } } constructor() { _define_property(this, "transpiler", void 0); _define_property(this, "source", void 0); } } export { TestGeneratorFromSource }; //# sourceMappingURL=TestGeneratorFromSource.js.map