codeceptjs 4.0.0-beta.2 → 4.0.0-beta.20
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 +133 -120
- package/bin/codecept.js +107 -96
- package/bin/test-server.js +64 -0
- package/docs/webapi/clearCookie.mustache +1 -1
- package/docs/webapi/click.mustache +5 -1
- package/lib/actor.js +71 -103
- package/lib/ai.js +159 -188
- package/lib/assert/empty.js +22 -24
- package/lib/assert/equal.js +30 -37
- package/lib/assert/error.js +14 -14
- package/lib/assert/include.js +43 -48
- package/lib/assert/throws.js +11 -11
- package/lib/assert/truth.js +22 -22
- package/lib/assert.js +20 -18
- package/lib/codecept.js +262 -162
- package/lib/colorUtils.js +50 -52
- package/lib/command/check.js +206 -0
- package/lib/command/configMigrate.js +56 -51
- package/lib/command/definitions.js +96 -109
- package/lib/command/dryRun.js +77 -79
- package/lib/command/generate.js +234 -194
- package/lib/command/gherkin/init.js +42 -33
- package/lib/command/gherkin/snippets.js +76 -74
- package/lib/command/gherkin/steps.js +20 -17
- package/lib/command/info.js +74 -38
- package/lib/command/init.js +301 -290
- package/lib/command/interactive.js +41 -32
- package/lib/command/list.js +28 -27
- package/lib/command/run-multiple/chunk.js +51 -48
- package/lib/command/run-multiple/collection.js +5 -5
- package/lib/command/run-multiple/run.js +5 -1
- package/lib/command/run-multiple.js +97 -97
- package/lib/command/run-rerun.js +19 -25
- package/lib/command/run-workers.js +68 -92
- package/lib/command/run.js +39 -27
- package/lib/command/utils.js +80 -64
- package/lib/command/workers/runTests.js +388 -226
- package/lib/config.js +109 -50
- package/lib/container.js +641 -261
- package/lib/data/context.js +60 -61
- package/lib/data/dataScenarioConfig.js +47 -47
- package/lib/data/dataTableArgument.js +32 -32
- package/lib/data/table.js +22 -22
- package/lib/effects.js +307 -0
- package/lib/element/WebElement.js +327 -0
- package/lib/els.js +160 -0
- package/lib/event.js +173 -163
- package/lib/globals.js +141 -0
- package/lib/heal.js +89 -85
- package/lib/helper/AI.js +131 -41
- package/lib/helper/ApiDataFactory.js +107 -75
- package/lib/helper/Appium.js +542 -404
- package/lib/helper/FileSystem.js +100 -79
- package/lib/helper/GraphQL.js +44 -43
- package/lib/helper/GraphQLDataFactory.js +52 -52
- package/lib/helper/JSONResponse.js +126 -88
- package/lib/helper/Mochawesome.js +54 -29
- package/lib/helper/Playwright.js +2547 -1316
- package/lib/helper/Puppeteer.js +1578 -1181
- package/lib/helper/REST.js +209 -68
- package/lib/helper/WebDriver.js +1482 -1342
- package/lib/helper/errors/ConnectionRefused.js +6 -6
- package/lib/helper/errors/ElementAssertion.js +11 -16
- package/lib/helper/errors/ElementNotFound.js +5 -9
- package/lib/helper/errors/RemoteBrowserConnectionRefused.js +5 -5
- package/lib/helper/extras/Console.js +11 -11
- package/lib/helper/extras/PlaywrightLocator.js +110 -0
- package/lib/helper/extras/PlaywrightPropEngine.js +18 -18
- package/lib/helper/extras/PlaywrightReactVueLocator.js +17 -8
- package/lib/helper/extras/PlaywrightRestartOpts.js +25 -11
- package/lib/helper/extras/Popup.js +22 -22
- package/lib/helper/extras/React.js +27 -28
- package/lib/helper/network/actions.js +36 -42
- package/lib/helper/network/utils.js +78 -84
- package/lib/helper/scripts/blurElement.js +5 -5
- package/lib/helper/scripts/focusElement.js +5 -5
- package/lib/helper/scripts/highlightElement.js +8 -8
- package/lib/helper/scripts/isElementClickable.js +34 -34
- package/lib/helper.js +2 -3
- package/lib/history.js +23 -19
- package/lib/hooks.js +8 -8
- package/lib/html.js +94 -104
- package/lib/index.js +38 -27
- package/lib/listener/config.js +30 -23
- package/lib/listener/emptyRun.js +54 -0
- package/lib/listener/enhancedGlobalRetry.js +110 -0
- package/lib/listener/exit.js +16 -18
- package/lib/listener/globalRetry.js +70 -0
- package/lib/listener/globalTimeout.js +181 -0
- package/lib/listener/helpers.js +76 -51
- package/lib/listener/mocha.js +10 -11
- package/lib/listener/result.js +11 -0
- package/lib/listener/retryEnhancer.js +85 -0
- package/lib/listener/steps.js +71 -59
- package/lib/listener/store.js +20 -0
- package/lib/locator.js +214 -197
- package/lib/mocha/asyncWrapper.js +274 -0
- package/lib/mocha/bdd.js +167 -0
- package/lib/mocha/cli.js +341 -0
- package/lib/mocha/factory.js +163 -0
- package/lib/mocha/featureConfig.js +89 -0
- package/lib/mocha/gherkin.js +231 -0
- package/lib/mocha/hooks.js +121 -0
- package/lib/mocha/index.js +21 -0
- package/lib/mocha/inject.js +46 -0
- package/lib/{interfaces → mocha}/scenarioConfig.js +58 -34
- package/lib/mocha/suite.js +89 -0
- package/lib/mocha/test.js +184 -0
- package/lib/mocha/types.d.ts +42 -0
- package/lib/mocha/ui.js +242 -0
- package/lib/output.js +141 -71
- package/lib/parser.js +47 -44
- package/lib/pause.js +173 -145
- package/lib/plugin/analyze.js +403 -0
- package/lib/plugin/{autoLogin.js → auth.js} +178 -79
- package/lib/plugin/autoDelay.js +36 -40
- package/lib/plugin/coverage.js +131 -78
- package/lib/plugin/customLocator.js +22 -21
- package/lib/plugin/customReporter.js +53 -0
- package/lib/plugin/enhancedRetryFailedStep.js +99 -0
- package/lib/plugin/heal.js +101 -110
- package/lib/plugin/htmlReporter.js +3648 -0
- package/lib/plugin/pageInfo.js +140 -0
- package/lib/plugin/pauseOnFail.js +12 -11
- package/lib/plugin/retryFailedStep.js +82 -47
- package/lib/plugin/screenshotOnFail.js +111 -92
- package/lib/plugin/stepByStepReport.js +159 -101
- package/lib/plugin/stepTimeout.js +20 -25
- package/lib/plugin/subtitles.js +38 -38
- package/lib/recorder.js +193 -130
- package/lib/rerun.js +94 -49
- package/lib/result.js +238 -0
- package/lib/retryCoordinator.js +207 -0
- package/lib/secret.js +20 -18
- package/lib/session.js +95 -89
- package/lib/step/base.js +239 -0
- package/lib/step/comment.js +10 -0
- package/lib/step/config.js +50 -0
- package/lib/step/func.js +46 -0
- package/lib/step/helper.js +50 -0
- package/lib/step/meta.js +99 -0
- package/lib/step/record.js +74 -0
- package/lib/step/retry.js +11 -0
- package/lib/step/section.js +55 -0
- package/lib/step.js +18 -329
- package/lib/steps.js +54 -0
- package/lib/store.js +38 -7
- package/lib/template/heal.js +3 -12
- package/lib/template/prompts/generatePageObject.js +31 -0
- package/lib/template/prompts/healStep.js +13 -0
- package/lib/template/prompts/writeStep.js +9 -0
- package/lib/test-server.js +334 -0
- package/lib/timeout.js +60 -0
- package/lib/transform.js +8 -8
- package/lib/translation.js +34 -21
- package/lib/utils/loaderCheck.js +124 -0
- package/lib/utils/mask_data.js +47 -0
- package/lib/utils/typescript.js +237 -0
- package/lib/utils.js +411 -228
- package/lib/workerStorage.js +37 -34
- package/lib/workers.js +532 -296
- package/package.json +124 -95
- package/translations/de-DE.js +5 -3
- package/translations/fr-FR.js +5 -4
- package/translations/index.js +22 -12
- package/translations/it-IT.js +4 -3
- package/translations/ja-JP.js +4 -3
- package/translations/nl-NL.js +76 -0
- package/translations/pl-PL.js +4 -3
- package/translations/pt-BR.js +4 -3
- package/translations/ru-RU.js +4 -3
- package/translations/utils.js +10 -0
- package/translations/zh-CN.js +4 -3
- package/translations/zh-TW.js +4 -3
- package/typings/index.d.ts +546 -185
- package/typings/promiseBasedTypes.d.ts +150 -875
- package/typings/types.d.ts +547 -992
- package/lib/cli.js +0 -249
- package/lib/dirname.js +0 -5
- package/lib/helper/Expect.js +0 -425
- package/lib/helper/ExpectHelper.js +0 -399
- package/lib/helper/MockServer.js +0 -223
- package/lib/helper/Nightmare.js +0 -1411
- package/lib/helper/Protractor.js +0 -1835
- package/lib/helper/SoftExpectHelper.js +0 -381
- package/lib/helper/TestCafe.js +0 -1410
- package/lib/helper/clientscripts/nightmare.js +0 -213
- package/lib/helper/testcafe/testControllerHolder.js +0 -42
- package/lib/helper/testcafe/testcafe-utils.js +0 -63
- package/lib/interfaces/bdd.js +0 -98
- package/lib/interfaces/featureConfig.js +0 -69
- package/lib/interfaces/gherkin.js +0 -195
- package/lib/listener/artifacts.js +0 -19
- package/lib/listener/retry.js +0 -68
- package/lib/listener/timeout.js +0 -109
- package/lib/mochaFactory.js +0 -110
- package/lib/plugin/allure.js +0 -15
- package/lib/plugin/commentStep.js +0 -136
- package/lib/plugin/debugErrors.js +0 -67
- package/lib/plugin/eachElement.js +0 -127
- package/lib/plugin/fakerTransform.js +0 -49
- package/lib/plugin/retryTo.js +0 -121
- package/lib/plugin/selenoid.js +0 -371
- package/lib/plugin/standardActingHelpers.js +0 -9
- package/lib/plugin/tryTo.js +0 -105
- package/lib/plugin/wdio.js +0 -246
- package/lib/scenario.js +0 -222
- package/lib/ui.js +0 -238
- package/lib/within.js +0 -70
package/lib/command/run-rerun.js
CHANGED
|
@@ -1,39 +1,33 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import Config from '../config.js';
|
|
5
|
-
import Codecept from '../rerun.js';
|
|
1
|
+
import { getConfig, getTestRoot, printError, createOutputDir } from './utils.js'
|
|
2
|
+
import Config from '../config.js'
|
|
3
|
+
import Codecept from '../rerun.js'
|
|
6
4
|
|
|
7
|
-
export async function
|
|
5
|
+
export default async function (test, options) {
|
|
8
6
|
// registering options globally to use in config
|
|
9
7
|
// Backward compatibility for --profile
|
|
10
|
-
process.profile = options.profile
|
|
11
|
-
process.env.profile = options.profile
|
|
12
|
-
const configFile = options.config
|
|
8
|
+
process.profile = options.profile
|
|
9
|
+
process.env.profile = options.profile
|
|
10
|
+
const configFile = options.config
|
|
13
11
|
|
|
14
|
-
let config = getConfig(configFile)
|
|
12
|
+
let config = await getConfig(configFile)
|
|
15
13
|
if (options.override) {
|
|
16
|
-
config = Config.append(JSON.parse(options.override))
|
|
14
|
+
config = Config.append(JSON.parse(options.override))
|
|
17
15
|
}
|
|
18
|
-
const testRoot = getTestRoot(configFile)
|
|
19
|
-
createOutputDir(config, testRoot)
|
|
16
|
+
const testRoot = getTestRoot(configFile)
|
|
17
|
+
createOutputDir(config, testRoot)
|
|
20
18
|
|
|
21
|
-
|
|
22
|
-
printError(err);
|
|
23
|
-
process.exit(1);
|
|
24
|
-
}
|
|
25
|
-
const codecept = new Codecept(config, options);
|
|
19
|
+
const codecept = new Codecept(config, options)
|
|
26
20
|
|
|
27
21
|
try {
|
|
28
|
-
codecept.init(testRoot)
|
|
22
|
+
await codecept.init(testRoot)
|
|
29
23
|
|
|
30
|
-
await codecept.bootstrap()
|
|
31
|
-
codecept.loadTests(test)
|
|
32
|
-
await codecept.run()
|
|
24
|
+
await codecept.bootstrap()
|
|
25
|
+
codecept.loadTests(test)
|
|
26
|
+
await codecept.run()
|
|
33
27
|
} catch (err) {
|
|
34
|
-
printError(err)
|
|
35
|
-
process.exitCode = 1
|
|
28
|
+
printError(err)
|
|
29
|
+
process.exitCode = 1
|
|
36
30
|
} finally {
|
|
37
|
-
await codecept.teardown()
|
|
31
|
+
await codecept.teardown()
|
|
38
32
|
}
|
|
39
33
|
}
|
|
@@ -1,117 +1,93 @@
|
|
|
1
1
|
// For Node version >=10.5.0, have to use experimental flag
|
|
2
|
-
import { tryOrDefault } from '../utils.js'
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
2
|
+
import { tryOrDefault } from '../utils.js'
|
|
3
|
+
import output from '../output.js'
|
|
4
|
+
import store from '../store.js'
|
|
5
|
+
import event from '../event.js'
|
|
6
|
+
import Workers from '../workers.js'
|
|
7
|
+
import Codecept from '../codecept.js'
|
|
8
|
+
import { getMachineInfo } from './info.js'
|
|
9
9
|
|
|
10
10
|
export default async function (workerCount, selectedRuns, options) {
|
|
11
|
-
process.env.profile = options.profile
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
11
|
+
process.env.profile = options.profile
|
|
12
|
+
|
|
13
|
+
const { config: testConfig, override = '' } = options
|
|
14
|
+
const overrideConfigs = tryOrDefault(() => JSON.parse(override), {})
|
|
15
|
+
|
|
16
|
+
// Determine test split strategy
|
|
17
|
+
let by = 'test' // default
|
|
18
|
+
if (options.by) {
|
|
19
|
+
// Explicit --by option takes precedence
|
|
20
|
+
by = options.by
|
|
21
|
+
} else if (options.suites) {
|
|
22
|
+
// Legacy --suites option
|
|
23
|
+
by = 'suite'
|
|
24
|
+
}
|
|
18
25
|
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
26
|
+
// Validate the by option
|
|
27
|
+
const validStrategies = ['test', 'suite', 'pool']
|
|
28
|
+
if (!validStrategies.includes(by)) {
|
|
29
|
+
throw new Error(`Invalid --by strategy: ${by}. Valid options are: ${validStrategies.join(', ')}`)
|
|
30
|
+
}
|
|
31
|
+
delete options.parent
|
|
23
32
|
const config = {
|
|
24
33
|
by,
|
|
25
34
|
testConfig,
|
|
26
35
|
options,
|
|
27
36
|
selectedRuns,
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const numberOfWorkers = parseInt(workerCount, 10);
|
|
31
|
-
|
|
32
|
-
const version = Codecept.version();
|
|
33
|
-
output.print(`CodeceptJS v${version} ${output.output.standWithUkraine()}`);
|
|
34
|
-
output.print(`Running tests in ${output.output.styles.bold(numberOfWorkers)} workers...`);
|
|
35
|
-
output.print();
|
|
36
|
-
|
|
37
|
-
const workers = new Workers(numberOfWorkers, config);
|
|
38
|
-
workers.overrideConfig(overrideConfigs);
|
|
39
|
-
|
|
40
|
-
workers.on(event.suite.before, (suite) => {
|
|
41
|
-
suiteArr.push(suite);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
workers.on(event.step.passed, (step) => {
|
|
45
|
-
stepArr.push(step);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
workers.on(event.step.failed, (step) => {
|
|
49
|
-
stepArr.push(step);
|
|
50
|
-
});
|
|
37
|
+
}
|
|
51
38
|
|
|
52
|
-
|
|
53
|
-
failedTestArr.push(test);
|
|
54
|
-
output.output.test.failed(test);
|
|
55
|
-
});
|
|
39
|
+
const numberOfWorkers = parseInt(workerCount, 10)
|
|
56
40
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
41
|
+
output.print(`CodeceptJS v${Codecept.version()} ${output.standWithUkraine()}`)
|
|
42
|
+
output.print(`Running tests in ${output.styles.bold(numberOfWorkers)} workers...`)
|
|
43
|
+
output.print()
|
|
44
|
+
store.hasWorkers = true
|
|
61
45
|
|
|
62
|
-
workers
|
|
63
|
-
|
|
64
|
-
output.output.test.skipped(test);
|
|
65
|
-
});
|
|
46
|
+
const workers = new Workers(numberOfWorkers, config)
|
|
47
|
+
workers.overrideConfig(overrideConfigs)
|
|
66
48
|
|
|
67
|
-
workers.on(event.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
stepArr.test.steps.forEach(step => {
|
|
71
|
-
if (test.steps.length === 0) {
|
|
72
|
-
test.steps.push(step);
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
}
|
|
49
|
+
workers.on(event.test.failed, test => {
|
|
50
|
+
output.test.failed(test)
|
|
51
|
+
})
|
|
76
52
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
addStepsToTest(test, step);
|
|
81
|
-
}
|
|
82
|
-
});
|
|
53
|
+
workers.on(event.test.passed, test => {
|
|
54
|
+
output.test.passed(test)
|
|
55
|
+
})
|
|
83
56
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
});
|
|
57
|
+
workers.on(event.test.skipped, test => {
|
|
58
|
+
output.test.skipped(test)
|
|
59
|
+
})
|
|
90
60
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
passed: passedTestArr,
|
|
95
|
-
failed: failedTestArr,
|
|
96
|
-
skipped: skippedTestArr,
|
|
97
|
-
},
|
|
98
|
-
});
|
|
99
|
-
workers.printResults();
|
|
100
|
-
});
|
|
61
|
+
workers.on(event.all.result, result => {
|
|
62
|
+
workers.printResults()
|
|
63
|
+
})
|
|
101
64
|
|
|
102
65
|
try {
|
|
103
|
-
if (options.verbose || options.debug) store.debugMode = true
|
|
66
|
+
if (options.verbose || options.debug) store.debugMode = true
|
|
104
67
|
|
|
105
68
|
if (options.verbose) {
|
|
106
|
-
|
|
107
|
-
await getMachineInfo();
|
|
69
|
+
await getMachineInfo()
|
|
108
70
|
}
|
|
109
|
-
await workers.bootstrapAll()
|
|
110
|
-
await workers.run()
|
|
71
|
+
await workers.bootstrapAll()
|
|
72
|
+
await workers.run()
|
|
111
73
|
} catch (err) {
|
|
112
|
-
output.
|
|
113
|
-
process.
|
|
74
|
+
output.error(err)
|
|
75
|
+
process.exitCode = 1
|
|
114
76
|
} finally {
|
|
115
|
-
await workers.teardownAll()
|
|
77
|
+
await workers.teardownAll()
|
|
78
|
+
|
|
79
|
+
// Force exit if event loop doesn't clear naturally
|
|
80
|
+
// This is needed because worker threads may leave handles open
|
|
81
|
+
// even after proper cleanup, preventing natural process termination
|
|
82
|
+
if (!options.noExit) {
|
|
83
|
+
// Use beforeExit to ensure we run after all other exit handlers
|
|
84
|
+
// have set the correct exit code
|
|
85
|
+
process.once('beforeExit', (code) => {
|
|
86
|
+
// Give cleanup a moment to complete, then force exit with the correct code
|
|
87
|
+
setTimeout(() => {
|
|
88
|
+
process.exit(code || process.exitCode || 0)
|
|
89
|
+
}, 100)
|
|
90
|
+
})
|
|
91
|
+
}
|
|
116
92
|
}
|
|
117
93
|
}
|
package/lib/command/run.js
CHANGED
|
@@ -1,49 +1,61 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import
|
|
6
|
-
import Codecept from '../codecept.js';
|
|
7
|
-
import { store } from '../store.js';
|
|
1
|
+
import { getConfig, printError, getTestRoot, createOutputDir } from './utils.js'
|
|
2
|
+
import Config from '../config.js'
|
|
3
|
+
import store from '../store.js'
|
|
4
|
+
import Codecept from '../codecept.js'
|
|
5
|
+
import container from '../container.js'
|
|
8
6
|
|
|
9
7
|
export default async function (test, options) {
|
|
10
8
|
// registering options globally to use in config
|
|
11
9
|
// Backward compatibility for --profile
|
|
12
10
|
// TODO: remove in CodeceptJS 4
|
|
13
|
-
process.profile = options.profile
|
|
11
|
+
process.profile = options.profile
|
|
14
12
|
|
|
15
13
|
if (options.profile) {
|
|
16
|
-
process.env.profile = options.profile
|
|
14
|
+
process.env.profile = options.profile
|
|
17
15
|
}
|
|
18
|
-
if (options.verbose || options.debug) store.debugMode = true
|
|
16
|
+
if (options.verbose || options.debug) store.debugMode = true
|
|
19
17
|
|
|
20
|
-
const configFile = options.config
|
|
21
|
-
|
|
22
|
-
let config = getConfig(configFile);
|
|
18
|
+
const configFile = options.config
|
|
23
19
|
|
|
20
|
+
let config = await getConfig(configFile)
|
|
24
21
|
if (options.override) {
|
|
25
|
-
config = Config.append(JSON.parse(options.override))
|
|
22
|
+
config = Config.append(JSON.parse(options.override))
|
|
26
23
|
}
|
|
27
|
-
const testRoot = getTestRoot(configFile)
|
|
28
|
-
createOutputDir(config, testRoot)
|
|
24
|
+
const testRoot = getTestRoot(configFile)
|
|
25
|
+
createOutputDir(config, testRoot)
|
|
26
|
+
|
|
27
|
+
const codecept = new Codecept(config, options)
|
|
29
28
|
|
|
30
|
-
const codecept = new Codecept(config, options);
|
|
31
29
|
try {
|
|
32
|
-
codecept.init(testRoot)
|
|
33
|
-
await codecept.bootstrap()
|
|
34
|
-
codecept.loadTests(test)
|
|
30
|
+
await codecept.init(testRoot)
|
|
31
|
+
await codecept.bootstrap()
|
|
32
|
+
codecept.loadTests(test)
|
|
35
33
|
|
|
36
34
|
if (options.verbose) {
|
|
37
|
-
global.debugMode = true
|
|
38
|
-
const { getMachineInfo } =
|
|
39
|
-
await getMachineInfo()
|
|
35
|
+
global.debugMode = true
|
|
36
|
+
const { getMachineInfo } = await import('./info.js')
|
|
37
|
+
await getMachineInfo()
|
|
40
38
|
}
|
|
41
39
|
|
|
42
|
-
await codecept.run()
|
|
40
|
+
await codecept.run()
|
|
43
41
|
} catch (err) {
|
|
44
|
-
printError(err)
|
|
45
|
-
process.exitCode = 1
|
|
42
|
+
printError(err)
|
|
43
|
+
process.exitCode = 1
|
|
46
44
|
} finally {
|
|
47
|
-
await codecept.teardown()
|
|
45
|
+
await codecept.teardown()
|
|
46
|
+
|
|
47
|
+
// Schedule a delayed exit to prevent process hanging due to browser helper event loops
|
|
48
|
+
// Only needed for Playwright/Puppeteer which keep the event loop alive
|
|
49
|
+
// Wait 1 second to allow final cleanup and output to complete
|
|
50
|
+
if (!process.env.CODECEPT_DISABLE_AUTO_EXIT) {
|
|
51
|
+
const helpers = container.helpers()
|
|
52
|
+
const hasBrowserHelper = helpers && (helpers.Playwright || helpers.Puppeteer || helpers.WebDriver)
|
|
53
|
+
|
|
54
|
+
if (hasBrowserHelper) {
|
|
55
|
+
setTimeout(() => {
|
|
56
|
+
process.exit(process.exitCode || 0)
|
|
57
|
+
}, 1000).unref()
|
|
58
|
+
}
|
|
59
|
+
}
|
|
48
60
|
}
|
|
49
61
|
}
|
package/lib/command/utils.js
CHANGED
|
@@ -1,103 +1,119 @@
|
|
|
1
|
-
import fs from 'fs'
|
|
2
|
-
import path from 'path'
|
|
3
|
-
import util from 'util'
|
|
4
|
-
import mkdirp from 'mkdirp'
|
|
5
|
-
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
import util from 'util'
|
|
4
|
+
import { mkdirp } from 'mkdirp'
|
|
5
|
+
|
|
6
|
+
import output from '../output.js'
|
|
7
|
+
import { fileExists, beautify, deepMerge } from '../utils.js'
|
|
8
|
+
|
|
9
|
+
// alias to deep merge
|
|
10
|
+
export { deepMerge }
|
|
11
|
+
|
|
12
|
+
export async function getConfig(configFile) {
|
|
10
13
|
try {
|
|
11
|
-
|
|
14
|
+
const configModule = await import('../config.js')
|
|
15
|
+
const config = configModule.default || configModule
|
|
16
|
+
return await config.load(configFile)
|
|
12
17
|
} catch (err) {
|
|
13
|
-
fail(err.stack)
|
|
18
|
+
fail(err.stack)
|
|
14
19
|
}
|
|
15
|
-
}
|
|
20
|
+
}
|
|
16
21
|
|
|
17
|
-
export
|
|
22
|
+
export function readConfig(configFile) {
|
|
18
23
|
try {
|
|
19
|
-
const data = fs.readFileSync(configFile, 'utf8')
|
|
20
|
-
return data
|
|
24
|
+
const data = fs.readFileSync(configFile, 'utf8')
|
|
25
|
+
return data
|
|
21
26
|
} catch (err) {
|
|
22
|
-
output.
|
|
27
|
+
output.error(err)
|
|
23
28
|
}
|
|
24
|
-
}
|
|
29
|
+
}
|
|
25
30
|
|
|
26
31
|
function getTestRoot(currentPath) {
|
|
27
|
-
if (!currentPath) currentPath = '.'
|
|
28
|
-
if (!path.isAbsolute(currentPath)) currentPath = path.join(process.cwd(), currentPath)
|
|
29
|
-
currentPath = fs.lstatSync(currentPath).isDirectory() || !path.extname(currentPath) ? currentPath : path.dirname(currentPath)
|
|
30
|
-
return currentPath
|
|
32
|
+
if (!currentPath) currentPath = '.'
|
|
33
|
+
if (!path.isAbsolute(currentPath)) currentPath = path.join(process.cwd(), currentPath)
|
|
34
|
+
currentPath = fs.lstatSync(currentPath).isDirectory() || !path.extname(currentPath) ? currentPath : path.dirname(currentPath)
|
|
35
|
+
return currentPath
|
|
31
36
|
}
|
|
32
|
-
export { getTestRoot }
|
|
37
|
+
export { getTestRoot }
|
|
33
38
|
|
|
34
39
|
function fail(msg) {
|
|
35
|
-
output.
|
|
36
|
-
process.exit(1)
|
|
40
|
+
output.error(msg)
|
|
41
|
+
process.exit(1)
|
|
37
42
|
}
|
|
38
43
|
|
|
39
|
-
export { fail }
|
|
44
|
+
export { fail }
|
|
40
45
|
|
|
41
|
-
function updateConfig(testsPath, config,
|
|
42
|
-
const configFile = path.join(testsPath, `codecept.conf.${extension}`)
|
|
46
|
+
function updateConfig(testsPath, config, extension) {
|
|
47
|
+
const configFile = path.join(testsPath, `codecept.conf.${extension}`)
|
|
43
48
|
if (!fileExists(configFile)) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
console.log(`${output.
|
|
47
|
-
console.log('Please update it manually:')
|
|
48
|
-
console.log()
|
|
49
|
-
console.log(
|
|
50
|
-
console.log()
|
|
51
|
-
return
|
|
49
|
+
const msg = `codecept.conf.${extension} config can\'t be updated automatically`
|
|
50
|
+
console.log()
|
|
51
|
+
console.log(`${output.colors.bold.red(msg)}`)
|
|
52
|
+
console.log(`${output.colors.bold.red('Please update it manually:')}`)
|
|
53
|
+
console.log()
|
|
54
|
+
console.log(config)
|
|
55
|
+
console.log()
|
|
56
|
+
return
|
|
52
57
|
}
|
|
53
|
-
console.log(`${output.
|
|
54
|
-
return fs.writeFileSync(configFile, beautify(`exports.config = ${util.inspect(config, false, 4, false)}`), 'utf-8')
|
|
58
|
+
console.log(`${output.colors.yellow('Updating configuration file...')}`)
|
|
59
|
+
return fs.writeFileSync(configFile, beautify(`exports.config = ${util.inspect(config, false, 4, false)}`), 'utf-8')
|
|
55
60
|
}
|
|
56
61
|
|
|
57
|
-
export { updateConfig }
|
|
62
|
+
export { updateConfig }
|
|
58
63
|
|
|
59
64
|
function safeFileWrite(file, contents) {
|
|
60
65
|
if (fileExists(file)) {
|
|
61
|
-
output.
|
|
62
|
-
return false
|
|
66
|
+
output.error(`File ${file} already exist, skipping...`)
|
|
67
|
+
return false
|
|
63
68
|
}
|
|
64
|
-
fs.writeFileSync(file, contents)
|
|
65
|
-
return true
|
|
69
|
+
fs.writeFileSync(file, contents)
|
|
70
|
+
return true
|
|
66
71
|
}
|
|
67
72
|
|
|
68
|
-
export { safeFileWrite }
|
|
73
|
+
export { safeFileWrite }
|
|
69
74
|
|
|
70
|
-
export const captureStream =
|
|
71
|
-
let oldStream
|
|
72
|
-
let buffer = ''
|
|
75
|
+
export const captureStream = stream => {
|
|
76
|
+
let oldStream
|
|
77
|
+
let buffer = ''
|
|
73
78
|
|
|
74
79
|
return {
|
|
75
80
|
startCapture() {
|
|
76
|
-
buffer = ''
|
|
77
|
-
oldStream = stream.write.bind(stream)
|
|
78
|
-
stream.write = chunk => (buffer += chunk)
|
|
81
|
+
buffer = ''
|
|
82
|
+
oldStream = stream.write.bind(stream)
|
|
83
|
+
stream.write = chunk => (buffer += chunk)
|
|
79
84
|
},
|
|
80
85
|
stopCapture() {
|
|
81
|
-
if (oldStream !== undefined) stream.write = oldStream
|
|
86
|
+
if (oldStream !== undefined) stream.write = oldStream
|
|
82
87
|
},
|
|
83
88
|
getData: () => buffer,
|
|
84
|
-
}
|
|
85
|
-
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
86
91
|
|
|
87
|
-
export const printError =
|
|
88
|
-
output.print('')
|
|
89
|
-
output.
|
|
90
|
-
output.print('')
|
|
91
|
-
output.print(output.
|
|
92
|
-
}
|
|
92
|
+
export const printError = err => {
|
|
93
|
+
output.print('')
|
|
94
|
+
output.error(err.message)
|
|
95
|
+
output.print('')
|
|
96
|
+
output.print(output.colors.grey(err.stack.replace(err.message, '')))
|
|
97
|
+
}
|
|
93
98
|
|
|
94
99
|
export const createOutputDir = (config, testRoot) => {
|
|
95
|
-
let outputDir
|
|
96
|
-
if (path.isAbsolute(config.output)) outputDir = config.output
|
|
97
|
-
else outputDir = path.join(testRoot, config.output)
|
|
100
|
+
let outputDir
|
|
101
|
+
if (path.isAbsolute(config.output)) outputDir = config.output
|
|
102
|
+
else outputDir = path.join(testRoot, config.output)
|
|
98
103
|
|
|
99
104
|
if (!fileExists(outputDir)) {
|
|
100
|
-
output.print(`creating output directory: ${outputDir}`)
|
|
101
|
-
mkdirp.sync(outputDir)
|
|
105
|
+
output.print(`creating output directory: ${outputDir}`)
|
|
106
|
+
mkdirp.sync(outputDir)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export const findConfigFile = testsPath => {
|
|
111
|
+
const extensions = ['js', 'ts']
|
|
112
|
+
for (const ext of extensions) {
|
|
113
|
+
const configFile = path.join(testsPath, `codecept.conf.${ext}`)
|
|
114
|
+
if (fileExists(configFile)) {
|
|
115
|
+
return configFile
|
|
116
|
+
}
|
|
102
117
|
}
|
|
103
|
-
|
|
118
|
+
return null
|
|
119
|
+
}
|