codeceptjs 4.0.0-beta.1 → 4.0.0-beta.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/bin/codecept.js +84 -81
- package/lib/actor.js +13 -13
- package/lib/ai.js +10 -13
- package/lib/assert/empty.js +20 -21
- package/lib/assert/equal.js +37 -39
- package/lib/assert/error.js +14 -14
- package/lib/assert/include.js +46 -47
- package/lib/assert/throws.js +13 -11
- package/lib/assert/truth.js +19 -22
- package/lib/assert.js +4 -2
- package/lib/cli.js +57 -49
- package/lib/codecept.js +142 -155
- package/lib/colorUtils.js +3 -3
- package/lib/command/configMigrate.js +58 -52
- package/lib/command/definitions.js +88 -89
- package/lib/command/dryRun.js +71 -68
- package/lib/command/generate.js +197 -188
- package/lib/command/gherkin/init.js +27 -16
- package/lib/command/gherkin/snippets.js +20 -20
- package/lib/command/gherkin/steps.js +8 -8
- package/lib/command/info.js +40 -38
- package/lib/command/init.js +290 -288
- package/lib/command/interactive.js +32 -32
- package/lib/command/list.js +26 -26
- package/lib/command/run-multiple/chunk.js +5 -5
- package/lib/command/run-multiple/collection.js +3 -3
- package/lib/command/run-multiple/run.js +6 -2
- package/lib/command/run-multiple.js +113 -93
- package/lib/command/run-rerun.js +20 -25
- package/lib/command/run-workers.js +64 -66
- package/lib/command/run.js +26 -29
- package/lib/command/utils.js +80 -65
- package/lib/command/workers/runTests.js +10 -10
- package/lib/config.js +10 -9
- package/lib/container.js +40 -48
- package/lib/data/context.js +60 -59
- package/lib/data/dataScenarioConfig.js +47 -47
- package/lib/data/dataTableArgument.js +29 -29
- package/lib/data/table.js +26 -20
- package/lib/event.js +163 -167
- package/lib/heal.js +13 -17
- package/lib/helper/AI.js +130 -41
- package/lib/helper/ApiDataFactory.js +73 -69
- package/lib/helper/Appium.js +413 -382
- package/lib/helper/ExpectHelper.js +40 -48
- package/lib/helper/FileSystem.js +80 -79
- package/lib/helper/GraphQL.js +44 -43
- package/lib/helper/GraphQLDataFactory.js +50 -50
- package/lib/helper/JSONResponse.js +65 -62
- package/lib/helper/Mochawesome.js +28 -28
- package/lib/helper/MockServer.js +12 -14
- package/lib/helper/Nightmare.js +662 -566
- package/lib/helper/Playwright.js +1361 -1216
- package/lib/helper/Protractor.js +663 -627
- package/lib/helper/Puppeteer.js +1231 -1128
- package/lib/helper/REST.js +159 -68
- package/lib/helper/SoftExpectHelper.js +2 -2
- package/lib/helper/TestCafe.js +490 -484
- package/lib/helper/WebDriver.js +1297 -1156
- package/lib/helper/clientscripts/PollyWebDriverExt.js +1 -1
- package/lib/helper/errors/ConnectionRefused.js +1 -1
- package/lib/helper/errors/ElementAssertion.js +2 -2
- package/lib/helper/errors/ElementNotFound.js +2 -2
- package/lib/helper/errors/RemoteBrowserConnectionRefused.js +1 -1
- package/lib/helper/extras/Console.js +1 -1
- package/lib/helper/extras/PlaywrightPropEngine.js +2 -2
- package/lib/helper/extras/PlaywrightReactVueLocator.js +1 -1
- package/lib/helper/extras/PlaywrightRestartOpts.js +21 -18
- package/lib/helper/extras/Popup.js +1 -1
- package/lib/helper/extras/React.js +3 -3
- package/lib/helper/network/actions.js +14 -7
- package/lib/helper/network/utils.js +3 -2
- package/lib/helper/scripts/blurElement.js +1 -1
- package/lib/helper/scripts/focusElement.js +1 -1
- package/lib/helper/scripts/highlightElement.js +1 -1
- package/lib/helper/scripts/isElementClickable.js +1 -1
- package/lib/helper/testcafe/testControllerHolder.js +1 -1
- package/lib/helper/testcafe/testcafe-utils.js +6 -7
- package/lib/helper.js +1 -3
- package/lib/history.js +6 -5
- package/lib/hooks.js +6 -6
- package/lib/html.js +7 -7
- package/lib/index.js +25 -41
- package/lib/interfaces/bdd.js +47 -64
- package/lib/interfaces/featureConfig.js +19 -19
- package/lib/interfaces/gherkin.js +124 -118
- package/lib/interfaces/scenarioConfig.js +29 -29
- package/lib/listener/artifacts.js +9 -9
- package/lib/listener/config.js +24 -24
- 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 -53
- package/lib/listener/timeout.js +54 -54
- package/lib/locator.js +6 -10
- package/lib/mochaFactory.js +18 -15
- package/lib/output.js +6 -10
- package/lib/parser.js +15 -12
- package/lib/pause.js +40 -33
- package/lib/plugin/allure.js +15 -15
- package/lib/plugin/autoDelay.js +29 -37
- package/lib/plugin/autoLogin.js +70 -65
- package/lib/plugin/commentStep.js +18 -18
- package/lib/plugin/coverage.js +115 -67
- package/lib/plugin/customLocator.js +21 -20
- package/lib/plugin/debugErrors.js +24 -24
- package/lib/plugin/eachElement.js +38 -38
- package/lib/plugin/fakerTransform.js +6 -6
- package/lib/plugin/heal.js +67 -108
- package/lib/plugin/pauseOnFail.js +11 -11
- package/lib/plugin/retryFailedStep.js +32 -39
- package/lib/plugin/retryTo.js +46 -40
- package/lib/plugin/screenshotOnFail.js +109 -87
- package/lib/plugin/selenoid.js +131 -118
- package/lib/plugin/standardActingHelpers.js +2 -8
- package/lib/plugin/stepByStepReport.js +110 -91
- package/lib/plugin/stepTimeout.js +24 -23
- package/lib/plugin/subtitles.js +34 -35
- package/lib/plugin/tryTo.js +40 -30
- package/lib/plugin/wdio.js +78 -75
- package/lib/recorder.js +14 -17
- package/lib/rerun.js +11 -10
- package/lib/scenario.js +25 -23
- package/lib/secret.js +4 -2
- package/lib/session.js +10 -10
- package/lib/step.js +12 -9
- package/lib/store.js +2 -3
- package/lib/transform.js +1 -1
- package/lib/translation.js +7 -8
- package/lib/ui.js +12 -14
- package/lib/utils.js +70 -72
- package/lib/within.js +10 -10
- package/lib/workerStorage.js +27 -25
- package/lib/workers.js +29 -32
- package/package.json +56 -57
- package/translations/de-DE.js +1 -1
- package/translations/fr-FR.js +1 -1
- package/translations/index.js +9 -13
- 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 +415 -65
- package/typings/promiseBasedTypes.d.ts +32 -0
- package/typings/types.d.ts +32 -0
- package/lib/dirname.js +0 -5
- package/lib/helper/Expect.js +0 -425
|
@@ -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
|
-
|
|
69
|
+
module.exports = FeatureConfig
|
|
@@ -1,195 +1,201 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
parser.stopAtFirstError = false;
|
|
23
|
-
|
|
24
|
-
export default (text, file) => {
|
|
25
|
-
const ast = parser.parse(text);
|
|
26
|
-
let currentLanguage;
|
|
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
|
+
|
|
19
|
+
module.exports = (text, file) => {
|
|
20
|
+
const ast = parser.parse(text)
|
|
21
|
+
let currentLanguage
|
|
27
22
|
|
|
28
23
|
if (ast.feature) {
|
|
29
|
-
currentLanguage = getTranslation(ast.feature.language)
|
|
24
|
+
currentLanguage = getTranslation(ast.feature.language)
|
|
30
25
|
}
|
|
31
26
|
|
|
32
27
|
if (!ast.feature) {
|
|
33
|
-
throw new Error(`No 'Features' available in Gherkin '${file}' provided!`)
|
|
28
|
+
throw new Error(`No 'Features' available in Gherkin '${file}' provided!`)
|
|
34
29
|
}
|
|
35
|
-
const suite = new Suite(ast.feature.name, new Context())
|
|
36
|
-
const tags = ast.feature.tags.map(t => t.name)
|
|
37
|
-
suite.title = `${suite.title} ${tags.join(' ')}`.trim()
|
|
38
|
-
suite.tags = tags || []
|
|
39
|
-
suite.comment = ast.feature.description
|
|
40
|
-
suite.feature = ast.feature
|
|
41
|
-
suite.file = file
|
|
42
|
-
suite.timeout(0)
|
|
43
|
-
|
|
44
|
-
suite.beforeEach('codeceptjs.before', () => scenario.setup(suite))
|
|
45
|
-
suite.afterEach('codeceptjs.after', () => scenario.teardown(suite))
|
|
46
|
-
suite.beforeAll('codeceptjs.beforeSuite', () => scenario.suiteSetup(suite))
|
|
47
|
-
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))
|
|
48
43
|
|
|
49
44
|
const runSteps = async (steps) => {
|
|
50
45
|
for (const step of steps) {
|
|
51
|
-
const metaStep = new Step.MetaStep(null, step.text)
|
|
52
|
-
metaStep.actor = step.keyword.trim()
|
|
53
|
-
let helperStep
|
|
46
|
+
const metaStep = new Step.MetaStep(null, step.text)
|
|
47
|
+
metaStep.actor = step.keyword.trim()
|
|
48
|
+
let helperStep
|
|
54
49
|
const setMetaStep = (step) => {
|
|
55
|
-
helperStep = step
|
|
50
|
+
helperStep = step
|
|
56
51
|
if (step.metaStep) {
|
|
57
52
|
if (step.metaStep === metaStep) {
|
|
58
|
-
return
|
|
53
|
+
return
|
|
59
54
|
}
|
|
60
|
-
setMetaStep(step.metaStep)
|
|
61
|
-
return
|
|
55
|
+
setMetaStep(step.metaStep)
|
|
56
|
+
return
|
|
62
57
|
}
|
|
63
|
-
step.metaStep = metaStep
|
|
64
|
-
}
|
|
65
|
-
const fn = matchStep(step.text)
|
|
58
|
+
step.metaStep = metaStep
|
|
59
|
+
}
|
|
60
|
+
const fn = matchStep(step.text)
|
|
66
61
|
|
|
67
62
|
if (step.dataTable) {
|
|
68
63
|
fn.params.push({
|
|
69
64
|
...step.dataTable,
|
|
70
65
|
parse: () => new DataTableArgument(step.dataTable),
|
|
71
|
-
})
|
|
72
|
-
metaStep.comment = `\n${transformTable(step.dataTable)}
|
|
66
|
+
})
|
|
67
|
+
metaStep.comment = `\n${transformTable(step.dataTable)}`
|
|
73
68
|
}
|
|
74
69
|
|
|
75
70
|
if (step.docString) {
|
|
76
|
-
fn.params.push(step.docString)
|
|
77
|
-
metaStep.comment = `\n"""\n${step.docString.content}\n"""
|
|
71
|
+
fn.params.push(step.docString)
|
|
72
|
+
metaStep.comment = `\n"""\n${step.docString.content}\n"""`
|
|
78
73
|
}
|
|
79
74
|
|
|
80
|
-
step.startTime = Date.now()
|
|
81
|
-
step.match = fn.line
|
|
82
|
-
event.emit(event.bddStep.before, step)
|
|
83
|
-
event.emit(event.bddStep.started, metaStep)
|
|
84
|
-
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)
|
|
85
80
|
try {
|
|
86
|
-
debug(`Step '${step.text}' started...`)
|
|
87
|
-
await fn(...fn.params)
|
|
88
|
-
debug('Step passed')
|
|
89
|
-
step.status = 'passed'
|
|
81
|
+
debug(`Step '${step.text}' started...`)
|
|
82
|
+
await fn(...fn.params)
|
|
83
|
+
debug('Step passed')
|
|
84
|
+
step.status = 'passed'
|
|
90
85
|
} catch (err) {
|
|
91
|
-
debug(`Step failed: ${err?.message}`)
|
|
92
|
-
step.status = 'failed'
|
|
93
|
-
step.err = err
|
|
94
|
-
throw err
|
|
86
|
+
debug(`Step failed: ${err?.message}`)
|
|
87
|
+
step.status = 'failed'
|
|
88
|
+
step.err = err
|
|
89
|
+
throw err
|
|
95
90
|
} finally {
|
|
96
|
-
step.endTime = Date.now()
|
|
97
|
-
event.dispatcher.removeListener(event.step.before, setMetaStep)
|
|
91
|
+
step.endTime = Date.now()
|
|
92
|
+
event.dispatcher.removeListener(event.step.before, setMetaStep)
|
|
98
93
|
}
|
|
99
|
-
event.emit(event.bddStep.finished, metaStep)
|
|
100
|
-
event.emit(event.bddStep.after, step)
|
|
94
|
+
event.emit(event.bddStep.finished, metaStep)
|
|
95
|
+
event.emit(event.bddStep.after, step)
|
|
101
96
|
}
|
|
102
|
-
}
|
|
97
|
+
}
|
|
103
98
|
|
|
104
99
|
for (const child of ast.feature.children) {
|
|
105
100
|
if (child.background) {
|
|
106
|
-
suite.beforeEach(
|
|
107
|
-
|
|
101
|
+
suite.beforeEach(
|
|
102
|
+
'Before',
|
|
103
|
+
scenario.injected(async () => runSteps(child.background.steps), suite, 'before'),
|
|
104
|
+
)
|
|
105
|
+
continue
|
|
108
106
|
}
|
|
109
|
-
if (
|
|
107
|
+
if (
|
|
108
|
+
child.scenario &&
|
|
109
|
+
(currentLanguage
|
|
110
|
+
? child.scenario.keyword === currentLanguage.contexts.ScenarioOutline
|
|
111
|
+
: child.scenario.keyword === 'Scenario Outline')
|
|
112
|
+
) {
|
|
110
113
|
for (const examples of child.scenario.examples) {
|
|
111
|
-
const fields = examples.tableHeader.cells.map(c => c.value)
|
|
114
|
+
const fields = examples.tableHeader.cells.map((c) => c.value)
|
|
112
115
|
for (const example of examples.tableBody) {
|
|
113
|
-
let exampleSteps = [...child.scenario.steps]
|
|
114
|
-
const current = {}
|
|
116
|
+
let exampleSteps = [...child.scenario.steps]
|
|
117
|
+
const current = {}
|
|
115
118
|
for (const index in example.cells) {
|
|
116
|
-
const placeholder = fields[index]
|
|
117
|
-
const value = transform('gherkin.examples', example.cells[index].value)
|
|
118
|
-
example.cells[index].value = value
|
|
119
|
-
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
|
|
120
123
|
exampleSteps = exampleSteps.map((step) => {
|
|
121
|
-
step = { ...step }
|
|
122
|
-
step.text = step.text.split(`<${placeholder}>`).join(value)
|
|
123
|
-
return step
|
|
124
|
-
})
|
|
124
|
+
step = { ...step }
|
|
125
|
+
step.text = step.text.split(`<${placeholder}>`).join(value)
|
|
126
|
+
return step
|
|
127
|
+
})
|
|
125
128
|
}
|
|
126
|
-
const tags = child.scenario.tags.map(t => t.name).concat(examples.tags.map(t => t.name))
|
|
127
|
-
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()
|
|
128
131
|
|
|
129
132
|
for (const [key, value] of Object.entries(current)) {
|
|
130
133
|
if (title.includes(`<${key}>`)) {
|
|
131
|
-
title = title.replace(JSON.stringify(current), '').replace(`<${key}>`, value)
|
|
134
|
+
title = title.replace(JSON.stringify(current), '').replace(`<${key}>`, value)
|
|
132
135
|
}
|
|
133
136
|
}
|
|
134
137
|
|
|
135
|
-
const test = new Test(title, async () => runSteps(addExampleInTable(exampleSteps, current)))
|
|
136
|
-
test.tags = suite.tags.concat(tags)
|
|
137
|
-
test.file = file
|
|
138
|
-
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))
|
|
139
142
|
}
|
|
140
143
|
}
|
|
141
|
-
continue
|
|
144
|
+
continue
|
|
142
145
|
}
|
|
143
146
|
|
|
144
147
|
if (child.scenario) {
|
|
145
|
-
const tags = child.scenario.tags.map(t => t.name)
|
|
146
|
-
const title = `${child.scenario.name} ${tags.join(' ')}`.trim()
|
|
147
|
-
const test = new Test(title, async () => runSteps(child.scenario.steps))
|
|
148
|
-
test.tags = suite.tags.concat(tags)
|
|
149
|
-
test.file = file
|
|
150
|
-
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))
|
|
151
154
|
}
|
|
152
155
|
}
|
|
153
156
|
|
|
154
|
-
return suite
|
|
155
|
-
}
|
|
157
|
+
return suite
|
|
158
|
+
}
|
|
156
159
|
|
|
157
160
|
function transformTable(table) {
|
|
158
|
-
let str = ''
|
|
161
|
+
let str = ''
|
|
159
162
|
for (const id in table.rows) {
|
|
160
|
-
const cells = table.rows[id].cells
|
|
161
|
-
str += cells
|
|
162
|
-
|
|
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'
|
|
163
169
|
}
|
|
164
|
-
return str
|
|
170
|
+
return str
|
|
165
171
|
}
|
|
166
172
|
function addExampleInTable(exampleSteps, placeholders) {
|
|
167
|
-
const steps = JSON.parse(JSON.stringify(exampleSteps))
|
|
173
|
+
const steps = JSON.parse(JSON.stringify(exampleSteps))
|
|
168
174
|
for (const placeholder in placeholders) {
|
|
169
175
|
steps.map((step) => {
|
|
170
|
-
step = { ...step }
|
|
176
|
+
step = { ...step }
|
|
171
177
|
if (step.dataTable) {
|
|
172
178
|
for (const id in step.dataTable.rows) {
|
|
173
|
-
const cells = step.dataTable.rows[id].cells
|
|
174
|
-
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])))
|
|
175
181
|
}
|
|
176
182
|
}
|
|
177
|
-
return step
|
|
178
|
-
})
|
|
183
|
+
return step
|
|
184
|
+
})
|
|
179
185
|
}
|
|
180
|
-
return steps
|
|
186
|
+
return steps
|
|
181
187
|
}
|
|
182
188
|
|
|
183
189
|
function getTranslation(language) {
|
|
184
|
-
const translations = Object.keys(
|
|
190
|
+
const translations = Object.keys(require('../../translations'))
|
|
185
191
|
|
|
186
192
|
for (const availableTranslation of translations) {
|
|
187
193
|
if (!language) {
|
|
188
|
-
break
|
|
194
|
+
break
|
|
189
195
|
}
|
|
190
196
|
|
|
191
197
|
if (availableTranslation.includes(language)) {
|
|
192
|
-
return
|
|
198
|
+
return require('../../translations')[availableTranslation]
|
|
193
199
|
}
|
|
194
200
|
}
|
|
195
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
|
-
|
|
114
|
+
module.exports = ScenarioConfig
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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
|
-
})
|
|
17
|
+
})
|
|
18
|
+
})
|
|
19
19
|
}
|
package/lib/listener/config.js
CHANGED
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
const event = require('../event')
|
|
2
|
+
const container = require('../container')
|
|
3
|
+
const recorder = require('../recorder')
|
|
4
|
+
const { deepMerge, deepClone, ucfirst } = require('../utils')
|
|
5
|
+
const { debug } = require('../output')
|
|
7
6
|
/**
|
|
8
7
|
* Enable Helpers to listen to test events
|
|
9
8
|
*/
|
|
10
|
-
|
|
11
|
-
const helpers = container.helpers()
|
|
9
|
+
module.exports = function () {
|
|
10
|
+
const helpers = container.helpers()
|
|
12
11
|
|
|
13
|
-
enableDynamicConfigFor('suite')
|
|
14
|
-
enableDynamicConfigFor('test')
|
|
12
|
+
enableDynamicConfigFor('suite')
|
|
13
|
+
enableDynamicConfigFor('test')
|
|
15
14
|
|
|
16
15
|
function enableDynamicConfigFor(type) {
|
|
17
16
|
event.dispatcher.on(event[type].before, (context = {}) => {
|
|
18
17
|
function updateHelperConfig(helper, config) {
|
|
19
|
-
const oldConfig = { ...helper.options }
|
|
18
|
+
const oldConfig = { ...helper.options }
|
|
20
19
|
try {
|
|
21
|
-
helper._setConfig(deepMerge(deepClone(oldConfig), config))
|
|
22
|
-
debug(`[${ucfirst(type)} Config] ${helper.constructor.name} ${JSON.stringify(config)}`)
|
|
20
|
+
helper._setConfig(deepMerge(deepClone(oldConfig), config))
|
|
21
|
+
debug(`[${ucfirst(type)} Config] ${helper.constructor.name} ${JSON.stringify(config)}`)
|
|
23
22
|
} catch (err) {
|
|
24
|
-
recorder.throw(err)
|
|
25
|
-
return
|
|
23
|
+
recorder.throw(err)
|
|
24
|
+
return
|
|
26
25
|
}
|
|
27
26
|
event.dispatcher.once(event[type].after, () => {
|
|
28
|
-
helper._setConfig(oldConfig)
|
|
29
|
-
debug(`[${ucfirst(type)} Config] Reverted for ${helper.constructor.name}`)
|
|
30
|
-
})
|
|
27
|
+
helper._setConfig(oldConfig)
|
|
28
|
+
debug(`[${ucfirst(type)} Config] Reverted for ${helper.constructor.name}`)
|
|
29
|
+
})
|
|
31
30
|
}
|
|
32
31
|
|
|
33
32
|
// change config
|
|
34
33
|
if (context.config) {
|
|
35
34
|
for (let name in context.config) {
|
|
36
|
-
const config = context.config[name]
|
|
37
|
-
if (name === '0') {
|
|
38
|
-
|
|
35
|
+
const config = context.config[name]
|
|
36
|
+
if (name === '0') {
|
|
37
|
+
// first helper
|
|
38
|
+
name = Object.keys(helpers)[0]
|
|
39
39
|
}
|
|
40
|
-
const helper = helpers[name]
|
|
41
|
-
updateHelperConfig(helper, config)
|
|
40
|
+
const helper = helpers[name]
|
|
41
|
+
updateHelperConfig(helper, config)
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
|
-
})
|
|
44
|
+
})
|
|
45
45
|
}
|
|
46
46
|
}
|
package/lib/listener/exit.js
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
|
|
1
|
+
const event = require('../event')
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
let failedTests = []
|
|
3
|
+
module.exports = function () {
|
|
4
|
+
let failedTests = []
|
|
5
5
|
|
|
6
6
|
event.dispatcher.on(event.test.failed, (testOrSuite) => {
|
|
7
7
|
// NOTE When an error happens in one of the hooks (BeforeAll/BeforeEach...) the event object
|
|
8
8
|
// is a suite and not a test
|
|
9
|
-
const id = testOrSuite.uid || (testOrSuite.ctx && testOrSuite.ctx.test.uid) || 'empty'
|
|
10
|
-
failedTests.push(id)
|
|
11
|
-
})
|
|
9
|
+
const id = testOrSuite.uid || (testOrSuite.ctx && testOrSuite.ctx.test.uid) || 'empty'
|
|
10
|
+
failedTests.push(id)
|
|
11
|
+
})
|
|
12
12
|
|
|
13
13
|
// if test was successful after retries
|
|
14
14
|
event.dispatcher.on(event.test.passed, (testOrSuite) => {
|
|
15
15
|
// NOTE When an error happens in one of the hooks (BeforeAll/BeforeEach...) the event object
|
|
16
16
|
// is a suite and not a test
|
|
17
|
-
const id = testOrSuite.uid || (testOrSuite.ctx && testOrSuite.ctx.test.uid) || 'empty'
|
|
18
|
-
failedTests = failedTests.filter(failed => id !== failed)
|
|
19
|
-
})
|
|
17
|
+
const id = testOrSuite.uid || (testOrSuite.ctx && testOrSuite.ctx.test.uid) || 'empty'
|
|
18
|
+
failedTests = failedTests.filter((failed) => id !== failed)
|
|
19
|
+
})
|
|
20
20
|
|
|
21
21
|
process.on('beforeExit', (code) => {
|
|
22
22
|
if (failedTests.length) {
|
|
23
|
-
code = 1
|
|
23
|
+
code = 1
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
if (code) {
|
|
27
|
-
process.exit(code)
|
|
27
|
+
process.exit(code)
|
|
28
28
|
}
|
|
29
|
-
})
|
|
29
|
+
})
|
|
30
30
|
}
|