codeceptjs 3.6.4-beta.2 → 3.6.5-beta.1
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/bin/codecept.js +84 -63
- package/lib/ai.js +47 -1
- package/lib/assert/empty.js +19 -19
- package/lib/assert/equal.js +32 -30
- package/lib/assert/error.js +14 -14
- package/lib/assert/include.js +42 -42
- package/lib/assert/throws.js +13 -11
- package/lib/assert/truth.js +17 -18
- package/lib/command/configMigrate.js +57 -52
- package/lib/command/definitions.js +88 -88
- package/lib/command/dryRun.js +65 -63
- package/lib/command/generate.js +191 -181
- package/lib/command/info.js +39 -37
- package/lib/command/init.js +289 -286
- package/lib/command/interactive.js +32 -32
- package/lib/command/list.js +26 -26
- package/lib/command/run-multiple.js +113 -93
- package/lib/command/run-rerun.js +22 -22
- package/lib/command/run-workers.js +63 -63
- package/lib/command/run.js +24 -26
- package/lib/command/utils.js +64 -63
- package/lib/data/context.js +60 -60
- package/lib/data/dataScenarioConfig.js +47 -47
- package/lib/data/dataTableArgument.js +29 -29
- package/lib/data/table.js +26 -20
- package/lib/helper/AI.js +114 -35
- package/lib/helper/ApiDataFactory.js +72 -69
- package/lib/helper/Appium.js +409 -379
- package/lib/helper/ExpectHelper.js +214 -248
- package/lib/helper/FileSystem.js +77 -78
- package/lib/helper/GraphQL.js +44 -43
- package/lib/helper/GraphQLDataFactory.js +49 -50
- package/lib/helper/JSONResponse.js +64 -62
- package/lib/helper/Mochawesome.js +28 -28
- package/lib/helper/MockServer.js +12 -12
- package/lib/helper/Nightmare.js +664 -572
- package/lib/helper/Playwright.js +1320 -1211
- package/lib/helper/Protractor.js +663 -629
- package/lib/helper/Puppeteer.js +1232 -1124
- package/lib/helper/REST.js +115 -69
- package/lib/helper/TestCafe.js +490 -491
- package/lib/helper/WebDriver.js +1294 -1156
- package/lib/history.js +16 -3
- package/lib/interfaces/bdd.js +38 -51
- package/lib/interfaces/featureConfig.js +19 -19
- package/lib/interfaces/gherkin.js +122 -111
- package/lib/interfaces/scenarioConfig.js +29 -29
- package/lib/listener/artifacts.js +9 -9
- package/lib/listener/config.js +24 -23
- package/lib/listener/exit.js +12 -12
- package/lib/listener/helpers.js +42 -42
- package/lib/listener/mocha.js +11 -11
- package/lib/listener/retry.js +32 -30
- package/lib/listener/steps.js +50 -51
- package/lib/listener/timeout.js +53 -53
- package/lib/pause.js +17 -3
- package/lib/plugin/allure.js +14 -14
- package/lib/plugin/autoDelay.js +29 -36
- package/lib/plugin/autoLogin.js +70 -66
- package/lib/plugin/commentStep.js +18 -18
- package/lib/plugin/coverage.js +92 -77
- package/lib/plugin/customLocator.js +20 -19
- package/lib/plugin/debugErrors.js +24 -24
- package/lib/plugin/eachElement.js +37 -37
- package/lib/plugin/fakerTransform.js +6 -6
- package/lib/plugin/heal.js +66 -63
- package/lib/plugin/pauseOnFail.js +10 -10
- package/lib/plugin/retryFailedStep.js +31 -38
- package/lib/plugin/retryTo.js +28 -28
- package/lib/plugin/screenshotOnFail.js +107 -86
- package/lib/plugin/selenoid.js +131 -117
- package/lib/plugin/standardActingHelpers.js +2 -8
- package/lib/plugin/stepByStepReport.js +102 -92
- package/lib/plugin/stepTimeout.js +23 -22
- package/lib/plugin/subtitles.js +34 -34
- package/lib/plugin/tryTo.js +39 -29
- package/lib/plugin/wdio.js +77 -72
- package/lib/template/heal.js +11 -14
- package/package.json +5 -3
- package/translations/de-DE.js +1 -1
- package/translations/fr-FR.js +1 -1
- package/translations/index.js +9 -9
- package/translations/it-IT.js +1 -1
- package/translations/ja-JP.js +1 -1
- package/translations/pl-PL.js +1 -1
- package/translations/pt-BR.js +1 -1
- package/translations/ru-RU.js +1 -1
- package/translations/zh-CN.js +1 -1
- package/translations/zh-TW.js +1 -1
- package/typings/index.d.ts +42 -19
- package/typings/promiseBasedTypes.d.ts +280 -1
- package/typings/types.d.ts +76 -1
package/lib/history.js
CHANGED
|
@@ -10,6 +10,9 @@ const output = require('./output');
|
|
|
10
10
|
*/
|
|
11
11
|
class ReplHistory {
|
|
12
12
|
constructor() {
|
|
13
|
+
if (global.output_dir) {
|
|
14
|
+
this.historyFile = path.join(global.output_dir, 'cli-history');
|
|
15
|
+
}
|
|
13
16
|
this.commands = [];
|
|
14
17
|
}
|
|
15
18
|
|
|
@@ -21,16 +24,26 @@ class ReplHistory {
|
|
|
21
24
|
this.commands.pop();
|
|
22
25
|
}
|
|
23
26
|
|
|
27
|
+
load() {
|
|
28
|
+
if (!this.historyFile) return;
|
|
29
|
+
if (!fs.existsSync(this.historyFile)) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const history = fs.readFileSync(this.historyFile, 'utf-8');
|
|
34
|
+
return history.split('\n').reverse().filter(line => line.startsWith('I.')).map(line => line.slice(2));
|
|
35
|
+
}
|
|
36
|
+
|
|
24
37
|
save() {
|
|
38
|
+
if (!this.historyFile) return;
|
|
25
39
|
if (this.commands.length === 0) {
|
|
26
40
|
return;
|
|
27
41
|
}
|
|
28
42
|
|
|
29
|
-
const historyFile = path.join(global.output_dir, 'cli-history');
|
|
30
43
|
const commandSnippet = `\n\n<<< Recorded commands on ${new Date()}\n${this.commands.join('\n')}`;
|
|
31
|
-
fs.appendFileSync(historyFile, commandSnippet);
|
|
44
|
+
fs.appendFileSync(this.historyFile, commandSnippet);
|
|
32
45
|
|
|
33
|
-
output.print(colors.yellow(` Commands have been saved to ${historyFile}`));
|
|
46
|
+
output.print(colors.yellow(` Commands have been saved to ${this.historyFile}`));
|
|
34
47
|
|
|
35
48
|
this.commands = [];
|
|
36
49
|
}
|
package/lib/interfaces/bdd.js
CHANGED
|
@@ -1,86 +1,73 @@
|
|
|
1
|
-
const { CucumberExpression, ParameterTypeRegistry, ParameterType } = require('@cucumber/cucumber-expressions')
|
|
2
|
-
const Config = require('../config')
|
|
1
|
+
const { CucumberExpression, ParameterTypeRegistry, ParameterType } = require('@cucumber/cucumber-expressions')
|
|
2
|
+
const Config = require('../config')
|
|
3
3
|
|
|
4
|
-
let steps = {}
|
|
4
|
+
let steps = {}
|
|
5
5
|
|
|
6
|
-
const STACK_POSITION = 2
|
|
6
|
+
const STACK_POSITION = 2
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* @param {*} step
|
|
10
10
|
* @param {*} fn
|
|
11
11
|
*/
|
|
12
12
|
const addStep = (step, fn) => {
|
|
13
|
-
const avoidDuplicateSteps = Config.get('gherkin', {}).avoidDuplicateSteps || false
|
|
14
|
-
const stack =
|
|
13
|
+
const avoidDuplicateSteps = Config.get('gherkin', {}).avoidDuplicateSteps || false
|
|
14
|
+
const stack = new Error().stack
|
|
15
15
|
if (avoidDuplicateSteps && steps[step]) {
|
|
16
|
-
throw new Error(`Step '${step}' is already defined`)
|
|
16
|
+
throw new Error(`Step '${step}' is already defined`)
|
|
17
17
|
}
|
|
18
|
-
steps[step] = fn
|
|
19
|
-
fn.line = stack && stack.split('\n')[STACK_POSITION]
|
|
18
|
+
steps[step] = fn
|
|
19
|
+
fn.line = stack && stack.split('\n')[STACK_POSITION]
|
|
20
20
|
if (fn.line) {
|
|
21
21
|
fn.line = fn.line
|
|
22
22
|
.trim()
|
|
23
23
|
.replace(/^at (.*?)\(/, '(')
|
|
24
|
-
.replace(codecept_dir, '.')
|
|
24
|
+
.replace(codecept_dir, '.')
|
|
25
25
|
}
|
|
26
|
-
}
|
|
26
|
+
}
|
|
27
27
|
|
|
28
|
-
const parameterTypeRegistry = new ParameterTypeRegistry()
|
|
28
|
+
const parameterTypeRegistry = new ParameterTypeRegistry()
|
|
29
29
|
|
|
30
30
|
const matchStep = (step) => {
|
|
31
31
|
for (const stepName in steps) {
|
|
32
32
|
if (stepName.indexOf('/') === 0) {
|
|
33
|
-
const regExpArr = stepName.match(/^\/(.*?)\/([gimy]*)$/) || []
|
|
34
|
-
const res = step.match(new RegExp(regExpArr[1], regExpArr[2]))
|
|
33
|
+
const regExpArr = stepName.match(/^\/(.*?)\/([gimy]*)$/) || []
|
|
34
|
+
const res = step.match(new RegExp(regExpArr[1], regExpArr[2]))
|
|
35
35
|
if (res) {
|
|
36
|
-
const fn = steps[stepName]
|
|
37
|
-
fn.params = res.slice(1)
|
|
38
|
-
return fn
|
|
36
|
+
const fn = steps[stepName]
|
|
37
|
+
fn.params = res.slice(1)
|
|
38
|
+
return fn
|
|
39
39
|
}
|
|
40
|
-
continue
|
|
40
|
+
continue
|
|
41
41
|
}
|
|
42
|
-
const expression = new CucumberExpression(stepName, parameterTypeRegistry)
|
|
43
|
-
const res = expression.match(step)
|
|
42
|
+
const expression = new CucumberExpression(stepName, parameterTypeRegistry)
|
|
43
|
+
const res = expression.match(step)
|
|
44
44
|
if (res) {
|
|
45
|
-
const fn = steps[stepName]
|
|
46
|
-
fn.params = res.map(arg => arg.getValue())
|
|
47
|
-
return fn
|
|
45
|
+
const fn = steps[stepName]
|
|
46
|
+
fn.params = res.map((arg) => arg.getValue())
|
|
47
|
+
return fn
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
|
-
throw new Error(`No steps matching "${step.toString()}"`)
|
|
51
|
-
}
|
|
50
|
+
throw new Error(`No steps matching "${step.toString()}"`)
|
|
51
|
+
}
|
|
52
52
|
|
|
53
53
|
const clearSteps = () => {
|
|
54
|
-
steps = {}
|
|
55
|
-
}
|
|
54
|
+
steps = {}
|
|
55
|
+
}
|
|
56
56
|
|
|
57
57
|
const getSteps = () => {
|
|
58
|
-
return steps
|
|
59
|
-
}
|
|
58
|
+
return steps
|
|
59
|
+
}
|
|
60
60
|
|
|
61
61
|
const defineParameterType = (options) => {
|
|
62
|
-
const parameterType = buildParameterType(options)
|
|
63
|
-
parameterTypeRegistry.defineParameterType(parameterType)
|
|
64
|
-
}
|
|
62
|
+
const parameterType = buildParameterType(options)
|
|
63
|
+
parameterTypeRegistry.defineParameterType(parameterType)
|
|
64
|
+
}
|
|
65
65
|
|
|
66
|
-
const buildParameterType = ({
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
transformer,
|
|
70
|
-
|
|
71
|
-
preferForRegexpMatch,
|
|
72
|
-
}) => {
|
|
73
|
-
if (typeof useForSnippets !== 'boolean') useForSnippets = true;
|
|
74
|
-
if (typeof preferForRegexpMatch !== 'boolean') preferForRegexpMatch = false;
|
|
75
|
-
return new ParameterType(
|
|
76
|
-
name,
|
|
77
|
-
regexp,
|
|
78
|
-
null,
|
|
79
|
-
transformer,
|
|
80
|
-
useForSnippets,
|
|
81
|
-
preferForRegexpMatch,
|
|
82
|
-
);
|
|
83
|
-
};
|
|
66
|
+
const buildParameterType = ({ name, regexp, transformer, useForSnippets, preferForRegexpMatch }) => {
|
|
67
|
+
if (typeof useForSnippets !== 'boolean') useForSnippets = true
|
|
68
|
+
if (typeof preferForRegexpMatch !== 'boolean') preferForRegexpMatch = false
|
|
69
|
+
return new ParameterType(name, regexp, null, transformer, useForSnippets, preferForRegexpMatch)
|
|
70
|
+
}
|
|
84
71
|
|
|
85
72
|
module.exports = {
|
|
86
73
|
Given: addStep,
|
|
@@ -91,4 +78,4 @@ module.exports = {
|
|
|
91
78
|
getSteps,
|
|
92
79
|
clearSteps,
|
|
93
80
|
defineParameterType,
|
|
94
|
-
}
|
|
81
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** @class */
|
|
2
2
|
class FeatureConfig {
|
|
3
3
|
constructor(suite) {
|
|
4
|
-
this.suite = suite
|
|
4
|
+
this.suite = suite
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -11,8 +11,8 @@ class FeatureConfig {
|
|
|
11
11
|
* @returns {this}
|
|
12
12
|
*/
|
|
13
13
|
retry(retries) {
|
|
14
|
-
this.suite.retries(retries)
|
|
15
|
-
return this
|
|
14
|
+
this.suite.retries(retries)
|
|
15
|
+
return this
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
/**
|
|
@@ -22,11 +22,11 @@ class FeatureConfig {
|
|
|
22
22
|
* @deprecated
|
|
23
23
|
*/
|
|
24
24
|
timeout(timeout) {
|
|
25
|
-
console.log(`Feature('${this.suite.title}').timeout(${timeout}) is deprecated!`)
|
|
26
|
-
console.log(`Please use Feature('${this.suite.title}', { timeout: ${timeout / 1000} }) instead`)
|
|
27
|
-
console.log('Timeout should be set in seconds')
|
|
28
|
-
this.suite.timeout(timeout)
|
|
29
|
-
return this
|
|
25
|
+
console.log(`Feature('${this.suite.title}').timeout(${timeout}) is deprecated!`)
|
|
26
|
+
console.log(`Please use Feature('${this.suite.title}', { timeout: ${timeout / 1000} }) instead`)
|
|
27
|
+
console.log('Timeout should be set in seconds')
|
|
28
|
+
this.suite.timeout(timeout)
|
|
29
|
+
return this
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
/**
|
|
@@ -38,17 +38,17 @@ class FeatureConfig {
|
|
|
38
38
|
*/
|
|
39
39
|
config(helper, obj) {
|
|
40
40
|
if (!obj) {
|
|
41
|
-
obj = helper
|
|
42
|
-
helper = 0
|
|
41
|
+
obj = helper
|
|
42
|
+
helper = 0
|
|
43
43
|
}
|
|
44
44
|
if (typeof obj === 'function') {
|
|
45
|
-
obj = obj(this.suite)
|
|
45
|
+
obj = obj(this.suite)
|
|
46
46
|
}
|
|
47
47
|
if (!this.suite.config) {
|
|
48
|
-
this.suite.config = {}
|
|
48
|
+
this.suite.config = {}
|
|
49
49
|
}
|
|
50
|
-
this.suite.config[helper] = obj
|
|
51
|
-
return this
|
|
50
|
+
this.suite.config[helper] = obj
|
|
51
|
+
return this
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
/**
|
|
@@ -58,12 +58,12 @@ class FeatureConfig {
|
|
|
58
58
|
*/
|
|
59
59
|
tag(tagName) {
|
|
60
60
|
if (tagName[0] !== '@') {
|
|
61
|
-
tagName = `@${tagName}
|
|
61
|
+
tagName = `@${tagName}`
|
|
62
62
|
}
|
|
63
|
-
this.suite.tags.push(tagName)
|
|
64
|
-
this.suite.title = `${this.suite.title.trim()} ${tagName}
|
|
65
|
-
return this
|
|
63
|
+
this.suite.tags.push(tagName)
|
|
64
|
+
this.suite.title = `${this.suite.title.trim()} ${tagName}`
|
|
65
|
+
return this
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
module.exports = FeatureConfig
|
|
69
|
+
module.exports = FeatureConfig
|
|
@@ -1,190 +1,201 @@
|
|
|
1
|
-
const Gherkin = require('@cucumber/gherkin')
|
|
2
|
-
const Messages = require('@cucumber/messages')
|
|
3
|
-
const { Context, Suite, Test } = require('mocha')
|
|
4
|
-
const debug = require('debug')('codeceptjs:bdd')
|
|
5
|
-
|
|
6
|
-
const { matchStep } = require('./bdd')
|
|
7
|
-
const event = require('../event')
|
|
8
|
-
const scenario = require('../scenario')
|
|
9
|
-
const Step = require('../step')
|
|
10
|
-
const DataTableArgument = require('../data/dataTableArgument')
|
|
11
|
-
const transform = require('../transform')
|
|
12
|
-
|
|
13
|
-
const uuidFn = Messages.IdGenerator.uuid()
|
|
14
|
-
const builder = new Gherkin.AstBuilder(uuidFn)
|
|
15
|
-
const matcher = new Gherkin.GherkinClassicTokenMatcher()
|
|
16
|
-
const parser = new Gherkin.Parser(builder, matcher)
|
|
17
|
-
parser.stopAtFirstError = false
|
|
1
|
+
const Gherkin = require('@cucumber/gherkin')
|
|
2
|
+
const Messages = require('@cucumber/messages')
|
|
3
|
+
const { Context, Suite, Test } = require('mocha')
|
|
4
|
+
const debug = require('debug')('codeceptjs:bdd')
|
|
5
|
+
|
|
6
|
+
const { matchStep } = require('./bdd')
|
|
7
|
+
const event = require('../event')
|
|
8
|
+
const scenario = require('../scenario')
|
|
9
|
+
const Step = require('../step')
|
|
10
|
+
const DataTableArgument = require('../data/dataTableArgument')
|
|
11
|
+
const transform = require('../transform')
|
|
12
|
+
|
|
13
|
+
const uuidFn = Messages.IdGenerator.uuid()
|
|
14
|
+
const builder = new Gherkin.AstBuilder(uuidFn)
|
|
15
|
+
const matcher = new Gherkin.GherkinClassicTokenMatcher()
|
|
16
|
+
const parser = new Gherkin.Parser(builder, matcher)
|
|
17
|
+
parser.stopAtFirstError = false
|
|
18
18
|
|
|
19
19
|
module.exports = (text, file) => {
|
|
20
|
-
const ast = parser.parse(text)
|
|
21
|
-
let currentLanguage
|
|
20
|
+
const ast = parser.parse(text)
|
|
21
|
+
let currentLanguage
|
|
22
22
|
|
|
23
23
|
if (ast.feature) {
|
|
24
|
-
currentLanguage = getTranslation(ast.feature.language)
|
|
24
|
+
currentLanguage = getTranslation(ast.feature.language)
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
if (!ast.feature) {
|
|
28
|
-
throw new Error(`No 'Features' available in Gherkin '${file}' provided!`)
|
|
28
|
+
throw new Error(`No 'Features' available in Gherkin '${file}' provided!`)
|
|
29
29
|
}
|
|
30
|
-
const suite = new Suite(ast.feature.name, new Context())
|
|
31
|
-
const tags = ast.feature.tags.map(t => t.name)
|
|
32
|
-
suite.title = `${suite.title} ${tags.join(' ')}`.trim()
|
|
33
|
-
suite.tags = tags || []
|
|
34
|
-
suite.comment = ast.feature.description
|
|
35
|
-
suite.feature = ast.feature
|
|
36
|
-
suite.file = file
|
|
37
|
-
suite.timeout(0)
|
|
38
|
-
|
|
39
|
-
suite.beforeEach('codeceptjs.before', () => scenario.setup(suite))
|
|
40
|
-
suite.afterEach('codeceptjs.after', () => scenario.teardown(suite))
|
|
41
|
-
suite.beforeAll('codeceptjs.beforeSuite', () => scenario.suiteSetup(suite))
|
|
42
|
-
suite.afterAll('codeceptjs.afterSuite', () => scenario.suiteTeardown(suite))
|
|
30
|
+
const suite = new Suite(ast.feature.name, new Context())
|
|
31
|
+
const tags = ast.feature.tags.map((t) => t.name)
|
|
32
|
+
suite.title = `${suite.title} ${tags.join(' ')}`.trim()
|
|
33
|
+
suite.tags = tags || []
|
|
34
|
+
suite.comment = ast.feature.description
|
|
35
|
+
suite.feature = ast.feature
|
|
36
|
+
suite.file = file
|
|
37
|
+
suite.timeout(0)
|
|
38
|
+
|
|
39
|
+
suite.beforeEach('codeceptjs.before', () => scenario.setup(suite))
|
|
40
|
+
suite.afterEach('codeceptjs.after', () => scenario.teardown(suite))
|
|
41
|
+
suite.beforeAll('codeceptjs.beforeSuite', () => scenario.suiteSetup(suite))
|
|
42
|
+
suite.afterAll('codeceptjs.afterSuite', () => scenario.suiteTeardown(suite))
|
|
43
43
|
|
|
44
44
|
const runSteps = async (steps) => {
|
|
45
45
|
for (const step of steps) {
|
|
46
|
-
const metaStep = new Step.MetaStep(null, step.text)
|
|
47
|
-
metaStep.actor = step.keyword.trim()
|
|
48
|
-
let helperStep
|
|
46
|
+
const metaStep = new Step.MetaStep(null, step.text)
|
|
47
|
+
metaStep.actor = step.keyword.trim()
|
|
48
|
+
let helperStep
|
|
49
49
|
const setMetaStep = (step) => {
|
|
50
|
-
helperStep = step
|
|
50
|
+
helperStep = step
|
|
51
51
|
if (step.metaStep) {
|
|
52
52
|
if (step.metaStep === metaStep) {
|
|
53
|
-
return
|
|
53
|
+
return
|
|
54
54
|
}
|
|
55
|
-
setMetaStep(step.metaStep)
|
|
56
|
-
return
|
|
55
|
+
setMetaStep(step.metaStep)
|
|
56
|
+
return
|
|
57
57
|
}
|
|
58
|
-
step.metaStep = metaStep
|
|
59
|
-
}
|
|
60
|
-
const fn = matchStep(step.text)
|
|
58
|
+
step.metaStep = metaStep
|
|
59
|
+
}
|
|
60
|
+
const fn = matchStep(step.text)
|
|
61
61
|
|
|
62
62
|
if (step.dataTable) {
|
|
63
63
|
fn.params.push({
|
|
64
64
|
...step.dataTable,
|
|
65
65
|
parse: () => new DataTableArgument(step.dataTable),
|
|
66
|
-
})
|
|
67
|
-
metaStep.comment = `\n${transformTable(step.dataTable)}
|
|
66
|
+
})
|
|
67
|
+
metaStep.comment = `\n${transformTable(step.dataTable)}`
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
if (step.docString) {
|
|
71
|
-
fn.params.push(step.docString)
|
|
72
|
-
metaStep.comment = `\n"""\n${step.docString.content}\n"""
|
|
71
|
+
fn.params.push(step.docString)
|
|
72
|
+
metaStep.comment = `\n"""\n${step.docString.content}\n"""`
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
step.startTime = Date.now()
|
|
76
|
-
step.match = fn.line
|
|
77
|
-
event.emit(event.bddStep.before, step)
|
|
78
|
-
event.emit(event.bddStep.started, metaStep)
|
|
79
|
-
event.dispatcher.prependListener(event.step.before, setMetaStep)
|
|
75
|
+
step.startTime = Date.now()
|
|
76
|
+
step.match = fn.line
|
|
77
|
+
event.emit(event.bddStep.before, step)
|
|
78
|
+
event.emit(event.bddStep.started, metaStep)
|
|
79
|
+
event.dispatcher.prependListener(event.step.before, setMetaStep)
|
|
80
80
|
try {
|
|
81
|
-
debug(`Step '${step.text}' started...`)
|
|
82
|
-
await fn(...fn.params)
|
|
83
|
-
debug('Step passed')
|
|
84
|
-
step.status = 'passed'
|
|
81
|
+
debug(`Step '${step.text}' started...`)
|
|
82
|
+
await fn(...fn.params)
|
|
83
|
+
debug('Step passed')
|
|
84
|
+
step.status = 'passed'
|
|
85
85
|
} catch (err) {
|
|
86
|
-
debug(`Step failed: ${err?.message}`)
|
|
87
|
-
step.status = 'failed'
|
|
88
|
-
step.err = err
|
|
89
|
-
throw err
|
|
86
|
+
debug(`Step failed: ${err?.message}`)
|
|
87
|
+
step.status = 'failed'
|
|
88
|
+
step.err = err
|
|
89
|
+
throw err
|
|
90
90
|
} finally {
|
|
91
|
-
step.endTime = Date.now()
|
|
92
|
-
event.dispatcher.removeListener(event.step.before, setMetaStep)
|
|
91
|
+
step.endTime = Date.now()
|
|
92
|
+
event.dispatcher.removeListener(event.step.before, setMetaStep)
|
|
93
93
|
}
|
|
94
|
-
event.emit(event.bddStep.finished, metaStep)
|
|
95
|
-
event.emit(event.bddStep.after, step)
|
|
94
|
+
event.emit(event.bddStep.finished, metaStep)
|
|
95
|
+
event.emit(event.bddStep.after, step)
|
|
96
96
|
}
|
|
97
|
-
}
|
|
97
|
+
}
|
|
98
98
|
|
|
99
99
|
for (const child of ast.feature.children) {
|
|
100
100
|
if (child.background) {
|
|
101
|
-
suite.beforeEach(
|
|
102
|
-
|
|
101
|
+
suite.beforeEach(
|
|
102
|
+
'Before',
|
|
103
|
+
scenario.injected(async () => runSteps(child.background.steps), suite, 'before'),
|
|
104
|
+
)
|
|
105
|
+
continue
|
|
103
106
|
}
|
|
104
|
-
if (
|
|
107
|
+
if (
|
|
108
|
+
child.scenario &&
|
|
109
|
+
(currentLanguage
|
|
110
|
+
? child.scenario.keyword === currentLanguage.contexts.ScenarioOutline
|
|
111
|
+
: child.scenario.keyword === 'Scenario Outline')
|
|
112
|
+
) {
|
|
105
113
|
for (const examples of child.scenario.examples) {
|
|
106
|
-
const fields = examples.tableHeader.cells.map(c => c.value)
|
|
114
|
+
const fields = examples.tableHeader.cells.map((c) => c.value)
|
|
107
115
|
for (const example of examples.tableBody) {
|
|
108
|
-
let exampleSteps = [...child.scenario.steps]
|
|
109
|
-
const current = {}
|
|
116
|
+
let exampleSteps = [...child.scenario.steps]
|
|
117
|
+
const current = {}
|
|
110
118
|
for (const index in example.cells) {
|
|
111
|
-
const placeholder = fields[index]
|
|
112
|
-
const value = transform('gherkin.examples', example.cells[index].value)
|
|
113
|
-
example.cells[index].value = value
|
|
114
|
-
current[placeholder] = value
|
|
119
|
+
const placeholder = fields[index]
|
|
120
|
+
const value = transform('gherkin.examples', example.cells[index].value)
|
|
121
|
+
example.cells[index].value = value
|
|
122
|
+
current[placeholder] = value
|
|
115
123
|
exampleSteps = exampleSteps.map((step) => {
|
|
116
|
-
step = { ...step }
|
|
117
|
-
step.text = step.text.split(`<${placeholder}>`).join(value)
|
|
118
|
-
return step
|
|
119
|
-
})
|
|
124
|
+
step = { ...step }
|
|
125
|
+
step.text = step.text.split(`<${placeholder}>`).join(value)
|
|
126
|
+
return step
|
|
127
|
+
})
|
|
120
128
|
}
|
|
121
|
-
const tags = child.scenario.tags.map(t => t.name).concat(examples.tags.map(t => t.name))
|
|
122
|
-
let title = `${child.scenario.name} ${JSON.stringify(current)} ${tags.join(' ')}`.trim()
|
|
129
|
+
const tags = child.scenario.tags.map((t) => t.name).concat(examples.tags.map((t) => t.name))
|
|
130
|
+
let title = `${child.scenario.name} ${JSON.stringify(current)} ${tags.join(' ')}`.trim()
|
|
123
131
|
|
|
124
132
|
for (const [key, value] of Object.entries(current)) {
|
|
125
133
|
if (title.includes(`<${key}>`)) {
|
|
126
|
-
title = title.replace(JSON.stringify(current), '').replace(`<${key}>`, value)
|
|
134
|
+
title = title.replace(JSON.stringify(current), '').replace(`<${key}>`, value)
|
|
127
135
|
}
|
|
128
136
|
}
|
|
129
137
|
|
|
130
|
-
const test = new Test(title, async () => runSteps(addExampleInTable(exampleSteps, current)))
|
|
131
|
-
test.tags = suite.tags.concat(tags)
|
|
132
|
-
test.file = file
|
|
133
|
-
suite.addTest(scenario.test(test))
|
|
138
|
+
const test = new Test(title, async () => runSteps(addExampleInTable(exampleSteps, current)))
|
|
139
|
+
test.tags = suite.tags.concat(tags)
|
|
140
|
+
test.file = file
|
|
141
|
+
suite.addTest(scenario.test(test))
|
|
134
142
|
}
|
|
135
143
|
}
|
|
136
|
-
continue
|
|
144
|
+
continue
|
|
137
145
|
}
|
|
138
146
|
|
|
139
147
|
if (child.scenario) {
|
|
140
|
-
const tags = child.scenario.tags.map(t => t.name)
|
|
141
|
-
const title = `${child.scenario.name} ${tags.join(' ')}`.trim()
|
|
142
|
-
const test = new Test(title, async () => runSteps(child.scenario.steps))
|
|
143
|
-
test.tags = suite.tags.concat(tags)
|
|
144
|
-
test.file = file
|
|
145
|
-
suite.addTest(scenario.test(test))
|
|
148
|
+
const tags = child.scenario.tags.map((t) => t.name)
|
|
149
|
+
const title = `${child.scenario.name} ${tags.join(' ')}`.trim()
|
|
150
|
+
const test = new Test(title, async () => runSteps(child.scenario.steps))
|
|
151
|
+
test.tags = suite.tags.concat(tags)
|
|
152
|
+
test.file = file
|
|
153
|
+
suite.addTest(scenario.test(test))
|
|
146
154
|
}
|
|
147
155
|
}
|
|
148
156
|
|
|
149
|
-
return suite
|
|
150
|
-
}
|
|
157
|
+
return suite
|
|
158
|
+
}
|
|
151
159
|
|
|
152
160
|
function transformTable(table) {
|
|
153
|
-
let str = ''
|
|
161
|
+
let str = ''
|
|
154
162
|
for (const id in table.rows) {
|
|
155
|
-
const cells = table.rows[id].cells
|
|
156
|
-
str += cells
|
|
157
|
-
|
|
163
|
+
const cells = table.rows[id].cells
|
|
164
|
+
str += cells
|
|
165
|
+
.map((c) => c.value)
|
|
166
|
+
.map((c) => c.padEnd(15))
|
|
167
|
+
.join(' | ')
|
|
168
|
+
str += '\n'
|
|
158
169
|
}
|
|
159
|
-
return str
|
|
170
|
+
return str
|
|
160
171
|
}
|
|
161
172
|
function addExampleInTable(exampleSteps, placeholders) {
|
|
162
|
-
const steps = JSON.parse(JSON.stringify(exampleSteps))
|
|
173
|
+
const steps = JSON.parse(JSON.stringify(exampleSteps))
|
|
163
174
|
for (const placeholder in placeholders) {
|
|
164
175
|
steps.map((step) => {
|
|
165
|
-
step = { ...step }
|
|
176
|
+
step = { ...step }
|
|
166
177
|
if (step.dataTable) {
|
|
167
178
|
for (const id in step.dataTable.rows) {
|
|
168
|
-
const cells = step.dataTable.rows[id].cells
|
|
169
|
-
cells.map(c => (c.value = c.value.replace(`<${placeholder}>`, placeholders[placeholder])))
|
|
179
|
+
const cells = step.dataTable.rows[id].cells
|
|
180
|
+
cells.map((c) => (c.value = c.value.replace(`<${placeholder}>`, placeholders[placeholder])))
|
|
170
181
|
}
|
|
171
182
|
}
|
|
172
|
-
return step
|
|
173
|
-
})
|
|
183
|
+
return step
|
|
184
|
+
})
|
|
174
185
|
}
|
|
175
|
-
return steps
|
|
186
|
+
return steps
|
|
176
187
|
}
|
|
177
188
|
|
|
178
189
|
function getTranslation(language) {
|
|
179
|
-
const translations = Object.keys(require('../../translations'))
|
|
190
|
+
const translations = Object.keys(require('../../translations'))
|
|
180
191
|
|
|
181
192
|
for (const availableTranslation of translations) {
|
|
182
193
|
if (!language) {
|
|
183
|
-
break
|
|
194
|
+
break
|
|
184
195
|
}
|
|
185
196
|
|
|
186
197
|
if (availableTranslation.includes(language)) {
|
|
187
|
-
return require('../../translations')[availableTranslation]
|
|
198
|
+
return require('../../translations')[availableTranslation]
|
|
188
199
|
}
|
|
189
200
|
}
|
|
190
201
|
}
|