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