codeceptjs 3.6.4 → 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/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 +67 -65
- 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 +87 -72
- package/lib/helper/TestCafe.js +490 -491
- package/lib/helper/WebDriver.js +1294 -1156
- 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/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 +4 -2
- 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/promiseBasedTypes.d.ts +238 -0
- package/typings/types.d.ts +32 -0
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
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** @class */
|
|
2
2
|
class ScenarioConfig {
|
|
3
3
|
constructor(test) {
|
|
4
|
-
this.test = test
|
|
4
|
+
this.test = test
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -12,8 +12,8 @@ class ScenarioConfig {
|
|
|
12
12
|
* @returns {this}
|
|
13
13
|
*/
|
|
14
14
|
throws(err) {
|
|
15
|
-
this.test.throws = err
|
|
16
|
-
return this
|
|
15
|
+
this.test.throws = err
|
|
16
|
+
return this
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
/**
|
|
@@ -24,8 +24,8 @@ class ScenarioConfig {
|
|
|
24
24
|
* @returns {this}
|
|
25
25
|
*/
|
|
26
26
|
fails() {
|
|
27
|
-
this.test.throws = new Error()
|
|
28
|
-
return this
|
|
27
|
+
this.test.throws = new Error()
|
|
28
|
+
return this
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
/**
|
|
@@ -35,9 +35,9 @@ class ScenarioConfig {
|
|
|
35
35
|
* @returns {this}
|
|
36
36
|
*/
|
|
37
37
|
retry(retries) {
|
|
38
|
-
if (process.env.SCENARIO_ONLY) retries = -retries
|
|
39
|
-
this.test.retries(retries)
|
|
40
|
-
return this
|
|
38
|
+
if (process.env.SCENARIO_ONLY) retries = -retries
|
|
39
|
+
this.test.retries(retries)
|
|
40
|
+
return this
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
/**
|
|
@@ -46,12 +46,12 @@ class ScenarioConfig {
|
|
|
46
46
|
* @returns {this}
|
|
47
47
|
*/
|
|
48
48
|
timeout(timeout) {
|
|
49
|
-
console.log(`Scenario('${this.test.title}', () => {}).timeout(${timeout}) is deprecated!`)
|
|
50
|
-
console.log(`Please use Scenario('${this.test.title}', { timeout: ${timeout / 1000} }, () => {}) instead`)
|
|
51
|
-
console.log('Timeout should be set in seconds')
|
|
49
|
+
console.log(`Scenario('${this.test.title}', () => {}).timeout(${timeout}) is deprecated!`)
|
|
50
|
+
console.log(`Please use Scenario('${this.test.title}', { timeout: ${timeout / 1000} }, () => {}) instead`)
|
|
51
|
+
console.log('Timeout should be set in seconds')
|
|
52
52
|
|
|
53
|
-
this.test.timeout(timeout)
|
|
54
|
-
return this
|
|
53
|
+
this.test.timeout(timeout)
|
|
54
|
+
return this
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
/**
|
|
@@ -60,8 +60,8 @@ class ScenarioConfig {
|
|
|
60
60
|
* @returns {this}
|
|
61
61
|
*/
|
|
62
62
|
inject(obj) {
|
|
63
|
-
this.test.inject = obj
|
|
64
|
-
return this
|
|
63
|
+
this.test.inject = obj
|
|
64
|
+
return this
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
/**
|
|
@@ -73,17 +73,17 @@ class ScenarioConfig {
|
|
|
73
73
|
*/
|
|
74
74
|
async config(helper, obj) {
|
|
75
75
|
if (!obj) {
|
|
76
|
-
obj = helper
|
|
77
|
-
helper = 0
|
|
76
|
+
obj = helper
|
|
77
|
+
helper = 0
|
|
78
78
|
}
|
|
79
79
|
if (typeof obj === 'function') {
|
|
80
|
-
obj = await obj(this.test)
|
|
80
|
+
obj = await obj(this.test)
|
|
81
81
|
}
|
|
82
82
|
if (!this.test.config) {
|
|
83
|
-
this.test.config = {}
|
|
83
|
+
this.test.config = {}
|
|
84
84
|
}
|
|
85
|
-
this.test.config[helper] = obj
|
|
86
|
-
return this
|
|
85
|
+
this.test.config[helper] = obj
|
|
86
|
+
return this
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
/**
|
|
@@ -92,10 +92,10 @@ class ScenarioConfig {
|
|
|
92
92
|
* @returns {this}
|
|
93
93
|
*/
|
|
94
94
|
tag(tagName) {
|
|
95
|
-
if (tagName[0] !== '@') tagName = `@${tagName}
|
|
96
|
-
this.test.tags.push(tagName)
|
|
97
|
-
this.test.title = `${this.test.title.trim()} ${tagName}
|
|
98
|
-
return this
|
|
95
|
+
if (tagName[0] !== '@') tagName = `@${tagName}`
|
|
96
|
+
this.test.tags.push(tagName)
|
|
97
|
+
this.test.title = `${this.test.title.trim()} ${tagName}`
|
|
98
|
+
return this
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
/**
|
|
@@ -105,10 +105,10 @@ class ScenarioConfig {
|
|
|
105
105
|
*/
|
|
106
106
|
injectDependencies(dependencies) {
|
|
107
107
|
Object.keys(dependencies).forEach((key) => {
|
|
108
|
-
this.test.inject[key] = dependencies[key]
|
|
109
|
-
})
|
|
110
|
-
return this
|
|
108
|
+
this.test.inject[key] = dependencies[key]
|
|
109
|
+
})
|
|
110
|
+
return this
|
|
111
111
|
}
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
module.exports = ScenarioConfig
|
|
114
|
+
module.exports = ScenarioConfig
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
const event = require('../event')
|
|
2
|
-
const recorder = require('../recorder')
|
|
1
|
+
const event = require('../event')
|
|
2
|
+
const recorder = require('../recorder')
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Create and clean up empty artifacts
|
|
6
6
|
*/
|
|
7
7
|
module.exports = function () {
|
|
8
8
|
event.dispatcher.on(event.test.before, (test) => {
|
|
9
|
-
test.artifacts = {}
|
|
10
|
-
})
|
|
9
|
+
test.artifacts = {}
|
|
10
|
+
})
|
|
11
11
|
|
|
12
12
|
event.dispatcher.on(event.test.after, (test) => {
|
|
13
13
|
recorder.add('clean up empty artifacts', () => {
|
|
14
|
-
for (const key in
|
|
15
|
-
if (!test.artifacts[key]) delete test.artifacts[key]
|
|
14
|
+
for (const key in test.artifacts || {}) {
|
|
15
|
+
if (!test.artifacts[key]) delete test.artifacts[key]
|
|
16
16
|
}
|
|
17
|
-
})
|
|
18
|
-
})
|
|
19
|
-
}
|
|
17
|
+
})
|
|
18
|
+
})
|
|
19
|
+
}
|