codeceptjs 4.0.0-beta.1 → 4.0.0-beta.11.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 +765 -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
package/lib/codecept.js
CHANGED
|
@@ -1,228 +1,304 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from 'fs'
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
import
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
import
|
|
16
|
-
import
|
|
17
|
-
import
|
|
18
|
-
import
|
|
19
|
-
import
|
|
20
|
-
import
|
|
21
|
-
import
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
import
|
|
26
|
-
import
|
|
27
|
-
import
|
|
28
|
-
import
|
|
29
|
-
import
|
|
30
|
-
import
|
|
31
|
-
import
|
|
32
|
-
|
|
33
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
34
|
-
const require = createRequire(import.meta.url);
|
|
1
|
+
import { existsSync, readFileSync } from 'fs'
|
|
2
|
+
import { globSync } from 'glob'
|
|
3
|
+
import shuffle from 'lodash.shuffle'
|
|
4
|
+
import fsPath from 'path'
|
|
5
|
+
import { resolve } from 'path'
|
|
6
|
+
import { fileURLToPath } from 'url'
|
|
7
|
+
import { dirname } from 'path'
|
|
8
|
+
|
|
9
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
10
|
+
const __dirname = dirname(__filename)
|
|
11
|
+
|
|
12
|
+
import Helper from '@codeceptjs/helper'
|
|
13
|
+
import container from './container.js'
|
|
14
|
+
import Config from './config.js'
|
|
15
|
+
import event from './event.js'
|
|
16
|
+
import runHook from './hooks.js'
|
|
17
|
+
import ActorFactory from './actor.js'
|
|
18
|
+
import output from './output.js'
|
|
19
|
+
import { emptyFolder } from './utils.js'
|
|
20
|
+
import { initCodeceptGlobals } from './globals.js'
|
|
21
|
+
import recorder from './recorder.js'
|
|
22
|
+
|
|
23
|
+
import storeListener from './listener/store.js'
|
|
24
|
+
import stepsListener from './listener/steps.js'
|
|
25
|
+
import configListener from './listener/config.js'
|
|
26
|
+
import resultListener from './listener/result.js'
|
|
27
|
+
import helpersListener from './listener/helpers.js'
|
|
28
|
+
import globalTimeoutListener from './listener/globalTimeout.js'
|
|
29
|
+
import globalRetryListener from './listener/globalRetry.js'
|
|
30
|
+
import exitListener from './listener/exit.js'
|
|
31
|
+
import emptyRunListener from './listener/emptyRun.js'
|
|
35
32
|
|
|
36
33
|
/**
|
|
37
|
-
* CodeceptJS runner
|
|
34
|
+
* CodeceptJS runner
|
|
38
35
|
*/
|
|
39
|
-
|
|
36
|
+
class Codecept {
|
|
40
37
|
/**
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
38
|
+
* Create CodeceptJS runner.
|
|
39
|
+
* Config and options should be passed
|
|
40
|
+
*
|
|
41
|
+
* @param {*} config
|
|
42
|
+
* @param {*} opts
|
|
44
43
|
*/
|
|
45
44
|
constructor(config, opts) {
|
|
46
|
-
this.config = Config.create(config)
|
|
47
|
-
this.opts = opts
|
|
48
|
-
this.testFiles =
|
|
49
|
-
this.
|
|
45
|
+
this.config = Config.create(config)
|
|
46
|
+
this.opts = opts
|
|
47
|
+
this.testFiles = new Array(0)
|
|
48
|
+
this.requiringModules = config.require
|
|
50
49
|
}
|
|
51
50
|
|
|
52
51
|
/**
|
|
53
|
-
*
|
|
54
|
-
*
|
|
52
|
+
* Require modules before codeceptjs running
|
|
53
|
+
*
|
|
54
|
+
* @param {string[]} requiringModules
|
|
55
55
|
*/
|
|
56
|
-
requireModules(requiringModules) {
|
|
57
|
-
requiringModules
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
56
|
+
async requireModules(requiringModules) {
|
|
57
|
+
if (requiringModules) {
|
|
58
|
+
for (const requiredModule of requiringModules) {
|
|
59
|
+
let modulePath = requiredModule
|
|
60
|
+
const isLocalFile = existsSync(modulePath) || existsSync(`${modulePath}.js`)
|
|
61
|
+
if (isLocalFile) {
|
|
62
|
+
modulePath = resolve(modulePath)
|
|
63
|
+
// For ESM, ensure .js extension for local files
|
|
64
|
+
if (!modulePath.endsWith('.js') && !modulePath.endsWith('.mjs') && !modulePath.endsWith('.cjs')) {
|
|
65
|
+
if (existsSync(`${modulePath}.js`)) {
|
|
66
|
+
modulePath = `${modulePath}.js`
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// Use dynamic import for ESM
|
|
71
|
+
await import(modulePath)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
62
74
|
}
|
|
63
75
|
|
|
64
76
|
/**
|
|
65
|
-
*
|
|
66
|
-
*
|
|
77
|
+
* Initialize CodeceptJS at specific dir.
|
|
78
|
+
* Loads config, requires factory methods
|
|
79
|
+
*
|
|
80
|
+
* @param {string} dir
|
|
67
81
|
*/
|
|
68
|
-
init(dir) {
|
|
69
|
-
this.initGlobals(dir)
|
|
70
|
-
|
|
71
|
-
this.
|
|
82
|
+
async init(dir) {
|
|
83
|
+
await this.initGlobals(dir)
|
|
84
|
+
// Require modules before initializing
|
|
85
|
+
await this.requireModules(this.requiringModules)
|
|
86
|
+
// initializing listeners
|
|
87
|
+
await container.create(this.config, this.opts)
|
|
88
|
+
// Store container globally for easy access
|
|
89
|
+
global.container = container
|
|
90
|
+
await this.runHooks()
|
|
72
91
|
}
|
|
73
92
|
|
|
74
93
|
/**
|
|
75
|
-
*
|
|
76
|
-
*
|
|
94
|
+
* Creates global variables
|
|
95
|
+
*
|
|
96
|
+
* @param {string} dir
|
|
77
97
|
*/
|
|
78
|
-
initGlobals(dir) {
|
|
79
|
-
|
|
80
|
-
global.output_dir = resolve(dir, this.config.output);
|
|
81
|
-
|
|
82
|
-
if (this.config.emptyOutputFolder) emptyFolder(global.output_dir);
|
|
83
|
-
|
|
84
|
-
if (!this.config.noGlobals) {
|
|
85
|
-
this.initGlobalHelpers();
|
|
86
|
-
}
|
|
98
|
+
async initGlobals(dir) {
|
|
99
|
+
await initCodeceptGlobals(dir, this.config, container)
|
|
87
100
|
}
|
|
88
101
|
|
|
89
102
|
/**
|
|
90
|
-
*
|
|
103
|
+
* Executes hooks.
|
|
91
104
|
*/
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
// BDD
|
|
107
|
-
global.Given = stepDefinitions.Given;
|
|
108
|
-
global.When = stepDefinitions.When;
|
|
109
|
-
global.Then = stepDefinitions.Then;
|
|
110
|
-
global.DefineParameterType = stepDefinitions.defineParameterType;
|
|
111
|
-
global.debugMode = false;
|
|
112
|
-
}
|
|
105
|
+
async runHooks() {
|
|
106
|
+
// default hooks - dynamic imports for ESM
|
|
107
|
+
const listenerModules = [
|
|
108
|
+
'./listener/store.js',
|
|
109
|
+
'./listener/steps.js',
|
|
110
|
+
'./listener/config.js',
|
|
111
|
+
'./listener/result.js',
|
|
112
|
+
'./listener/helpers.js',
|
|
113
|
+
'./listener/globalTimeout.js',
|
|
114
|
+
'./listener/globalRetry.js',
|
|
115
|
+
'./listener/retryEnhancer.js',
|
|
116
|
+
'./listener/exit.js',
|
|
117
|
+
'./listener/emptyRun.js',
|
|
118
|
+
]
|
|
113
119
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
listenerConfig,
|
|
122
|
-
listenerHelpers,
|
|
123
|
-
listenerRetry,
|
|
124
|
-
listenerTimeout,
|
|
125
|
-
listenerExit,
|
|
126
|
-
];
|
|
127
|
-
|
|
128
|
-
listeners.forEach(runHook);
|
|
129
|
-
|
|
130
|
-
// Run custom hooks
|
|
131
|
-
this.config.hooks.forEach(runHook);
|
|
120
|
+
for (const modulePath of listenerModules) {
|
|
121
|
+
const module = await import(modulePath)
|
|
122
|
+
runHook(module.default || module)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// custom hooks (previous iteration of plugins)
|
|
126
|
+
this.config.hooks.forEach(hook => runHook(hook))
|
|
132
127
|
}
|
|
133
128
|
|
|
134
129
|
/**
|
|
135
|
-
* Executes
|
|
130
|
+
* Executes bootstrap.
|
|
131
|
+
*
|
|
132
|
+
* @returns {Promise<void>}
|
|
136
133
|
*/
|
|
137
134
|
async bootstrap() {
|
|
138
|
-
return runHook(this.config.bootstrap, 'bootstrap')
|
|
135
|
+
return runHook(this.config.bootstrap, 'bootstrap')
|
|
139
136
|
}
|
|
140
137
|
|
|
141
138
|
/**
|
|
142
|
-
* Executes
|
|
139
|
+
* Executes teardown.
|
|
140
|
+
*
|
|
141
|
+
* @returns {Promise<void>}
|
|
143
142
|
*/
|
|
144
143
|
async teardown() {
|
|
145
|
-
return runHook(this.config.teardown, 'teardown')
|
|
144
|
+
return runHook(this.config.teardown, 'teardown')
|
|
146
145
|
}
|
|
147
146
|
|
|
148
147
|
/**
|
|
149
|
-
* Loads
|
|
150
|
-
*
|
|
148
|
+
* Loads tests by pattern or by config.tests
|
|
149
|
+
*
|
|
150
|
+
* @param {string} [pattern]
|
|
151
151
|
*/
|
|
152
152
|
loadTests(pattern) {
|
|
153
|
-
const
|
|
154
|
-
|
|
153
|
+
const options = {
|
|
154
|
+
cwd: global.codecept_dir,
|
|
155
|
+
}
|
|
155
156
|
|
|
156
|
-
patterns
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
const fullPath = isAbsolute(file) ? file : join(global.codecept_dir, file);
|
|
160
|
-
const resolvedFile = resolve(fullPath);
|
|
157
|
+
let patterns = [pattern]
|
|
158
|
+
if (!pattern) {
|
|
159
|
+
patterns = []
|
|
161
160
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
161
|
+
// If the user wants to test a specific set of test files as an array or string.
|
|
162
|
+
if (this.config.tests && !this.opts.features) {
|
|
163
|
+
if (Array.isArray(this.config.tests)) {
|
|
164
|
+
patterns.push(...this.config.tests)
|
|
165
|
+
} else {
|
|
166
|
+
patterns.push(this.config.tests)
|
|
165
167
|
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (this.config.gherkin && this.config.gherkin.features && !this.opts.tests) {
|
|
171
|
+
if (Array.isArray(this.config.gherkin.features)) {
|
|
172
|
+
this.config.gherkin.features.forEach(feature => {
|
|
173
|
+
patterns.push(feature)
|
|
174
|
+
})
|
|
175
|
+
} else {
|
|
176
|
+
patterns.push(this.config.gherkin.features)
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
for (pattern of patterns) {
|
|
182
|
+
if (pattern) {
|
|
183
|
+
globSync(pattern, options).forEach(file => {
|
|
184
|
+
if (file.includes('node_modules')) return
|
|
185
|
+
if (!fsPath.isAbsolute(file)) {
|
|
186
|
+
file = fsPath.join(global.codecept_dir, file)
|
|
187
|
+
}
|
|
188
|
+
if (!this.testFiles.includes(fsPath.resolve(file))) {
|
|
189
|
+
this.testFiles.push(fsPath.resolve(file))
|
|
190
|
+
}
|
|
191
|
+
})
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (this.opts.shuffle) {
|
|
196
|
+
this.testFiles = shuffle(this.testFiles)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (this.opts.shard) {
|
|
200
|
+
this.testFiles = this._applySharding(this.testFiles, this.opts.shard)
|
|
201
|
+
}
|
|
168
202
|
}
|
|
169
203
|
|
|
170
204
|
/**
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
* @
|
|
205
|
+
* Apply sharding to test files based on shard configuration
|
|
206
|
+
*
|
|
207
|
+
* @param {Array<string>} testFiles - Array of test file paths
|
|
208
|
+
* @param {string} shardConfig - Shard configuration in format "index/total" (e.g., "1/4")
|
|
209
|
+
* @returns {Array<string>} - Filtered array of test files for this shard
|
|
174
210
|
*/
|
|
175
|
-
|
|
176
|
-
|
|
211
|
+
_applySharding(testFiles, shardConfig) {
|
|
212
|
+
const shardMatch = shardConfig.match(/^(\d+)\/(\d+)$/)
|
|
213
|
+
if (!shardMatch) {
|
|
214
|
+
throw new Error('Invalid shard format. Expected format: "index/total" (e.g., "1/4")')
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const shardIndex = parseInt(shardMatch[1], 10)
|
|
218
|
+
const shardTotal = parseInt(shardMatch[2], 10)
|
|
177
219
|
|
|
178
|
-
|
|
179
|
-
|
|
220
|
+
if (shardTotal < 1) {
|
|
221
|
+
throw new Error('Shard total must be at least 1')
|
|
222
|
+
}
|
|
180
223
|
|
|
181
|
-
if (
|
|
182
|
-
|
|
224
|
+
if (shardIndex < 1 || shardIndex > shardTotal) {
|
|
225
|
+
throw new Error(`Shard index ${shardIndex} must be between 1 and ${shardTotal}`)
|
|
183
226
|
}
|
|
184
227
|
|
|
185
|
-
if (
|
|
186
|
-
|
|
228
|
+
if (testFiles.length === 0) {
|
|
229
|
+
return testFiles
|
|
187
230
|
}
|
|
188
231
|
|
|
189
|
-
|
|
232
|
+
// Calculate which tests belong to this shard
|
|
233
|
+
const shardSize = Math.ceil(testFiles.length / shardTotal)
|
|
234
|
+
const startIndex = (shardIndex - 1) * shardSize
|
|
235
|
+
const endIndex = Math.min(startIndex + shardSize, testFiles.length)
|
|
236
|
+
|
|
237
|
+
return testFiles.slice(startIndex, endIndex)
|
|
190
238
|
}
|
|
191
239
|
|
|
192
240
|
/**
|
|
193
|
-
*
|
|
194
|
-
*
|
|
241
|
+
* Run a specific test or all loaded tests.
|
|
242
|
+
*
|
|
243
|
+
* @param {string} [test]
|
|
195
244
|
* @returns {Promise<void>}
|
|
196
245
|
*/
|
|
197
246
|
async run(test) {
|
|
198
|
-
|
|
199
|
-
mocha.files = this.testFiles;
|
|
247
|
+
await container.started()
|
|
200
248
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
249
|
+
// Ensure translations are loaded for Gherkin features
|
|
250
|
+
try {
|
|
251
|
+
const { loadTranslations } = await import('./mocha/gherkin.js')
|
|
252
|
+
await loadTranslations()
|
|
253
|
+
} catch (e) {
|
|
254
|
+
// Ignore if gherkin module not available
|
|
204
255
|
}
|
|
205
256
|
|
|
206
257
|
return new Promise((resolve, reject) => {
|
|
258
|
+
const mocha = container.mocha()
|
|
259
|
+
mocha.files = this.testFiles
|
|
260
|
+
|
|
261
|
+
if (test) {
|
|
262
|
+
if (!fsPath.isAbsolute(test)) {
|
|
263
|
+
test = fsPath.join(global.codecept_dir, test)
|
|
264
|
+
}
|
|
265
|
+
const testBasename = fsPath.basename(test, '.js')
|
|
266
|
+
const testFeatureBasename = fsPath.basename(test, '.feature')
|
|
267
|
+
mocha.files = mocha.files.filter(t => {
|
|
268
|
+
return fsPath.basename(t, '.js') === testBasename || fsPath.basename(t, '.feature') === testFeatureBasename || t === test
|
|
269
|
+
})
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const done = async (failures) => {
|
|
273
|
+
event.emit(event.all.result, container.result())
|
|
274
|
+
event.emit(event.all.after, this)
|
|
275
|
+
// Wait for any recorder tasks added by event.all.after handlers
|
|
276
|
+
await recorder.promise()
|
|
277
|
+
// Set exit code based on test failures
|
|
278
|
+
if (failures) {
|
|
279
|
+
process.exitCode = 1
|
|
280
|
+
}
|
|
281
|
+
resolve()
|
|
282
|
+
}
|
|
283
|
+
|
|
207
284
|
try {
|
|
208
|
-
event.emit(event.all.before, this)
|
|
209
|
-
mocha.run(() =>
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
});
|
|
214
|
-
} catch (error) {
|
|
215
|
-
output.output.error(error.stack);
|
|
216
|
-
reject(error);
|
|
285
|
+
event.emit(event.all.before, this)
|
|
286
|
+
mocha.run(async (failures) => await done(failures))
|
|
287
|
+
} catch (e) {
|
|
288
|
+
output.error(e.stack)
|
|
289
|
+
reject(e)
|
|
217
290
|
}
|
|
218
|
-
})
|
|
291
|
+
})
|
|
219
292
|
}
|
|
220
|
-
}
|
|
221
293
|
|
|
222
|
-
/**
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
294
|
+
/**
|
|
295
|
+
* Returns the version string of CodeceptJS.
|
|
296
|
+
*
|
|
297
|
+
* @returns {string} The version string.
|
|
298
|
+
*/
|
|
299
|
+
static version() {
|
|
300
|
+
return JSON.parse(readFileSync(`${__dirname}/../package.json`, 'utf8')).version
|
|
301
|
+
}
|
|
228
302
|
}
|
|
303
|
+
|
|
304
|
+
export default Codecept
|
package/lib/colorUtils.js
CHANGED
|
@@ -144,14 +144,14 @@ function convertColorNameToHex(color) {
|
|
|
144
144
|
whitesmoke: '#f5f5f5',
|
|
145
145
|
yellow: '#ffff00',
|
|
146
146
|
yellowgreen: '#9acd32',
|
|
147
|
-
}
|
|
147
|
+
}
|
|
148
148
|
|
|
149
|
-
const cColor = `${color}`.toLowerCase()
|
|
149
|
+
const cColor = `${color}`.toLowerCase()
|
|
150
150
|
if (typeof colors[cColor] !== 'undefined') {
|
|
151
|
-
return colors[cColor]
|
|
151
|
+
return colors[cColor]
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
return color
|
|
154
|
+
return color
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
/**
|
|
@@ -160,23 +160,23 @@ function convertColorNameToHex(color) {
|
|
|
160
160
|
*/
|
|
161
161
|
function convertHexColorToRgba(hex) {
|
|
162
162
|
// Expand shorthand form (e.g. "#03F") to full form (e.g. "#0033FF")
|
|
163
|
-
const shorthandRegex = /^#([a-f\d])([a-f\d])([a-f\d])$/i
|
|
163
|
+
const shorthandRegex = /^#([a-f\d])([a-f\d])([a-f\d])$/i
|
|
164
164
|
const hexFull = `${hex}`.replace(shorthandRegex, (m, r, g, b) => {
|
|
165
|
-
return r + r + g + g + b + b
|
|
166
|
-
})
|
|
165
|
+
return r + r + g + g + b + b
|
|
166
|
+
})
|
|
167
167
|
|
|
168
|
-
const result = /^#([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hexFull)
|
|
168
|
+
const result = /^#([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hexFull)
|
|
169
169
|
if (!result) {
|
|
170
170
|
// Return untouched if not a hex code
|
|
171
|
-
return hex
|
|
171
|
+
return hex
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
-
const r = parseInt(result[1], 16)
|
|
175
|
-
const g = parseInt(result[2], 16)
|
|
176
|
-
const b = parseInt(result[3], 16)
|
|
177
|
-
const a = 1
|
|
174
|
+
const r = parseInt(result[1], 16)
|
|
175
|
+
const g = parseInt(result[2], 16)
|
|
176
|
+
const b = parseInt(result[3], 16)
|
|
177
|
+
const a = 1
|
|
178
178
|
|
|
179
|
-
return `rgba(${r}, ${g}, ${b}, ${a})
|
|
179
|
+
return `rgba(${r}, ${g}, ${b}, ${a})`
|
|
180
180
|
}
|
|
181
181
|
|
|
182
182
|
/**
|
|
@@ -189,30 +189,30 @@ function convertHexColorToRgba(hex) {
|
|
|
189
189
|
*
|
|
190
190
|
* @param {string} color Color as a string, i.e. rgb(85,0,0)
|
|
191
191
|
*/
|
|
192
|
-
|
|
193
|
-
const cstr = `${color}`.toLowerCase().trim() || ''
|
|
192
|
+
function convertColorToRGBA(color) {
|
|
193
|
+
const cstr = `${color}`.toLowerCase().trim() || ''
|
|
194
194
|
|
|
195
195
|
if (!/^rgba?\(.+?\)$/.test(cstr)) {
|
|
196
196
|
// Convert both color names and hex colors to rgba
|
|
197
|
-
const hexColor = convertColorNameToHex(color)
|
|
198
|
-
return convertHexColorToRgba(hexColor)
|
|
197
|
+
const hexColor = convertColorNameToHex(color)
|
|
198
|
+
return convertHexColorToRgba(hexColor)
|
|
199
199
|
}
|
|
200
200
|
|
|
201
201
|
// Convert rgb to rgba
|
|
202
|
-
const channels = cstr.match(/([\-0-9.]+)/g) || []
|
|
202
|
+
const channels = cstr.match(/([\-0-9.]+)/g) || []
|
|
203
203
|
|
|
204
204
|
switch (channels.length) {
|
|
205
205
|
case 3:
|
|
206
206
|
// Convert rgb to rgba
|
|
207
|
-
return `rgba(${channels.join(', ')}, 1)
|
|
207
|
+
return `rgba(${channels.join(', ')}, 1)`
|
|
208
208
|
|
|
209
209
|
case 4:
|
|
210
210
|
// Format rgba
|
|
211
|
-
return `rgba(${channels.join(', ')})
|
|
211
|
+
return `rgba(${channels.join(', ')})`
|
|
212
212
|
|
|
213
213
|
default:
|
|
214
214
|
// Unexpected color format. Leave it untouched (let the user handle it)
|
|
215
|
-
return color
|
|
215
|
+
return color
|
|
216
216
|
}
|
|
217
217
|
}
|
|
218
218
|
|
|
@@ -221,35 +221,33 @@ export function convertColorToRGBA(color) {
|
|
|
221
221
|
*
|
|
222
222
|
* @param {string} prop CSS Property name
|
|
223
223
|
*/
|
|
224
|
-
|
|
225
|
-
return
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
224
|
+
function isColorProperty(prop) {
|
|
225
|
+
return (
|
|
226
|
+
[
|
|
227
|
+
'color',
|
|
228
|
+
'background',
|
|
229
|
+
'backgroundColor',
|
|
230
|
+
'background-color',
|
|
231
|
+
'borderColor',
|
|
232
|
+
'border-color',
|
|
233
|
+
'borderBottomColor',
|
|
234
|
+
'border-bottom-color',
|
|
235
|
+
'borderLeftColor',
|
|
236
|
+
'border-left-color',
|
|
237
|
+
'borderRightColor',
|
|
238
|
+
'borderTopColor',
|
|
239
|
+
'caretColor',
|
|
240
|
+
'columnRuleColor',
|
|
241
|
+
'outlineColor',
|
|
242
|
+
'textDecorationColor',
|
|
243
|
+
'border-right-color',
|
|
244
|
+
'border-top-color',
|
|
245
|
+
'caret-color',
|
|
246
|
+
'column-rule-color',
|
|
247
|
+
'outline-color',
|
|
248
|
+
'text-decoration-color',
|
|
249
|
+
].indexOf(prop) > -1
|
|
250
|
+
)
|
|
249
251
|
}
|
|
250
252
|
|
|
251
|
-
export
|
|
252
|
-
isColorProperty,
|
|
253
|
-
convertColorToRGBA,
|
|
254
|
-
convertColorNameToHex,
|
|
255
|
-
};
|
|
253
|
+
export { isColorProperty, convertColorToRGBA, convertColorNameToHex }
|