UNPKG

@serenity-js/cucumber

Version:

Serenity/JS test runner adapter for seamless integration with any version of Cucumber.js, facilitating BDD-style test automation and leveraging Serenity/JS reporting capabilities

130 lines 8.49 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.cucumberEventProtocolAdapter = cucumberEventProtocolAdapter; const core_1 = require("@serenity-js/core"); const errors_1 = require("@serenity-js/core/lib/errors"); const io_1 = require("@serenity-js/core/lib/io"); const model_1 = require("@serenity-js/core/lib/model"); const tiny_types_1 = require("tiny-types"); const errors_2 = require("../../errors"); const gherkin_1 = require("./gherkin"); /** * @private */ function cucumberEventProtocolAdapter({ serenity, notifier, mapper, cache }) { return class CucumberEventProtocolAdapter { // note: exported class expression can't have private properties log; constructor({ eventBroadcaster, log }) { this.log = log; eventBroadcaster.on('gherkin-document', ({ uri, document }) => { (0, tiny_types_1.ensure)('gherkin-document :: uri', uri, (0, tiny_types_1.isDefined)()); (0, tiny_types_1.ensure)('gherkin-document :: document', document, (0, tiny_types_1.isDefined)()); const path = new io_1.Path(uri); cache.set(path, mapper.map(document, path)); // eslint-disable-line unicorn/no-array-method-this-argument }); eventBroadcaster.on('test-case-prepared', ({ steps, sourceLocation }) => { (0, tiny_types_1.ensure)('test-case-prepared :: steps', steps, (0, tiny_types_1.isDefined)()); (0, tiny_types_1.ensure)('test-case-prepared :: sourceLocation', sourceLocation, (0, tiny_types_1.isDefined)()); const path = new io_1.Path(sourceLocation.uri), map = cache.get(path), scenario = map.get(gherkin_1.Scenario).onLine(sourceLocation.line); if (scenario.outline) { const outline = map.get(gherkin_1.ScenarioOutline).onLine(scenario.outline.line); map.set(new gherkin_1.ScenarioOutline(outline.location, outline.name, outline.description, outline.steps, outline.parameters)).onLine(scenario.outline.line); } map.set(new gherkin_1.Scenario(scenario.location, scenario.name, scenario.description, interleaveStepsAndHooks(scenario.steps, steps), scenario.tags, scenario.outline)).onLine(sourceLocation.line); }); eventBroadcaster.on('test-case-started', ({ sourceLocation }) => { (0, tiny_types_1.ensure)('test-case-started :: sourceLocation', sourceLocation, (0, tiny_types_1.isDefined)()); const map = cache.get(new io_1.Path(sourceLocation.uri)), scenario = map.get(gherkin_1.Scenario).onLine(sourceLocation.line), sceneId = serenity.assignNewSceneId(); if (scenario.outline) { const outline = map.get(gherkin_1.ScenarioOutline).onLine(scenario.outline.line); notifier.outlineDetected(sceneId, scenario, outline, map.getFirst(gherkin_1.Feature)); } notifier.scenarioStarts(sceneId, scenario, map.getFirst(gherkin_1.Feature)); }); eventBroadcaster.on('test-step-started', ({ index, testCase }) => { (0, tiny_types_1.ensure)('test-step-started :: index', index, (0, tiny_types_1.isDefined)()); (0, tiny_types_1.ensure)('test-step-started :: testCase', testCase, (0, tiny_types_1.isDefined)()); const map = cache.get(new io_1.Path(testCase.sourceLocation.uri)), scenario = map.get(gherkin_1.Scenario).onLine(testCase.sourceLocation.line), step = scenario.steps[index]; if (step instanceof gherkin_1.Step) { // ignore hooks notifier.stepStarts(step); } }); eventBroadcaster.on('test-step-finished', ({ index, result, testCase }) => { (0, tiny_types_1.ensure)('test-step-finished :: index', index, (0, tiny_types_1.isDefined)()); (0, tiny_types_1.ensure)('test-step-finished :: result', result, (0, tiny_types_1.isDefined)()); (0, tiny_types_1.ensure)('test-step-finished :: testCase', testCase, (0, tiny_types_1.isDefined)()); const map = cache.get(new io_1.Path(testCase.sourceLocation.uri)), scenario = map.get(gherkin_1.Scenario).onLine(testCase.sourceLocation.line), step = scenario.steps[index]; if (step instanceof gherkin_1.Step) { // ignore hooks notifier.stepFinished(step, this.outcomeFrom(result)); } }); eventBroadcaster.on('test-case-finished', ({ result, sourceLocation }) => { (0, tiny_types_1.ensure)('test-case-finished :: result', result, (0, tiny_types_1.isDefined)()); (0, tiny_types_1.ensure)('test-case-finished :: sourceLocation', sourceLocation, (0, tiny_types_1.isDefined)()); const map = cache.get(new io_1.Path(sourceLocation.uri)), scenario = map.get(gherkin_1.Scenario).onLine(sourceLocation.line), nonHookSteps = scenario.steps.filter(step => step instanceof gherkin_1.Step); const outcome = nonHookSteps.length > 0 ? this.outcomeFrom(result) : new model_1.ImplementationPending(new errors_1.ImplementationPendingError(`"${scenario.name.value}" has no test steps`)); notifier.scenarioFinished(scenario, map.getFirst(gherkin_1.Feature), outcome); }); } outcomeFrom(result) { const error = !!result.exception && this.errorFrom(result.exception); switch (result.status) { case 'undefined': return new model_1.ImplementationPending(new errors_1.ImplementationPendingError('Step not implemented')); case 'ambiguous': case 'failed': switch (true) { case error instanceof errors_1.AssertionError: return new model_1.ExecutionFailedWithAssertionError(error); case error instanceof errors_1.TestCompromisedError: return new model_1.ExecutionCompromised(error); default: return new model_1.ExecutionFailedWithError(error); } case 'pending': return new model_1.ImplementationPending(new errors_1.ImplementationPendingError('Step not implemented')); case 'skipped': return new model_1.ExecutionSkipped(); // case 'passed': default: return new model_1.ExecutionSuccessful(); } } errorFrom(maybeError) { switch (true) { case maybeError instanceof core_1.RuntimeError: return maybeError; case maybeError instanceof Error && maybeError.name === 'AssertionError' && maybeError.message && hasOwnProperty(maybeError, 'expected') && hasOwnProperty(maybeError, 'actual'): return serenity.createError(errors_1.AssertionError, { message: maybeError.message, diff: { expected: maybeError.expected, actual: maybeError.actual, }, cause: maybeError }); case typeof maybeError === 'string' && maybeError.startsWith('Multiple step definitions match'): return new errors_2.AmbiguousStepDefinitionError(maybeError); default: return errors_1.ErrorSerialiser.deserialiseFromStackTrace(maybeError); } } }; } /** * @private */ function interleaveStepsAndHooks(steps, stepsLocations) { const isAHook = (stepLocations) => stepLocations.actionLocation && !stepLocations.sourceLocation, matching = (location) => (step) => step.location.path.equals(new io_1.Path(location.sourceLocation.uri)) && step.location.line === location.sourceLocation.line; return stepsLocations.map(location => isAHook(location) ? new gherkin_1.Hook(new io_1.FileSystemLocation(new io_1.Path(location.actionLocation.uri), location.actionLocation.line), new model_1.Name('Setup')) : steps.find(matching(location))); } /** * @private */ function hasOwnProperty(value, fieldName) { return Object.prototype.hasOwnProperty.call(value, fieldName); } //# sourceMappingURL=CucumberEventProtocolAdapter.js.map