@g_package/jest-cucumber-fusion 1.0.0
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/.prettierignore +16 -0
- package/.prettierrc.json +0 -0
- package/LICENSE +201 -0
- package/README.md +165 -0
- package/codecov +0 -0
- package/codecov.SHA256SUM +1 -0
- package/codecov.SHA256SUM.sig +16 -0
- package/docs/AdditionalConfiguration.md +155 -0
- package/docs/GherkinTables.md +61 -0
- package/docs/Language.md +76 -0
- package/docs/ReusingStepDefinitions.md +110 -0
- package/docs/RunningTheExamples.md +16 -0
- package/docs/ScenarioOutlines.md +43 -0
- package/docs/StepDefinitionArguments.md +37 -0
- package/package.json +82 -0
- package/src/index.d.ts +25 -0
- package/src/index.js +404 -0
- package/test/specs/features/basic-scenarios.feature +28 -0
- package/test/specs/features/language.feature +41 -0
- package/test/specs/features/reuse-definition.feature +13 -0
- package/test/specs/features/scenario-outline2.feature +71 -0
- package/test/specs/features/scenario-outlines.feature +88 -0
- package/test/specs/features/step-definitions/basic-scenarios.steps.js +45 -0
- package/test/specs/features/step-definitions/language.steps.js +86 -0
- package/test/specs/features/step-definitions/reuse-code.js +17 -0
- package/test/specs/features/step-definitions/reuse-definition.steps.js +22 -0
- package/test/specs/features/step-definitions/scenario-outline2.steps.js +46 -0
- package/test/specs/features/step-definitions/scenario-outlines.steps.js +110 -0
- package/test/specs/features/step-definitions/using-dynamic-values.steps.js +70 -0
- package/test/specs/features/step-definitions/using-gherkin-tables.steps.js +42 -0
- package/test/specs/features/using-dynamic-values.feature +34 -0
- package/test/specs/features/using-gherkin-tables.feature +16 -0
- package/test/src/bank-account.js +17 -0
- package/test/src/online-sales.js +33 -0
- package/test/src/rocket.js +13 -0
- package/test/src/todo-list.js +20 -0
package/src/index.js
ADDED
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
const stepsDefinition = {
|
|
2
|
+
given: {},
|
|
3
|
+
when: {},
|
|
4
|
+
then: {},
|
|
5
|
+
and: {},
|
|
6
|
+
but: {},
|
|
7
|
+
before: null,
|
|
8
|
+
after: null,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const addDefinitionFunction = (
|
|
12
|
+
definitionType,
|
|
13
|
+
regexpSentence,
|
|
14
|
+
fnForDefinition
|
|
15
|
+
) => {
|
|
16
|
+
if (stepsDefinition[definitionType]) {
|
|
17
|
+
if (regexpSentence.constructor === RegExp)
|
|
18
|
+
stepsDefinition[definitionType][regexpSentence.source] = {
|
|
19
|
+
stepRegExp: regexpSentence,
|
|
20
|
+
stepExpression: null,
|
|
21
|
+
stepFn: fnForDefinition,
|
|
22
|
+
};
|
|
23
|
+
else if (typeof regexpSentence === "string")
|
|
24
|
+
stepsDefinition[definitionType][regexpSentence] = {
|
|
25
|
+
stepRegExp: null,
|
|
26
|
+
stepExpression: regexpSentence,
|
|
27
|
+
stepFn: fnForDefinition,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const Given = (regexpSentenceOrChainedObject, fnForDefinition) => {
|
|
33
|
+
return defineAndChain(
|
|
34
|
+
"given",
|
|
35
|
+
regexpSentenceOrChainedObject,
|
|
36
|
+
fnForDefinition
|
|
37
|
+
);
|
|
38
|
+
};
|
|
39
|
+
const When = (regexpSentenceOrChainedObject, fnForDefinition) => {
|
|
40
|
+
return defineAndChain("when", regexpSentenceOrChainedObject, fnForDefinition);
|
|
41
|
+
};
|
|
42
|
+
const Then = (regexpSentenceOrChainedObject, fnForDefinition) => {
|
|
43
|
+
return defineAndChain("then", regexpSentenceOrChainedObject, fnForDefinition);
|
|
44
|
+
};
|
|
45
|
+
const And = (regexpSentenceOrChainedObject, fnForDefinition) => {
|
|
46
|
+
return defineAndChain("and", regexpSentenceOrChainedObject, fnForDefinition);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const But = (regexpSentenceOrChainedObject, fnForDefinition) => {
|
|
50
|
+
return defineAndChain("but", regexpSentenceOrChainedObject, fnForDefinition);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const defineAndChain = (stepType, stepObjectOrSentence, fnForStep) => {
|
|
54
|
+
if (
|
|
55
|
+
!fnForStep &&
|
|
56
|
+
stepObjectOrSentence instanceof Object &&
|
|
57
|
+
Object.prototype.toString.call(stepObjectOrSentence) !==
|
|
58
|
+
"[object RegExp]" &&
|
|
59
|
+
stepObjectOrSentence.stepSentence
|
|
60
|
+
) {
|
|
61
|
+
addDefinitionFunction(
|
|
62
|
+
stepType,
|
|
63
|
+
stepObjectOrSentence.stepSentence,
|
|
64
|
+
stepObjectOrSentence.stepFnDefinition
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
return stepObjectOrSentence;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
addDefinitionFunction(stepType, stepObjectOrSentence, fnForStep);
|
|
71
|
+
|
|
72
|
+
return { stepSentence: stepObjectOrSentence, stepFnDefinition: fnForStep };
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const Before = (fnDefinition) => {
|
|
76
|
+
stepsDefinition.before = fnDefinition;
|
|
77
|
+
};
|
|
78
|
+
const After = (fnDefinition) => {
|
|
79
|
+
stepsDefinition.after = fnDefinition;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const Fusion = (featureFileToLoad, optionsToPassToJestCucumber) => {
|
|
83
|
+
const path = require("path");
|
|
84
|
+
const callerSites = require("callsites");
|
|
85
|
+
const callerSiteCaller = callerSites.default()[1].getFileName();
|
|
86
|
+
const dirOfCaller = path.dirname(callerSiteCaller || "");
|
|
87
|
+
const absoluteFeatureFilePath = path.resolve(dirOfCaller, featureFileToLoad);
|
|
88
|
+
|
|
89
|
+
const jestCucumber = require("jest-cucumber");
|
|
90
|
+
const feature = jestCucumber.loadFeature(
|
|
91
|
+
absoluteFeatureFilePath,
|
|
92
|
+
optionsToPassToJestCucumber
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
jestCucumber.defineFeature(feature, (testFn) => {
|
|
96
|
+
if (feature.scenarios.length > 0)
|
|
97
|
+
matchJestTestSuiteWithCucumberFeature(
|
|
98
|
+
feature.scenarios,
|
|
99
|
+
beforeEach,
|
|
100
|
+
afterEach,
|
|
101
|
+
testFn
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
if (feature.scenarioOutlines.length > 0)
|
|
105
|
+
matchJestTestSuiteWithCucumberFeature(
|
|
106
|
+
feature.scenarioOutlines,
|
|
107
|
+
beforeEach,
|
|
108
|
+
afterEach,
|
|
109
|
+
testFn,
|
|
110
|
+
true
|
|
111
|
+
);
|
|
112
|
+
});
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const matchJestTestSuiteWithCucumberFeature = (
|
|
116
|
+
featureScenariosOrOutline,
|
|
117
|
+
beforeEachFn,
|
|
118
|
+
afterEachFn,
|
|
119
|
+
testFn,
|
|
120
|
+
isOutline
|
|
121
|
+
) => {
|
|
122
|
+
featureScenariosOrOutline.forEach((currentScenarioOrOutline) => {
|
|
123
|
+
if (stepsDefinition.before) beforeEachFn(stepsDefinition.before);
|
|
124
|
+
|
|
125
|
+
matchJestTestWithCucumberScenario(
|
|
126
|
+
currentScenarioOrOutline.title,
|
|
127
|
+
currentScenarioOrOutline.steps,
|
|
128
|
+
testFn,
|
|
129
|
+
isOutline
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
if (stepsDefinition.after) afterEachFn(stepsDefinition.after);
|
|
133
|
+
});
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const matchJestTestWithCucumberScenario = (
|
|
137
|
+
currentScenarioTitle,
|
|
138
|
+
currentScenarioSteps,
|
|
139
|
+
testFn,
|
|
140
|
+
isOutline
|
|
141
|
+
) => {
|
|
142
|
+
testFn(currentScenarioTitle, ({ given, when, then, and, but }) => {
|
|
143
|
+
currentScenarioSteps.forEach((currentStep) => {
|
|
144
|
+
matchJestDefinitionWithCucumberStep(
|
|
145
|
+
{ given, when, then, and, but },
|
|
146
|
+
currentStep,
|
|
147
|
+
isOutline
|
|
148
|
+
);
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const matchJestDefinitionWithCucumberStep = (
|
|
154
|
+
verbFunction,
|
|
155
|
+
currentStep,
|
|
156
|
+
isOutline
|
|
157
|
+
) => {
|
|
158
|
+
const foundMatchingStep = findMatchingStep(currentStep, isOutline);
|
|
159
|
+
if (!foundMatchingStep) return;
|
|
160
|
+
|
|
161
|
+
// this will be the "given", "when", "then"...functions
|
|
162
|
+
verbFunction[currentStep.keyword](
|
|
163
|
+
foundMatchingStep.stepExpression,
|
|
164
|
+
foundMatchingStep.stepFn
|
|
165
|
+
);
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
const findMatchingStep = (currentStep, isOutline) => {
|
|
169
|
+
const scenarioType = currentStep.keyword;
|
|
170
|
+
const scenarioSentence = currentStep.stepText;
|
|
171
|
+
const foundStep = Object.keys(stepsDefinition[scenarioType]).find(
|
|
172
|
+
(currentStepDefinitionFunction) => {
|
|
173
|
+
return isFunctionForScenario(
|
|
174
|
+
scenarioSentence,
|
|
175
|
+
stepsDefinition[scenarioType][currentStepDefinitionFunction],
|
|
176
|
+
isOutline
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
);
|
|
180
|
+
if (!foundStep) return null;
|
|
181
|
+
|
|
182
|
+
return injectVariable(
|
|
183
|
+
scenarioType,
|
|
184
|
+
scenarioSentence,
|
|
185
|
+
foundStep,
|
|
186
|
+
currentStep.stepArgument
|
|
187
|
+
);
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
const isFunctionForScenario = (
|
|
191
|
+
scenarioSentence,
|
|
192
|
+
stepDefinitionFunction,
|
|
193
|
+
isOutline
|
|
194
|
+
) => {
|
|
195
|
+
if (stepDefinitionFunction.stepRegExp) {
|
|
196
|
+
if (isOutline && /<[\w]*>/.test(scenarioSentence)) {
|
|
197
|
+
return isPotentialStepFunctionForScenario(
|
|
198
|
+
scenarioSentence,
|
|
199
|
+
stepDefinitionFunction.stepRegExp
|
|
200
|
+
);
|
|
201
|
+
} else return scenarioSentence.match(stepDefinitionFunction.stepRegExp);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return scenarioSentence === stepDefinitionFunction.stepExpression;
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
const isPotentialStepFunctionForScenario = (
|
|
208
|
+
scenarioDefinition,
|
|
209
|
+
regStepFunc
|
|
210
|
+
) => {
|
|
211
|
+
//so this one is tricky, to ensure we only find the
|
|
212
|
+
// step definition corresponding to actual steps function in the case of outlined gherkin
|
|
213
|
+
// we have to "disable" the outlining (since it can replace regular expression
|
|
214
|
+
// and then ensure that all "non-outlined" part do respect the regular expression of
|
|
215
|
+
// of the step function
|
|
216
|
+
// FIRST, we clean the string version of the step definition that has outline variable
|
|
217
|
+
const cleanedStepFunc = regStepFunc.source
|
|
218
|
+
.replace(/^\^/, "")
|
|
219
|
+
// .replace( /\\\(/g, '(' )
|
|
220
|
+
// .replace( /\\\)/g, ')')
|
|
221
|
+
// .replace( /\\\^/g, '^')
|
|
222
|
+
// .replace( /\\\$/g, '$')
|
|
223
|
+
.replace(/\$$/, "");
|
|
224
|
+
// .replace( /\([.\\]+[sSdDwWbB*][*?+]?\)|\(\[.*\](?:[+?*]{1}|\{\d\})\)/g, '' )
|
|
225
|
+
|
|
226
|
+
let currentScenarioPart;
|
|
227
|
+
let currentStepFuncLeft = cleanedStepFunc;
|
|
228
|
+
let currentScenarioDefLeft = scenarioDefinition;
|
|
229
|
+
|
|
230
|
+
//we step through each of the scenario outline variables
|
|
231
|
+
// from there, we will try to detect any regexp present in the
|
|
232
|
+
// step definition, so that we can ensure to find the right match
|
|
233
|
+
while (
|
|
234
|
+
(currentScenarioPart = /<[\w]*>/gi.exec(currentScenarioDefLeft)) != null
|
|
235
|
+
) {
|
|
236
|
+
let fixedPart = currentScenarioPart.input.substring(
|
|
237
|
+
0,
|
|
238
|
+
currentScenarioPart.index
|
|
239
|
+
);
|
|
240
|
+
let idxCutScenarioPart =
|
|
241
|
+
currentScenarioPart.index + currentScenarioPart[0].length;
|
|
242
|
+
|
|
243
|
+
const regEscapedStepFunc = /\([a-zA-Z0!|,:?*+.^=${}><\\\-]+\)/g.exec(
|
|
244
|
+
currentStepFuncLeft
|
|
245
|
+
.replace(/\\\(/g, "(")
|
|
246
|
+
.replace(/\\\)/g, ")")
|
|
247
|
+
.replace(/\\\^/g, "^")
|
|
248
|
+
.replace(/\\\$/g, "$")
|
|
249
|
+
);
|
|
250
|
+
const regStepFuncLeft = /\([a-zA-Z0!|,:?*+.^=${}><\\\-]+\)/g.exec(
|
|
251
|
+
currentStepFuncLeft
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
if (
|
|
255
|
+
regStepFuncLeft &&
|
|
256
|
+
regEscapedStepFunc.index == currentScenarioPart.index
|
|
257
|
+
) {
|
|
258
|
+
//if we have a regex inside our step function definition
|
|
259
|
+
// and that regex is at the same position than our Outlined variable
|
|
260
|
+
// we just need to check that the sentence match,
|
|
261
|
+
// so we can "evaluate" the step function and remove the regex in it
|
|
262
|
+
currentStepFuncLeft =
|
|
263
|
+
regEscapedStepFunc.input.substring(0, regEscapedStepFunc.index) +
|
|
264
|
+
currentStepFuncLeft.substring(
|
|
265
|
+
regStepFuncLeft.index + regStepFuncLeft[0].length
|
|
266
|
+
);
|
|
267
|
+
} else if (
|
|
268
|
+
regStepFuncLeft &&
|
|
269
|
+
regStepFuncLeft.index < currentScenarioPart.index
|
|
270
|
+
) {
|
|
271
|
+
//if we have a regex inside our step function definition
|
|
272
|
+
// but that regex is not at the same position than our outlined variable
|
|
273
|
+
// we need to evaluate the regex against the scenario part
|
|
274
|
+
const strRegexToEvaluate = regStepFuncLeft.input.substring(
|
|
275
|
+
0,
|
|
276
|
+
regStepFuncLeft.index + regStepFuncLeft[0].length
|
|
277
|
+
);
|
|
278
|
+
const regexToEvaluate = new RegExp(strRegexToEvaluate);
|
|
279
|
+
const regIntermediatePart = regexToEvaluate.exec(
|
|
280
|
+
currentScenarioPart.input
|
|
281
|
+
);
|
|
282
|
+
if (regIntermediatePart) {
|
|
283
|
+
fixedPart = regStepFuncLeft.input.substring(
|
|
284
|
+
0,
|
|
285
|
+
regStepFuncLeft.index + regStepFuncLeft[0].length
|
|
286
|
+
);
|
|
287
|
+
idxCutScenarioPart = regIntermediatePart[0].length;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const partIndex = currentStepFuncLeft.indexOf(fixedPart);
|
|
292
|
+
if (partIndex !== -1) {
|
|
293
|
+
currentStepFuncLeft = currentStepFuncLeft.substring(
|
|
294
|
+
partIndex + fixedPart.length
|
|
295
|
+
);
|
|
296
|
+
currentScenarioDefLeft =
|
|
297
|
+
currentScenarioDefLeft.substring(idxCutScenarioPart);
|
|
298
|
+
} else {
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return (
|
|
304
|
+
(currentScenarioDefLeft === "" && currentStepFuncLeft === "") ||
|
|
305
|
+
evaluateStepFuncEndVsScenarioEnd(
|
|
306
|
+
currentStepFuncLeft,
|
|
307
|
+
currentScenarioDefLeft
|
|
308
|
+
)
|
|
309
|
+
);
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
const evaluateStepFuncEndVsScenarioEnd = (
|
|
313
|
+
stepFunctionDef,
|
|
314
|
+
scenarioDefinition
|
|
315
|
+
) => {
|
|
316
|
+
if (
|
|
317
|
+
/\(.*(\?\:)?[.\\]*[sSdDwWbB*][*?+]?.*\)|\(\[.*\](?:[+?*]{1}|\{\d\})\)/g.test(
|
|
318
|
+
stepFunctionDef
|
|
319
|
+
)
|
|
320
|
+
) {
|
|
321
|
+
return new RegExp(stepFunctionDef).test(scenarioDefinition);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
return stepFunctionDef.endsWith(scenarioDefinition);
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
const injectVariable = (
|
|
328
|
+
scenarioType,
|
|
329
|
+
scenarioSentence,
|
|
330
|
+
stepFunctionDefinition,
|
|
331
|
+
stepArgs
|
|
332
|
+
) => {
|
|
333
|
+
const stepObject = stepsDefinition[scenarioType][stepFunctionDefinition];
|
|
334
|
+
|
|
335
|
+
if (!stepObject.stepRegExp)
|
|
336
|
+
return {
|
|
337
|
+
stepExpression: scenarioSentence,
|
|
338
|
+
// Forward through a rest-param wrapper so the reported arity is 0.
|
|
339
|
+
// jest-cucumber v4.4.0+ treats an arity mismatch (stepFn.length >
|
|
340
|
+
// matched args) as a request for a done() callback and then blocks
|
|
341
|
+
// on a Promise that never resolves. A rest param has length 0 while
|
|
342
|
+
// still passing along whatever args jest-cucumber provides.
|
|
343
|
+
stepFn: (...args) => stepObject.stepFn(...args),
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
const exprMatches = stepObject.stepRegExp.exec(scenarioSentence);
|
|
347
|
+
|
|
348
|
+
if (!exprMatches || /<.*>/.test(scenarioSentence))
|
|
349
|
+
return {
|
|
350
|
+
stepExpression: stepObject.stepRegExp,
|
|
351
|
+
// See note above: keep arity 0 to avoid jest-cucumber's done-callback
|
|
352
|
+
// heuristic hanging the step (matters for plain scenarios whose text
|
|
353
|
+
// contains "<...>" and for outline template steps).
|
|
354
|
+
stepFn: (...args) => stepObject.stepFn(...args),
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
const dynamicMatchThatAreVariables = [];
|
|
358
|
+
|
|
359
|
+
exprMatches.forEach((match, groupIndex) => {
|
|
360
|
+
if (groupIndex > 0) dynamicMatchThatAreVariables.push(match);
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
if (Array.isArray(stepArgs) && stepArgs.length > 0) {
|
|
364
|
+
dynamicMatchThatAreVariables.push(stepArgs);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
return {
|
|
368
|
+
stepExpression: stepObject.stepRegExp,
|
|
369
|
+
stepFn: () => stepObject.stepFn(...dynamicMatchThatAreVariables),
|
|
370
|
+
};
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
// const path = require( 'path' )
|
|
374
|
+
//
|
|
375
|
+
// function walkthroughDirectory( directoryName, bRecursive, fnDoForEachFile ) {
|
|
376
|
+
// const filesystem = require( 'fs' )
|
|
377
|
+
// let filenamesOrDirectorynames = filesystem.readdirSync( directoryName )
|
|
378
|
+
//
|
|
379
|
+
// filenamesOrDirectorynames.forEach( ( currentFilenameOrDirectoryname ) => {
|
|
380
|
+
// let currentFilepath = path.join( directoryName, currentFilenameOrDirectoryname )
|
|
381
|
+
// let currentFileStats = filesystem.statSync( currentFilepath )
|
|
382
|
+
// if( bRecursive && currentFileStats.isDirectory() )
|
|
383
|
+
// walkthroughDirectory( currentFilepath, activeLoadings, bRecursive, fnOnLoading )
|
|
384
|
+
//
|
|
385
|
+
// else
|
|
386
|
+
// fnDoForEachFile( currentFilepath )
|
|
387
|
+
// } )
|
|
388
|
+
// }
|
|
389
|
+
|
|
390
|
+
// function FusionAll( dirFeatureFiles, bRecursive ) {
|
|
391
|
+
// const dirFinalDirectory = ( !dirFeatureFiles ? '<rootDir>/test/feature' : dirFeatureFiles )
|
|
392
|
+
//
|
|
393
|
+
// walkthroughDirectory( dirFinalDirectory, bRecursive, Fusion )
|
|
394
|
+
// }
|
|
395
|
+
|
|
396
|
+
module.exports.Before = Before;
|
|
397
|
+
module.exports.After = After;
|
|
398
|
+
module.exports.Given = Given;
|
|
399
|
+
module.exports.When = When;
|
|
400
|
+
module.exports.Then = Then;
|
|
401
|
+
module.exports.And = And;
|
|
402
|
+
module.exports.But = But;
|
|
403
|
+
module.exports.Fusion = Fusion;
|
|
404
|
+
// module.exports.FusionAll = FusionAll
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
Feature: Rocket Launching
|
|
2
|
+
|
|
3
|
+
Scenario: Launching a SpaceX rocket
|
|
4
|
+
Given I am Elon Musk attempting to launch a rocket into space
|
|
5
|
+
When I launch the rocket
|
|
6
|
+
Then the rocket should end up in space
|
|
7
|
+
And the booster(s) should land back on the launch pad
|
|
8
|
+
But nobody should doubt me ever again
|
|
9
|
+
|
|
10
|
+
Scenario: Launching my ASCII rocket
|
|
11
|
+
Given I am Elon Musk attempting to launch a rocket into space
|
|
12
|
+
When I launch the '<rocket>'
|
|
13
|
+
Then the rocket should end up in space
|
|
14
|
+
And the booster(s) should land back on the launch pad
|
|
15
|
+
But nobody should doubt me ever again
|
|
16
|
+
|
|
17
|
+
Scenario: Launching my personal ASCII rocket
|
|
18
|
+
Given I am Elon Musk attempting to launch a rocket into space
|
|
19
|
+
When I launch my personal rocket named '<space poney==>'
|
|
20
|
+
Then the rocket should end up in space
|
|
21
|
+
And the booster(s) should land back on the launch pad
|
|
22
|
+
But nobody should doubt me ever again
|
|
23
|
+
|
|
24
|
+
Scenario: Folding ourselves in 2D
|
|
25
|
+
Given I am Elon Musk attempting to launch a rocket into space
|
|
26
|
+
And my position in 2D space is [ 0, 2 ]
|
|
27
|
+
When I launch the rocket
|
|
28
|
+
Then the rocket should end up in space
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# language: nl
|
|
2
|
+
|
|
3
|
+
Functionaliteit: Online verkopen
|
|
4
|
+
|
|
5
|
+
Scenario: t-shirt verkopen
|
|
6
|
+
Gegeven ik heb een t-shirt
|
|
7
|
+
Als ik een t-shirt wil verkopen
|
|
8
|
+
Dan ontvang ik €22
|
|
9
|
+
En ben ik blij
|
|
10
|
+
Maar heb ik geen t-shirts over
|
|
11
|
+
|
|
12
|
+
Abstract Scenario: <Object> verkopen
|
|
13
|
+
Gegeven ik heb een: <Object>
|
|
14
|
+
Als ik <Object> verkoop
|
|
15
|
+
Dan zou ik er €<Bedrag> voor moeten krijgen
|
|
16
|
+
|
|
17
|
+
Voorbeelden:
|
|
18
|
+
|
|
19
|
+
| Object | Bedrag |
|
|
20
|
+
| Autographed Neil deGrasse Tyson book | 100 |
|
|
21
|
+
| Rick Astley t-shirt | 22 |
|
|
22
|
+
| An idea to replace EVERYTHING with blockchains | 0 |
|
|
23
|
+
|
|
24
|
+
Scenario: Boek kopen
|
|
25
|
+
Gegeven 'Autographed Neil deGrasse Tyson book' is te koop
|
|
26
|
+
Als ik 'Autographed Neil deGrasse Tyson book' koop
|
|
27
|
+
Dan heb ik €100 uitgegeven
|
|
28
|
+
|
|
29
|
+
Scenario: voorraad bijvullen
|
|
30
|
+
Gegeven mijn voorraad bevat:
|
|
31
|
+
| Object |
|
|
32
|
+
| Autographed Neil deGrasse Tyson book |
|
|
33
|
+
| Rick Astley t-shirt |
|
|
34
|
+
Als ik de volgende producten toevoeg:
|
|
35
|
+
| Object |
|
|
36
|
+
| Smurfen stripboek |
|
|
37
|
+
Dan zitten er 3 objecten in mijn voorraad, bestaant uit:
|
|
38
|
+
| Object |
|
|
39
|
+
| Autographed Neil deGrasse Tyson book |
|
|
40
|
+
| Rick Astley t-shirt |
|
|
41
|
+
| Smurfen stripboek |
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Feature: Rocket reuse
|
|
2
|
+
|
|
3
|
+
Scenario: Reusing a SpaceX rocket
|
|
4
|
+
Given I am Elon Musk and I launched a rocket in space already
|
|
5
|
+
When I relaunch the rocket
|
|
6
|
+
Then the rocket end up in space again
|
|
7
|
+
And I drop my mic
|
|
8
|
+
|
|
9
|
+
Scenario: Reading the critics
|
|
10
|
+
Given I am Elon Musk and I launched a rocket in space already
|
|
11
|
+
When I relaunch the rocket
|
|
12
|
+
Then the mission was said to be 'a success'
|
|
13
|
+
And the mission was said to be 'a wonder'
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
Feature: Scenario Outline verification
|
|
2
|
+
|
|
3
|
+
Scenario Outline: Simple Scenario Outline. Buy item: <Item>
|
|
4
|
+
This scenario use Before fusion hook (see scenario-outline2.steps.js)
|
|
5
|
+
This hook is remove all items from list of onlineSales if number of items >=2.
|
|
6
|
+
This scenario also demonstrate case dependancy in scenario outline:
|
|
7
|
+
if you are using some global variable it is not clear between scenarious.
|
|
8
|
+
|
|
9
|
+
Given I have <nItems> items for sale
|
|
10
|
+
When I bought "<Item>"
|
|
11
|
+
Then I have <aItems> items for sale
|
|
12
|
+
|
|
13
|
+
Examples:
|
|
14
|
+
| nItems | Item | aItems |
|
|
15
|
+
| 0 | Mist written by Stephen King | 1 |
|
|
16
|
+
| 1 | Metallica. ReLoad. | 2 |
|
|
17
|
+
|
|
18
|
+
Scenario Outline: Complex Scenario Outline. <nItems>
|
|
19
|
+
Given I have <nItems> items for sale
|
|
20
|
+
When I bought the following items:
|
|
21
|
+
| Item |
|
|
22
|
+
| Mist written by Stephen King |
|
|
23
|
+
| Metallica. ReLoad. |
|
|
24
|
+
|
|
25
|
+
Then I have <aItems> items for sale
|
|
26
|
+
|
|
27
|
+
Examples:
|
|
28
|
+
| nItems | aItems |
|
|
29
|
+
| 0 | 2 |
|
|
30
|
+
|
|
31
|
+
Scenario: Complex Scenario
|
|
32
|
+
This scenario is necessary to make sure that related steps are working without examples.
|
|
33
|
+
|
|
34
|
+
Given I have 0 items for sale
|
|
35
|
+
|
|
36
|
+
When I bought the following items:
|
|
37
|
+
| Item |
|
|
38
|
+
| Mist written by Stephen King |
|
|
39
|
+
| Metallica. ReLoad. |
|
|
40
|
+
| Sabaton. Great War |
|
|
41
|
+
|
|
42
|
+
Then I have 3 items for sale
|
|
43
|
+
|
|
44
|
+
Then I want to sell 2 items if they in list
|
|
45
|
+
| Item |
|
|
46
|
+
| Sabaton. Great War |
|
|
47
|
+
| Cucumber for dummies |
|
|
48
|
+
|
|
49
|
+
Scenario Outline: Using examples in sentance and in table
|
|
50
|
+
|
|
51
|
+
Given I have 0 items for sale
|
|
52
|
+
|
|
53
|
+
When I bought the following items:
|
|
54
|
+
| Item |
|
|
55
|
+
| Mist written by Stephen King |
|
|
56
|
+
| Metallica. ReLoad. |
|
|
57
|
+
| Sabaton. Great War |
|
|
58
|
+
|
|
59
|
+
Then I have 3 items for sale
|
|
60
|
+
|
|
61
|
+
Then I want to sell <nSale> items if they in list
|
|
62
|
+
| Item |
|
|
63
|
+
| Sabaton. Great War |
|
|
64
|
+
| <SaleItemName> |
|
|
65
|
+
|
|
66
|
+
Then I have <NItems> items for sale
|
|
67
|
+
|
|
68
|
+
Examples:
|
|
69
|
+
| nSale | SaleItemName | NItems |
|
|
70
|
+
| 2 | Cucumber for dummies | 2 |
|
|
71
|
+
| 3 | Mist written by Stephen King | 1 |
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
Feature: Online sales
|
|
2
|
+
|
|
3
|
+
Scenario Outline: Selling an <Item>
|
|
4
|
+
Given I have a(n) <Item>
|
|
5
|
+
When I sell the <Item>
|
|
6
|
+
Then I should get $<Amount>
|
|
7
|
+
|
|
8
|
+
Examples:
|
|
9
|
+
|
|
10
|
+
| Item | Amount |
|
|
11
|
+
| Autographed Neil deGrasse Tyson book | 100 |
|
|
12
|
+
| Rick Astley t-shirt | 22 |
|
|
13
|
+
| An idea to replace EVERYTHING with blockchains | 0 |
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
Scenario Outline: Selling all of one
|
|
17
|
+
Given I want to sell all my <Item>
|
|
18
|
+
When I sell all my <Item> at the price of $<Amount> CAD
|
|
19
|
+
Then I should still get $<Amount>
|
|
20
|
+
|
|
21
|
+
Examples:
|
|
22
|
+
|
|
23
|
+
| Item | Amount |
|
|
24
|
+
| Autographed Neil deGrasse Tyson book | 100 |
|
|
25
|
+
| Rick Astley t-shirt | 22 |
|
|
26
|
+
| An idea to replace EVERYTHING with blockchains | 0 |
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
Scenario: Selling a thing
|
|
30
|
+
Given I have an Item named '<ThatCouldLookLikeAnOutlineVariable>'
|
|
31
|
+
When I sell <ThatCouldLookLikeAnOutlineVariable With Spaces in it>
|
|
32
|
+
Then I get $<Amount>
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
Scenario Outline: Additional regexp in outline line
|
|
36
|
+
Given I want to sell all my <Item>
|
|
37
|
+
When I sell all my <Item> at the price of $100 CAD
|
|
38
|
+
Then I should still get $<Amount>
|
|
39
|
+
|
|
40
|
+
Examples:
|
|
41
|
+
| Item | Amount |
|
|
42
|
+
| Autographed Neil deGrasse Tyson book | 100 |
|
|
43
|
+
| Rick Astley t-shirt | 100 |
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
Scenario Outline: Additional regexp in outline line with non-string variables for <Item>
|
|
47
|
+
Given I want to sell all my <Item>
|
|
48
|
+
When I sell all my <Item> with a starting price of $<StartingPrice> at the rebate price of $100
|
|
49
|
+
Then I should still get $<Amount>
|
|
50
|
+
|
|
51
|
+
Examples:
|
|
52
|
+
| Item | StartingPrice | Amount |
|
|
53
|
+
| Autographed Neil deGrasse Tyson book | 100 | 100 |
|
|
54
|
+
| Rick Astley t-shirt | 22 | 100 |
|
|
55
|
+
#
|
|
56
|
+
#
|
|
57
|
+
Scenario Outline: Additional regexp in outline line with non-string variables and static one in the middle for <Item>
|
|
58
|
+
Given I want to sell all my <Item>
|
|
59
|
+
When I sell all my <Item> with a starting price of $100 at the rebate price of $<RebatePrice>
|
|
60
|
+
Then I should still get $<Amount>
|
|
61
|
+
|
|
62
|
+
Examples:
|
|
63
|
+
| Item | RebatePrice | Amount |
|
|
64
|
+
| Autographed Neil deGrasse Tyson book | 20 | 20 |
|
|
65
|
+
| Rick Astley t-shirt | 50 | 50 |
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
Scenario Outline: Additional regepx in outline line with non-string variable at the end for <Item>
|
|
69
|
+
Given I want to sell all my <Item>
|
|
70
|
+
When I sell all my <Item> with a starting price of $100 at the rebate price of $<RebatePrice>
|
|
71
|
+
Then the 1st item 1st price has a price amount of <Amount> which is a 'Number'
|
|
72
|
+
|
|
73
|
+
Examples:
|
|
74
|
+
| Item | RebatePrice | Amount |
|
|
75
|
+
| Autographed Neil deGrasse Tyson book | 20 | 20 |
|
|
76
|
+
| Rick Astley t-shirt | 50 | 50 |
|
|
77
|
+
# Ability: this ones are not currently possible
|
|
78
|
+
##
|
|
79
|
+
# Scenario Outline: Additional mix regexp and non-regexp in outline line with non-string variables and static one in the middle for <Item>
|
|
80
|
+
# Given I want to sell all my <Item>
|
|
81
|
+
# When I sell all my <Item> with a starting price <Description> price of <RebatePrice>$ <Currency> which is nice
|
|
82
|
+
# Then I should still get $<Amount>
|
|
83
|
+
#
|
|
84
|
+
# Examples:
|
|
85
|
+
# | Item | Description | RebatePrice | Amount | Currency |
|
|
86
|
+
# | Autographed Neil deGrasse Tyson book | of $100 at the fantastic | 20 | 20 | USD |
|
|
87
|
+
# | Rick Astley t-shirt | of $100 at the fantastic | 50 | 50 | CAD |
|
|
88
|
+
# | Rick Astley t-shirt | of $100 at the rebate | 50 | 50 | CAD |
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const { Given, When, Then, And, But, Fusion } = require("../../../../src");
|
|
2
|
+
|
|
3
|
+
const { Rocket } = require("../../../src/rocket");
|
|
4
|
+
|
|
5
|
+
let rocket;
|
|
6
|
+
|
|
7
|
+
Given("I am Elon Musk attempting to launch a rocket into space", () => {
|
|
8
|
+
rocket = new Rocket();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
When("I launch the rocket", () => {
|
|
12
|
+
rocket.launch();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
When("I launch the '<rocket>'", () => {
|
|
16
|
+
rocket.launch();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
When(/^I launch my personal rocket named '(.*)'$/, (nameRocket) => {
|
|
20
|
+
expect(nameRocket).toBeDefined();
|
|
21
|
+
rocket.launch();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
Then("the rocket should end up in space", () => {
|
|
25
|
+
expect(rocket.isInSpace).toBe(true);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
/// Complex Regex : at position (\[(?: *\d+(?: |, |,)*)+\]) with no value
|
|
29
|
+
And(
|
|
30
|
+
/^my position in 2D space is (\[(?: *\d+(?: |, |,)*)+\])$/,
|
|
31
|
+
(arrayPosition) => {
|
|
32
|
+
const isAnArray = JSON.parse(arrayPosition);
|
|
33
|
+
expect(isAnArray).toBeInstanceOf(Array);
|
|
34
|
+
}
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
And(/^the booster\(s\) should land back on the launch pad$/, () => {
|
|
38
|
+
expect(rocket.boostersLanded).toBe(true);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
But("nobody should doubt me ever again", () => {
|
|
42
|
+
expect("people").not.toBe("haters");
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
Fusion("../basic-scenarios.feature");
|