166 lines
4.6 KiB
JavaScript
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 };
|