Skip to content
Permalink
Browse files
feat(cucumber): scenarios are tagged with Feature, Capability and The…
…me tags

affects: @serenity-js/cucumber, @integration/cucumber
  • Loading branch information
jan-molak committed Aug 7, 2018
1 parent 56ee581 commit a1fef6ce22273bf14518668a286e69c7db021dbb
Showing 5 changed files with 120 additions and 5 deletions.
@@ -0,0 +1,9 @@
Feature: Serenity/JS recognises capabilities

This feature file is nested in a 1-level deep directory structure.
The name of the folder becomes the name of the Capability.

Scenario: A passing scenario

Given a step that passes

@@ -0,0 +1,10 @@
Feature: Serenity/JS recognises capabilities and themes

This feature file is nested in a 2-level deep directory structure.
The name of the folder in which the feature file lives becomes the name of the Capability.
The name of the folder in which the capability folder lives becomes the name of the Theme.

Scenario: A passing scenario

Given a step that passes

@@ -0,0 +1,35 @@
import { expect, ifExitCodeIsOtherThan, logOutput } from '@integration/testing-tools';
import { SceneDescriptionDetected, SceneFinished, SceneTagged } from '@serenity-js/core/lib/events';
import { CapabilityTag, Description, ExecutionSuccessful, FeatureTag } from '@serenity-js/core/lib/model';

import 'mocha';
import { given } from 'mocha-testdata';

import { cucumber, Pick } from '../src';

describe('@serenity-js/cucumber', function() {

this.timeout(5000);

given([
'promise',
'callback',
'synchronous',
]).
it('recognises directories features are grouped in as capabilities', (stepInterface: string) =>
cucumber(
'--require', 'features/support/configure_serenity.ts',
'--require', `features/step_definitions/${ stepInterface }.steps.ts`,
'--require', 'node_modules/@serenity-js/cucumber/register.js',
'features/example_capability/example.feature',
).
then(ifExitCodeIsOtherThan(0, logOutput)).
then(res => {
expect(res.exitCode).to.equal(0);

Pick.from(res.events)
.next(SceneTagged, event => expect(event.tag).to.equal(new CapabilityTag('example capability')))
.next(SceneTagged, event => expect(event.tag).to.equal(new FeatureTag('Serenity/JS recognises capabilities')))
;
}));
});
@@ -0,0 +1,36 @@
import { expect, ifExitCodeIsOtherThan, logOutput } from '@integration/testing-tools';
import { SceneDescriptionDetected, SceneFinished, SceneTagged } from '@serenity-js/core/lib/events';
import { CapabilityTag, Description, ExecutionSuccessful, FeatureTag, ThemeTag } from '@serenity-js/core/lib/model';

import 'mocha';
import { given } from 'mocha-testdata';

import { cucumber, Pick } from '../src';

describe('@serenity-js/cucumber', function() {

this.timeout(5000);

given([
'promise',
'callback',
'synchronous',
]).
it('recognises directories that group capabilities as themes', (stepInterface: string) =>
cucumber(
'--require', 'features/support/configure_serenity.ts',
'--require', `features/step_definitions/${ stepInterface }.steps.ts`,
'--require', 'node_modules/@serenity-js/cucumber/register.js',
'features/example_theme/example_capability/example.feature',
).
then(ifExitCodeIsOtherThan(0, logOutput)).
then(res => {
expect(res.exitCode).to.equal(0);

Pick.from(res.events)
.next(SceneTagged, event => expect(event.tag).to.equal(new ThemeTag('example theme')))
.next(SceneTagged, event => expect(event.tag).to.equal(new CapabilityTag('example capability')))
.next(SceneTagged, event => expect(event.tag).to.equal(new FeatureTag('Serenity/JS recognises capabilities and themes')))
;
}));
});
@@ -11,6 +11,7 @@ import {
import { FileSystemLocation, Path } from '@serenity-js/core/lib/io';
import {
ActivityDetails,
CapabilityTag,
Category,
Description,
ExecutionFailedWithError,
@@ -21,7 +22,9 @@ import {
Name,
Outcome,
ScenarioDetails,
Tag,
Tags,
ThemeTag,
} from '@serenity-js/core/lib/model';
import { StageManager } from '@serenity-js/core/lib/stage';
import * as cucumber from 'cucumber';
@@ -39,12 +42,9 @@ export class Notifier {
this.emit(...notEmpty([
new SceneStarts(details),
new TestRunnerDetected(new Name('Cucumber')),
new SceneTagged(details, new FeatureTag(scenario.getFeature().getName())),
...this.scenarioHierarchyTagsFor(scenario).map(tag => new SceneTagged(details, tag)),
!! scenario.getDescription() && new SceneDescriptionDetected(new Description(scenario.getDescription())),
...scenario.getTags()
.map(cucumberTag => Tags.from(cucumberTag.getName()))
.reduce(flatten, [])
.map(tag => new SceneTagged(details, tag)),
...this.customTagsFor(scenario).map(tag => new SceneTagged(details, tag)),
]));
}

@@ -87,6 +87,31 @@ export class Notifier {
);
}

private customTagsFor(scenario: cucumber.events.ScenarioPayload): Tag[] {
return scenario.getTags()
.map(cucumberTag => Tags.from(cucumberTag.getName()))
.reduce(flatten, []);
}

private scenarioHierarchyTagsFor(scenario: cucumber.events.ScenarioPayload): Tag[] {

const humanReadable = (text: string) => text.replace(/_/g, ' ');

const
separator = '/',
directories = notEmpty(new Path(scenario.getFeature().getUri()).directory().value.split(separator)),
featuresIndex = directories.indexOf('features'),
hierarchy = [ ...directories.slice(featuresIndex + 1), scenario.getFeature().getName() ];

const [ feature, capability, theme ] = hierarchy.reverse();

return notEmpty([
theme && new ThemeTag(humanReadable(theme)),
capability && new CapabilityTag(humanReadable(capability)),
feature && new FeatureTag(feature),
]);
}

private activityDetailsOf(step: cucumber.events.StepPayload): ActivityDetails {

const serialise = (argument: any) => {

0 comments on commit a1fef6c

Please sign in to comment.