Skip to content

Commit 8956523

Browse files
sawasawasawalgandecki
authored andcommitted
Add tags support (#100)
* Add basic tags support * Add cucumber-tag-expressions package * Remove unused code * Add basic tests for tags implementation * Refactor tags_implementation step * Refactor TagsImplemetation.feature * Lint * Fix logic - enable running scenarios with no tags while the feature is tagged and there is a tagged scenario present NEEDS REFACTORING * Add tests to check whether appropriate tests are run with cypress env TAGS present * Let tests pass when the env TAGS is not set * Improve eslint commments, make error message more explicit * Update package.lock using 6.4.1 * Handle eslint warnings * Update README.ms with tags description * Rename proceedCurrentStep to shouldProceedCurrentStep, fix tests * Add simple test for using 'this' object in step definitions * Install husky and lint-staged, set up pre-commit hook * Fix lint-staged * Requested tweaks * 1.6.0 - added tagging tests
1 parent 51b9b04 commit 8956523

15 files changed

+1116
-101
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
# Changelog
22
All notable changes to this project will be documented in this file.
33

4+
## [1.6.0] - 2018-10-23
5+
### Added
6+
Finally! Tagging tests! (#100, #58, #46, #24 - Thanks @GlynnJKW @ChrisBAshton @jlin412 @sawasawasawa @lucetius for all the great work!)
7+
48
## [1.5.1] - 2018-09-16
59

610
### Fixed

README.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,15 @@ Feature: The Facebook
9090
Then I see "Facebook" in the title
9191
```
9292
93+
## Tagging tests
94+
You can use tags to select which test should run using [cucumber's tag expressions](https://github.com/cucumber/cucumber/tree/master/tag-expressions).
95+
Keep in mind we are using newer syntax, eg. `'not @foo and (@bar or @zap)'`.
96+
In order to initialize tests using tags you will have to run cypress and pass TAGS environment variable.
97+
98+
Example:
99+
```cypress run -e TAGS='not @foo and (@bar or @zap)'```
100+
101+
93102
## Configuration
94103
Add it to your plugins:
95104
@@ -201,8 +210,7 @@ const {given, when, then} = require('cypress-cucumber-preprocessor/resolveStepDe
201210
202211
## TODO
203212
204-
Tags!
205-
(Maybe?) Option to customize mocha template ( #3 )
213+
(Maybe?) Option to customize mocha template ( #3 )
206214
207215
## Credit where it's due!
208216

createTestsFromFeature.js

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,47 @@
11
const { createTestFromScenario } = require("./createTestFromScenario");
2+
const { shouldProceedCurrentStep, getEnvTags } = require("./tagsHelper");
23

34
const createTestsFromFeature = parsedFeature => {
5+
const featureTags = parsedFeature.feature.tags;
6+
const hasEnvTags = !!getEnvTags();
7+
const hasFeatureTags = featureTags && featureTags.length > 0;
8+
9+
let featureShouldRun = true;
10+
if (hasEnvTags) {
11+
if (hasFeatureTags) {
12+
featureShouldRun = shouldProceedCurrentStep(featureTags);
13+
} else {
14+
featureShouldRun = false;
15+
}
16+
}
17+
18+
const taggedScenarioShouldRun = parsedFeature.feature.children.some(
19+
section =>
20+
section.tags &&
21+
section.tags.length &&
22+
shouldProceedCurrentStep(section.tags)
23+
);
24+
425
// eslint-disable-next-line prefer-arrow-callback
526
describe(parsedFeature.feature.name, function() {
6-
const backgroundSection = parsedFeature.feature.children.find(
7-
section => section.type === "Background"
8-
);
9-
const otherSections = parsedFeature.feature.children.filter(
10-
section => section.type !== "Background"
11-
);
12-
otherSections.forEach(section => {
13-
createTestFromScenario(section, backgroundSection);
14-
});
27+
if (featureShouldRun || taggedScenarioShouldRun) {
28+
const backgroundSection = parsedFeature.feature.children.find(
29+
section => section.type === "Background"
30+
);
31+
const otherSections = parsedFeature.feature.children.filter(
32+
section => section.type !== "Background"
33+
);
34+
otherSections.forEach(section => {
35+
const scenarioHasTags = section.tags.length > 0;
36+
const shouldRun =
37+
hasEnvTags && scenarioHasTags
38+
? shouldProceedCurrentStep(section.tags.concat(featureTags)) // concat handles inheritance of tags from feature
39+
: featureShouldRun;
40+
if (shouldRun) {
41+
createTestFromScenario(section, backgroundSection);
42+
}
43+
});
44+
}
1545
});
1646
};
1747

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
Feature: Tags Implementation
2+
3+
As a cucumber cypress plugin which handles Tags
4+
I want to allow people to tag their scenarios with any tag
5+
And then they can use those tags as per https://docs.cucumber.io/cucumber/api/#tags
6+
7+
Scenario: Pass no tags
8+
Given my cypress environment variable TAGS is 'lots of random things'
9+
Then the cypress runner should not break
10+
11+
Scenario: Pass a single tag
12+
Given my cypress environment variable TAGS is '@smoke-tests'
13+
Then tests tagged '@smoke-tests' should proceed
14+
And tests tagged '@wrong-tag' should not proceed
15+
16+
Scenario: Pass a tag to ignore
17+
Given my cypress environment variable TAGS is 'not @ignore'
18+
Then tests tagged '@ignore' should not proceed
19+
Then tests tagged '@do-not-ignore' should proceed
20+
21+
Scenario: Passing multiple tags joined by AND operator
22+
Given my cypress environment variable TAGS is '@foo and @bar'
23+
Then tests tagged '@foo @bar' should proceed
24+
And tests tagged '@foo @ba' should not proceed
25+
26+
Scenario: Passing multiple tags joined by OR operator
27+
Given my cypress environment variable TAGS is '@foo or @bar'
28+
Then tests tagged '@foo' should proceed
29+
And tests tagged '@bar' should proceed
30+
And tests tagged '@foo @baz' should proceed
31+
And tests tagged '@fo @ba' should not proceed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
@test-tag
2+
Feature: Tags Implementation with environmental variables set
3+
4+
As a cucumber cypress plugin which handles Tags
5+
I want to allow people set any tags via CLI
6+
And run only tests selected by given tags
7+
8+
@ignore-tag
9+
Scenario: This scenario should not run if @ignore-tag is present in env
10+
Given 'not @ignore-tag' is in current TAGS environmental variable
11+
Then this should not run
12+
13+
Scenario: This scenario should run
14+
Given '@test-tag' is in current TAGS environmental variable
15+
Then this should run
16+
17+
@this-tag-affects-nothing
18+
Scenario: This scenario should also run
19+
Given '@test-tag' is in current TAGS environmental variable
20+
Then this should run
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
Feature: Tags Implementation with environmental variables set only at scenario level
2+
3+
As a cucumber cypress plugin which handles Tags
4+
I want to allow people set any tags via CLI
5+
And run only tests selected even if they are tagged only at scenario level
6+
7+
Scenario: This scenario should not run if @test-tag is present in env
8+
Given '@test-tag' is in current TAGS environmental variable
9+
Then this should not run
10+
11+
@test-tag
12+
Scenario: This scenario should run
13+
Given '@test-tag' is in current TAGS environmental variable
14+
Then this should run
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Feature: Test for using 'this' keyword in step definitions
2+
3+
Scenario: Keyword 'this' test with a classic function
4+
5+
When I assign a variable to 'this' object
6+
Then 'this' object contains the given value
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/* global given, then */
2+
3+
const {
4+
shouldProceedCurrentStep
5+
} = require("cypress-cucumber-preprocessor/tagsHelper"); // eslint-disable-line
6+
7+
let parsedTags;
8+
9+
given(/my cypress environment variable TAGS is '(.+)'/, envTagsString => {
10+
parsedTags = envTagsString;
11+
});
12+
13+
then(/the cypress runner should not break/, () => {
14+
const shouldNeverThrow = () => {
15+
shouldProceedCurrentStep([{ name: "@test-tag" }], parsedTags);
16+
};
17+
expect(shouldNeverThrow).to.not.throw();
18+
});
19+
20+
then(
21+
/tests tagged '(.+)' should (not )?proceed/,
22+
(tags, shouldProceed = false) => {
23+
const tagsArray = tags.split(" ").map(tag => ({ name: tag }));
24+
expect(shouldProceedCurrentStep(tagsArray, parsedTags)).to.equal(
25+
!shouldProceed
26+
);
27+
}
28+
);
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/* global given, then */
2+
3+
let isPresentInTagsEnv;
4+
const cypressEnvTags = Cypress.env("TAGS");
5+
6+
given(/'(.+)' is in current TAGS environmental variable/, envTagsString => {
7+
isPresentInTagsEnv = RegExp(envTagsString).test(cypressEnvTags);
8+
});
9+
10+
then(/this should (not )?run/, shouldNotRun => {
11+
if (typeof cypressEnvTags !== "undefined") {
12+
expect(!shouldNotRun).to.equal(isPresentInTagsEnv);
13+
}
14+
});
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/* global then, when */
2+
/* eslint-env mocha */
3+
4+
when("I assign a variable to 'this' object", function() {
5+
this.testVariable = "testValue";
6+
});
7+
8+
then("'this' object contains the given value", function() {
9+
expect(this.testVariable).to.equal("testValue");
10+
});

0 commit comments

Comments
 (0)