codeceptjs 3.6.7 → 4.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/codecept.js +81 -84
- package/lib/actor.js +13 -13
- package/lib/ai.js +13 -10
- package/lib/assert/empty.js +21 -20
- package/lib/assert/equal.js +39 -37
- package/lib/assert/error.js +14 -14
- package/lib/assert/include.js +47 -46
- package/lib/assert/throws.js +11 -13
- package/lib/assert/truth.js +22 -19
- package/lib/assert.js +2 -4
- package/lib/cli.js +49 -57
- package/lib/codecept.js +155 -142
- package/lib/colorUtils.js +3 -3
- package/lib/command/configMigrate.js +52 -58
- package/lib/command/definitions.js +89 -88
- package/lib/command/dryRun.js +68 -71
- package/lib/command/generate.js +188 -197
- package/lib/command/gherkin/init.js +16 -27
- package/lib/command/gherkin/snippets.js +20 -20
- package/lib/command/gherkin/steps.js +8 -8
- package/lib/command/info.js +38 -40
- package/lib/command/init.js +288 -290
- package/lib/command/interactive.js +32 -32
- package/lib/command/list.js +26 -26
- package/lib/command/run-multiple/chunk.js +5 -5
- package/lib/command/run-multiple/collection.js +3 -3
- package/lib/command/run-multiple/run.js +2 -6
- package/lib/command/run-multiple.js +93 -113
- package/lib/command/run-rerun.js +25 -20
- package/lib/command/run-workers.js +66 -64
- package/lib/command/run.js +29 -26
- package/lib/command/utils.js +65 -80
- package/lib/command/workers/runTests.js +10 -10
- package/lib/config.js +9 -10
- package/lib/container.js +48 -40
- package/lib/data/context.js +59 -60
- package/lib/data/dataScenarioConfig.js +47 -47
- package/lib/data/dataTableArgument.js +29 -29
- package/lib/data/table.js +20 -26
- package/lib/dirname.js +5 -0
- package/lib/event.js +167 -163
- package/lib/heal.js +17 -13
- package/lib/helper/AI.js +41 -130
- package/lib/helper/ApiDataFactory.js +69 -73
- package/lib/helper/Appium.js +381 -412
- package/lib/helper/Expect.js +425 -0
- package/lib/helper/ExpectHelper.js +48 -40
- package/lib/helper/FileSystem.js +79 -80
- package/lib/helper/GraphQL.js +43 -44
- package/lib/helper/GraphQLDataFactory.js +50 -50
- package/lib/helper/JSONResponse.js +62 -65
- package/lib/helper/Mochawesome.js +28 -28
- package/lib/helper/MockServer.js +14 -12
- package/lib/helper/Nightmare.js +566 -662
- package/lib/helper/Playwright.js +1216 -1361
- package/lib/helper/Protractor.js +627 -663
- package/lib/helper/Puppeteer.js +1128 -1231
- package/lib/helper/REST.js +68 -159
- package/lib/helper/SoftExpectHelper.js +2 -2
- package/lib/helper/TestCafe.js +484 -490
- package/lib/helper/WebDriver.js +1156 -1297
- package/lib/helper/clientscripts/PollyWebDriverExt.js +1 -1
- package/lib/helper/errors/ConnectionRefused.js +1 -1
- package/lib/helper/errors/ElementAssertion.js +2 -2
- package/lib/helper/errors/ElementNotFound.js +2 -2
- package/lib/helper/errors/RemoteBrowserConnectionRefused.js +1 -1
- package/lib/helper/extras/Console.js +1 -1
- package/lib/helper/extras/PlaywrightPropEngine.js +2 -2
- package/lib/helper/extras/PlaywrightReactVueLocator.js +1 -1
- package/lib/helper/extras/PlaywrightRestartOpts.js +18 -21
- package/lib/helper/extras/Popup.js +1 -1
- package/lib/helper/extras/React.js +3 -3
- package/lib/helper/network/actions.js +7 -14
- package/lib/helper/network/utils.js +2 -3
- package/lib/helper/scripts/blurElement.js +1 -1
- package/lib/helper/scripts/focusElement.js +1 -1
- package/lib/helper/scripts/highlightElement.js +1 -1
- package/lib/helper/scripts/isElementClickable.js +1 -1
- package/lib/helper/testcafe/testControllerHolder.js +1 -1
- package/lib/helper/testcafe/testcafe-utils.js +7 -6
- package/lib/helper.js +3 -1
- package/lib/history.js +5 -6
- package/lib/hooks.js +6 -6
- package/lib/html.js +7 -7
- package/lib/index.js +41 -25
- package/lib/interfaces/bdd.js +64 -47
- package/lib/interfaces/featureConfig.js +19 -19
- package/lib/interfaces/gherkin.js +118 -124
- package/lib/interfaces/scenarioConfig.js +29 -29
- package/lib/listener/artifacts.js +9 -9
- package/lib/listener/config.js +24 -24
- package/lib/listener/exit.js +12 -12
- package/lib/listener/helpers.js +42 -42
- package/lib/listener/mocha.js +11 -11
- package/lib/listener/retry.js +30 -32
- package/lib/listener/steps.js +53 -50
- package/lib/listener/timeout.js +54 -54
- package/lib/locator.js +10 -6
- package/lib/mochaFactory.js +15 -18
- package/lib/output.js +10 -6
- package/lib/parser.js +12 -15
- package/lib/pause.js +33 -40
- package/lib/plugin/allure.js +15 -15
- package/lib/plugin/autoDelay.js +37 -29
- package/lib/plugin/autoLogin.js +65 -70
- package/lib/plugin/commentStep.js +18 -18
- package/lib/plugin/coverage.js +67 -115
- package/lib/plugin/customLocator.js +20 -21
- package/lib/plugin/debugErrors.js +24 -24
- package/lib/plugin/eachElement.js +38 -38
- package/lib/plugin/fakerTransform.js +6 -6
- package/lib/plugin/heal.js +108 -67
- package/lib/plugin/pauseOnFail.js +11 -11
- package/lib/plugin/retryFailedStep.js +39 -32
- package/lib/plugin/retryTo.js +40 -46
- package/lib/plugin/screenshotOnFail.js +87 -109
- package/lib/plugin/selenoid.js +118 -131
- package/lib/plugin/standardActingHelpers.js +8 -2
- package/lib/plugin/stepByStepReport.js +91 -110
- package/lib/plugin/stepTimeout.js +23 -24
- package/lib/plugin/subtitles.js +35 -34
- package/lib/plugin/tryTo.js +30 -40
- package/lib/plugin/wdio.js +75 -78
- package/lib/recorder.js +17 -14
- package/lib/rerun.js +10 -11
- package/lib/scenario.js +23 -25
- package/lib/secret.js +2 -4
- package/lib/session.js +10 -10
- package/lib/step.js +9 -12
- package/lib/store.js +3 -2
- package/lib/transform.js +1 -1
- package/lib/translation.js +8 -7
- package/lib/ui.js +14 -12
- package/lib/utils.js +72 -70
- package/lib/within.js +10 -10
- package/lib/workerStorage.js +25 -27
- package/lib/workers.js +32 -29
- package/package.json +53 -51
- package/translations/de-DE.js +1 -1
- package/translations/fr-FR.js +1 -1
- package/translations/index.js +13 -9
- package/translations/it-IT.js +1 -1
- package/translations/ja-JP.js +1 -1
- package/translations/pl-PL.js +1 -1
- package/translations/pt-BR.js +1 -1
- package/translations/ru-RU.js +1 -1
- package/translations/zh-CN.js +1 -1
- package/translations/zh-TW.js +1 -1
- package/typings/index.d.ts +65 -415
package/lib/translation.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import merge from 'lodash.merge';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
4
|
+
import importSync from 'import-sync';
|
|
5
|
+
import * as translations from '../translations/index.js';
|
|
3
6
|
|
|
4
7
|
const defaultVocabulary = {
|
|
5
8
|
I: 'I',
|
|
6
9
|
actions: {},
|
|
7
10
|
};
|
|
8
11
|
|
|
9
|
-
class Translation {
|
|
12
|
+
export default class Translation {
|
|
10
13
|
constructor(vocabulary, loaded) {
|
|
11
14
|
this.vocabulary = vocabulary;
|
|
12
15
|
this.loaded = loaded !== false;
|
|
@@ -17,7 +20,7 @@ class Translation {
|
|
|
17
20
|
const filePath = path.join(global.codecept_dir, vocabularyFile);
|
|
18
21
|
|
|
19
22
|
try {
|
|
20
|
-
const vocabulary =
|
|
23
|
+
const vocabulary = importSync(filePath);
|
|
21
24
|
this.vocabulary = merge(this.vocabulary, vocabulary);
|
|
22
25
|
} catch (err) {
|
|
23
26
|
throw new Error(`Can't load vocabulary from ${filePath}; ${err}`);
|
|
@@ -40,7 +43,7 @@ class Translation {
|
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
static get langs() {
|
|
43
|
-
return
|
|
46
|
+
return translations;
|
|
44
47
|
}
|
|
45
48
|
|
|
46
49
|
static createDefault() {
|
|
@@ -51,5 +54,3 @@ class Translation {
|
|
|
51
54
|
return new Translation(defaultVocabulary, false);
|
|
52
55
|
}
|
|
53
56
|
}
|
|
54
|
-
|
|
55
|
-
module.exports = Translation;
|
package/lib/ui.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
import escapeRe from 'escape-string-regexp';
|
|
2
|
+
import Suite from 'mocha/lib/suite.js';
|
|
3
|
+
import Test from 'mocha/lib/test.js';
|
|
4
|
+
import mocha0 from 'mocha/lib/interfaces/common.js';
|
|
5
|
+
import * as scenario from './scenario.js';
|
|
6
|
+
import ScenarioConfig from './interfaces/scenarioConfig.js';
|
|
7
|
+
import FeatureConfig from './interfaces/featureConfig.js';
|
|
8
|
+
import addDataContext from './data/context.js';
|
|
9
|
+
import container from './container.js';
|
|
10
10
|
|
|
11
11
|
const setContextTranslation = (context) => {
|
|
12
12
|
const contexts = container.translation().value('contexts');
|
|
@@ -34,7 +34,7 @@ const setContextTranslation = (context) => {
|
|
|
34
34
|
* @param {Mocha.Suite} suite Root suite.
|
|
35
35
|
* @ignore
|
|
36
36
|
*/
|
|
37
|
-
|
|
37
|
+
export function suite(suite) {
|
|
38
38
|
const suites = [suite];
|
|
39
39
|
suite.timeout(0);
|
|
40
40
|
let afterAllHooks;
|
|
@@ -43,7 +43,7 @@ module.exports = function (suite) {
|
|
|
43
43
|
let afterEachHooksAreLoaded;
|
|
44
44
|
|
|
45
45
|
suite.on('pre-require', (context, file, mocha) => {
|
|
46
|
-
const common =
|
|
46
|
+
const common = mocha0(suites, context, mocha);
|
|
47
47
|
|
|
48
48
|
const addScenario = function (title, opts = {}, fn) {
|
|
49
49
|
const suite = suites[0];
|
|
@@ -233,4 +233,6 @@ module.exports = function (suite) {
|
|
|
233
233
|
afterAllHooksAreLoaded = true;
|
|
234
234
|
}
|
|
235
235
|
});
|
|
236
|
-
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export default suite;
|
package/lib/utils.js
CHANGED
|
@@ -1,42 +1,45 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import os from 'os';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import getFunctionArguments from 'fn-args';
|
|
5
|
+
import deepClone from 'lodash.clonedeep';
|
|
6
|
+
import merge from 'lodash.merge';
|
|
7
|
+
import { createHash } from 'crypto';
|
|
8
|
+
import format from 'js-beautify';
|
|
9
|
+
import importSync from 'import-sync';
|
|
10
|
+
import { convertColorToRGBA, isColorProperty } from './colorUtils.js';
|
|
11
|
+
|
|
12
|
+
const __dirname = path.resolve();
|
|
13
|
+
|
|
14
|
+
export function deepMerge(target, source) {
|
|
10
15
|
return merge(target, source);
|
|
11
16
|
}
|
|
12
17
|
|
|
13
|
-
|
|
14
|
-
return
|
|
18
|
+
export const genTestId = (test) => {
|
|
19
|
+
return createHash('sha256').update(test.fullTitle()).digest('base64')
|
|
15
20
|
.slice(0, -2);
|
|
16
21
|
};
|
|
17
22
|
|
|
18
|
-
|
|
23
|
+
export { deepClone };
|
|
19
24
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
module.exports.isGenerator = function (fn) {
|
|
25
|
+
export const isGenerator = function (fn) {
|
|
23
26
|
return fn.constructor.name === 'GeneratorFunction';
|
|
24
27
|
};
|
|
25
28
|
|
|
26
|
-
const isFunction =
|
|
29
|
+
export const isFunction = function (fn) {
|
|
27
30
|
return typeof fn === 'function';
|
|
28
31
|
};
|
|
29
32
|
|
|
30
|
-
|
|
33
|
+
export function isAsyncFunction(fn) {
|
|
31
34
|
if (!fn) return false;
|
|
32
35
|
return fn[Symbol.toStringTag] === 'AsyncFunction';
|
|
33
|
-
}
|
|
36
|
+
}
|
|
34
37
|
|
|
35
|
-
|
|
38
|
+
export const fileExists = function (filePath) {
|
|
36
39
|
return fs.existsSync(filePath);
|
|
37
40
|
};
|
|
38
41
|
|
|
39
|
-
|
|
42
|
+
export const isFile = function (filePath) {
|
|
40
43
|
let filestat;
|
|
41
44
|
try {
|
|
42
45
|
filestat = fs.statSync(filePath);
|
|
@@ -47,16 +50,16 @@ module.exports.isFile = function (filePath) {
|
|
|
47
50
|
return filestat.isFile();
|
|
48
51
|
};
|
|
49
52
|
|
|
50
|
-
|
|
53
|
+
export const getParamNames = function (fn) {
|
|
51
54
|
if (fn.isSinonProxy) return [];
|
|
52
55
|
return getFunctionArguments(fn);
|
|
53
56
|
};
|
|
54
57
|
|
|
55
|
-
|
|
58
|
+
export const installedLocally = function () {
|
|
56
59
|
return path.resolve(`${__dirname}/../`).indexOf(process.cwd()) === 0;
|
|
57
60
|
};
|
|
58
61
|
|
|
59
|
-
|
|
62
|
+
export const methodsOfObject = function (obj, className) {
|
|
60
63
|
const methods = [];
|
|
61
64
|
|
|
62
65
|
const standard = [
|
|
@@ -92,7 +95,7 @@ module.exports.methodsOfObject = function (obj, className) {
|
|
|
92
95
|
return methods;
|
|
93
96
|
};
|
|
94
97
|
|
|
95
|
-
|
|
98
|
+
export const template = function (template, data) {
|
|
96
99
|
return template.replace(/{{([^{}]*)}}/g, (a, b) => {
|
|
97
100
|
const r = data[b];
|
|
98
101
|
if (r === undefined) return '';
|
|
@@ -105,7 +108,7 @@ module.exports.template = function (template, data) {
|
|
|
105
108
|
* @param {string} str
|
|
106
109
|
* @returns {string}
|
|
107
110
|
*/
|
|
108
|
-
|
|
111
|
+
export const ucfirst = function (str) {
|
|
109
112
|
return str.charAt(0).toUpperCase() + str.substr(1);
|
|
110
113
|
};
|
|
111
114
|
|
|
@@ -114,11 +117,11 @@ module.exports.ucfirst = function (str) {
|
|
|
114
117
|
* @param {string} str
|
|
115
118
|
* @returns {string}
|
|
116
119
|
*/
|
|
117
|
-
|
|
120
|
+
export const lcfirst = function (str) {
|
|
118
121
|
return str.charAt(0).toLowerCase() + str.substr(1);
|
|
119
122
|
};
|
|
120
123
|
|
|
121
|
-
|
|
124
|
+
export const chunkArray = function (arr, chunk) {
|
|
122
125
|
let i;
|
|
123
126
|
let j;
|
|
124
127
|
const tmp = [];
|
|
@@ -128,7 +131,7 @@ module.exports.chunkArray = function (arr, chunk) {
|
|
|
128
131
|
return tmp;
|
|
129
132
|
};
|
|
130
133
|
|
|
131
|
-
|
|
134
|
+
export const clearString = function (str) {
|
|
132
135
|
if (!str) return '';
|
|
133
136
|
/* Replace forbidden symbols in string
|
|
134
137
|
*/
|
|
@@ -149,13 +152,13 @@ module.exports.clearString = function (str) {
|
|
|
149
152
|
.replace(/'/g, '');
|
|
150
153
|
};
|
|
151
154
|
|
|
152
|
-
|
|
155
|
+
export const decodeUrl = function (url) {
|
|
153
156
|
/* Replace forbidden symbols in string
|
|
154
157
|
*/
|
|
155
158
|
return decodeURIComponent(decodeURIComponent(decodeURIComponent(url)));
|
|
156
159
|
};
|
|
157
160
|
|
|
158
|
-
|
|
161
|
+
export const xpathLocator = {
|
|
159
162
|
/**
|
|
160
163
|
* @param {string} string
|
|
161
164
|
* @returns {string}
|
|
@@ -176,25 +179,7 @@ module.exports.xpathLocator = {
|
|
|
176
179
|
combine: locators => locators.join(' | '),
|
|
177
180
|
};
|
|
178
181
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
grepLines(array, startString, endString) {
|
|
182
|
-
let startIndex = 0;
|
|
183
|
-
let endIndex;
|
|
184
|
-
array.every((elem, index) => {
|
|
185
|
-
if (elem === startString) {
|
|
186
|
-
startIndex = index;
|
|
187
|
-
return true;
|
|
188
|
-
}
|
|
189
|
-
if (elem === endString) {
|
|
190
|
-
endIndex = index;
|
|
191
|
-
return false;
|
|
192
|
-
}
|
|
193
|
-
return true;
|
|
194
|
-
});
|
|
195
|
-
return array.slice(startIndex + 1, endIndex);
|
|
196
|
-
},
|
|
197
|
-
|
|
182
|
+
export default {
|
|
198
183
|
submittedData(dataFile) {
|
|
199
184
|
return function (key) {
|
|
200
185
|
if (!fs.existsSync(dataFile)) {
|
|
@@ -214,6 +199,23 @@ module.exports.test = {
|
|
|
214
199
|
|
|
215
200
|
};
|
|
216
201
|
|
|
202
|
+
export function grepLines(array, startString, endString) {
|
|
203
|
+
let startIndex = 0;
|
|
204
|
+
let endIndex;
|
|
205
|
+
array.every((elem, index) => {
|
|
206
|
+
if (elem === startString) {
|
|
207
|
+
startIndex = index;
|
|
208
|
+
return true;
|
|
209
|
+
}
|
|
210
|
+
if (elem === endString) {
|
|
211
|
+
endIndex = index;
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
return true;
|
|
215
|
+
});
|
|
216
|
+
return array.slice(startIndex + 1, endIndex);
|
|
217
|
+
}
|
|
218
|
+
|
|
217
219
|
function toCamelCase(name) {
|
|
218
220
|
if (typeof name !== 'string') {
|
|
219
221
|
return name;
|
|
@@ -222,7 +224,7 @@ function toCamelCase(name) {
|
|
|
222
224
|
return letter.toUpperCase();
|
|
223
225
|
});
|
|
224
226
|
}
|
|
225
|
-
|
|
227
|
+
export { toCamelCase };
|
|
226
228
|
|
|
227
229
|
function convertFontWeightToNumber(name) {
|
|
228
230
|
const fontWeightPatterns = [
|
|
@@ -253,7 +255,7 @@ function isFontWeightProperty(prop) {
|
|
|
253
255
|
return prop === 'fontWeight';
|
|
254
256
|
}
|
|
255
257
|
|
|
256
|
-
|
|
258
|
+
export const convertCssPropertiesToCamelCase = function (props) {
|
|
257
259
|
const output = {};
|
|
258
260
|
Object.keys(props).forEach((key) => {
|
|
259
261
|
const keyCamel = toCamelCase(key);
|
|
@@ -269,7 +271,7 @@ module.exports.convertCssPropertiesToCamelCase = function (props) {
|
|
|
269
271
|
return output;
|
|
270
272
|
};
|
|
271
273
|
|
|
272
|
-
|
|
274
|
+
export const deleteDir = function (dir_path) {
|
|
273
275
|
if (fs.existsSync(dir_path)) {
|
|
274
276
|
fs.readdirSync(dir_path).forEach(function (entry) {
|
|
275
277
|
const entry_path = path.join(dir_path, entry);
|
|
@@ -287,7 +289,7 @@ module.exports.deleteDir = function (dir_path) {
|
|
|
287
289
|
* Returns absolute filename to save screenshot.
|
|
288
290
|
* @param fileName {string} - filename.
|
|
289
291
|
*/
|
|
290
|
-
|
|
292
|
+
export const screenshotOutputFolder = function (fileName) {
|
|
291
293
|
const fileSep = path.sep;
|
|
292
294
|
|
|
293
295
|
if (!fileName.includes(fileSep) || fileName.includes('record_')) {
|
|
@@ -296,8 +298,7 @@ module.exports.screenshotOutputFolder = function (fileName) {
|
|
|
296
298
|
return path.resolve(global.codecept_dir, fileName);
|
|
297
299
|
};
|
|
298
300
|
|
|
299
|
-
|
|
300
|
-
const format = require('js-beautify').js;
|
|
301
|
+
export const beautify = function (code) {
|
|
301
302
|
return format(code, { indent_size: 2, space_in_empty_paren: true });
|
|
302
303
|
};
|
|
303
304
|
|
|
@@ -317,7 +318,7 @@ function joinUrl(baseUrl, url) {
|
|
|
317
318
|
return shouldAppendBaseUrl(url) ? `${baseUrl}/${trimUrl(url)}` : url;
|
|
318
319
|
}
|
|
319
320
|
|
|
320
|
-
|
|
321
|
+
export const appendBaseUrl = function (baseUrl = '', oneOrMoreUrls) {
|
|
321
322
|
if (typeof baseUrl !== 'string') {
|
|
322
323
|
throw new Error(`Invalid value for baseUrl: ${baseUrl}`);
|
|
323
324
|
}
|
|
@@ -343,7 +344,7 @@ module.exports.appendBaseUrl = function (baseUrl = '', oneOrMoreUrls) {
|
|
|
343
344
|
* @param {string} key key to search
|
|
344
345
|
* @param {*} value value to set for key
|
|
345
346
|
*/
|
|
346
|
-
|
|
347
|
+
export const replaceValueDeep = function replaceValueDeep(obj, key, value) {
|
|
347
348
|
if (!obj) return;
|
|
348
349
|
|
|
349
350
|
if (obj instanceof Array) {
|
|
@@ -365,7 +366,7 @@ module.exports.replaceValueDeep = function replaceValueDeep(obj, key, value) {
|
|
|
365
366
|
return obj;
|
|
366
367
|
};
|
|
367
368
|
|
|
368
|
-
|
|
369
|
+
export const ansiRegExp = function ({ onlyFirst = false } = {}) {
|
|
369
370
|
const pattern = [
|
|
370
371
|
'[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)',
|
|
371
372
|
'(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))',
|
|
@@ -374,7 +375,7 @@ module.exports.ansiRegExp = function ({ onlyFirst = false } = {}) {
|
|
|
374
375
|
return new RegExp(pattern, onlyFirst ? undefined : 'g');
|
|
375
376
|
};
|
|
376
377
|
|
|
377
|
-
|
|
378
|
+
export const tryOrDefault = function (fn, defaultValue) {
|
|
378
379
|
try {
|
|
379
380
|
return fn();
|
|
380
381
|
} catch (_) {
|
|
@@ -401,7 +402,7 @@ function normalizeKeyReplacer(match, prefix, key, suffix, offset, string) {
|
|
|
401
402
|
* @param {string} key
|
|
402
403
|
* @returns {string}
|
|
403
404
|
*/
|
|
404
|
-
|
|
405
|
+
export const getNormalizedKeyAttributeValue = function (key) {
|
|
405
406
|
// Use operation modifier key based on operating system
|
|
406
407
|
key = key.replace(/(Ctrl|Control|Cmd|Command)[ _]?Or[ _]?(Ctrl|Control|Cmd|Command)/i, os.platform() === 'darwin' ? 'Meta' : 'Control');
|
|
407
408
|
// Selection of keys (https://www.w3.org/TR/uievents-key/#named-key-attribute-values)
|
|
@@ -425,15 +426,16 @@ const modifierKeys = [
|
|
|
425
426
|
'Shift', 'ShiftLeft', 'ShiftRight',
|
|
426
427
|
];
|
|
427
428
|
|
|
428
|
-
|
|
429
|
-
|
|
429
|
+
export { modifierKeys };
|
|
430
|
+
|
|
431
|
+
export const isModifierKey = function (key) {
|
|
430
432
|
return modifierKeys.includes(key);
|
|
431
433
|
};
|
|
432
434
|
|
|
433
|
-
|
|
435
|
+
export const requireWithFallback = function (...packages) {
|
|
434
436
|
const exists = function (pkg) {
|
|
435
437
|
try {
|
|
436
|
-
|
|
438
|
+
importSync(pkg);
|
|
437
439
|
} catch (e) {
|
|
438
440
|
return false;
|
|
439
441
|
}
|
|
@@ -443,24 +445,24 @@ module.exports.requireWithFallback = function (...packages) {
|
|
|
443
445
|
|
|
444
446
|
for (const pkg of packages) {
|
|
445
447
|
if (exists(pkg)) {
|
|
446
|
-
return
|
|
448
|
+
return importSync(pkg);
|
|
447
449
|
}
|
|
448
450
|
}
|
|
449
451
|
|
|
450
452
|
throw new Error(`Cannot find modules ${packages.join(',')}`);
|
|
451
453
|
};
|
|
452
454
|
|
|
453
|
-
|
|
455
|
+
export const isNotSet = function (obj) {
|
|
454
456
|
if (obj === null) return true;
|
|
455
457
|
if (obj === undefined) return true;
|
|
456
458
|
return false;
|
|
457
459
|
};
|
|
458
460
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
+
export const emptyFolder = async (directoryPath) => {
|
|
462
|
+
importSync('child_process').execSync(`rm -rf ${directoryPath}/*`);
|
|
461
463
|
};
|
|
462
464
|
|
|
463
|
-
|
|
465
|
+
export const printObjectProperties = (obj) => {
|
|
464
466
|
if (typeof obj !== 'object' || obj === null) {
|
|
465
467
|
return obj;
|
|
466
468
|
}
|
|
@@ -473,6 +475,6 @@ module.exports.printObjectProperties = (obj) => {
|
|
|
473
475
|
return `{${result}}`;
|
|
474
476
|
};
|
|
475
477
|
|
|
476
|
-
|
|
478
|
+
export const normalizeSpacesInString = (string) => {
|
|
477
479
|
return string.replace(/\s+/g, ' ');
|
|
478
480
|
};
|
package/lib/within.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import * as output from './output.js';
|
|
2
|
+
import { store } from './store.js';
|
|
3
|
+
import recorder from './recorder.js';
|
|
4
|
+
import container from './container.js';
|
|
5
|
+
import * as event from './event.js';
|
|
6
|
+
import { Step } from './step.js';
|
|
7
|
+
import { isAsyncFunction } from './utils.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* @param {CodeceptJS.LocatorOrString} context
|
|
@@ -29,7 +29,7 @@ function within(context, fn) {
|
|
|
29
29
|
const finalize = () => {
|
|
30
30
|
event.dispatcher.removeListener(event.step.before, defineMetaStep);
|
|
31
31
|
recorder.add('Finalize session within session', () => {
|
|
32
|
-
output.stepShift = 1;
|
|
32
|
+
output.output.stepShift = 1;
|
|
33
33
|
recorder.session.restore('within');
|
|
34
34
|
});
|
|
35
35
|
};
|
|
@@ -58,7 +58,7 @@ function within(context, fn) {
|
|
|
58
58
|
} finally {
|
|
59
59
|
finishHelpers();
|
|
60
60
|
recorder.catch((err) => {
|
|
61
|
-
output.stepShift = 1;
|
|
61
|
+
output.output.stepShift = 1;
|
|
62
62
|
throw err;
|
|
63
63
|
});
|
|
64
64
|
}
|
|
@@ -67,4 +67,4 @@ function within(context, fn) {
|
|
|
67
67
|
}, false, false);
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
export default within;
|
package/lib/workerStorage.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
import { isMainThread, parentPort } from 'worker_threads';
|
|
2
2
|
|
|
3
3
|
const workerObjects = {};
|
|
4
4
|
const shareEvent = 'share';
|
|
5
5
|
|
|
6
|
-
const invokeWorkerListeners = (workerObj) => {
|
|
6
|
+
export const invokeWorkerListeners = (workerObj) => {
|
|
7
7
|
const { threadId } = workerObj;
|
|
8
8
|
workerObj.on('message', (messageData) => {
|
|
9
9
|
if (messageData.event === shareEvent) {
|
|
@@ -15,32 +15,30 @@ const invokeWorkerListeners = (workerObj) => {
|
|
|
15
15
|
});
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Add worker object
|
|
20
|
+
*
|
|
21
|
+
* @api
|
|
22
|
+
* @param {Worker} workerObj
|
|
23
|
+
*/
|
|
24
|
+
export function addWorker(workerObj) {
|
|
25
|
+
// @ts-ignore
|
|
26
|
+
workerObjects[workerObj.threadId] = workerObj;
|
|
27
|
+
invokeWorkerListeners(workerObj);
|
|
28
|
+
}
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
} else {
|
|
41
|
-
parentPort.postMessage({ data, event: shareEvent });
|
|
30
|
+
/**
|
|
31
|
+
* Share data across workers
|
|
32
|
+
*
|
|
33
|
+
* @param {*} data
|
|
34
|
+
*/
|
|
35
|
+
export function share(data) {
|
|
36
|
+
if (isMainThread) {
|
|
37
|
+
for (const workerObj of Object.values(workerObjects)) {
|
|
38
|
+
workerObj.postMessage({ data });
|
|
42
39
|
}
|
|
40
|
+
} else {
|
|
41
|
+
// @ts-ignore
|
|
42
|
+
parentPort.postMessage({ data, event: shareEvent });
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
|
-
|
|
46
|
-
module.exports = WorkerStorage;
|
package/lib/workers.js
CHANGED
|
@@ -1,24 +1,27 @@
|
|
|
1
1
|
/* eslint-disable max-classes-per-file */
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import mkdirp from 'mkdirp';
|
|
4
|
+
import { Worker } from 'worker_threads';
|
|
5
|
+
|
|
6
|
+
import { Suite, Test } from 'mocha';
|
|
7
|
+
import { EventEmitter } from 'events';
|
|
8
|
+
import ms from 'ms';
|
|
9
|
+
import Codecept from './codecept.js';
|
|
10
|
+
import { MochaFactory } from './mochaFactory.js';
|
|
11
|
+
import Container from './container.js';
|
|
12
|
+
import { getTestRoot } from './command/utils.js';
|
|
13
|
+
import {
|
|
14
|
+
deepClone, fileExists, isFunction, replaceValueDeep,
|
|
15
|
+
} from './utils.js';
|
|
16
|
+
import mainConfig from './config.js';
|
|
17
|
+
import * as output from './output.js';
|
|
18
|
+
import * as event from './event.js';
|
|
19
|
+
import recorder from './recorder.js';
|
|
20
|
+
import runHook from './hooks.js';
|
|
21
|
+
import * as WorkerStorage from './workerStorage.js';
|
|
22
|
+
import collection from './command/run-multiple/collection.js';
|
|
23
|
+
|
|
24
|
+
const __dirname = path.resolve('.', 'lib');
|
|
22
25
|
const pathToWorker = path.join(__dirname, 'command', 'workers', 'runTests.js');
|
|
23
26
|
|
|
24
27
|
const initializeCodecept = (configPath, options = {}) => {
|
|
@@ -40,14 +43,14 @@ const createOutputDir = (configPath) => {
|
|
|
40
43
|
}
|
|
41
44
|
};
|
|
42
45
|
|
|
43
|
-
|
|
46
|
+
export function populateGroups(numberOfWorkers) {
|
|
44
47
|
const groups = [];
|
|
45
48
|
for (let i = 0; i < numberOfWorkers; i++) {
|
|
46
49
|
groups[i] = [];
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
return groups;
|
|
50
|
-
}
|
|
53
|
+
}
|
|
51
54
|
|
|
52
55
|
const createWorker = (workerObject) => {
|
|
53
56
|
const worker = new Worker(pathToWorker, {
|
|
@@ -58,8 +61,9 @@ const createWorker = (workerObject) => {
|
|
|
58
61
|
workerIndex: workerObject.workerIndex + 1,
|
|
59
62
|
},
|
|
60
63
|
});
|
|
61
|
-
worker.on('error', err => output.error(`Worker Error: ${err.stack}`));
|
|
64
|
+
worker.on('error', err => output.output.error(`Worker Error: ${err.stack}`));
|
|
62
65
|
|
|
66
|
+
// @ts-ignore
|
|
63
67
|
WorkerStorage.addWorker(worker);
|
|
64
68
|
return worker;
|
|
65
69
|
};
|
|
@@ -224,7 +228,7 @@ class WorkerObject {
|
|
|
224
228
|
}
|
|
225
229
|
}
|
|
226
230
|
|
|
227
|
-
class Workers extends EventEmitter {
|
|
231
|
+
export class Workers extends EventEmitter {
|
|
228
232
|
/**
|
|
229
233
|
* @param {Number} numberOfWorkers
|
|
230
234
|
* @param {Object} config
|
|
@@ -388,7 +392,7 @@ class Workers extends EventEmitter {
|
|
|
388
392
|
|
|
389
393
|
_listenWorkerEvents(worker) {
|
|
390
394
|
worker.on('message', (message) => {
|
|
391
|
-
output.process(message.workerIndex);
|
|
395
|
+
output.output.process(message.workerIndex);
|
|
392
396
|
|
|
393
397
|
// deal with events that are not test cycle related
|
|
394
398
|
if (!message.event) {
|
|
@@ -463,7 +467,7 @@ class Workers extends EventEmitter {
|
|
|
463
467
|
process.exitCode = 0;
|
|
464
468
|
}
|
|
465
469
|
// removed this.finishedTests because in all /lib only first argument (!this.isFailed()) is used)
|
|
466
|
-
this.emit(event.all.result, !this.isFailed());
|
|
470
|
+
this.emit(event.all.result, { status: !this.isFailed(), stats: this.stats });
|
|
467
471
|
this.emit('end'); // internal event
|
|
468
472
|
}
|
|
469
473
|
|
|
@@ -480,7 +484,7 @@ class Workers extends EventEmitter {
|
|
|
480
484
|
this.stats.duration = this.stats.end - this.stats.start;
|
|
481
485
|
|
|
482
486
|
// Reset process for logs in main thread
|
|
483
|
-
output.process(null);
|
|
487
|
+
output.output.process(null);
|
|
484
488
|
output.print();
|
|
485
489
|
|
|
486
490
|
this.failuresLog = this.failuresLog
|
|
@@ -495,8 +499,7 @@ class Workers extends EventEmitter {
|
|
|
495
499
|
}
|
|
496
500
|
|
|
497
501
|
output.result(this.stats.passes, this.stats.failures, this.stats.pending, ms(this.stats.duration), this.stats.failedHooks);
|
|
502
|
+
output.result(cts.passes, this.stats.failures, this.stats.pending, ms(this.stats.duration));
|
|
498
503
|
process.env.RUNS_WITH_WORKERS = 'false';
|
|
499
504
|
}
|
|
500
505
|
}
|
|
501
|
-
|
|
502
|
-
module.exports = Workers;
|