Simon Priet 9e2991e668 init
2021-09-05 22:53:58 +02:00

166 lines
4.6 KiB
JavaScript

const { Parser } = require("gherkin");
const statuses = require("cucumber/lib/status").default;
class CucumberDataCollector {
constructor(uri, spec) {
this.feature = new Parser().parse(spec.toString()).feature;
this.scenarioSteps = {};
this.runScenarios = {};
this.runTests = {};
this.stepResults = {};
this.testError = null;
this.uri = uri;
this.spec = spec;
this.currentScenario = null;
this.currentStep = 0;
this.timer = Date.now();
this.logStep = (step) => {
Cypress.log({
name: "step",
displayName: step.keyword,
message: `**${step.text}**`,
consoleProps: () => ({ feature: this.uri, step }),
});
};
this.onStartTest = () => {};
this.onFinishTest = () => {
if (this.testError) {
this.attachErrorToFailingStep();
}
};
this.onStartScenario = (scenario, stepsToRun) => {
this.currentScenario = scenario;
this.currentStep = 0;
this.stepResults = {};
this.scenarioSteps[scenario.name] = stepsToRun;
this.testError = null;
stepsToRun.forEach((step) => {
this.stepResults[step.index] = { status: statuses.PENDING };
});
this.runScenarios[scenario.name] = scenario;
};
this.onFinishScenario = (scenario) => {
this.markStillPendingStepsAsSkipped(scenario);
this.recordScenarioResult(scenario);
};
this.onStartStep = (step) => {
this.currentStep = step.index;
this.setStepToPending(step);
this.logStep(step);
};
this.onFinishStep = (step, result) => {
this.recordStepResult(step, result);
};
this.onFail = (err) => {
this.testError = err;
if (
err.message &&
err.message.indexOf("Step implementation missing for") > -1
) {
this.stepResults[this.currentStep] = {
status: statuses.UNDEFINED,
duration: this.timeTaken(),
};
} else if (err.constructor.name === "Pending") {
// cypress marks skipped mocha tests as pending
// https://github.com/cypress-io/cypress/issues/3092
// don't record this error and mark the step as skipped
this.stepResults[this.currentStep] = {
status: statuses.SKIPPED,
duration: this.timeTaken(),
};
} else {
this.stepResults[this.currentStep] = {
status: statuses.FAILED,
duration: this.timeTaken(),
exception: this.testError,
};
}
this.onFinishScenario(this.currentScenario);
};
this.timeTaken = () => {
const now = Date.now();
const duration = now - this.timer;
this.timer = now;
return duration;
};
this.formatTestCase = (scenario) => {
const line = scenario.example
? scenario.example.line
: scenario.location.line;
return {
sourceLocation: { uri, line },
};
};
this.attachErrorToFailingStep = () => {
Object.keys(this.runTests).forEach((test) => {
const stepResults = this.runTests[test];
Object.keys(stepResults).forEach((stepIdx) => {
const stepResult = stepResults[stepIdx];
if (stepResult.result === statuses.FAILED) {
stepResult.exception = this.testError;
}
});
});
};
this.markStillPendingStepsAsSkipped = (scenario) => {
this.runTests[scenario.name] = Object.keys(this.stepResults).map(
(key) => {
const result = this.stepResults[key];
return {
...result,
status:
result.status === statuses.PENDING
? statuses.SKIPPED
: result.status,
};
}
);
};
this.recordScenarioResult = (scenario) => {
const allSkipped = this.areAllStepsSkipped(scenario.name);
const anyFailed = this.anyStepsHaveFailed(scenario.name);
if (allSkipped) this.runTests[scenario.name].result = statuses.SKIPPED;
else
this.runTests[scenario.name].result = anyFailed
? statuses.FAILED
: statuses.PASSED;
};
this.setStepToPending = (step) => {
this.stepResults[step.index] = { status: statuses.PENDING };
};
this.recordStepResult = (step, result) => {
this.stepResults[step.index] = {
status: result,
duration: this.timeTaken(),
};
};
this.areAllStepsSkipped = (name) =>
this.runTests[name].every((e) => e.status === statuses.SKIPPED);
this.anyStepsHaveFailed = (name) =>
this.runTests[name].find((e) => e.status === statuses.FAILED) !==
undefined;
}
}
module.exports = { CucumberDataCollector };