codeceptjs 4.0.0-beta.2 → 4.0.0-beta.4
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/README.md +2 -2
- 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 +56 -49
- package/lib/codecept.js +145 -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 +79 -81
- package/lib/command/generate.js +197 -188
- package/lib/command/gherkin/init.js +27 -16
- package/lib/command/gherkin/snippets.js +21 -21
- 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 +11 -12
- 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 +14 -18
- package/lib/helper/AI.js +130 -41
- package/lib/helper/ApiDataFactory.js +74 -70
- package/lib/helper/Appium.js +416 -388
- 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 +51 -51
- package/lib/helper/JSONResponse.js +65 -62
- package/lib/helper/Mochawesome.js +28 -28
- package/lib/helper/Nightmare.js +664 -571
- package/lib/helper/Playwright.js +1367 -1222
- package/lib/helper/Protractor.js +663 -635
- package/lib/helper/Puppeteer.js +1232 -1132
- package/lib/helper/REST.js +183 -68
- package/lib/helper/SoftExpectHelper.js +2 -2
- package/lib/helper/TestCafe.js +490 -486
- package/lib/helper/WebDriver.js +1246 -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 +4 -4
- 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 +4 -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 -8
- 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 +7 -11
- package/lib/mochaFactory.js +18 -15
- package/lib/output.js +19 -15
- package/lib/parser.js +15 -12
- package/lib/pause.js +45 -38
- 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 +112 -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 -3
- 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 -33
- package/package.json +67 -68
- package/translations/de-DE.js +2 -1
- package/translations/fr-FR.js +2 -2
- 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 +423 -65
- package/typings/promiseBasedTypes.d.ts +41 -172
- package/typings/types.d.ts +43 -178
- package/lib/dirname.js +0 -5
- package/lib/helper/Expect.js +0 -425
- package/lib/helper/MockServer.js +0 -223
package/lib/plugin/wdio.js
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
const debug = require('debug')('codeceptjs:plugin:wdio')
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
debug('codeceptjs:plugin:wdio');
|
|
3
|
+
const container = require('../container')
|
|
4
|
+
const mainConfig = require('../config')
|
|
5
|
+
const recorder = require('../recorder')
|
|
6
|
+
const event = require('../event')
|
|
7
|
+
const output = require('../output')
|
|
10
8
|
|
|
11
9
|
const defaultConfig = {
|
|
12
10
|
services: [],
|
|
13
11
|
capabilities: {},
|
|
14
|
-
}
|
|
12
|
+
}
|
|
15
13
|
|
|
16
|
-
let restartsSession
|
|
14
|
+
let restartsSession
|
|
17
15
|
|
|
18
16
|
/**
|
|
19
17
|
* Webdriverio services runner.
|
|
@@ -83,164 +81,169 @@ let restartsSession;
|
|
|
83
81
|
* * ... - additional configuration passed into services.
|
|
84
82
|
*
|
|
85
83
|
*/
|
|
86
|
-
|
|
84
|
+
module.exports = (config) => {
|
|
87
85
|
// Keep initial configs to pass as options to wdio services
|
|
88
|
-
const wdioOptions = { ...config }
|
|
89
|
-
const webDriver = container.helpers('WebDriver')
|
|
86
|
+
const wdioOptions = { ...config }
|
|
87
|
+
const webDriver = container.helpers('WebDriver')
|
|
90
88
|
if (webDriver) {
|
|
91
|
-
config = Object.assign(webDriver.options, config)
|
|
92
|
-
restartsSession = !!config.restart
|
|
89
|
+
config = Object.assign(webDriver.options, config)
|
|
90
|
+
restartsSession = !!config.restart
|
|
93
91
|
}
|
|
94
|
-
config = Object.assign(defaultConfig, config)
|
|
95
|
-
const seleniumInstallArgs = { ...config.seleniumInstallArgs }
|
|
96
|
-
const seleniumArgs = { ...config.seleniumArgs }
|
|
92
|
+
config = Object.assign(defaultConfig, config)
|
|
93
|
+
const seleniumInstallArgs = { ...config.seleniumInstallArgs }
|
|
94
|
+
const seleniumArgs = { ...config.seleniumArgs }
|
|
97
95
|
|
|
98
|
-
const services = []
|
|
99
|
-
const launchers = []
|
|
96
|
+
const services = []
|
|
97
|
+
const launchers = []
|
|
100
98
|
|
|
101
99
|
for (const name of config.services) {
|
|
102
|
-
const Service = safeRequire(`@wdio/${name.toLowerCase()}-service`)
|
|
100
|
+
const Service = safeRequire(`@wdio/${name.toLowerCase()}-service`)
|
|
103
101
|
if (Service) {
|
|
104
102
|
if (Service.launcher && typeof Service.launcher === 'function') {
|
|
105
|
-
const Launcher = Service.launcher
|
|
103
|
+
const Launcher = Service.launcher
|
|
106
104
|
|
|
107
105
|
const options = {
|
|
108
|
-
logPath: global.output_dir,
|
|
109
|
-
|
|
110
|
-
|
|
106
|
+
logPath: global.output_dir,
|
|
107
|
+
installArgs: seleniumInstallArgs,
|
|
108
|
+
args: seleniumArgs,
|
|
109
|
+
...wdioOptions,
|
|
110
|
+
}
|
|
111
|
+
launchers.push(new Launcher(options, [config.capabilities], config))
|
|
111
112
|
}
|
|
112
113
|
if (typeof Service === 'function') {
|
|
113
|
-
services.push(new Service(config, config.capabilities))
|
|
114
|
+
services.push(new Service(config, config.capabilities))
|
|
114
115
|
}
|
|
115
|
-
continue
|
|
116
|
+
continue
|
|
116
117
|
}
|
|
117
118
|
|
|
118
|
-
throw new Error(
|
|
119
|
+
throw new Error(
|
|
120
|
+
`Couldn't initialize service ${name} from wdio plugin config.\nIt should be available either in '@wdio/${name.toLowerCase()}-service' package`,
|
|
121
|
+
)
|
|
119
122
|
}
|
|
120
123
|
|
|
121
|
-
debug(`services ${services}, launchers ${launchers}`)
|
|
124
|
+
debug(`services ${services}, launchers ${launchers}`)
|
|
122
125
|
|
|
123
|
-
recorder.startUnlessRunning()
|
|
126
|
+
recorder.startUnlessRunning()
|
|
124
127
|
|
|
125
128
|
for (const launcher of launchers) {
|
|
126
|
-
registerLauncher(launcher)
|
|
129
|
+
registerLauncher(launcher)
|
|
127
130
|
}
|
|
128
131
|
|
|
129
132
|
for (const service of services) {
|
|
130
|
-
registerService(service)
|
|
133
|
+
registerService(service)
|
|
131
134
|
}
|
|
132
135
|
|
|
133
136
|
function registerService(service) {
|
|
134
|
-
const name = service.constructor.name
|
|
137
|
+
const name = service.constructor.name
|
|
135
138
|
if (service.beforeSession) {
|
|
136
139
|
event.dispatcher.on(event.all.before, () => {
|
|
137
140
|
recorder.add(`service ${name} all.before`, async () => {
|
|
138
|
-
await service.beforeSession(config, config.capabilities)
|
|
139
|
-
})
|
|
140
|
-
})
|
|
141
|
+
await service.beforeSession(config, config.capabilities)
|
|
142
|
+
})
|
|
143
|
+
})
|
|
141
144
|
}
|
|
142
145
|
|
|
143
146
|
if (service.afterSession) {
|
|
144
147
|
event.dispatcher.on(event.all.result, (result) => {
|
|
145
148
|
recorder.add(`service ${name} all.after`, async () => {
|
|
146
|
-
await service.afterSession(result)
|
|
147
|
-
})
|
|
148
|
-
})
|
|
149
|
+
await service.afterSession(result)
|
|
150
|
+
})
|
|
151
|
+
})
|
|
149
152
|
}
|
|
150
153
|
|
|
151
154
|
if (service.beforeSuite) {
|
|
152
155
|
event.dispatcher.on(event.suite.before, (suite) => {
|
|
153
|
-
debug(`suite started: ${suite.title}`)
|
|
154
|
-
recorder.add(`service ${name} suite.before`, () => service.beforeSuite(suite))
|
|
155
|
-
})
|
|
156
|
+
debug(`suite started: ${suite.title}`)
|
|
157
|
+
recorder.add(`service ${name} suite.before`, () => service.beforeSuite(suite))
|
|
158
|
+
})
|
|
156
159
|
}
|
|
157
160
|
|
|
158
161
|
if (service.afterSuite) {
|
|
159
162
|
event.dispatcher.on(event.suite.after, (suite) => {
|
|
160
|
-
debug(`suite finished: ${suite.title}`)
|
|
161
|
-
recorder.add(`service ${name} suite.after`, () => service.afterSuite(suite))
|
|
162
|
-
})
|
|
163
|
+
debug(`suite finished: ${suite.title}`)
|
|
164
|
+
recorder.add(`service ${name} suite.after`, () => service.afterSuite(suite))
|
|
165
|
+
})
|
|
163
166
|
}
|
|
164
167
|
|
|
165
168
|
if (service.beforeTest) {
|
|
166
169
|
event.dispatcher.on(event.test.started, async (test) => {
|
|
167
170
|
if (test.parent) {
|
|
168
|
-
test.parent.toString = () => test.parent.title
|
|
171
|
+
test.parent.toString = () => test.parent.title
|
|
169
172
|
}
|
|
170
173
|
// test.parent = test.parent ? test.parent.title : null;
|
|
171
|
-
debug(`test started: ${test.title}`)
|
|
174
|
+
debug(`test started: ${test.title}`)
|
|
172
175
|
if (webDriver) {
|
|
173
|
-
global.browser = webDriver.browser
|
|
174
|
-
global.browser.config = Object.assign(mainConfig.get('test', 1), global.browser.config)
|
|
176
|
+
global.browser = webDriver.browser
|
|
177
|
+
global.browser.config = Object.assign(mainConfig.get('test', 1), global.browser.config)
|
|
175
178
|
}
|
|
176
|
-
await service.beforeTest(test)
|
|
177
|
-
})
|
|
179
|
+
await service.beforeTest(test)
|
|
180
|
+
})
|
|
178
181
|
}
|
|
179
182
|
|
|
180
183
|
if (service.afterTest) {
|
|
181
184
|
event.dispatcher.on(event.test.finished, async (test) => {
|
|
182
|
-
debug(`test finished: ${test.title}`)
|
|
183
|
-
await service.afterTest(test)
|
|
184
|
-
})
|
|
185
|
+
debug(`test finished: ${test.title}`)
|
|
186
|
+
await service.afterTest(test)
|
|
187
|
+
})
|
|
185
188
|
}
|
|
186
189
|
|
|
187
190
|
if (restartsSession && service.before) {
|
|
188
|
-
event.dispatcher.on(event.test.started, () => service.before())
|
|
191
|
+
event.dispatcher.on(event.test.started, () => service.before())
|
|
189
192
|
}
|
|
190
193
|
|
|
191
194
|
if (restartsSession && service.after) {
|
|
192
|
-
event.dispatcher.on(event.test.finished, () => service.after())
|
|
195
|
+
event.dispatcher.on(event.test.finished, () => service.after())
|
|
193
196
|
}
|
|
194
197
|
|
|
195
198
|
if (!restartsSession && service.before) {
|
|
196
|
-
let initializedBrowser = false
|
|
199
|
+
let initializedBrowser = false
|
|
197
200
|
event.dispatcher.on(event.test.started, async () => {
|
|
198
201
|
if (!initializedBrowser) {
|
|
199
|
-
await service.before()
|
|
200
|
-
initializedBrowser = true
|
|
202
|
+
await service.before()
|
|
203
|
+
initializedBrowser = true
|
|
201
204
|
}
|
|
202
|
-
})
|
|
205
|
+
})
|
|
203
206
|
}
|
|
204
207
|
|
|
205
208
|
if (!restartsSession && service.after) {
|
|
206
|
-
event.dispatcher.on(event.all.result, result => service.after(result))
|
|
209
|
+
event.dispatcher.on(event.all.result, (result) => service.after(result))
|
|
207
210
|
}
|
|
208
211
|
}
|
|
209
212
|
|
|
210
213
|
function registerLauncher(launcher) {
|
|
211
|
-
const name = launcher.constructor.name
|
|
214
|
+
const name = launcher.constructor.name
|
|
212
215
|
if (launcher.onPrepare) {
|
|
213
216
|
event.dispatcher.on(event.all.before, () => {
|
|
214
217
|
recorder.add(`launcher ${name} start`, async () => {
|
|
215
218
|
// browserstack-service expects capabilities as array
|
|
216
219
|
if (launcher.constructor.name === 'BrowserstackLauncherService') {
|
|
217
|
-
await launcher.onPrepare(config, [config.capabilities])
|
|
220
|
+
await launcher.onPrepare(config, [config.capabilities])
|
|
218
221
|
} else {
|
|
219
|
-
await launcher.onPrepare(config, config.capabilities)
|
|
222
|
+
await launcher.onPrepare(config, config.capabilities)
|
|
220
223
|
}
|
|
221
|
-
output.debug(`Started ${name}`)
|
|
222
|
-
})
|
|
223
|
-
})
|
|
224
|
+
output.debug(`Started ${name}`)
|
|
225
|
+
})
|
|
226
|
+
})
|
|
224
227
|
}
|
|
225
228
|
|
|
226
229
|
if (launcher.onComplete) {
|
|
227
230
|
event.dispatcher.on(event.all.after, () => {
|
|
228
231
|
recorder.add(`launcher ${name} start`, async () => {
|
|
229
|
-
await launcher.onComplete(process.exitCode, config, config.capabilities)
|
|
230
|
-
output.debug(`Stopped ${name}`)
|
|
231
|
-
})
|
|
232
|
-
})
|
|
232
|
+
await launcher.onComplete(process.exitCode, config, config.capabilities)
|
|
233
|
+
output.debug(`Stopped ${name}`)
|
|
234
|
+
})
|
|
235
|
+
})
|
|
233
236
|
}
|
|
234
237
|
}
|
|
235
|
-
}
|
|
238
|
+
}
|
|
236
239
|
|
|
237
240
|
function safeRequire(name) {
|
|
238
241
|
try {
|
|
239
|
-
return require(name)
|
|
242
|
+
return require(name)
|
|
240
243
|
} catch (e) {
|
|
241
244
|
if (!e.message.match(`Cannot find module '${name}'`)) {
|
|
242
|
-
throw new Error(`Couldn't initialise "${name}".\n${e.stack}`)
|
|
245
|
+
throw new Error(`Couldn't initialise "${name}".\n${e.stack}`)
|
|
243
246
|
}
|
|
244
|
-
return null
|
|
247
|
+
return null
|
|
245
248
|
}
|
|
246
249
|
}
|
package/lib/recorder.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
const debug = require('debug')('codeceptjs:recorder');
|
|
2
|
+
const promiseRetry = require('promise-retry');
|
|
3
|
+
const chalk = require('chalk');
|
|
4
|
+
const { printObjectProperties } = require('./utils');
|
|
5
|
+
const { log } = require('./output');
|
|
6
6
|
|
|
7
|
-
debug('codeceptjs:recorder');
|
|
8
7
|
const MAX_TASKS = 100;
|
|
9
8
|
|
|
10
9
|
let promise;
|
|
@@ -29,7 +28,7 @@ const defaultRetryOptions = {
|
|
|
29
28
|
* @alias recorder
|
|
30
29
|
* @interface
|
|
31
30
|
*/
|
|
32
|
-
|
|
31
|
+
module.exports = {
|
|
33
32
|
|
|
34
33
|
/**
|
|
35
34
|
* @type {Array<Object<string, *>>}
|
|
@@ -48,7 +47,6 @@ export default {
|
|
|
48
47
|
running = true;
|
|
49
48
|
asyncErr = null;
|
|
50
49
|
errFn = null;
|
|
51
|
-
// @ts-ignore
|
|
52
50
|
this.reset();
|
|
53
51
|
},
|
|
54
52
|
|
|
@@ -93,7 +91,7 @@ export default {
|
|
|
93
91
|
queueId++;
|
|
94
92
|
sessionId = null;
|
|
95
93
|
asyncErr = null;
|
|
96
|
-
|
|
94
|
+
log(`${currentQueue()} Starting recording promises`);
|
|
97
95
|
promise = Promise.resolve();
|
|
98
96
|
oldPromises = [];
|
|
99
97
|
tasks = [];
|
|
@@ -165,10 +163,10 @@ export default {
|
|
|
165
163
|
* @param {boolean} [force=false]
|
|
166
164
|
* @param {boolean} [retry]
|
|
167
165
|
* undefined: `add(fn)` -> `false` and `add('step',fn)` -> `true`
|
|
168
|
-
* true: it will
|
|
166
|
+
* true: it will retries if `retryOpts` set.
|
|
169
167
|
* false: ignore `retryOpts` and won't retry.
|
|
170
168
|
* @param {number} [timeout]
|
|
171
|
-
* @return {Promise
|
|
169
|
+
* @return {Promise<*>}
|
|
172
170
|
* @inner
|
|
173
171
|
*/
|
|
174
172
|
add(taskName, fn = undefined, force = false, retry = undefined, timeout = undefined) {
|
|
@@ -197,7 +195,7 @@ export default {
|
|
|
197
195
|
|
|
198
196
|
const retryRules = this.retries.slice().reverse();
|
|
199
197
|
return promiseRetry(Object.assign(defaultRetryOptions, retryOpts), (retry, number) => {
|
|
200
|
-
if (number > 1)
|
|
198
|
+
if (number > 1) log(`${currentQueue()}Retrying... Attempt #${number}`);
|
|
201
199
|
const [promise, timer] = getTimeoutPromise(timeout, taskName);
|
|
202
200
|
return Promise.race([promise, Promise.resolve(res).then(fn)]).finally(() => clearTimeout(timer)).catch((err) => {
|
|
203
201
|
if (ignoredErrs.includes(err)) return;
|
|
@@ -237,7 +235,7 @@ export default {
|
|
|
237
235
|
const fnDescription = customErrFn?.toString()?.replace(/\s{2,}/g, ' ').replace(/\n/g, ' ')?.slice(0, 50);
|
|
238
236
|
debug(chalk.gray(`${currentQueue()} Queued | catch with error handler ${fnDescription || ''}`));
|
|
239
237
|
return promise = promise.catch((err) => {
|
|
240
|
-
|
|
238
|
+
log(`${currentQueue()}Error | ${err} ${fnDescription}...`);
|
|
241
239
|
if (!(err instanceof Error)) { // strange things may happen
|
|
242
240
|
err = new Error(`[Wrapped Error] ${printObjectProperties(err)}`); // we should be prepared for them
|
|
243
241
|
}
|
|
@@ -259,7 +257,7 @@ export default {
|
|
|
259
257
|
const fnDescription = customErrFn?.toString()?.replace(/\s{2,}/g, ' ').replace(/\n/g, ' ')?.slice(0, 50);
|
|
260
258
|
return promise = promise.catch((err) => {
|
|
261
259
|
if (ignoredErrs.includes(err)) return; // already caught
|
|
262
|
-
|
|
260
|
+
log(`${currentQueue()} Error (Non-Terminated) | ${err} | ${fnDescription || ''}...`);
|
|
263
261
|
if (!(err instanceof Error)) { // strange things may happen
|
|
264
262
|
err = new Error(`[Wrapped Error] ${JSON.stringify(err)}`); // we should be prepared for them
|
|
265
263
|
}
|
|
@@ -321,10 +319,8 @@ export default {
|
|
|
321
319
|
* @inner
|
|
322
320
|
*/
|
|
323
321
|
stop() {
|
|
324
|
-
if (process.env.DEBUG) debug(this.toString());
|
|
325
|
-
output.output.log(`${currentQueue()}Stopping recording promises`);
|
|
326
322
|
debug(this.toString());
|
|
327
|
-
|
|
323
|
+
log(`${currentQueue()} Stopping recording promises`);
|
|
328
324
|
running = false;
|
|
329
325
|
},
|
|
330
326
|
|
|
@@ -365,6 +361,7 @@ export default {
|
|
|
365
361
|
toString() {
|
|
366
362
|
return `Queue: ${currentQueue()}\n\nTasks: ${this.scheduled()}`;
|
|
367
363
|
},
|
|
364
|
+
|
|
368
365
|
};
|
|
369
366
|
|
|
370
367
|
function getTimeoutPromise(timeoutMs, taskName) {
|
package/lib/rerun.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
const fsPath = require('path');
|
|
2
|
+
const container = require('./container');
|
|
3
|
+
const event = require('./event');
|
|
4
|
+
const BaseCodecept = require('./codecept');
|
|
5
|
+
const output = require('./output');
|
|
6
6
|
|
|
7
7
|
class CodeceptRerunner extends BaseCodecept {
|
|
8
8
|
runOnce(test) {
|
|
@@ -11,7 +11,7 @@ class CodeceptRerunner extends BaseCodecept {
|
|
|
11
11
|
container.createMocha();
|
|
12
12
|
const mocha = container.mocha();
|
|
13
13
|
this.testFiles.forEach((file) => {
|
|
14
|
-
|
|
14
|
+
delete require.cache[file];
|
|
15
15
|
});
|
|
16
16
|
mocha.files = this.testFiles;
|
|
17
17
|
if (test) {
|
|
@@ -53,9 +53,9 @@ class CodeceptRerunner extends BaseCodecept {
|
|
|
53
53
|
try {
|
|
54
54
|
await this.runOnce(test);
|
|
55
55
|
successCounter++;
|
|
56
|
-
output.
|
|
56
|
+
output.success(`\nProcess run ${rerunsCounter} of max ${maxReruns}, success runs ${successCounter}/${minSuccess}\n`);
|
|
57
57
|
} catch (e) {
|
|
58
|
-
output.
|
|
58
|
+
output.error(`\nFail run ${rerunsCounter} of max ${maxReruns}, success runs ${successCounter}/${minSuccess} \n`);
|
|
59
59
|
console.error(e);
|
|
60
60
|
}
|
|
61
61
|
}
|
|
@@ -69,7 +69,8 @@ class CodeceptRerunner extends BaseCodecept {
|
|
|
69
69
|
try {
|
|
70
70
|
await this.runTests(test);
|
|
71
71
|
} catch (e) {
|
|
72
|
-
output.
|
|
72
|
+
output.error(e.stack);
|
|
73
|
+
throw e;
|
|
73
74
|
} finally {
|
|
74
75
|
event.emit(event.all.result, this);
|
|
75
76
|
event.emit(event.all.after, this);
|
|
@@ -77,4 +78,4 @@ class CodeceptRerunner extends BaseCodecept {
|
|
|
77
78
|
}
|
|
78
79
|
}
|
|
79
80
|
|
|
80
|
-
|
|
81
|
+
module.exports = CodeceptRerunner;
|
package/lib/scenario.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import Container from './container.js';
|
|
1
|
+
const promiseRetry = require('promise-retry');
|
|
2
|
+
const event = require('./event');
|
|
3
|
+
const recorder = require('./recorder');
|
|
4
|
+
const assertThrown = require('./assert/throws');
|
|
5
|
+
const { ucfirst, isAsyncFunction } = require('./utils');
|
|
6
|
+
const parser = require('./parser');
|
|
8
7
|
|
|
9
8
|
const injectHook = function (inject, suite) {
|
|
10
9
|
try {
|
|
@@ -34,7 +33,7 @@ function makeDoneCallableOnce(done) {
|
|
|
34
33
|
* starts promise chain with recorder, performs before/after hooks
|
|
35
34
|
* through event system.
|
|
36
35
|
*/
|
|
37
|
-
|
|
36
|
+
module.exports.test = (test) => {
|
|
38
37
|
const testFn = test.fn;
|
|
39
38
|
if (!testFn) {
|
|
40
39
|
return test;
|
|
@@ -101,12 +100,12 @@ export function test(test) {
|
|
|
101
100
|
}
|
|
102
101
|
};
|
|
103
102
|
return test;
|
|
104
|
-
}
|
|
103
|
+
};
|
|
105
104
|
|
|
106
105
|
/**
|
|
107
106
|
* Injects arguments to function from controller
|
|
108
107
|
*/
|
|
109
|
-
|
|
108
|
+
module.exports.injected = function (fn, suite, hookName) {
|
|
110
109
|
return function (done) {
|
|
111
110
|
const doneFn = makeDoneCallableOnce(done);
|
|
112
111
|
const errHandler = (err) => {
|
|
@@ -168,43 +167,44 @@ export function injected(fn, suite, hookName) {
|
|
|
168
167
|
recorder.add('fire hook.failed', () => event.emit(event.hook.failed, suite, e));
|
|
169
168
|
});
|
|
170
169
|
};
|
|
171
|
-
}
|
|
170
|
+
};
|
|
172
171
|
|
|
173
172
|
/**
|
|
174
173
|
* Starts promise chain, so helpers could enqueue their hooks
|
|
175
174
|
*/
|
|
176
|
-
|
|
175
|
+
module.exports.setup = function (suite) {
|
|
177
176
|
return injectHook(() => {
|
|
178
177
|
recorder.startUnlessRunning();
|
|
179
178
|
event.emit(event.test.before, suite && suite.ctx && suite.ctx.currentTest);
|
|
180
179
|
}, suite);
|
|
181
|
-
}
|
|
180
|
+
};
|
|
182
181
|
|
|
183
|
-
|
|
182
|
+
module.exports.teardown = function (suite) {
|
|
184
183
|
return injectHook(() => {
|
|
185
184
|
recorder.startUnlessRunning();
|
|
186
185
|
event.emit(event.test.after, suite && suite.ctx && suite.ctx.currentTest);
|
|
187
186
|
}, suite);
|
|
188
|
-
}
|
|
187
|
+
};
|
|
189
188
|
|
|
190
|
-
|
|
189
|
+
module.exports.suiteSetup = function (suite) {
|
|
191
190
|
return injectHook(() => {
|
|
192
191
|
recorder.startUnlessRunning();
|
|
193
192
|
event.emit(event.suite.before, suite);
|
|
194
193
|
}, suite);
|
|
195
|
-
}
|
|
194
|
+
};
|
|
196
195
|
|
|
197
|
-
|
|
196
|
+
module.exports.suiteTeardown = function (suite) {
|
|
198
197
|
return injectHook(() => {
|
|
199
198
|
recorder.startUnlessRunning();
|
|
200
199
|
event.emit(event.suite.after, suite);
|
|
201
200
|
}, suite);
|
|
202
|
-
}
|
|
201
|
+
};
|
|
203
202
|
|
|
204
|
-
|
|
203
|
+
const getInjectedArguments = (fn, test) => {
|
|
204
|
+
const container = require('./container');
|
|
205
205
|
const testArgs = {};
|
|
206
206
|
const params = parser.getParams(fn) || [];
|
|
207
|
-
const objects =
|
|
207
|
+
const objects = container.support();
|
|
208
208
|
for (const key of params) {
|
|
209
209
|
testArgs[key] = {};
|
|
210
210
|
if (test && test.inject && test.inject[key]) {
|
|
@@ -215,8 +215,10 @@ export function getInjectedArguments(fn, test) {
|
|
|
215
215
|
if (!objects[key]) {
|
|
216
216
|
throw new Error(`Object of type ${key} is not defined in container`);
|
|
217
217
|
}
|
|
218
|
-
testArgs[key] =
|
|
218
|
+
testArgs[key] = container.support(key);
|
|
219
219
|
}
|
|
220
220
|
|
|
221
221
|
return testArgs;
|
|
222
|
-
}
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
module.exports.getInjectedArguments = getInjectedArguments;
|
package/lib/secret.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
import { deepClone } from './utils.js';
|
|
1
|
+
const { deepClone } = require('./utils');
|
|
3
2
|
|
|
4
3
|
const maskedString = '*****';
|
|
5
4
|
|
|
6
5
|
/** @param {string} secret */
|
|
7
|
-
|
|
6
|
+
class Secret {
|
|
8
7
|
constructor(secret) {
|
|
9
8
|
this._secret = secret;
|
|
10
9
|
}
|
|
@@ -48,3 +47,5 @@ function secretObject(obj, fieldsToHide = []) {
|
|
|
48
47
|
|
|
49
48
|
return new Proxy(obj, handler);
|
|
50
49
|
}
|
|
50
|
+
|
|
51
|
+
module.exports = Secret;
|
package/lib/session.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
const recorder = require('./recorder');
|
|
2
|
+
const container = require('./container');
|
|
3
|
+
const event = require('./event');
|
|
4
|
+
const output = require('./output');
|
|
5
|
+
const store = require('./store');
|
|
6
|
+
const { isAsyncFunction } = require('./utils');
|
|
7
7
|
|
|
8
8
|
const sessionColors = [
|
|
9
9
|
'cyan',
|
|
@@ -90,7 +90,7 @@ function session(sessionName, config, fn) {
|
|
|
90
90
|
|
|
91
91
|
const finalize = () => {
|
|
92
92
|
recorder.add('Finalize session', async () => {
|
|
93
|
-
output.
|
|
93
|
+
output.stepShift = 0;
|
|
94
94
|
event.dispatcher.removeListener(event.step.after, addContextToStep);
|
|
95
95
|
await session.restoreVars();
|
|
96
96
|
recorder.session.restore(`session:${sessionName}`);
|
|
@@ -103,7 +103,7 @@ function session(sessionName, config, fn) {
|
|
|
103
103
|
finalize();
|
|
104
104
|
return recorder.promise().then(() => res);
|
|
105
105
|
}).catch((e) => {
|
|
106
|
-
output.
|
|
106
|
+
output.stepShift = 0;
|
|
107
107
|
session.restoreVars(sessionName);
|
|
108
108
|
event.dispatcher.removeListener(event.step.after, addContextToStep);
|
|
109
109
|
recorder.throw(e);
|
|
@@ -119,7 +119,7 @@ function session(sessionName, config, fn) {
|
|
|
119
119
|
} finally {
|
|
120
120
|
recorder.catch((e) => {
|
|
121
121
|
session.restoreVars(sessionName);
|
|
122
|
-
output.
|
|
122
|
+
output.stepShift = 0;
|
|
123
123
|
event.dispatcher.removeListener(event.step.after, addContextToStep);
|
|
124
124
|
throw e;
|
|
125
125
|
});
|
|
@@ -129,4 +129,4 @@ function session(sessionName, config, fn) {
|
|
|
129
129
|
}, false, false);
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
-
|
|
132
|
+
module.exports = session;
|
package/lib/step.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
// TODO: place MetaStep in other file, disable rule
|
|
2
|
-
/* eslint-disable max-classes-per-file */
|
|
3
|
-
import { store } from './store.js';
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
const store = require('./store');
|
|
4
|
+
const Secret = require('./secret');
|
|
5
|
+
const event = require('./event');
|
|
7
6
|
|
|
8
7
|
const STACK_LINE = 4;
|
|
9
8
|
|
|
@@ -13,7 +12,7 @@ const STACK_LINE = 4;
|
|
|
13
12
|
* @param {CodeceptJS.Helper} helper
|
|
14
13
|
* @param {string} name
|
|
15
14
|
*/
|
|
16
|
-
|
|
15
|
+
class Step {
|
|
17
16
|
static get TIMEOUT_ORDER() {
|
|
18
17
|
return {
|
|
19
18
|
/**
|
|
@@ -72,11 +71,13 @@ export class Step {
|
|
|
72
71
|
new Map([...timeouts.entries()].sort().reverse()).forEach((timeout, order) => {
|
|
73
72
|
if (timeout !== undefined && (
|
|
74
73
|
// when orders >= 0 - timeout value overrides those set with higher order elements
|
|
75
|
-
|
|
76
|
-
(order >= 0
|
|
74
|
+
order >= 0
|
|
77
75
|
|
|
78
76
|
// when `order < 0 && totalTimeout === undefined` - timeout is used when nothing is set by elements with higher order
|
|
79
|
-
|| totalTimeout === undefined
|
|
77
|
+
|| totalTimeout === undefined
|
|
78
|
+
|
|
79
|
+
// when `order < 0` - timeout overrides higher values of timeout or 'no timeout' (totalTimeout === 0) set by elements with higher order
|
|
80
|
+
|| timeout > 0 && (timeout < totalTimeout || totalTimeout === 0)
|
|
80
81
|
)) {
|
|
81
82
|
totalTimeout = timeout;
|
|
82
83
|
}
|
|
@@ -220,7 +221,7 @@ export class Step {
|
|
|
220
221
|
}
|
|
221
222
|
|
|
222
223
|
/** @extends Step */
|
|
223
|
-
|
|
224
|
+
class MetaStep extends Step {
|
|
224
225
|
constructor(obj, method) {
|
|
225
226
|
super(null, method);
|
|
226
227
|
this.actor = obj;
|
|
@@ -310,6 +311,8 @@ Step.TIMEOUTS = {};
|
|
|
310
311
|
/** @type {Class<MetaStep>} */
|
|
311
312
|
Step.MetaStep = MetaStep;
|
|
312
313
|
|
|
314
|
+
module.exports = Step;
|
|
315
|
+
|
|
313
316
|
function dryRunResolver() {
|
|
314
317
|
return {
|
|
315
318
|
get(target, prop) {
|
package/lib/store.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* global values for current session
|
|
3
3
|
* @namespace
|
|
4
4
|
*/
|
|
5
|
-
|
|
5
|
+
const store = {
|
|
6
6
|
/** @type {boolean} */
|
|
7
7
|
debugMode: false,
|
|
8
8
|
/** @type {boolean} */
|
|
@@ -11,5 +11,4 @@ export const store = {
|
|
|
11
11
|
dryRun: false,
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
export const timeouts = true;
|
|
14
|
+
module.exports = store;
|
package/lib/transform.js
CHANGED