codeceptjs 4.0.0-beta.1 → 4.0.0-beta.10.esm-aria
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 +238 -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 +300 -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 +124 -50
- package/lib/container.js +751 -260
- 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/mask_data.js +47 -0
- package/lib/utils.js +411 -228
- package/lib/workerStorage.js +37 -34
- package/lib/workers.js +532 -296
- package/package.json +115 -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 -879
- package/typings/types.d.ts +547 -996
- 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
|
@@ -1,55 +1,64 @@
|
|
|
1
|
-
import { getConfig, getTestRoot } from './utils.js'
|
|
2
|
-
import recorder from '../recorder.js'
|
|
3
|
-
import Codecept from '../codecept.js'
|
|
4
|
-
import Container from '../container.js'
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
1
|
+
import { getConfig, getTestRoot } from './utils.js'
|
|
2
|
+
import recorder from '../recorder.js'
|
|
3
|
+
import Codecept from '../codecept.js'
|
|
4
|
+
import Container from '../container.js'
|
|
5
|
+
import event from '../event.js'
|
|
6
|
+
import pause from '../pause.js'
|
|
7
|
+
import output from '../output.js'
|
|
8
|
+
const webHelpers = Container.STANDARD_ACTING_HELPERS
|
|
8
9
|
|
|
9
10
|
export default async function (path, options) {
|
|
10
11
|
// Backward compatibility for --profile
|
|
11
|
-
process.profile = options.profile
|
|
12
|
-
process.env.profile = options.profile
|
|
13
|
-
const configFile = options.config
|
|
12
|
+
process.profile = options.profile
|
|
13
|
+
process.env.profile = options.profile
|
|
14
|
+
const configFile = options.config
|
|
14
15
|
|
|
15
|
-
const config = getConfig(configFile)
|
|
16
|
-
const testsPath = getTestRoot(configFile)
|
|
16
|
+
const config = await getConfig(configFile)
|
|
17
|
+
const testsPath = getTestRoot(configFile)
|
|
17
18
|
|
|
18
|
-
const codecept = new Codecept(config, options)
|
|
19
|
-
codecept.init(testsPath)
|
|
19
|
+
const codecept = new Codecept(config, options)
|
|
20
|
+
codecept.init(testsPath)
|
|
20
21
|
|
|
21
22
|
try {
|
|
22
|
-
await codecept.bootstrap()
|
|
23
|
+
await codecept.bootstrap()
|
|
24
|
+
await Container.started()
|
|
23
25
|
|
|
24
|
-
if (options.verbose) output.level(3)
|
|
26
|
+
if (options.verbose) output.level(3)
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
+
let addGlobalRetries
|
|
29
|
+
|
|
30
|
+
if (config.retry) {
|
|
31
|
+
addGlobalRetries = function retries() {}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
output.print('Starting interactive shell for current suite...')
|
|
35
|
+
recorder.start()
|
|
28
36
|
event.emit(event.suite.before, {
|
|
29
37
|
fullTitle: () => 'Interactive Shell',
|
|
30
38
|
tests: [],
|
|
31
|
-
|
|
39
|
+
retries: addGlobalRetries,
|
|
40
|
+
})
|
|
32
41
|
event.emit(event.test.before, {
|
|
33
42
|
title: '',
|
|
34
43
|
artifacts: {},
|
|
35
|
-
|
|
44
|
+
retries: addGlobalRetries,
|
|
45
|
+
})
|
|
36
46
|
|
|
37
|
-
const enabledHelpers = Container.helpers()
|
|
47
|
+
const enabledHelpers = Container.helpers()
|
|
38
48
|
for (const helperName of Object.keys(enabledHelpers)) {
|
|
39
49
|
if (webHelpers.includes(helperName)) {
|
|
40
|
-
const I = enabledHelpers[helperName]
|
|
41
|
-
recorder.add(() => I.amOnPage('/'))
|
|
42
|
-
recorder.catchWithoutStop(e => output.print(`Error while loading home page: ${e.message}}`))
|
|
43
|
-
break
|
|
50
|
+
const I = enabledHelpers[helperName]
|
|
51
|
+
recorder.add(() => I.amOnPage('/'))
|
|
52
|
+
recorder.catchWithoutStop(e => output.print(`Error while loading home page: ${e.message}}`))
|
|
53
|
+
break
|
|
44
54
|
}
|
|
45
55
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
recorder.add(() => event.emit(event.
|
|
49
|
-
recorder.add(() => event.emit(event.
|
|
50
|
-
recorder.add(() =>
|
|
51
|
-
recorder.add(() => codecept.teardown());
|
|
56
|
+
pause()
|
|
57
|
+
recorder.add(() => event.emit(event.test.after, {}))
|
|
58
|
+
recorder.add(() => event.emit(event.suite.after, {}))
|
|
59
|
+
recorder.add(() => event.emit(event.all.result, {}))
|
|
60
|
+
recorder.add(() => codecept.teardown())
|
|
52
61
|
} catch (err) {
|
|
53
|
-
output.
|
|
62
|
+
output.error(`Error while running bootstrap file :${err}`)
|
|
54
63
|
}
|
|
55
64
|
}
|
package/lib/command/list.js
CHANGED
|
@@ -1,36 +1,37 @@
|
|
|
1
|
-
import { getConfig, getTestRoot } from './utils.js'
|
|
2
|
-
import Codecept from '../codecept.js'
|
|
3
|
-
import container from '../container.js'
|
|
4
|
-
import { getParamsToString } from '../parser.js'
|
|
5
|
-
import { methodsOfObject } from '../utils.js'
|
|
6
|
-
import
|
|
1
|
+
import { getConfig, getTestRoot } from './utils.js'
|
|
2
|
+
import Codecept from '../codecept.js'
|
|
3
|
+
import container from '../container.js'
|
|
4
|
+
import { getParamsToString } from '../parser.js'
|
|
5
|
+
import { methodsOfObject } from '../utils.js'
|
|
6
|
+
import output from '../output.js'
|
|
7
7
|
|
|
8
|
-
export default function (path) {
|
|
9
|
-
const testsPath = getTestRoot(path)
|
|
10
|
-
const config = getConfig(testsPath)
|
|
11
|
-
const codecept = new Codecept(config, {})
|
|
12
|
-
codecept.init(testsPath)
|
|
8
|
+
export default async function (path) {
|
|
9
|
+
const testsPath = getTestRoot(path)
|
|
10
|
+
const config = await getConfig(testsPath)
|
|
11
|
+
const codecept = new Codecept(config, {})
|
|
12
|
+
await codecept.init(testsPath)
|
|
13
|
+
await container.started()
|
|
13
14
|
|
|
14
|
-
output.print('List of test actions: -- ')
|
|
15
|
-
const helpers = container.helpers()
|
|
16
|
-
const supportI = container.support('I')
|
|
17
|
-
const actions = []
|
|
15
|
+
output.print('List of test actions: -- ')
|
|
16
|
+
const helpers = container.helpers()
|
|
17
|
+
const supportI = container.support('I')
|
|
18
|
+
const actions = []
|
|
18
19
|
for (const name in helpers) {
|
|
19
|
-
const helper = helpers[name]
|
|
20
|
-
methodsOfObject(helper).forEach(
|
|
21
|
-
const params = getParamsToString(helper[action])
|
|
22
|
-
actions[action] = 1
|
|
23
|
-
output.print(` ${output.
|
|
24
|
-
})
|
|
20
|
+
const helper = helpers[name]
|
|
21
|
+
methodsOfObject(helper).forEach(action => {
|
|
22
|
+
const params = getParamsToString(helper[action])
|
|
23
|
+
actions[action] = 1
|
|
24
|
+
output.print(` ${output.colors.grey(name)} I.${output.colors.bold(action)}(${params})`)
|
|
25
|
+
})
|
|
25
26
|
}
|
|
26
27
|
for (const name in supportI) {
|
|
27
28
|
if (actions[name]) {
|
|
28
|
-
continue
|
|
29
|
+
continue
|
|
29
30
|
}
|
|
30
|
-
const actor = supportI[name]
|
|
31
|
-
const params = getParamsToString(actor)
|
|
32
|
-
output.print(` I.${output.
|
|
31
|
+
const actor = supportI[name]
|
|
32
|
+
const params = getParamsToString(actor)
|
|
33
|
+
output.print(` I.${output.colors.bold(name)}(${params})`)
|
|
33
34
|
}
|
|
34
|
-
output.print('PS: Actions are retrieved from enabled helpers. ')
|
|
35
|
-
output.print('Implement custom actions in your helper classes.')
|
|
35
|
+
output.print('PS: Actions are retrieved from enabled helpers. ')
|
|
36
|
+
output.print('Implement custom actions in your helper classes.')
|
|
36
37
|
}
|
|
@@ -1,91 +1,94 @@
|
|
|
1
|
-
import
|
|
2
|
-
import path from 'path'
|
|
3
|
-
import fs from 'fs'
|
|
1
|
+
import { globSync } from 'glob'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
import fs from 'fs'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Splits a list to (n) parts, defined via the size argument.
|
|
7
7
|
*/
|
|
8
8
|
const splitFiles = (list, size) => {
|
|
9
|
-
const sets = []
|
|
10
|
-
const chunks = list.length / size
|
|
11
|
-
let i = 0
|
|
9
|
+
const sets = []
|
|
10
|
+
const chunks = list.length / size
|
|
11
|
+
let i = 0
|
|
12
12
|
|
|
13
13
|
while (i < chunks) {
|
|
14
|
-
sets[i] = list.splice(0, size)
|
|
15
|
-
i
|
|
14
|
+
sets[i] = list.splice(0, size)
|
|
15
|
+
i++
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
return sets
|
|
19
|
-
}
|
|
18
|
+
return sets
|
|
19
|
+
}
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* Executes a glob pattern and pushes the results to a list.
|
|
23
23
|
*/
|
|
24
|
-
const findFiles =
|
|
25
|
-
const files = []
|
|
24
|
+
const findFiles = pattern => {
|
|
25
|
+
const files = []
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
files.push(path.resolve(file))
|
|
29
|
-
})
|
|
27
|
+
globSync(pattern).forEach(file => {
|
|
28
|
+
files.push(path.resolve(file))
|
|
29
|
+
})
|
|
30
30
|
|
|
31
|
-
return files
|
|
32
|
-
}
|
|
31
|
+
return files
|
|
32
|
+
}
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
35
|
* Joins a list of files to a valid glob pattern
|
|
36
36
|
*/
|
|
37
|
-
const flattenFiles =
|
|
38
|
-
const pattern = list.join(',')
|
|
39
|
-
return pattern.indexOf(',') > -1 ? `{${pattern}}` : pattern
|
|
40
|
-
}
|
|
37
|
+
const flattenFiles = list => {
|
|
38
|
+
const pattern = list.join(',')
|
|
39
|
+
return pattern.indexOf(',') > -1 ? `{${pattern}}` : pattern
|
|
40
|
+
}
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
43
|
* Greps a file by its content, checks if Scenario or Feature text'
|
|
44
44
|
* matches the grep text.
|
|
45
45
|
*/
|
|
46
46
|
const grepFile = (file, grep) => {
|
|
47
|
-
const contents = fs.readFileSync(file, 'utf8')
|
|
48
|
-
const pattern = new RegExp(`((Scenario|Feature)\(.*${grep}.*\))`, 'g')
|
|
49
|
-
return !!pattern.exec(contents)
|
|
50
|
-
}
|
|
47
|
+
const contents = fs.readFileSync(file, 'utf8')
|
|
48
|
+
const pattern = new RegExp(`((Scenario|Feature)\(.*${grep}.*\))`, 'g') // <- How future proof/solid is this?
|
|
49
|
+
return !!pattern.exec(contents)
|
|
50
|
+
}
|
|
51
51
|
|
|
52
|
-
const mapFileFormats =
|
|
52
|
+
const mapFileFormats = files => {
|
|
53
53
|
return {
|
|
54
54
|
gherkin: files.filter(file => file.match(/\.feature$/)),
|
|
55
55
|
js: files.filter(file => file.match(/\.t|js$/)),
|
|
56
|
-
}
|
|
57
|
-
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
58
|
|
|
59
59
|
/**
|
|
60
60
|
* Creates a list of chunks incl. configuration by either dividing a list of scenario
|
|
61
61
|
* files by the passed number or executing a usder deifned function to perform
|
|
62
62
|
* the splitting.
|
|
63
63
|
*/
|
|
64
|
-
|
|
65
|
-
const files = patterns
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
64
|
+
const createChunks = (config, patterns = []) => {
|
|
65
|
+
const files = patterns
|
|
66
|
+
.filter(pattern => !!pattern)
|
|
67
|
+
.map(pattern => {
|
|
68
|
+
return findFiles(pattern).filter(file => {
|
|
69
|
+
return config.grep ? grepFile(file, config.grep) : true
|
|
70
|
+
})
|
|
71
|
+
})
|
|
72
|
+
.reduce((acc, val) => acc.concat(val), [])
|
|
70
73
|
|
|
71
|
-
let chunks = []
|
|
74
|
+
let chunks = []
|
|
72
75
|
if (typeof config.chunks === 'function') {
|
|
73
|
-
chunks = config.chunks.call(this, files)
|
|
76
|
+
chunks = config.chunks.call(this, files)
|
|
74
77
|
} else if (typeof config.chunks === 'number' || typeof config.chunks === 'string') {
|
|
75
|
-
chunks = splitFiles(files, Math.ceil(files.length / config.chunks))
|
|
78
|
+
chunks = splitFiles(files, Math.ceil(files.length / config.chunks))
|
|
76
79
|
} else {
|
|
77
|
-
throw new Error('chunks is neither a finite number or a valid function')
|
|
80
|
+
throw new Error('chunks is neither a finite number or a valid function')
|
|
78
81
|
}
|
|
79
82
|
|
|
80
|
-
const chunkConfig = { ...config }
|
|
81
|
-
delete chunkConfig.chunks
|
|
83
|
+
const chunkConfig = { ...config }
|
|
84
|
+
delete chunkConfig.chunks
|
|
82
85
|
|
|
83
|
-
return chunks.map(
|
|
84
|
-
const { js, gherkin } = mapFileFormats(chunkFiles)
|
|
85
|
-
return { ...chunkConfig, tests: flattenFiles(js), gherkin: { features: flattenFiles(gherkin) } }
|
|
86
|
-
})
|
|
87
|
-
}
|
|
86
|
+
return chunks.map(chunkFiles => {
|
|
87
|
+
const { js, gherkin } = mapFileFormats(chunkFiles)
|
|
88
|
+
return { ...chunkConfig, tests: flattenFiles(js), gherkin: { features: flattenFiles(gherkin) } }
|
|
89
|
+
})
|
|
90
|
+
}
|
|
88
91
|
|
|
89
|
-
export
|
|
90
|
-
createChunks
|
|
91
|
-
}
|
|
92
|
+
export {
|
|
93
|
+
createChunks
|
|
94
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { createChunks } from './chunk.js'
|
|
2
|
-
import { createRun } from './run.js'
|
|
1
|
+
import { createChunks } from './chunk.js'
|
|
2
|
+
import { createRun } from './run.js'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Bootstraps a collection of runs, it combines user defined selection of runs
|
|
@@ -190,6 +190,6 @@ function guessBrowser(config) {
|
|
|
190
190
|
return [config.helpers[firstHelper].browser];
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
-
export
|
|
194
|
-
createRuns
|
|
195
|
-
}
|
|
193
|
+
export {
|
|
194
|
+
createRuns
|
|
195
|
+
}
|
|
@@ -1,186 +1,186 @@
|
|
|
1
|
-
import { fork } from 'child_process'
|
|
2
|
-
import path
|
|
3
|
-
import crypto from 'crypto'
|
|
4
|
-
import { fileURLToPath } from 'url'
|
|
5
|
-
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
|
|
1
|
+
import { fork } from 'child_process'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
import crypto from 'crypto'
|
|
4
|
+
import { fileURLToPath } from 'url'
|
|
5
|
+
|
|
6
|
+
import runHook from '../hooks.js'
|
|
7
|
+
import event from '../event.js'
|
|
8
|
+
import { createRuns } from './run-multiple/collection.js'
|
|
9
|
+
import { clearString, replaceValueDeep } from '../utils.js'
|
|
10
|
+
import { getConfig, getTestRoot, fail } from './utils.js'
|
|
11
|
+
|
|
12
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
13
|
+
const __dirname = path.dirname(__filename)
|
|
14
|
+
const runner = path.join(__dirname, '/../../bin/codecept')
|
|
15
|
+
let config
|
|
16
|
+
const childOpts = {}
|
|
17
|
+
const copyOptions = ['override', 'steps', 'reporter', 'verbose', 'config', 'reporter-options', 'grep', 'fgrep', 'invert', 'debug', 'plugins', 'colors']
|
|
18
|
+
let overrides = {}
|
|
18
19
|
|
|
19
20
|
// codeceptjs run-multiple smoke:chrome regression:firefox - will launch smoke run in chrome and regression in firefox
|
|
20
21
|
// codeceptjs run-multiple smoke:chrome regression - will launch smoke run in chrome and regression in firefox and chrome
|
|
21
22
|
// codeceptjs run-multiple --all - will launch all runs
|
|
22
23
|
// codeceptjs run-multiple smoke regression'
|
|
23
24
|
|
|
24
|
-
let runId = 1
|
|
25
|
-
let subprocessCount = 0
|
|
26
|
-
let totalSubprocessCount = 0
|
|
27
|
-
let processesDone
|
|
25
|
+
let runId = 1
|
|
26
|
+
let subprocessCount = 0
|
|
27
|
+
let totalSubprocessCount = 0
|
|
28
|
+
let processesDone
|
|
28
29
|
|
|
29
30
|
export default async function (selectedRuns, options) {
|
|
30
31
|
// registering options globally to use in config
|
|
31
32
|
if (options.profile) {
|
|
32
|
-
process.env.profile = options.profile
|
|
33
|
+
process.env.profile = options.profile
|
|
33
34
|
}
|
|
34
|
-
const configFile = options.config
|
|
35
|
+
const configFile = options.config
|
|
35
36
|
|
|
36
|
-
const testRoot = getTestRoot(configFile)
|
|
37
|
-
global.codecept_dir = testRoot
|
|
37
|
+
const testRoot = getTestRoot(configFile)
|
|
38
|
+
global.codecept_dir = testRoot
|
|
38
39
|
|
|
39
40
|
// copy opts to run
|
|
40
41
|
Object.keys(options)
|
|
41
42
|
.filter(key => copyOptions.indexOf(key) > -1)
|
|
42
|
-
.forEach(
|
|
43
|
-
childOpts[key] = options[key]
|
|
44
|
-
})
|
|
43
|
+
.forEach(key => {
|
|
44
|
+
childOpts[key] = options[key]
|
|
45
|
+
})
|
|
45
46
|
|
|
46
47
|
try {
|
|
47
|
-
overrides = JSON.parse(childOpts.override)
|
|
48
|
-
delete childOpts.override
|
|
48
|
+
overrides = JSON.parse(childOpts.override)
|
|
49
|
+
delete childOpts.override
|
|
49
50
|
} catch (e) {
|
|
50
|
-
overrides = {}
|
|
51
|
+
overrides = {}
|
|
51
52
|
}
|
|
52
53
|
|
|
53
54
|
config = {
|
|
54
|
-
...getConfig(configFile),
|
|
55
|
+
...(await getConfig(configFile)),
|
|
55
56
|
...overrides,
|
|
56
|
-
}
|
|
57
|
+
}
|
|
57
58
|
|
|
58
59
|
if (!config.multiple) {
|
|
59
|
-
fail('Multiple runs not configured, add "multiple": { /../ } section to config')
|
|
60
|
+
fail('Multiple runs not configured, add "multiple": { /../ } section to config')
|
|
60
61
|
}
|
|
61
62
|
|
|
62
|
-
selectedRuns = options.all ? Object.keys(config.multiple) : selectedRuns
|
|
63
|
+
selectedRuns = options.all ? Object.keys(config.multiple) : selectedRuns
|
|
63
64
|
if (!selectedRuns.length) {
|
|
64
|
-
fail('No runs provided. Use --all option to run all configured runs')
|
|
65
|
+
fail('No runs provided. Use --all option to run all configured runs')
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
await runHook(config.bootstrapAll, 'bootstrapAll')
|
|
68
|
+
await runHook(config.bootstrapAll, 'bootstrapAll')
|
|
68
69
|
|
|
69
|
-
event.emit(event.multiple.before, null)
|
|
70
|
-
if (options.config) {
|
|
70
|
+
event.emit(event.multiple.before, null)
|
|
71
|
+
if (options.config) {
|
|
72
|
+
// update paths to config path
|
|
71
73
|
if (config.tests) {
|
|
72
|
-
config.tests = path.resolve(testRoot, config.tests)
|
|
74
|
+
config.tests = path.resolve(testRoot, config.tests)
|
|
73
75
|
}
|
|
74
76
|
if (config.gherkin && config.gherkin.features) {
|
|
75
|
-
config.gherkin.features = path.resolve(testRoot, config.gherkin.features)
|
|
77
|
+
config.gherkin.features = path.resolve(testRoot, config.gherkin.features)
|
|
76
78
|
}
|
|
77
79
|
}
|
|
78
80
|
|
|
79
81
|
if (options.features) {
|
|
80
|
-
config.tests = ''
|
|
82
|
+
config.tests = ''
|
|
81
83
|
}
|
|
82
84
|
|
|
83
85
|
if (options.tests && config.gherkin) {
|
|
84
|
-
config.gherkin.features = ''
|
|
86
|
+
config.gherkin.features = ''
|
|
85
87
|
}
|
|
86
88
|
|
|
87
|
-
const childProcessesPromise = new Promise(
|
|
88
|
-
processesDone = resolve
|
|
89
|
-
})
|
|
89
|
+
const childProcessesPromise = new Promise(resolve => {
|
|
90
|
+
processesDone = resolve
|
|
91
|
+
})
|
|
90
92
|
|
|
91
|
-
const runsToExecute = []
|
|
92
|
-
|
|
93
|
-
const runName = run.getOriginalName() || run.getName()
|
|
94
|
-
const runConfig = run.getConfig()
|
|
95
|
-
runsToExecute.push(executeRun(runName, runConfig))
|
|
96
|
-
})
|
|
93
|
+
const runsToExecute = []
|
|
94
|
+
createRuns(selectedRuns, config).forEach(run => {
|
|
95
|
+
const runName = run.getOriginalName() || run.getName()
|
|
96
|
+
const runConfig = run.getConfig()
|
|
97
|
+
runsToExecute.push(executeRun(runName, runConfig))
|
|
98
|
+
})
|
|
97
99
|
|
|
98
100
|
if (!runsToExecute.length) {
|
|
99
|
-
fail('Nothing scheduled for execution')
|
|
101
|
+
fail('Nothing scheduled for execution')
|
|
100
102
|
}
|
|
101
103
|
|
|
102
104
|
// Execute all forks
|
|
103
|
-
totalSubprocessCount = runsToExecute.length
|
|
104
|
-
runsToExecute.forEach(runToExecute => runToExecute.call(this))
|
|
105
|
+
totalSubprocessCount = runsToExecute.length
|
|
106
|
+
runsToExecute.forEach(runToExecute => runToExecute.call(this))
|
|
105
107
|
|
|
106
108
|
return childProcessesPromise.then(async () => {
|
|
107
109
|
// fire hook
|
|
108
|
-
await runHook(config.teardownAll, 'teardownAll')
|
|
109
|
-
event.emit(event.multiple.after, null)
|
|
110
|
-
})
|
|
110
|
+
await runHook(config.teardownAll, 'teardownAll')
|
|
111
|
+
event.emit(event.multiple.after, null)
|
|
112
|
+
})
|
|
111
113
|
}
|
|
112
114
|
|
|
113
115
|
function executeRun(runName, runConfig) {
|
|
114
116
|
// clone config
|
|
115
|
-
let overriddenConfig = { ...config }
|
|
117
|
+
let overriddenConfig = { ...config }
|
|
116
118
|
|
|
117
119
|
// get configuration
|
|
118
|
-
const browserConfig = runConfig.browser
|
|
119
|
-
const browserName = browserConfig.browser
|
|
120
|
+
const browserConfig = runConfig.browser
|
|
121
|
+
const browserName = browserConfig.browser
|
|
120
122
|
|
|
121
123
|
for (const key in browserConfig) {
|
|
122
|
-
overriddenConfig.helpers = replaceValueDeep(overriddenConfig.helpers, key, browserConfig[key])
|
|
124
|
+
overriddenConfig.helpers = replaceValueDeep(overriddenConfig.helpers, key, browserConfig[key])
|
|
123
125
|
}
|
|
124
126
|
|
|
125
|
-
let outputDir = `${runName}_
|
|
127
|
+
let outputDir = `${runName}_`
|
|
126
128
|
if (browserConfig.outputName) {
|
|
127
|
-
outputDir += typeof browserConfig.outputName === 'function' ? browserConfig.outputName() : browserConfig.outputName
|
|
129
|
+
outputDir += typeof browserConfig.outputName === 'function' ? browserConfig.outputName() : browserConfig.outputName
|
|
128
130
|
} else {
|
|
129
|
-
const hash = crypto.createHash('sha256')
|
|
130
|
-
hash.update(JSON.stringify(browserConfig))
|
|
131
|
-
outputDir += hash.digest('hex')
|
|
131
|
+
const hash = crypto.createHash('sha256')
|
|
132
|
+
hash.update(JSON.stringify(browserConfig))
|
|
133
|
+
outputDir += hash.digest('hex')
|
|
132
134
|
}
|
|
133
|
-
outputDir += `_${runId}
|
|
135
|
+
outputDir += `_${runId}`
|
|
134
136
|
|
|
135
|
-
outputDir = clearString(outputDir)
|
|
137
|
+
outputDir = clearString(outputDir)
|
|
136
138
|
|
|
137
139
|
// tweaking default output directories and for mochawesome
|
|
138
|
-
overriddenConfig = replaceValueDeep(overriddenConfig, 'output', path.join(config.output, outputDir))
|
|
139
|
-
overriddenConfig = replaceValueDeep(overriddenConfig, 'reportDir', path.join(config.output, outputDir))
|
|
140
|
-
overriddenConfig = replaceValueDeep(overriddenConfig, 'mochaFile', path.join(config.output, outputDir, `${browserName}_report.xml`))
|
|
140
|
+
overriddenConfig = replaceValueDeep(overriddenConfig, 'output', path.join(config.output, outputDir))
|
|
141
|
+
overriddenConfig = replaceValueDeep(overriddenConfig, 'reportDir', path.join(config.output, outputDir))
|
|
142
|
+
overriddenConfig = replaceValueDeep(overriddenConfig, 'mochaFile', path.join(config.output, outputDir, `${browserName}_report.xml`))
|
|
141
143
|
|
|
142
144
|
// override tests configuration
|
|
143
145
|
if (overriddenConfig.tests) {
|
|
144
|
-
overriddenConfig.tests = runConfig.tests
|
|
146
|
+
overriddenConfig.tests = runConfig.tests
|
|
145
147
|
}
|
|
146
148
|
|
|
147
149
|
if (overriddenConfig.gherkin && runConfig.gherkin && runConfig.gherkin.features) {
|
|
148
|
-
overriddenConfig.gherkin.features = runConfig.gherkin.features
|
|
150
|
+
overriddenConfig.gherkin.features = runConfig.gherkin.features
|
|
149
151
|
}
|
|
150
152
|
|
|
151
153
|
// override grep param and collect all params
|
|
152
|
-
const params = ['run',
|
|
153
|
-
'--child', `${runId++}.${runName}:${browserName}`,
|
|
154
|
-
'--override', JSON.stringify(overriddenConfig),
|
|
155
|
-
];
|
|
154
|
+
const params = ['run', '--child', `${runId++}.${runName}:${browserName}`, '--override', JSON.stringify(overriddenConfig)]
|
|
156
155
|
|
|
157
|
-
Object.keys(childOpts).forEach(
|
|
158
|
-
params.push(`--${key}`)
|
|
159
|
-
if (childOpts[key] !== true) params.push(childOpts[key])
|
|
160
|
-
})
|
|
156
|
+
Object.keys(childOpts).forEach(key => {
|
|
157
|
+
params.push(`--${key}`)
|
|
158
|
+
if (childOpts[key] !== true) params.push(childOpts[key])
|
|
159
|
+
})
|
|
161
160
|
|
|
162
161
|
if (runConfig.grep) {
|
|
163
|
-
params.push('--grep')
|
|
164
|
-
params.push(runConfig.grep)
|
|
162
|
+
params.push('--grep')
|
|
163
|
+
params.push(runConfig.grep)
|
|
165
164
|
}
|
|
166
165
|
|
|
167
|
-
const onProcessEnd =
|
|
166
|
+
const onProcessEnd = errorCode => {
|
|
168
167
|
if (errorCode !== 0) {
|
|
169
|
-
process.exitCode = errorCode
|
|
168
|
+
process.exitCode = errorCode
|
|
170
169
|
}
|
|
171
|
-
subprocessCount += 1
|
|
170
|
+
subprocessCount += 1
|
|
172
171
|
if (subprocessCount === totalSubprocessCount) {
|
|
173
|
-
processesDone()
|
|
172
|
+
processesDone()
|
|
174
173
|
}
|
|
175
|
-
return errorCode
|
|
176
|
-
}
|
|
174
|
+
return errorCode
|
|
175
|
+
}
|
|
177
176
|
|
|
178
177
|
// Return function of fork for later execution
|
|
179
|
-
return () =>
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
178
|
+
return () =>
|
|
179
|
+
fork(runner, params, { stdio: [0, 1, 2, 'ipc'] })
|
|
180
|
+
.on('exit', code => {
|
|
181
|
+
return onProcessEnd(code)
|
|
182
|
+
})
|
|
183
|
+
.on('error', () => {
|
|
184
|
+
return onProcessEnd(1)
|
|
185
|
+
})
|
|
186
186
|
}
|