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/src/gherkin.ne
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
@{%
|
|
2
|
+
const fp = require('lodash/fp.js');
|
|
3
|
+
const moo = require('moo');
|
|
4
|
+
const log = require('./logger.js').log;
|
|
5
|
+
const lexer = moo.compile({
|
|
6
|
+
emptyLine : { match: /^[ \t]*(?:\#[^\n]+)?\n/, lineBreaks : true },
|
|
7
|
+
newline : { match : '\n', lineBreaks : true },
|
|
8
|
+
ws : /[ \t]+/,
|
|
9
|
+
at : '@',
|
|
10
|
+
colon : ':',
|
|
11
|
+
step : '*',
|
|
12
|
+
pipe : '|',
|
|
13
|
+
backSlash : '\\',
|
|
14
|
+
scenarioOutline : ['Scenario Outline','Scenario Template'],
|
|
15
|
+
word : {
|
|
16
|
+
match : /[^ \t\n:|\\]+/,
|
|
17
|
+
type : moo.keywords({
|
|
18
|
+
feature : 'Feature',
|
|
19
|
+
examples : ['Examples','Scenarios'],
|
|
20
|
+
step : ['Given','When','Then','And','But'],
|
|
21
|
+
example : ['Example','Scenario'],
|
|
22
|
+
background : 'Background',
|
|
23
|
+
}),
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
%}
|
|
27
|
+
|
|
28
|
+
@lexer lexer
|
|
29
|
+
|
|
30
|
+
main -> emptyLines tags feature {% data => fp.set('tags',data[1],data[2]) %}
|
|
31
|
+
|
|
32
|
+
feature -> featureStatement freeform background statements {%
|
|
33
|
+
(data) => fp.assign(data[0],{ description : data[1].trim(), background : data[2], statements : data[3] })
|
|
34
|
+
%}
|
|
35
|
+
featureStatement -> _ %feature _ %colon text %newline {%
|
|
36
|
+
(data) => { return { type : { type : 'feature', name : data[1].value.trim() }, name : data[4].trim() } }
|
|
37
|
+
%}
|
|
38
|
+
|
|
39
|
+
tags -> null {% data => [] %}
|
|
40
|
+
| _ tag tagList %newline {% data => fp.concat(data[1],data[2]) %}
|
|
41
|
+
|
|
42
|
+
tagList -> null {% data => [] %}
|
|
43
|
+
| tagList %ws tag {% data => fp.concat(data[0],data[2]) %}
|
|
44
|
+
|
|
45
|
+
tag -> %at %word {% data => data[1].value.trim() %}
|
|
46
|
+
|
|
47
|
+
background -> null {% data => null %}
|
|
48
|
+
| backgroundStatement freeform steps {%
|
|
49
|
+
data => fp.assign(data[0],{ description : data[1].trim(), steps : data[2] })
|
|
50
|
+
%}
|
|
51
|
+
|
|
52
|
+
backgroundStatement -> _ %background _ %colon text %newline {%
|
|
53
|
+
(data) => { return { type : { type : 'background', name : data[1].value }, name : data[4].trim() } }
|
|
54
|
+
%}
|
|
55
|
+
|
|
56
|
+
statement -> example {% data => data[0] %}
|
|
57
|
+
| scenarioOutline {% data => data[0] %}
|
|
58
|
+
|
|
59
|
+
statements -> null {% data => [] %}
|
|
60
|
+
| statements statement {% data => fp.concat(data[0],data[1]) %}
|
|
61
|
+
|
|
62
|
+
example -> tags exampleStatement steps {% (data) => fp.assign(data[1],{ tags : data[0], steps : data[2] }) %}
|
|
63
|
+
exampleStatement -> _ exampleKeyword _ %colon text %newline {%
|
|
64
|
+
(data) => { return { type : { type : 'example', name : data[1] }, name : data[4].trim() } }
|
|
65
|
+
%}
|
|
66
|
+
exampleKeyword -> %example {% data => data[0].value %}
|
|
67
|
+
|
|
68
|
+
scenarioOutline -> tags scenarioOutlineStatement steps examplesList {%
|
|
69
|
+
data => fp.assign(data[1],{ tags : data[0], steps : data[2], examples : data[3] })
|
|
70
|
+
%}
|
|
71
|
+
scenarioOutlineStatement -> _ scenarioOutlineKeyword _ %colon text %newline {%
|
|
72
|
+
(data) => { return { type : { type : 'scenarioOutline', name : data[1] }, name : data[4].trim() } }
|
|
73
|
+
%}
|
|
74
|
+
scenarioOutlineKeyword -> %scenarioOutline {% data => data[0].value %}
|
|
75
|
+
|
|
76
|
+
examplesList -> null {% data => [] %}
|
|
77
|
+
| examplesList examples {% data => fp.concat(data[0],data[1]) %}
|
|
78
|
+
|
|
79
|
+
examples -> tags examplesStatement dataTable emptyLines {%
|
|
80
|
+
data => fp.assign(data[1],{ tags : data[0], dataTable : data[2] })
|
|
81
|
+
%}
|
|
82
|
+
examplesStatement -> _ examplesKeyword _ %colon text %newline {%
|
|
83
|
+
(data) => { return { type : { type : 'examples', name : data[1] }, name : data[4] } }
|
|
84
|
+
%}
|
|
85
|
+
examplesKeyword -> %examples {% data => data[0].value %}
|
|
86
|
+
|
|
87
|
+
dataTable -> null {% data => [] %}
|
|
88
|
+
| dataTable dataTableRow {% data => fp.concat(data[0],[data[1]]) %}
|
|
89
|
+
|
|
90
|
+
dataTableRow -> _ %pipe dataTableColumns %newline {% data => data[2] %}
|
|
91
|
+
|
|
92
|
+
dataTableColumns -> null {% data => [] %}
|
|
93
|
+
| dataTableColumns text %pipe {% data => fp.concat(data[0],data[1].trim()) %}
|
|
94
|
+
|
|
95
|
+
steps -> stepAndTable moreSteps {% data => fp.concat(data[0],data[1]) %}
|
|
96
|
+
|
|
97
|
+
moreSteps -> null {% data => [] %}
|
|
98
|
+
| moreSteps stepAndTable {% data => fp.concat(data[0],data[1]) %}
|
|
99
|
+
| moreSteps %emptyLine {% data => data[0] %}
|
|
100
|
+
|
|
101
|
+
step -> _ stepKeyword text %newline {% data => { return { type : data[1], text : data[2].trim() } } %}
|
|
102
|
+
stepAndTable -> step dataTable {% data => fp.set('dataTable',data[1],data[0]) %}
|
|
103
|
+
|
|
104
|
+
stepKeyword -> %step {% (data) => { return { type : 'step', name : data[0].value } } %}
|
|
105
|
+
|
|
106
|
+
text -> null {% data => '' %}
|
|
107
|
+
| text %word {% data => data[0]+data[1].value %}
|
|
108
|
+
| text %ws {% data => data[0]+data[1].value %}
|
|
109
|
+
| text %step {% data => data[0]+data[1].value %}
|
|
110
|
+
| text %colon {% data => data[0]+data[1].value %}
|
|
111
|
+
| text %example {% data => data[0]+data[1].value %}
|
|
112
|
+
| text %examples {% data => data[0]+data[1].value %}
|
|
113
|
+
| text %scenarioOutline {% data => data[0]+data[1].value %}
|
|
114
|
+
| text %background {% data => data[0]+data[1].value %}
|
|
115
|
+
|
|
116
|
+
bolText -> %ws %word {% data => data[1].value %}
|
|
117
|
+
| %word {% data => data[0].value %}
|
|
118
|
+
|
|
119
|
+
freeform -> null {% data => '' %}
|
|
120
|
+
| freeform bolText text %newline {% (data) => {
|
|
121
|
+
return data[0]+data[1]+data[2]+'\n'
|
|
122
|
+
}
|
|
123
|
+
%}
|
|
124
|
+
| freeform %emptyLine {% data => data[0]+'\n' %}
|
|
125
|
+
|
|
126
|
+
_ -> null {% data => '' %}
|
|
127
|
+
| %ws {% data => data[0].value %}
|
|
128
|
+
|
|
129
|
+
emptyLines -> null {% data => '' %}
|
|
130
|
+
| emptyLines %emptyLine {% data => data[0]+'\n' %}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// Generated automatically by nearley, version 2.20.1
|
|
2
|
+
// http://github.com/Hardmath123/nearley
|
|
3
|
+
(function () {
|
|
4
|
+
function id(x) { return x[0]; }
|
|
5
|
+
|
|
6
|
+
const fp = require('lodash/fp.js');
|
|
7
|
+
const moo = require('moo');
|
|
8
|
+
const log = require('./logger.js').log;
|
|
9
|
+
const lexer = moo.compile({
|
|
10
|
+
emptyLine : { match: /^[ \t]*(?:\#[^\n]+)?\n/, lineBreaks : true },
|
|
11
|
+
newline : { match : '\n', lineBreaks : true },
|
|
12
|
+
ws : /[ \t]+/,
|
|
13
|
+
at : '@',
|
|
14
|
+
colon : ':',
|
|
15
|
+
step : '*',
|
|
16
|
+
pipe : '|',
|
|
17
|
+
backSlash : '\\',
|
|
18
|
+
scenarioOutline : ['Scenario Outline','Scenario Template'],
|
|
19
|
+
word : {
|
|
20
|
+
match : /[^ \t\n:|\\]+/,
|
|
21
|
+
type : moo.keywords({
|
|
22
|
+
feature : 'Feature',
|
|
23
|
+
examples : ['Examples','Scenarios'],
|
|
24
|
+
step : ['Given','When','Then','And','But'],
|
|
25
|
+
example : ['Example','Scenario'],
|
|
26
|
+
background : 'Background',
|
|
27
|
+
}),
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
var grammar = {
|
|
31
|
+
Lexer: lexer,
|
|
32
|
+
ParserRules: [
|
|
33
|
+
{"name": "main", "symbols": ["emptyLines", "tags", "feature"], "postprocess": data => fp.set('tags',data[1],data[2])},
|
|
34
|
+
{"name": "feature", "symbols": ["featureStatement", "freeform", "background", "statements"], "postprocess":
|
|
35
|
+
(data) => fp.assign(data[0],{ description : data[1].trim(), background : data[2], statements : data[3] })
|
|
36
|
+
},
|
|
37
|
+
{"name": "featureStatement", "symbols": ["_", (lexer.has("feature") ? {type: "feature"} : feature), "_", (lexer.has("colon") ? {type: "colon"} : colon), "text", (lexer.has("newline") ? {type: "newline"} : newline)], "postprocess":
|
|
38
|
+
(data) => { return { type : { type : 'feature', name : data[1].value.trim() }, name : data[4].trim() } }
|
|
39
|
+
},
|
|
40
|
+
{"name": "tags", "symbols": [], "postprocess": data => []},
|
|
41
|
+
{"name": "tags", "symbols": ["_", "tag", "tagList", (lexer.has("newline") ? {type: "newline"} : newline)], "postprocess": data => fp.concat(data[1],data[2])},
|
|
42
|
+
{"name": "tagList", "symbols": [], "postprocess": data => []},
|
|
43
|
+
{"name": "tagList", "symbols": ["tagList", (lexer.has("ws") ? {type: "ws"} : ws), "tag"], "postprocess": data => fp.concat(data[0],data[2])},
|
|
44
|
+
{"name": "tag", "symbols": [(lexer.has("at") ? {type: "at"} : at), (lexer.has("word") ? {type: "word"} : word)], "postprocess": data => data[1].value.trim()},
|
|
45
|
+
{"name": "background", "symbols": [], "postprocess": data => null},
|
|
46
|
+
{"name": "background", "symbols": ["backgroundStatement", "freeform", "steps"], "postprocess":
|
|
47
|
+
data => fp.assign(data[0],{ description : data[1].trim(), steps : data[2] })
|
|
48
|
+
},
|
|
49
|
+
{"name": "backgroundStatement", "symbols": ["_", (lexer.has("background") ? {type: "background"} : background), "_", (lexer.has("colon") ? {type: "colon"} : colon), "text", (lexer.has("newline") ? {type: "newline"} : newline)], "postprocess":
|
|
50
|
+
(data) => { return { type : { type : 'background', name : data[1].value }, name : data[4].trim() } }
|
|
51
|
+
},
|
|
52
|
+
{"name": "statement", "symbols": ["example"], "postprocess": data => data[0]},
|
|
53
|
+
{"name": "statement", "symbols": ["scenarioOutline"], "postprocess": data => data[0]},
|
|
54
|
+
{"name": "statements", "symbols": [], "postprocess": data => []},
|
|
55
|
+
{"name": "statements", "symbols": ["statements", "statement"], "postprocess": data => fp.concat(data[0],data[1])},
|
|
56
|
+
{"name": "example", "symbols": ["tags", "exampleStatement", "steps"], "postprocess": (data) => fp.assign(data[1],{ tags : data[0], steps : data[2] })},
|
|
57
|
+
{"name": "exampleStatement", "symbols": ["_", "exampleKeyword", "_", (lexer.has("colon") ? {type: "colon"} : colon), "text", (lexer.has("newline") ? {type: "newline"} : newline)], "postprocess":
|
|
58
|
+
(data) => { return { type : { type : 'example', name : data[1] }, name : data[4].trim() } }
|
|
59
|
+
},
|
|
60
|
+
{"name": "exampleKeyword", "symbols": [(lexer.has("example") ? {type: "example"} : example)], "postprocess": data => data[0].value},
|
|
61
|
+
{"name": "scenarioOutline", "symbols": ["tags", "scenarioOutlineStatement", "steps", "examplesList"], "postprocess":
|
|
62
|
+
data => fp.assign(data[1],{ tags : data[0], steps : data[2], examples : data[3] })
|
|
63
|
+
},
|
|
64
|
+
{"name": "scenarioOutlineStatement", "symbols": ["_", "scenarioOutlineKeyword", "_", (lexer.has("colon") ? {type: "colon"} : colon), "text", (lexer.has("newline") ? {type: "newline"} : newline)], "postprocess":
|
|
65
|
+
(data) => { return { type : { type : 'scenarioOutline', name : data[1] }, name : data[4].trim() } }
|
|
66
|
+
},
|
|
67
|
+
{"name": "scenarioOutlineKeyword", "symbols": [(lexer.has("scenarioOutline") ? {type: "scenarioOutline"} : scenarioOutline)], "postprocess": data => data[0].value},
|
|
68
|
+
{"name": "examplesList", "symbols": [], "postprocess": data => []},
|
|
69
|
+
{"name": "examplesList", "symbols": ["examplesList", "examples"], "postprocess": data => fp.concat(data[0],data[1])},
|
|
70
|
+
{"name": "examples", "symbols": ["tags", "examplesStatement", "dataTable", "emptyLines"], "postprocess":
|
|
71
|
+
data => fp.assign(data[1],{ tags : data[0], dataTable : data[2] })
|
|
72
|
+
},
|
|
73
|
+
{"name": "examplesStatement", "symbols": ["_", "examplesKeyword", "_", (lexer.has("colon") ? {type: "colon"} : colon), "text", (lexer.has("newline") ? {type: "newline"} : newline)], "postprocess":
|
|
74
|
+
(data) => { return { type : { type : 'examples', name : data[1] }, name : data[4] } }
|
|
75
|
+
},
|
|
76
|
+
{"name": "examplesKeyword", "symbols": [(lexer.has("examples") ? {type: "examples"} : examples)], "postprocess": data => data[0].value},
|
|
77
|
+
{"name": "dataTable", "symbols": [], "postprocess": data => []},
|
|
78
|
+
{"name": "dataTable", "symbols": ["dataTable", "dataTableRow"], "postprocess": data => fp.concat(data[0],[data[1]])},
|
|
79
|
+
{"name": "dataTableRow", "symbols": ["_", (lexer.has("pipe") ? {type: "pipe"} : pipe), "dataTableColumns", (lexer.has("newline") ? {type: "newline"} : newline)], "postprocess": data => data[2]},
|
|
80
|
+
{"name": "dataTableColumns", "symbols": [], "postprocess": data => []},
|
|
81
|
+
{"name": "dataTableColumns", "symbols": ["dataTableColumns", "text", (lexer.has("pipe") ? {type: "pipe"} : pipe)], "postprocess": data => fp.concat(data[0],data[1].trim())},
|
|
82
|
+
{"name": "steps", "symbols": ["stepAndTable", "moreSteps"], "postprocess": data => fp.concat(data[0],data[1])},
|
|
83
|
+
{"name": "moreSteps", "symbols": [], "postprocess": data => []},
|
|
84
|
+
{"name": "moreSteps", "symbols": ["moreSteps", "stepAndTable"], "postprocess": data => fp.concat(data[0],data[1])},
|
|
85
|
+
{"name": "moreSteps", "symbols": ["moreSteps", (lexer.has("emptyLine") ? {type: "emptyLine"} : emptyLine)], "postprocess": data => data[0]},
|
|
86
|
+
{"name": "step", "symbols": ["_", "stepKeyword", "text", (lexer.has("newline") ? {type: "newline"} : newline)], "postprocess": data => { return { type : data[1], text : data[2].trim() } }},
|
|
87
|
+
{"name": "stepAndTable", "symbols": ["step", "dataTable"], "postprocess": data => fp.set('dataTable',data[1],data[0])},
|
|
88
|
+
{"name": "stepKeyword", "symbols": [(lexer.has("step") ? {type: "step"} : step)], "postprocess": (data) => { return { type : 'step', name : data[0].value } }},
|
|
89
|
+
{"name": "text", "symbols": [], "postprocess": data => ''},
|
|
90
|
+
{"name": "text", "symbols": ["text", (lexer.has("word") ? {type: "word"} : word)], "postprocess": data => data[0]+data[1].value},
|
|
91
|
+
{"name": "text", "symbols": ["text", (lexer.has("ws") ? {type: "ws"} : ws)], "postprocess": data => data[0]+data[1].value},
|
|
92
|
+
{"name": "text", "symbols": ["text", (lexer.has("step") ? {type: "step"} : step)], "postprocess": data => data[0]+data[1].value},
|
|
93
|
+
{"name": "text", "symbols": ["text", (lexer.has("colon") ? {type: "colon"} : colon)], "postprocess": data => data[0]+data[1].value},
|
|
94
|
+
{"name": "text", "symbols": ["text", (lexer.has("example") ? {type: "example"} : example)], "postprocess": data => data[0]+data[1].value},
|
|
95
|
+
{"name": "text", "symbols": ["text", (lexer.has("examples") ? {type: "examples"} : examples)], "postprocess": data => data[0]+data[1].value},
|
|
96
|
+
{"name": "text", "symbols": ["text", (lexer.has("scenarioOutline") ? {type: "scenarioOutline"} : scenarioOutline)], "postprocess": data => data[0]+data[1].value},
|
|
97
|
+
{"name": "text", "symbols": ["text", (lexer.has("background") ? {type: "background"} : background)], "postprocess": data => data[0]+data[1].value},
|
|
98
|
+
{"name": "bolText", "symbols": [(lexer.has("ws") ? {type: "ws"} : ws), (lexer.has("word") ? {type: "word"} : word)], "postprocess": data => data[1].value},
|
|
99
|
+
{"name": "bolText", "symbols": [(lexer.has("word") ? {type: "word"} : word)], "postprocess": data => data[0].value},
|
|
100
|
+
{"name": "freeform", "symbols": [], "postprocess": data => ''},
|
|
101
|
+
{"name": "freeform", "symbols": ["freeform", "bolText", "text", (lexer.has("newline") ? {type: "newline"} : newline)], "postprocess": (data) => {
|
|
102
|
+
return data[0]+data[1]+data[2]+'\n'
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
{"name": "freeform", "symbols": ["freeform", (lexer.has("emptyLine") ? {type: "emptyLine"} : emptyLine)], "postprocess": data => data[0]+'\n'},
|
|
106
|
+
{"name": "_", "symbols": [], "postprocess": data => ''},
|
|
107
|
+
{"name": "_", "symbols": [(lexer.has("ws") ? {type: "ws"} : ws)], "postprocess": data => data[0].value},
|
|
108
|
+
{"name": "emptyLines", "symbols": [], "postprocess": data => ''},
|
|
109
|
+
{"name": "emptyLines", "symbols": ["emptyLines", (lexer.has("emptyLine") ? {type: "emptyLine"} : emptyLine)], "postprocess": data => data[0]+'\n'}
|
|
110
|
+
]
|
|
111
|
+
, ParserStart: "main"
|
|
112
|
+
}
|
|
113
|
+
if (typeof module !== 'undefined'&& typeof module.exports !== 'undefined') {
|
|
114
|
+
module.exports = grammar;
|
|
115
|
+
} else {
|
|
116
|
+
window.grammar = grammar;
|
|
117
|
+
}
|
|
118
|
+
})();
|
package/src/index.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import _ from 'lodash/fp.js';
|
|
2
|
+
import { addStepDefinition, findStepDefinitionMatch } from './steps.js';
|
|
3
|
+
import { parameterizeText } from './parameterize.js';
|
|
4
|
+
import { generateFeature } from './generate/index.js';
|
|
5
|
+
import { log, setLogLevel } from './logger.js';
|
|
6
|
+
import { parse } from './parse.js';
|
|
7
|
+
|
|
8
|
+
const featureRegex = /\.feature$/;
|
|
9
|
+
|
|
10
|
+
const compileFeatureToJS = (config,featureSrc) => {
|
|
11
|
+
const feature = parse(featureSrc);
|
|
12
|
+
|
|
13
|
+
const code = generateFeature(config,feature);
|
|
14
|
+
|
|
15
|
+
log.debug(code);
|
|
16
|
+
|
|
17
|
+
return code;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const Given = addStepDefinition;
|
|
21
|
+
export const When = addStepDefinition;
|
|
22
|
+
export const Then = addStepDefinition;
|
|
23
|
+
|
|
24
|
+
export const Test = (state,step) => {
|
|
25
|
+
log.debug('Test step: '+JSON.stringify(step)+' state:'+JSON.stringify(state));
|
|
26
|
+
const stepDefinitionMatch = findStepDefinitionMatch(step);
|
|
27
|
+
|
|
28
|
+
const newState = stepDefinitionMatch.stepDefinition.f(state,stepDefinitionMatch.parameters,step.dataTable);
|
|
29
|
+
log.debug('Test newState: '+JSON.stringify(newState));
|
|
30
|
+
|
|
31
|
+
return newState;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const DataTable = (dataTable) => {
|
|
35
|
+
const parameters = _.first(dataTable);
|
|
36
|
+
const rows = _.tail(dataTable);
|
|
37
|
+
|
|
38
|
+
return _.map((row) => _.zipObject(parameters,row))(rows);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export default function vitestCucumberPlugin() {
|
|
42
|
+
let config;
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
name : 'vitest-cucumber-transform',
|
|
46
|
+
configResolved : (resolvedConfig) => {
|
|
47
|
+
if (_.has('test.cucumber.logLevel',resolvedConfig)) {
|
|
48
|
+
setLogLevel(resolvedConfig.test.cucumber.logLevel);
|
|
49
|
+
}
|
|
50
|
+
log.debug('config: resolvedConfig:'+JSON.stringify(resolvedConfig,null,2));
|
|
51
|
+
config = _.get('test.cucumber',resolvedConfig);
|
|
52
|
+
config = _.set('root',resolvedConfig.root,config);
|
|
53
|
+
log.debug('config: '+JSON.stringify(config));
|
|
54
|
+
},
|
|
55
|
+
transform : async (src,id) => {
|
|
56
|
+
if (featureRegex.test(id)) {
|
|
57
|
+
const code = compileFeatureToJS(config,src);
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
code
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
package/src/logger.js
ADDED
package/src/parse.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import nearley from 'nearley';
|
|
2
|
+
import gherkin from './gherkin.js';
|
|
3
|
+
import { log } from './logger.js';
|
|
4
|
+
|
|
5
|
+
export const parse = (src) => {
|
|
6
|
+
const parser = new nearley.Parser(nearley.Grammar.fromCompiled(gherkin));
|
|
7
|
+
|
|
8
|
+
log.debug('parsing src: '+src);
|
|
9
|
+
parser.feed(src);
|
|
10
|
+
|
|
11
|
+
if (parser.results.length == 0) {
|
|
12
|
+
throw new Error('Unexpected end of file');
|
|
13
|
+
}
|
|
14
|
+
log.debug('parsing result: '+JSON.stringify(parser.results,null,2));
|
|
15
|
+
if (parser.results.length > 1) {
|
|
16
|
+
throw new Error('Ambiguous parsing: '+parser.results.length);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const results = parser.results;
|
|
20
|
+
return results[0];
|
|
21
|
+
}
|
package/src/steps.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { ExpressionFactory, ParameterTypeRegistry } from '@cucumber/cucumber-expressions';
|
|
2
|
+
import _ from 'lodash/fp.js';
|
|
3
|
+
import { log } from './logger.js';
|
|
4
|
+
|
|
5
|
+
var steps = [];
|
|
6
|
+
|
|
7
|
+
const expressionFactory = new ExpressionFactory(new ParameterTypeRegistry());
|
|
8
|
+
|
|
9
|
+
export const addStepDefinition = (expression,f) => {
|
|
10
|
+
log.debug('addStepDefinition expression: '+JSON.stringify(expression));
|
|
11
|
+
const cucumberExpression = expressionFactory.createExpression(expression);
|
|
12
|
+
steps = _.concat(steps,{ expression, f, cucumberExpression });
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const findStepDefinitionMatches = (step) => {
|
|
16
|
+
const matchesMapper = _.map((match) => match.getValue());
|
|
17
|
+
const reducer = _.reduce((accumulator,stepDefinition) => {
|
|
18
|
+
const matches = stepDefinition.cucumberExpression.match(step.text);
|
|
19
|
+
if (matches) {
|
|
20
|
+
//console.log(accumulator,stepDefinition,matches);
|
|
21
|
+
return _.concat(accumulator,{ stepDefinition, parameters : matchesMapper(matches) });
|
|
22
|
+
} else {
|
|
23
|
+
return accumulator;
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
return reducer([])(steps);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const findStepDefinitionMatch = (step) => {
|
|
31
|
+
const stepDefinitionMatches = findStepDefinitionMatches(step);
|
|
32
|
+
|
|
33
|
+
if (!stepDefinitionMatches || (stepDefinitionMatches.length == 0)) {
|
|
34
|
+
throw new Error('Step not defined: \''+step.type.name+' '+step.text+'\'');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (stepDefinitionMatches.length > 1) {
|
|
38
|
+
throw new Error('More than one step which matches: \''+step.type.name+' '+step.text+'\'');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return stepDefinitionMatches[0];
|
|
42
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
Feature: The Background keyword behaviors
|
|
2
|
+
The Background keyword allow you to add context to scenarios that follow it.
|
|
3
|
+
|
|
4
|
+
# This is the background.
|
|
5
|
+
Background: Set up some background data
|
|
6
|
+
It's the cool thing to do.
|
|
7
|
+
|
|
8
|
+
Given I have a "orange"
|
|
9
|
+
And I have a "grape"
|
|
10
|
+
|
|
11
|
+
Scenario: What's the scenario?
|
|
12
|
+
Given I have a "apple"
|
|
13
|
+
When I get a "pea"
|
|
14
|
+
Then I have the following items:
|
|
15
|
+
| orange |
|
|
16
|
+
| grape |
|
|
17
|
+
| apple |
|
|
18
|
+
| pea |
|
|
19
|
+
|
|
20
|
+
Scenario: It's another scenario!
|
|
21
|
+
When I get a "pea"
|
|
22
|
+
Then I have the following items:
|
|
23
|
+
| orange |
|
|
24
|
+
| grape |
|
|
25
|
+
| pea |
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Given, When, Then, DataTable } from 'vitest-cucumber-plugin';
|
|
2
|
+
import { expect } from 'vitest'
|
|
3
|
+
import _ from 'lodash/fp';
|
|
4
|
+
|
|
5
|
+
const addItem = (state,[ item ],data) => { return { items : _.concat(state.items ? state.items : [],item) } };
|
|
6
|
+
|
|
7
|
+
Given('I have a {string}',addItem);
|
|
8
|
+
Then('I get a {string}',addItem);
|
|
9
|
+
Then('I have the following items:',(state,params,data) => {
|
|
10
|
+
const items = _.flatten(data);
|
|
11
|
+
expect(state.items).toEqual(items);
|
|
12
|
+
return state;
|
|
13
|
+
});
|
|
14
|
+
Then('I don\'t have a {string}',(state,[ item ],data) => {
|
|
15
|
+
expect(state.items).not.toContain(item);
|
|
16
|
+
return state;
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
Given('there are {int} cucumbers',(state,[ count ],data) => {
|
|
20
|
+
return _.set('cucumbers',count,state);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
When('I eat {int} cucumbers',(state,[ count ],data) => {
|
|
24
|
+
return _.set('cucumbers',state.cucumbers - count,state);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
Then('I should have {int} cucumbers',(state,[ count ],data) => {
|
|
28
|
+
expect(state.cucumbers).toEqual(count);
|
|
29
|
+
return state;
|
|
30
|
+
});
|