192 lines
6.0 KiB
JavaScript

/* eslint-disable prefer-template */
const statuses = require("cucumber/lib/status").default;
const {
resolveStepDefinition,
resolveAndRunStepDefinition,
resolveAndRunBeforeHooks,
resolveAndRunAfterHooks,
} = require("./resolveStepDefinition");
const { generateCucumberJson } = require("./cukejson/generateCucumberJson");
const { shouldProceedCurrentStep, getEnvTags } = require("./tagsHelper");
const replaceParameterTags = (rowData, text) =>
Object.keys(rowData).reduce(
(value, key) => value.replace(new RegExp(`<${key}>`, "g"), rowData[key]),
text
);
// eslint-disable-next-line func-names
const stepTest = function (state, stepDetails, exampleRowData) {
const step = resolveStepDefinition.call(
this,
stepDetails,
state.feature.name
);
cy.then(() => state.onStartStep(stepDetails))
.then((step && step.config) || {}, () =>
resolveAndRunStepDefinition.call(
this,
stepDetails,
replaceParameterTags,
exampleRowData,
state.feature.name
)
)
.then(() => state.onFinishStep(stepDetails, statuses.PASSED));
};
const runTest = (scenario, stepsToRun, rowData) => {
const indexedSteps = stepsToRun.map((step, index) => ({ ...step, index }));
// should we actually run this scenario
// or just mark it as skipped
if (scenario.shouldRun) {
// eslint-disable-next-line func-names
it(scenario.name, function () {
const state = window.testState;
return cy
.then(() => state.onStartScenario(scenario, indexedSteps))
.then(() =>
resolveAndRunBeforeHooks.call(this, scenario.tags, state.feature.name)
)
.then(() =>
indexedSteps.forEach((step) =>
stepTest.call(this, state, step, rowData)
)
)
.then(() => state.onFinishScenario(scenario));
});
} else {
// eslint-disable-next-line func-names,prefer-arrow-callback
it(scenario.name, function () {
// register this scenario with the cucumber data collector
// but don't run it
// Tell mocha this is a skipped test so it also shows correctly in Cypress
const state = window.testState;
cy.then(() => state.onStartScenario(scenario, indexedSteps))
.then(() => state.onFinishScenario(scenario))
// eslint-disable-next-line func-names
.then(function () {
return this.skip();
});
});
}
};
const cleanupFilename = (s) => s.split(".")[0];
const writeCucumberJsonFile = (json) => {
const outputFolder =
window.cucumberJson.outputFolder || "cypress/cucumber-json";
const outputPrefix = window.cucumberJson.filePrefix || "";
const outputSuffix = window.cucumberJson.fileSuffix || ".cucumber";
const fileName = json[0] ? cleanupFilename(json[0].uri) : "empty";
const outFile = `${outputFolder}/${outputPrefix}${fileName}${outputSuffix}.json`;
cy.writeFile(outFile, json, { log: false });
};
const createTestFromScenarios = (
allScenarios,
backgroundSection,
testState
) => {
// eslint-disable-next-line func-names, prefer-arrow-callback
before(function () {
cy.then(() => testState.onStartTest());
});
// ctx is cleared between each 'it'
// eslint-disable-next-line func-names, prefer-arrow-callback
beforeEach(function () {
window.testState = testState;
const failHandler = (_, err) => {
testState.onFail(err);
};
Cypress.mocha.getRunner().on("fail", failHandler);
});
allScenarios.forEach((section) => {
if (section.examples) {
const hasEnvTags = !!getEnvTags();
section.examples.forEach((example) => {
const exampleValues = [];
const exampleLocations = [];
const shouldRunExamples =
!hasEnvTags ||
shouldProceedCurrentStep(example.tags.concat(section.tags));
example.tableBody.forEach((row, rowIndex) => {
exampleLocations[rowIndex] = row.location;
example.tableHeader.cells.forEach((header, headerIndex) => {
exampleValues[rowIndex] = {
...exampleValues[rowIndex],
[header.value]: row.cells[headerIndex].value,
};
});
});
exampleValues.forEach((rowData, index) => {
// eslint-disable-next-line prefer-arrow-callback
const scenarioName = replaceParameterTags(rowData, section.name);
const uniqueScenarioName = `${scenarioName} (example #${index + 1})`;
const exampleSteps = section.steps.map((step) => {
const newStep = { ...step };
newStep.text = replaceParameterTags(rowData, newStep.text);
return newStep;
});
const stepsToRun = backgroundSection
? backgroundSection.steps.concat(exampleSteps)
: exampleSteps;
const scenarioExample = {
...section,
// tags on scenario's should be inherited by examples (https://cucumber.io/docs/cucumber/api/#tags)
tags: example.tags.concat(section.tags),
shouldRun: shouldRunExamples,
name: uniqueScenarioName,
example: exampleLocations[index],
};
runTest.call(this, scenarioExample, stepsToRun, rowData);
});
});
} else {
const stepsToRun = backgroundSection
? backgroundSection.steps.concat(section.steps)
: section.steps;
runTest.call(this, section, stepsToRun);
}
});
// eslint-disable-next-line func-names, prefer-arrow-callback
after(function () {
cy.then(() => testState.onFinishTest()).then(() => {
if (window.cucumberJson && window.cucumberJson.generate) {
const json = generateCucumberJson(testState);
writeCucumberJsonFile(json);
}
});
});
// eslint-disable-next-line func-names, prefer-arrow-callback
afterEach(function () {
if (testState.currentScenario && testState.currentScenario.shouldRun) {
cy.then(() =>
resolveAndRunAfterHooks.call(
this,
testState.currentScenario.tags,
testState.feature.name
)
);
}
});
};
module.exports = {
createTestFromScenarios,
};