vitest-cucumber-plugin 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTING.md +42 -0
- package/LICENSE +21 -0
- package/README.md +113 -0
- package/RELEASE_NOTES.md +9 -0
- package/package.json +34 -0
- package/rollup-nearley.js +10 -0
- package/run-tests +8 -0
- package/src/generate/example.js +20 -0
- package/src/generate/examples.js +47 -0
- package/src/generate/feature.js +45 -0
- package/src/generate/index.js +13 -0
- package/src/generate/scenarioOutline.js +18 -0
- package/src/generate/tests.js +23 -0
- package/src/generate/util.js +10 -0
- package/src/gherkin.js +171 -0
- package/src/gherkin.ne +130 -0
- package/src/gherkin.umd.js +118 -0
- package/src/index.js +65 -0
- package/src/logger.js +7 -0
- package/src/parameterize.js +7 -0
- package/src/parse.js +21 -0
- package/src/steps.js +42 -0
- package/tests/background/features/background.feature +25 -0
- package/tests/background/features/step_definitions/steps.js +30 -0
- package/tests/background/package-lock.json +1967 -0
- package/tests/background/package.json +11 -0
- package/tests/background/vite.config.js +9 -0
- package/tests/comments/features/is-it-friday.feature +10 -0
- package/tests/comments/features/step_definitions/stepdefs.js +15 -0
- package/tests/comments/package-lock.json +1967 -0
- package/tests/comments/package.json +11 -0
- package/tests/comments/vite.config.js +9 -0
- package/tests/data-tables/features/data-tables.feature +25 -0
- package/tests/data-tables/features/step_definitions/data-tables.js +21 -0
- package/tests/data-tables/package-lock.json +1967 -0
- package/tests/data-tables/package.json +11 -0
- package/tests/data-tables/vite.config.js +9 -0
- package/tests/data-tables/vite.config.js.timestamp-1682359000824-3876ac2e9095b.mjs +13 -0
- package/tests/is-it-friday/features/is-it-friday.feature +7 -0
- package/tests/is-it-friday/features/step_definitions/stepdefs.js +15 -0
- package/tests/is-it-friday/package-lock.json +1967 -0
- package/tests/is-it-friday/package.json +11 -0
- package/tests/is-it-friday/vite.config.js +9 -0
- package/tests/is-it-friday-scenario-outline/features/is-it-friday.feature +13 -0
- package/tests/is-it-friday-scenario-outline/features/step_definitions/stepdefs.js +15 -0
- package/tests/is-it-friday-scenario-outline/package-lock.json +1967 -0
- package/tests/is-it-friday-scenario-outline/package.json +11 -0
- package/tests/is-it-friday-scenario-outline/vite.config.js +9 -0
- package/tests/is-it-friday-two-scenarios/features/is-it-friday.feature +12 -0
- package/tests/is-it-friday-two-scenarios/features/step_definitions/stepdefs.js +19 -0
- package/tests/is-it-friday-two-scenarios/package-lock.json +1967 -0
- package/tests/is-it-friday-two-scenarios/package.json +11 -0
- package/tests/is-it-friday-two-scenarios/vite.config.js +9 -0
- package/tests/is-it-friday-two-scenarios-multiple-feature-files/features/friday.feature +7 -0
- package/tests/is-it-friday-two-scenarios-multiple-feature-files/features/step_definitions/stepdefs.js +19 -0
- package/tests/is-it-friday-two-scenarios-multiple-feature-files/features/sunday.feature +8 -0
- package/tests/is-it-friday-two-scenarios-multiple-feature-files/package-lock.json +1967 -0
- package/tests/is-it-friday-two-scenarios-multiple-feature-files/package.json +11 -0
- package/tests/is-it-friday-two-scenarios-multiple-feature-files/vite.config.js +9 -0
- package/tests/keyword-aliases/features/scenario-outline.feature +20 -0
- package/tests/keyword-aliases/features/scenario.feature +14 -0
- package/tests/keyword-aliases/features/step_definitions/steps.js +30 -0
- package/tests/keyword-aliases/features/steps.feature +28 -0
- package/tests/keyword-aliases/package-lock.json +1967 -0
- package/tests/keyword-aliases/package.json +11 -0
- package/tests/keyword-aliases/vite.config.js +9 -0
- package/tests/tags/features/skip.feature +9 -0
- package/tests/tags/features/step_definitions/steps.js +30 -0
- package/tests/tags/features/tags-scenario-outline.feature +30 -0
- package/tests/tags/features/tags.feature +26 -0
- package/tests/tags/package-lock.json +1967 -0
- package/tests/tags/package.json +11 -0
- package/tests/tags/vite.config.js +12 -0
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Contributing Guide
|
|
2
|
+
|
|
3
|
+
## Testing
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
$ npm test
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Running this does a "npm install" followed by a "npm test" in each of the directories found in the [tests](tests)
|
|
10
|
+
directory. The test suite fails if either of these commands returns with a non-zero exit code.
|
|
11
|
+
|
|
12
|
+
## Gherkin parser
|
|
13
|
+
|
|
14
|
+
This plugin uses [nearley](https://nearley.js.org/) with [moo](https://github.com/no-context/moo) to create it's
|
|
15
|
+
Gherkin parser.
|
|
16
|
+
|
|
17
|
+
Before you can run the parser generation script, you must install nearly globally:
|
|
18
|
+
```
|
|
19
|
+
$ npm install -g nearly
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The parser nearley file is [src/gherkin.ne](src/gherkin.ne). If you modify this file, you must
|
|
23
|
+
regenerate the generated parser JS file via:
|
|
24
|
+
```
|
|
25
|
+
$ npm run nearley
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
In addition to running nearley, this script also runs rollup in order to convert the generated parser into an
|
|
29
|
+
ECMAScript module.
|
|
30
|
+
|
|
31
|
+
## Branching
|
|
32
|
+
|
|
33
|
+
This repo uses [git flow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow) as it's
|
|
34
|
+
branching model. The 'main' branch the release branch and is only pushed to during the release process. The
|
|
35
|
+
'develop' branch is the cutting edge branch which is pushed to whenever a feature branch is finished.
|
|
36
|
+
|
|
37
|
+
## Doing a release
|
|
38
|
+
|
|
39
|
+
1. git flow release start <version>
|
|
40
|
+
1. Update version number in package.json
|
|
41
|
+
1. Add the release notes to [RELEASE_NOTES.md](RELEASE_NOTES.md).
|
|
42
|
+
1. git flow release finish <version>
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 SamZiegler
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# vitest-cucumber-plugin
|
|
2
|
+
|
|
3
|
+
Plugin for [Vitest](https://vitest.dev/) to allow tests to be written in [Cucumber](https://cucumber.io/) format.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
$ npm install --save-dev SamZiegler/vitest-cucumber-plugin
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### vite.config.js
|
|
15
|
+
|
|
16
|
+
Import the plugin then add it to the plugins array. Change test.inclue to look for .feature files.
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
import { defineConfig } from 'vitest/config'
|
|
20
|
+
import vitestCucumberPlugin from 'vitest-cucumber-plugin';
|
|
21
|
+
|
|
22
|
+
export default defineConfig({
|
|
23
|
+
plugins: [vitestCucumberPlugin()],
|
|
24
|
+
test: {
|
|
25
|
+
include : [ '**/*.feature' ]
|
|
26
|
+
},
|
|
27
|
+
})
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Writing tests
|
|
31
|
+
|
|
32
|
+
Put feature files into the 'features/' directory and step definitions into the 'features/step_definitions/' directory.
|
|
33
|
+
|
|
34
|
+
See below for the differences between tests written for Cucumber and for this plugin.
|
|
35
|
+
|
|
36
|
+
## Examples
|
|
37
|
+
|
|
38
|
+
Look in the [tests directory](tests) for examples on how to use the plugin.
|
|
39
|
+
|
|
40
|
+
## Differences between this plugin and Cucumber
|
|
41
|
+
|
|
42
|
+
The goal of this plugin is to fully implement Cucumber's Gherkin syntax for feature files, but
|
|
43
|
+
there are a few differences in how step definitions are written.
|
|
44
|
+
|
|
45
|
+
### Changes to Given/When/Then
|
|
46
|
+
|
|
47
|
+
The function signatures for Given, When and Then callbacks have been modified in order to make the step definitions
|
|
48
|
+
more friendly for functional programming. Specifically, the callback functions differ in that they
|
|
49
|
+
now have two parameters, a state object and array of parameters. The callback functions then return a new state
|
|
50
|
+
object which is passed to the next step definition in the chain.
|
|
51
|
+
|
|
52
|
+
For example, here is how you'd write step definitions in Cucumber:
|
|
53
|
+
```
|
|
54
|
+
const assert = require('assert');
|
|
55
|
+
const { Given, When, Then } = require('@cucumber/cucumber');
|
|
56
|
+
|
|
57
|
+
function isItFriday(today) {
|
|
58
|
+
if (today === "Friday") {
|
|
59
|
+
return "TGIF";
|
|
60
|
+
} else {
|
|
61
|
+
return "Nope";
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
Given('today is {string}', function (givenDay) {
|
|
66
|
+
this.today = givenDay;
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
When('I ask whether it\'s Friday yet', function () {
|
|
70
|
+
this.actualAnswer = isItFriday(this.today);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
Then('I should be told {string}', function (expectedAnswer) {
|
|
74
|
+
assert.strictEqual(this.actualAnswer, expectedAnswer);
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Here is how you'd write the same step functions in this plugin:
|
|
79
|
+
```
|
|
80
|
+
import { Given, When, Then } from 'vitest-cucumber-plugin';
|
|
81
|
+
import _ from 'lodash/fp.js';
|
|
82
|
+
import { expect } from 'vitest'
|
|
83
|
+
|
|
84
|
+
Given('today is Sunday', function () {
|
|
85
|
+
return { today : 'Sunday' };
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
Given('today is Friday', function () {
|
|
89
|
+
return { today : 'Friday' };
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
When('I ask whether it\'s Friday yet', function (state) {
|
|
93
|
+
return _.set('answer',(state.today === 'Friday') ? 'TGIF' : 'Nope',state);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
Then('I should be told {string}', function (state,[ answer ]) {
|
|
97
|
+
expect(state.answer).toBe(answer);
|
|
98
|
+
});
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Step definitions must be ECMAScript modules
|
|
102
|
+
|
|
103
|
+
Currently, all step definition files must be in ECMAScript module format. CommonJS files might
|
|
104
|
+
work, but this configuration isn't tested.
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
### Not yet implemented
|
|
108
|
+
|
|
109
|
+
This plugin is not yet feature complete. Here is the list of features from Cucumber which aren't yet implemented:
|
|
110
|
+
* Rule keyword
|
|
111
|
+
* Doc strings
|
|
112
|
+
* Data Table escape characters
|
|
113
|
+
* Boolean expression support for tags
|
package/RELEASE_NOTES.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
* v0.1.3 : Import modules from generated code to make sure they are processed correctly
|
|
2
|
+
* v0.1.2 : Set default log level to warn and make it configurable
|
|
3
|
+
* v0.1.1 : Use root dir from the config to find step_definitions dir
|
|
4
|
+
* v0.1.0 : Added basic support for tags.
|
|
5
|
+
* v0.0.5 : Implemented keyword aliases and comments
|
|
6
|
+
* v0.0.4 : Implemented Data Tables
|
|
7
|
+
* v0.0.3 : Implemented Scenario Outline
|
|
8
|
+
* v0.0.2 : Updated README
|
|
9
|
+
* v0.0.1 : Initial release
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vitest-cucumber-plugin",
|
|
3
|
+
"version": "0.1.3",
|
|
4
|
+
"description": "Plugin for Vitest which allows for tests to be written in Cucumber format.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"vite",
|
|
7
|
+
"vitest",
|
|
8
|
+
"cucumber"
|
|
9
|
+
],
|
|
10
|
+
"homepage": "https://github.com/SamZiegler/vitest-cucumber-plugin#readme",
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/SamZiegler/vitest-cucumber-plugin/issues"
|
|
13
|
+
},
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"main": "src/index.js",
|
|
16
|
+
"type": "module",
|
|
17
|
+
"scripts": {
|
|
18
|
+
"nearley": "nearleyc src/gherkin.ne -o src/gherkin.umd.js && rollup -c rollup-nearley.js",
|
|
19
|
+
"test": "./run-tests"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@cucumber/cucumber-expressions": "^16.1.2",
|
|
23
|
+
"lodash": "^4.17.21",
|
|
24
|
+
"moo": "^0.5.2",
|
|
25
|
+
"nearley": "^2.20.1",
|
|
26
|
+
"pino": "^8.11.0"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@rollup/plugin-commonjs": "^24.1.0",
|
|
30
|
+
"@types/lodash": "^4.14.194",
|
|
31
|
+
"rollup": "^3.20.7"
|
|
32
|
+
},
|
|
33
|
+
"repository" : "https://github.com/SamZiegler/vitest-cucumber-plugin.git"
|
|
34
|
+
}
|
package/run-tests
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { escape, shouldSkip } from './util.js';
|
|
2
|
+
import { generateTests } from './tests.js';
|
|
3
|
+
import _ from 'lodash/fp.js';
|
|
4
|
+
import { log } from '../logger.js';
|
|
5
|
+
|
|
6
|
+
export const generateExample = (config,example) => {
|
|
7
|
+
log.debug('generateExample config: '+JSON.stringify(config)+' example: '+JSON.stringify(example));
|
|
8
|
+
var tests = '';
|
|
9
|
+
|
|
10
|
+
const steps = _.has('background.steps',example) ? _.concat(example.background.steps,example.steps) : example.steps;
|
|
11
|
+
|
|
12
|
+
tests += generateTests(steps);
|
|
13
|
+
|
|
14
|
+
const skip = shouldSkip(config,example.tags) ? '.skip' : '';
|
|
15
|
+
|
|
16
|
+
const code = ` describe${skip}('${escape(example.type.name)}: ${escape(example.name)}', () => {${tests}
|
|
17
|
+
});
|
|
18
|
+
`;
|
|
19
|
+
return code;
|
|
20
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { escape, shouldSkip } from './util.js';
|
|
2
|
+
import { generateTests } from './tests.js';
|
|
3
|
+
import _ from 'lodash/fp.js';
|
|
4
|
+
import { log } from '../logger.js';
|
|
5
|
+
|
|
6
|
+
const createParameterMap = (parameters,values) => {
|
|
7
|
+
const parameterMap = _.reduce((parameterMap,value) => {
|
|
8
|
+
return {
|
|
9
|
+
map : _.set(parameters[parameterMap.index],value,parameterMap.map),
|
|
10
|
+
index : parameterMap.index + 1
|
|
11
|
+
};
|
|
12
|
+
},{ map : {}, index : 0 })(values);
|
|
13
|
+
|
|
14
|
+
return parameterMap.map;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const generateAllTests = (steps,parameters,parameterValues) => {
|
|
18
|
+
const allTests = _.reduce((allTests,values) => {
|
|
19
|
+
const parameterMap = createParameterMap(parameters,values);
|
|
20
|
+
log.debug('parameterMap : '+JSON.stringify(parameterMap));
|
|
21
|
+
|
|
22
|
+
const tests = generateTests(steps,parameterMap,' ');
|
|
23
|
+
|
|
24
|
+
return { tests : allTests.tests + `
|
|
25
|
+
describe('${allTests.index}',() => {${tests}
|
|
26
|
+
});`, index : allTests.index + 1 };
|
|
27
|
+
},{ tests : '', index : 0})(parameterValues);
|
|
28
|
+
|
|
29
|
+
return allTests.tests;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const generateExamples = (config,steps,examplesStatement) => {
|
|
33
|
+
log.debug('generateExamples steps:'+JSON.stringify(steps)+' examples: '+JSON.stringify(examplesStatement));
|
|
34
|
+
|
|
35
|
+
const parameters = _.head(examplesStatement.dataTable);
|
|
36
|
+
const parameterValues = _.tail(examplesStatement.dataTable);
|
|
37
|
+
|
|
38
|
+
log.debug('generateExamples parameters:'+JSON.stringify(parameters)+' parameterValues: '+
|
|
39
|
+
JSON.stringify(parameterValues));
|
|
40
|
+
|
|
41
|
+
const skip = shouldSkip(config,examplesStatement.tags) ? '.skip' : '';
|
|
42
|
+
|
|
43
|
+
const allTests = generateAllTests(steps,parameters,parameterValues);
|
|
44
|
+
const code = ` describe${skip}('${escape(examplesStatement.type.name)}: ${escape(examplesStatement.name)}', () => {${allTests}
|
|
45
|
+
});`;
|
|
46
|
+
return code;
|
|
47
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import _ from 'lodash/fp.js';
|
|
2
|
+
import { log } from '../logger.js';
|
|
3
|
+
import { generateExample, generateScenarioOutline } from './index.js';
|
|
4
|
+
import { escape, shouldSkip } from './util.js';
|
|
5
|
+
|
|
6
|
+
export const generateFeature = (config,feature) => {
|
|
7
|
+
const name = feature.name;
|
|
8
|
+
const statements = feature.statements;
|
|
9
|
+
|
|
10
|
+
const testStatements = _.reduce((testStatements,statement) => {
|
|
11
|
+
if (feature.background) {
|
|
12
|
+
statement = _.set('background',feature.background,statement);
|
|
13
|
+
}
|
|
14
|
+
if (statement.type.type === 'example') {
|
|
15
|
+
return testStatements + generateExample(config,statement);
|
|
16
|
+
} else if (statement.type.type === 'scenarioOutline') {
|
|
17
|
+
return testStatements + generateScenarioOutline(config,statement);
|
|
18
|
+
}
|
|
19
|
+
},'')(statements);
|
|
20
|
+
|
|
21
|
+
const skip = shouldSkip(config,feature.tags) ? '.skip' : '';
|
|
22
|
+
const configStr = JSON.stringify(config);
|
|
23
|
+
|
|
24
|
+
const code = `import { expect, test, describe } from 'vitest';
|
|
25
|
+
import { Test } from 'vitest-cucumber-plugin';
|
|
26
|
+
import { readdir } from 'node:fs/promises';
|
|
27
|
+
|
|
28
|
+
const importStepDefinitions = async (config) => {
|
|
29
|
+
const stepDefinitionDirectory = config.root+'/features/step_definitions';
|
|
30
|
+
const files = await readdir(stepDefinitionDirectory);
|
|
31
|
+
for (const file of files) {
|
|
32
|
+
const stepDefinition = stepDefinitionDirectory+'/'+file;
|
|
33
|
+
await import(stepDefinition);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
await importStepDefinitions(${configStr});
|
|
38
|
+
|
|
39
|
+
describe${skip}('${escape(feature.type.name)}: ${escape(name)}', () => {
|
|
40
|
+
${testStatements}});
|
|
41
|
+
`;
|
|
42
|
+
log.debug(code);
|
|
43
|
+
|
|
44
|
+
return code;
|
|
45
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { generateTests } from './tests.js';
|
|
2
|
+
import { generateExample } from './example.js';
|
|
3
|
+
import { generateExamples } from './examples.js';
|
|
4
|
+
import { generateScenarioOutline } from './scenarioOutline.js';
|
|
5
|
+
import { generateFeature } from './feature.js';
|
|
6
|
+
|
|
7
|
+
export {
|
|
8
|
+
generateTests,
|
|
9
|
+
generateExample,
|
|
10
|
+
generateExamples,
|
|
11
|
+
generateScenarioOutline,
|
|
12
|
+
generateFeature
|
|
13
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import _ from 'lodash/fp.js';
|
|
2
|
+
import { generateExamples } from './examples.js';
|
|
3
|
+
import { escape, shouldSkip } from './util.js';
|
|
4
|
+
|
|
5
|
+
export const generateScenarioOutline = (config,scenarioOutline) => {
|
|
6
|
+
const examplesStatements = _.reduce((examplesStatements,examplesStatement) => {
|
|
7
|
+
return examplesStatements + generateExamples(config,scenarioOutline.steps,examplesStatement);
|
|
8
|
+
},'')(scenarioOutline.examples);
|
|
9
|
+
|
|
10
|
+
const skip = shouldSkip(config,scenarioOutline.tags) ? '.skip' : '';
|
|
11
|
+
|
|
12
|
+
const code = ` describe${skip}('${escape(scenarioOutline.type.name)}: ${escape(scenarioOutline.name)}', () => {
|
|
13
|
+
${examplesStatements}
|
|
14
|
+
});
|
|
15
|
+
`;
|
|
16
|
+
|
|
17
|
+
return code;
|
|
18
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import _ from 'lodash/fp.js';
|
|
2
|
+
import { escape } from './util.js';
|
|
3
|
+
import { parameterizeText } from '../parameterize.js';
|
|
4
|
+
import { log } from '../logger.js';
|
|
5
|
+
|
|
6
|
+
export const generateTests = (steps,parameterMap,extraIndent) => {
|
|
7
|
+
log.debug('generateTests steps : '+JSON.stringify(steps));
|
|
8
|
+
const indent = extraIndent ? extraIndent : '';
|
|
9
|
+
let tests = `
|
|
10
|
+
${indent} var state = {};`;
|
|
11
|
+
|
|
12
|
+
_.forEach((step) => {
|
|
13
|
+
const parameterizedText = ( parameterMap ? parameterizeText(step.text,parameterMap) : step.text);
|
|
14
|
+
const name = parameterizedText;
|
|
15
|
+
const parameterizedStep = _.set('text',parameterizedText,step);
|
|
16
|
+
|
|
17
|
+
const stepString = JSON.stringify(parameterizedStep);
|
|
18
|
+
tests = tests+`
|
|
19
|
+
${indent} test('${escape(step.type.name)} ${escape(name)}', () => { state = Test(state,${stepString}); });`;
|
|
20
|
+
},steps);
|
|
21
|
+
|
|
22
|
+
return tests;
|
|
23
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import _ from 'lodash/fp.js';
|
|
2
|
+
import { log } from '../logger.js';
|
|
3
|
+
|
|
4
|
+
export const escape = (str) => str.replace(/'/g,"\\'");
|
|
5
|
+
export const shouldSkip = (config,tags) => {
|
|
6
|
+
const exclude = _.getOr([],'tags.exclude',config);
|
|
7
|
+
const intersection = _.intersection(exclude,tags);
|
|
8
|
+
log.debug('shouldSkip config: '+JSON.stringify(config)+' tags: '+JSON.stringify(tags)+' intersection: '+JSON.stringify(intersection));
|
|
9
|
+
return intersection.length > 0;
|
|
10
|
+
}
|
package/src/gherkin.js
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import require$$0 from 'lodash/fp.js';
|
|
2
|
+
import require$$1 from 'moo';
|
|
3
|
+
import pino from 'pino';
|
|
4
|
+
|
|
5
|
+
function getDefaultExportFromCjs (x) {
|
|
6
|
+
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function getAugmentedNamespace(n) {
|
|
10
|
+
if (n.__esModule) return n;
|
|
11
|
+
var f = n.default;
|
|
12
|
+
if (typeof f == "function") {
|
|
13
|
+
var a = function a () {
|
|
14
|
+
if (this instanceof a) {
|
|
15
|
+
var args = [null];
|
|
16
|
+
args.push.apply(args, arguments);
|
|
17
|
+
var Ctor = Function.bind.apply(f, args);
|
|
18
|
+
return new Ctor();
|
|
19
|
+
}
|
|
20
|
+
return f.apply(this, arguments);
|
|
21
|
+
};
|
|
22
|
+
a.prototype = f.prototype;
|
|
23
|
+
} else a = {};
|
|
24
|
+
Object.defineProperty(a, '__esModule', {value: true});
|
|
25
|
+
Object.keys(n).forEach(function (k) {
|
|
26
|
+
var d = Object.getOwnPropertyDescriptor(n, k);
|
|
27
|
+
Object.defineProperty(a, k, d.get ? d : {
|
|
28
|
+
enumerable: true,
|
|
29
|
+
get: function () {
|
|
30
|
+
return n[k];
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
return a;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
var gherkin_umd$1 = {exports: {}};
|
|
38
|
+
|
|
39
|
+
const log = pino();
|
|
40
|
+
|
|
41
|
+
log.level = 'warn';
|
|
42
|
+
|
|
43
|
+
var logger = /*#__PURE__*/Object.freeze({
|
|
44
|
+
__proto__: null,
|
|
45
|
+
log: log
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
var require$$2 = /*@__PURE__*/getAugmentedNamespace(logger);
|
|
49
|
+
|
|
50
|
+
(function (module) {
|
|
51
|
+
// Generated automatically by nearley, version 2.20.1
|
|
52
|
+
// http://github.com/Hardmath123/nearley
|
|
53
|
+
(function () {
|
|
54
|
+
|
|
55
|
+
const fp = require$$0;
|
|
56
|
+
const moo = require$$1;
|
|
57
|
+
require$$2.log;
|
|
58
|
+
const lexer = moo.compile({
|
|
59
|
+
emptyLine : { match: /^[ \t]*(?:\#[^\n]+)?\n/, lineBreaks : true },
|
|
60
|
+
newline : { match : '\n', lineBreaks : true },
|
|
61
|
+
ws : /[ \t]+/,
|
|
62
|
+
at : '@',
|
|
63
|
+
colon : ':',
|
|
64
|
+
step : '*',
|
|
65
|
+
pipe : '|',
|
|
66
|
+
backSlash : '\\',
|
|
67
|
+
scenarioOutline : ['Scenario Outline','Scenario Template'],
|
|
68
|
+
word : {
|
|
69
|
+
match : /[^ \t\n:|\\]+/,
|
|
70
|
+
type : moo.keywords({
|
|
71
|
+
feature : 'Feature',
|
|
72
|
+
examples : ['Examples','Scenarios'],
|
|
73
|
+
step : ['Given','When','Then','And','But'],
|
|
74
|
+
example : ['Example','Scenario'],
|
|
75
|
+
background : 'Background',
|
|
76
|
+
}),
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
var grammar = {
|
|
80
|
+
Lexer: lexer,
|
|
81
|
+
ParserRules: [
|
|
82
|
+
{"name": "main", "symbols": ["emptyLines", "tags", "feature"], "postprocess": data => fp.set('tags',data[1],data[2])},
|
|
83
|
+
{"name": "feature", "symbols": ["featureStatement", "freeform", "background", "statements"], "postprocess":
|
|
84
|
+
(data) => fp.assign(data[0],{ description : data[1].trim(), background : data[2], statements : data[3] })
|
|
85
|
+
},
|
|
86
|
+
{"name": "featureStatement", "symbols": ["_", (lexer.has("feature") ? {type: "feature"} : feature), "_", (lexer.has("colon") ? {type: "colon"} : colon), "text", (lexer.has("newline") ? {type: "newline"} : newline)], "postprocess":
|
|
87
|
+
(data) => { return { type : { type : 'feature', name : data[1].value.trim() }, name : data[4].trim() } }
|
|
88
|
+
},
|
|
89
|
+
{"name": "tags", "symbols": [], "postprocess": data => []},
|
|
90
|
+
{"name": "tags", "symbols": ["_", "tag", "tagList", (lexer.has("newline") ? {type: "newline"} : newline)], "postprocess": data => fp.concat(data[1],data[2])},
|
|
91
|
+
{"name": "tagList", "symbols": [], "postprocess": data => []},
|
|
92
|
+
{"name": "tagList", "symbols": ["tagList", (lexer.has("ws") ? {type: "ws"} : ws), "tag"], "postprocess": data => fp.concat(data[0],data[2])},
|
|
93
|
+
{"name": "tag", "symbols": [(lexer.has("at") ? {type: "at"} : at), (lexer.has("word") ? {type: "word"} : word)], "postprocess": data => data[1].value.trim()},
|
|
94
|
+
{"name": "background", "symbols": [], "postprocess": data => null},
|
|
95
|
+
{"name": "background", "symbols": ["backgroundStatement", "freeform", "steps"], "postprocess":
|
|
96
|
+
data => fp.assign(data[0],{ description : data[1].trim(), steps : data[2] })
|
|
97
|
+
},
|
|
98
|
+
{"name": "backgroundStatement", "symbols": ["_", (lexer.has("background") ? {type: "background"} : background), "_", (lexer.has("colon") ? {type: "colon"} : colon), "text", (lexer.has("newline") ? {type: "newline"} : newline)], "postprocess":
|
|
99
|
+
(data) => { return { type : { type : 'background', name : data[1].value }, name : data[4].trim() } }
|
|
100
|
+
},
|
|
101
|
+
{"name": "statement", "symbols": ["example"], "postprocess": data => data[0]},
|
|
102
|
+
{"name": "statement", "symbols": ["scenarioOutline"], "postprocess": data => data[0]},
|
|
103
|
+
{"name": "statements", "symbols": [], "postprocess": data => []},
|
|
104
|
+
{"name": "statements", "symbols": ["statements", "statement"], "postprocess": data => fp.concat(data[0],data[1])},
|
|
105
|
+
{"name": "example", "symbols": ["tags", "exampleStatement", "steps"], "postprocess": (data) => fp.assign(data[1],{ tags : data[0], steps : data[2] })},
|
|
106
|
+
{"name": "exampleStatement", "symbols": ["_", "exampleKeyword", "_", (lexer.has("colon") ? {type: "colon"} : colon), "text", (lexer.has("newline") ? {type: "newline"} : newline)], "postprocess":
|
|
107
|
+
(data) => { return { type : { type : 'example', name : data[1] }, name : data[4].trim() } }
|
|
108
|
+
},
|
|
109
|
+
{"name": "exampleKeyword", "symbols": [(lexer.has("example") ? {type: "example"} : example)], "postprocess": data => data[0].value},
|
|
110
|
+
{"name": "scenarioOutline", "symbols": ["tags", "scenarioOutlineStatement", "steps", "examplesList"], "postprocess":
|
|
111
|
+
data => fp.assign(data[1],{ tags : data[0], steps : data[2], examples : data[3] })
|
|
112
|
+
},
|
|
113
|
+
{"name": "scenarioOutlineStatement", "symbols": ["_", "scenarioOutlineKeyword", "_", (lexer.has("colon") ? {type: "colon"} : colon), "text", (lexer.has("newline") ? {type: "newline"} : newline)], "postprocess":
|
|
114
|
+
(data) => { return { type : { type : 'scenarioOutline', name : data[1] }, name : data[4].trim() } }
|
|
115
|
+
},
|
|
116
|
+
{"name": "scenarioOutlineKeyword", "symbols": [(lexer.has("scenarioOutline") ? {type: "scenarioOutline"} : scenarioOutline)], "postprocess": data => data[0].value},
|
|
117
|
+
{"name": "examplesList", "symbols": [], "postprocess": data => []},
|
|
118
|
+
{"name": "examplesList", "symbols": ["examplesList", "examples"], "postprocess": data => fp.concat(data[0],data[1])},
|
|
119
|
+
{"name": "examples", "symbols": ["tags", "examplesStatement", "dataTable", "emptyLines"], "postprocess":
|
|
120
|
+
data => fp.assign(data[1],{ tags : data[0], dataTable : data[2] })
|
|
121
|
+
},
|
|
122
|
+
{"name": "examplesStatement", "symbols": ["_", "examplesKeyword", "_", (lexer.has("colon") ? {type: "colon"} : colon), "text", (lexer.has("newline") ? {type: "newline"} : newline)], "postprocess":
|
|
123
|
+
(data) => { return { type : { type : 'examples', name : data[1] }, name : data[4] } }
|
|
124
|
+
},
|
|
125
|
+
{"name": "examplesKeyword", "symbols": [(lexer.has("examples") ? {type: "examples"} : examples)], "postprocess": data => data[0].value},
|
|
126
|
+
{"name": "dataTable", "symbols": [], "postprocess": data => []},
|
|
127
|
+
{"name": "dataTable", "symbols": ["dataTable", "dataTableRow"], "postprocess": data => fp.concat(data[0],[data[1]])},
|
|
128
|
+
{"name": "dataTableRow", "symbols": ["_", (lexer.has("pipe") ? {type: "pipe"} : pipe), "dataTableColumns", (lexer.has("newline") ? {type: "newline"} : newline)], "postprocess": data => data[2]},
|
|
129
|
+
{"name": "dataTableColumns", "symbols": [], "postprocess": data => []},
|
|
130
|
+
{"name": "dataTableColumns", "symbols": ["dataTableColumns", "text", (lexer.has("pipe") ? {type: "pipe"} : pipe)], "postprocess": data => fp.concat(data[0],data[1].trim())},
|
|
131
|
+
{"name": "steps", "symbols": ["stepAndTable", "moreSteps"], "postprocess": data => fp.concat(data[0],data[1])},
|
|
132
|
+
{"name": "moreSteps", "symbols": [], "postprocess": data => []},
|
|
133
|
+
{"name": "moreSteps", "symbols": ["moreSteps", "stepAndTable"], "postprocess": data => fp.concat(data[0],data[1])},
|
|
134
|
+
{"name": "moreSteps", "symbols": ["moreSteps", (lexer.has("emptyLine") ? {type: "emptyLine"} : emptyLine)], "postprocess": data => data[0]},
|
|
135
|
+
{"name": "step", "symbols": ["_", "stepKeyword", "text", (lexer.has("newline") ? {type: "newline"} : newline)], "postprocess": data => { return { type : data[1], text : data[2].trim() } }},
|
|
136
|
+
{"name": "stepAndTable", "symbols": ["step", "dataTable"], "postprocess": data => fp.set('dataTable',data[1],data[0])},
|
|
137
|
+
{"name": "stepKeyword", "symbols": [(lexer.has("step") ? {type: "step"} : step)], "postprocess": (data) => { return { type : 'step', name : data[0].value } }},
|
|
138
|
+
{"name": "text", "symbols": [], "postprocess": data => ''},
|
|
139
|
+
{"name": "text", "symbols": ["text", (lexer.has("word") ? {type: "word"} : word)], "postprocess": data => data[0]+data[1].value},
|
|
140
|
+
{"name": "text", "symbols": ["text", (lexer.has("ws") ? {type: "ws"} : ws)], "postprocess": data => data[0]+data[1].value},
|
|
141
|
+
{"name": "text", "symbols": ["text", (lexer.has("step") ? {type: "step"} : step)], "postprocess": data => data[0]+data[1].value},
|
|
142
|
+
{"name": "text", "symbols": ["text", (lexer.has("colon") ? {type: "colon"} : colon)], "postprocess": data => data[0]+data[1].value},
|
|
143
|
+
{"name": "text", "symbols": ["text", (lexer.has("example") ? {type: "example"} : example)], "postprocess": data => data[0]+data[1].value},
|
|
144
|
+
{"name": "text", "symbols": ["text", (lexer.has("examples") ? {type: "examples"} : examples)], "postprocess": data => data[0]+data[1].value},
|
|
145
|
+
{"name": "text", "symbols": ["text", (lexer.has("scenarioOutline") ? {type: "scenarioOutline"} : scenarioOutline)], "postprocess": data => data[0]+data[1].value},
|
|
146
|
+
{"name": "text", "symbols": ["text", (lexer.has("background") ? {type: "background"} : background)], "postprocess": data => data[0]+data[1].value},
|
|
147
|
+
{"name": "bolText", "symbols": [(lexer.has("ws") ? {type: "ws"} : ws), (lexer.has("word") ? {type: "word"} : word)], "postprocess": data => data[1].value},
|
|
148
|
+
{"name": "bolText", "symbols": [(lexer.has("word") ? {type: "word"} : word)], "postprocess": data => data[0].value},
|
|
149
|
+
{"name": "freeform", "symbols": [], "postprocess": data => ''},
|
|
150
|
+
{"name": "freeform", "symbols": ["freeform", "bolText", "text", (lexer.has("newline") ? {type: "newline"} : newline)], "postprocess": (data) => {
|
|
151
|
+
return data[0]+data[1]+data[2]+'\n'
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
{"name": "freeform", "symbols": ["freeform", (lexer.has("emptyLine") ? {type: "emptyLine"} : emptyLine)], "postprocess": data => data[0]+'\n'},
|
|
155
|
+
{"name": "_", "symbols": [], "postprocess": data => ''},
|
|
156
|
+
{"name": "_", "symbols": [(lexer.has("ws") ? {type: "ws"} : ws)], "postprocess": data => data[0].value},
|
|
157
|
+
{"name": "emptyLines", "symbols": [], "postprocess": data => ''},
|
|
158
|
+
{"name": "emptyLines", "symbols": ["emptyLines", (lexer.has("emptyLine") ? {type: "emptyLine"} : emptyLine)], "postprocess": data => data[0]+'\n'}
|
|
159
|
+
]
|
|
160
|
+
, ParserStart: "main"
|
|
161
|
+
};
|
|
162
|
+
{
|
|
163
|
+
module.exports = grammar;
|
|
164
|
+
}
|
|
165
|
+
})();
|
|
166
|
+
} (gherkin_umd$1));
|
|
167
|
+
|
|
168
|
+
var gherkin_umdExports = gherkin_umd$1.exports;
|
|
169
|
+
var gherkin_umd = /*@__PURE__*/getDefaultExportFromCjs(gherkin_umdExports);
|
|
170
|
+
|
|
171
|
+
export { gherkin_umd as default };
|