codeceptjs 3.4.1 → 3.5.1-2.beta.7
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 +31 -30
- package/bin/codecept.js +1 -1
- package/lib/actor.js +6 -3
- package/lib/ai.js +180 -0
- package/lib/cli.js +13 -3
- package/lib/codecept.js +8 -0
- package/lib/colorUtils.js +10 -0
- package/lib/command/definitions.js +2 -7
- package/lib/command/dryRun.js +11 -2
- package/lib/command/generate.js +46 -3
- package/lib/command/info.js +24 -0
- package/lib/command/init.js +64 -6
- package/lib/command/interactive.js +15 -1
- package/lib/command/run-multiple/collection.js +17 -5
- package/lib/command/run-multiple.js +4 -2
- package/lib/command/run-workers.js +68 -5
- package/lib/command/run.js +7 -0
- package/lib/command/workers/runTests.js +39 -0
- package/lib/container.js +13 -3
- package/lib/data/context.js +14 -6
- package/lib/event.js +4 -0
- package/lib/helper/ApiDataFactory.js +2 -1
- package/lib/helper/Appium.js +116 -29
- package/lib/helper/Expect.js +422 -0
- package/lib/helper/FileSystem.js +1 -1
- package/lib/helper/GraphQL.js +25 -0
- package/lib/helper/JSONResponse.js +4 -4
- package/lib/helper/Nightmare.js +10 -5
- package/lib/helper/OpenAI.js +126 -0
- package/lib/helper/Playwright.js +1298 -229
- package/lib/helper/Protractor.js +12 -7
- package/lib/helper/Puppeteer.js +204 -64
- package/lib/helper/REST.js +15 -5
- package/lib/helper/TestCafe.js +45 -10
- package/lib/helper/WebDriver.js +252 -83
- package/lib/helper/errors/ElementNotFound.js +2 -1
- package/lib/helper/extras/PlaywrightReactVueLocator.js +38 -0
- package/lib/helper/scripts/blurElement.js +17 -0
- package/lib/helper/scripts/focusElement.js +17 -0
- package/lib/helper/scripts/highlightElement.js +20 -0
- package/lib/html.js +258 -0
- package/lib/interfaces/bdd.js +1 -1
- package/lib/interfaces/gherkin.js +37 -3
- package/lib/interfaces/scenarioConfig.js +1 -0
- package/lib/listener/retry.js +2 -1
- package/lib/locator.js +17 -4
- package/lib/mochaFactory.js +2 -1
- package/lib/output.js +1 -1
- package/lib/pause.js +78 -19
- package/lib/plugin/autoLogin.js +45 -10
- package/lib/plugin/debugErrors.js +67 -0
- package/lib/plugin/fakerTransform.js +4 -6
- package/lib/plugin/heal.js +209 -0
- package/lib/plugin/retryFailedStep.js +10 -1
- package/lib/plugin/retryTo.js +2 -4
- package/lib/plugin/screenshotOnFail.js +11 -2
- package/lib/plugin/selenoid.js +6 -1
- package/lib/plugin/standardActingHelpers.js +0 -2
- package/lib/plugin/stepByStepReport.js +2 -2
- package/lib/plugin/tryTo.js +5 -7
- package/lib/plugin/wdio.js +0 -1
- package/lib/recorder.js +22 -11
- package/lib/secret.js +5 -4
- package/lib/session.js +1 -1
- package/lib/step.js +36 -12
- package/lib/ui.js +5 -3
- package/lib/utils.js +22 -1
- package/lib/workers.js +83 -10
- package/package.json +117 -95
- package/translations/de-DE.js +5 -0
- package/translations/fr-FR.js +14 -1
- package/translations/it-IT.js +1 -0
- package/translations/ja-JP.js +14 -9
- package/translations/pl-PL.js +5 -0
- package/translations/pt-BR.js +1 -0
- package/translations/ru-RU.js +1 -0
- package/translations/zh-CN.js +5 -0
- package/translations/zh-TW.js +5 -0
- package/typings/index.d.ts +51 -15
- package/typings/promiseBasedTypes.d.ts +864 -802
- package/typings/types.d.ts +1339 -744
- package/CHANGELOG.md +0 -2427
- package/docs/advanced.md +0 -351
- package/docs/api.md +0 -323
- package/docs/basics.md +0 -980
- package/docs/bdd.md +0 -535
- package/docs/best.md +0 -237
- package/docs/books.md +0 -37
- package/docs/bootstrap.md +0 -135
- package/docs/build/ApiDataFactory.js +0 -409
- package/docs/build/Appium.js +0 -1938
- package/docs/build/FileSystem.js +0 -228
- package/docs/build/GraphQL.js +0 -204
- package/docs/build/GraphQLDataFactory.js +0 -309
- package/docs/build/JSONResponse.js +0 -338
- package/docs/build/Mochawesome.js +0 -71
- package/docs/build/Nightmare.js +0 -2145
- package/docs/build/Playwright.js +0 -3986
- package/docs/build/Polly.js +0 -42
- package/docs/build/Protractor.js +0 -2699
- package/docs/build/Puppeteer.js +0 -3710
- package/docs/build/REST.js +0 -334
- package/docs/build/SeleniumWebdriver.js +0 -76
- package/docs/build/TestCafe.js +0 -2057
- package/docs/build/WebDriver.js +0 -4017
- package/docs/changelog.md +0 -2436
- package/docs/commands.md +0 -254
- package/docs/community-helpers.md +0 -58
- package/docs/configuration.md +0 -157
- package/docs/continuous-integration.md +0 -22
- package/docs/custom-helpers.md +0 -306
- package/docs/data.md +0 -375
- package/docs/detox.md +0 -235
- package/docs/docker.md +0 -137
- package/docs/email.md +0 -183
- package/docs/examples.md +0 -149
- package/docs/helpers/ApiDataFactory.md +0 -266
- package/docs/helpers/Appium.md +0 -1312
- package/docs/helpers/Detox.md +0 -586
- package/docs/helpers/FileSystem.md +0 -152
- package/docs/helpers/GraphQL.md +0 -130
- package/docs/helpers/GraphQLDataFactory.md +0 -226
- package/docs/helpers/JSONResponse.md +0 -254
- package/docs/helpers/Mochawesome.md +0 -8
- package/docs/helpers/MockRequest.md +0 -377
- package/docs/helpers/Nightmare.md +0 -1256
- package/docs/helpers/Playwright.md +0 -2208
- package/docs/helpers/Polly.md +0 -44
- package/docs/helpers/Puppeteer-firefox.md +0 -86
- package/docs/helpers/Puppeteer.md +0 -2141
- package/docs/helpers/REST.md +0 -217
- package/docs/helpers/TestCafe.md +0 -1222
- package/docs/helpers/WebDriver.md +0 -2319
- package/docs/hooks.md +0 -340
- package/docs/index.md +0 -111
- package/docs/installation.md +0 -75
- package/docs/internal-api.md +0 -265
- package/docs/locators.md +0 -331
- package/docs/mobile-react-native-locators.md +0 -67
- package/docs/mobile.md +0 -297
- package/docs/nightmare.md +0 -223
- package/docs/pageobjects.md +0 -291
- package/docs/parallel.md +0 -232
- package/docs/playwright.md +0 -609
- package/docs/plugins.md +0 -1171
- package/docs/puppeteer.md +0 -316
- package/docs/quickstart.md +0 -163
- package/docs/react.md +0 -69
- package/docs/reports.md +0 -392
- package/docs/secrets.md +0 -30
- package/docs/shadow.md +0 -68
- package/docs/shared/keys.mustache +0 -31
- package/docs/shared/react.mustache +0 -1
- package/docs/testcafe.md +0 -174
- package/docs/translation.md +0 -247
- package/docs/tutorial.md +0 -271
- package/docs/typescript.md +0 -180
- package/docs/ui.md +0 -59
- package/docs/videos.md +0 -28
- package/docs/visual.md +0 -202
- package/docs/vue.md +0 -121
- package/docs/webapi/amOnPage.mustache +0 -11
- package/docs/webapi/appendField.mustache +0 -9
- package/docs/webapi/attachFile.mustache +0 -12
- package/docs/webapi/checkOption.mustache +0 -13
- package/docs/webapi/clearCookie.mustache +0 -10
- package/docs/webapi/clearField.mustache +0 -9
- package/docs/webapi/click.mustache +0 -25
- package/docs/webapi/clickLink.mustache +0 -8
- package/docs/webapi/closeCurrentTab.mustache +0 -7
- package/docs/webapi/closeOtherTabs.mustache +0 -8
- package/docs/webapi/dontSee.mustache +0 -11
- package/docs/webapi/dontSeeCheckboxIsChecked.mustache +0 -10
- package/docs/webapi/dontSeeCookie.mustache +0 -8
- package/docs/webapi/dontSeeCurrentUrlEquals.mustache +0 -10
- package/docs/webapi/dontSeeElement.mustache +0 -8
- package/docs/webapi/dontSeeElementInDOM.mustache +0 -8
- package/docs/webapi/dontSeeInCurrentUrl.mustache +0 -4
- package/docs/webapi/dontSeeInField.mustache +0 -11
- package/docs/webapi/dontSeeInSource.mustache +0 -8
- package/docs/webapi/dontSeeInTitle.mustache +0 -8
- package/docs/webapi/doubleClick.mustache +0 -13
- package/docs/webapi/downloadFile.mustache +0 -12
- package/docs/webapi/dragAndDrop.mustache +0 -9
- package/docs/webapi/dragSlider.mustache +0 -11
- package/docs/webapi/executeAsyncScript.mustache +0 -24
- package/docs/webapi/executeScript.mustache +0 -26
- package/docs/webapi/fillField.mustache +0 -16
- package/docs/webapi/forceClick.mustache +0 -28
- package/docs/webapi/forceRightClick.mustache +0 -18
- package/docs/webapi/grabAllWindowHandles.mustache +0 -7
- package/docs/webapi/grabAttributeFrom.mustache +0 -10
- package/docs/webapi/grabAttributeFromAll.mustache +0 -9
- package/docs/webapi/grabBrowserLogs.mustache +0 -9
- package/docs/webapi/grabCookie.mustache +0 -11
- package/docs/webapi/grabCssPropertyFrom.mustache +0 -11
- package/docs/webapi/grabCssPropertyFromAll.mustache +0 -10
- package/docs/webapi/grabCurrentUrl.mustache +0 -9
- package/docs/webapi/grabCurrentWindowHandle.mustache +0 -6
- package/docs/webapi/grabDataFromPerformanceTiming.mustache +0 -20
- package/docs/webapi/grabElementBoundingRect.mustache +0 -20
- package/docs/webapi/grabGeoLocation.mustache +0 -8
- package/docs/webapi/grabHTMLFrom.mustache +0 -10
- package/docs/webapi/grabHTMLFromAll.mustache +0 -9
- package/docs/webapi/grabNumberOfOpenTabs.mustache +0 -8
- package/docs/webapi/grabNumberOfVisibleElements.mustache +0 -9
- package/docs/webapi/grabPageScrollPosition.mustache +0 -8
- package/docs/webapi/grabPopupText.mustache +0 -5
- package/docs/webapi/grabSource.mustache +0 -8
- package/docs/webapi/grabTextFrom.mustache +0 -10
- package/docs/webapi/grabTextFromAll.mustache +0 -9
- package/docs/webapi/grabTitle.mustache +0 -8
- package/docs/webapi/grabValueFrom.mustache +0 -9
- package/docs/webapi/grabValueFromAll.mustache +0 -8
- package/docs/webapi/moveCursorTo.mustache +0 -12
- package/docs/webapi/openNewTab.mustache +0 -7
- package/docs/webapi/pressKey.mustache +0 -12
- package/docs/webapi/pressKeyDown.mustache +0 -12
- package/docs/webapi/pressKeyUp.mustache +0 -12
- package/docs/webapi/pressKeyWithKeyNormalization.mustache +0 -60
- package/docs/webapi/refreshPage.mustache +0 -6
- package/docs/webapi/resizeWindow.mustache +0 -6
- package/docs/webapi/rightClick.mustache +0 -14
- package/docs/webapi/saveElementScreenshot.mustache +0 -10
- package/docs/webapi/saveScreenshot.mustache +0 -12
- package/docs/webapi/say.mustache +0 -10
- package/docs/webapi/scrollIntoView.mustache +0 -11
- package/docs/webapi/scrollPageToBottom.mustache +0 -6
- package/docs/webapi/scrollPageToTop.mustache +0 -6
- package/docs/webapi/scrollTo.mustache +0 -12
- package/docs/webapi/see.mustache +0 -11
- package/docs/webapi/seeAttributesOnElements.mustache +0 -9
- package/docs/webapi/seeCheckboxIsChecked.mustache +0 -10
- package/docs/webapi/seeCookie.mustache +0 -8
- package/docs/webapi/seeCssPropertiesOnElements.mustache +0 -9
- package/docs/webapi/seeCurrentUrlEquals.mustache +0 -11
- package/docs/webapi/seeElement.mustache +0 -8
- package/docs/webapi/seeElementInDOM.mustache +0 -8
- package/docs/webapi/seeInCurrentUrl.mustache +0 -8
- package/docs/webapi/seeInField.mustache +0 -12
- package/docs/webapi/seeInPopup.mustache +0 -8
- package/docs/webapi/seeInSource.mustache +0 -7
- package/docs/webapi/seeInTitle.mustache +0 -8
- package/docs/webapi/seeNumberOfElements.mustache +0 -11
- package/docs/webapi/seeNumberOfVisibleElements.mustache +0 -10
- package/docs/webapi/seeTextEquals.mustache +0 -9
- package/docs/webapi/seeTitleEquals.mustache +0 -8
- package/docs/webapi/selectOption.mustache +0 -21
- package/docs/webapi/setCookie.mustache +0 -16
- package/docs/webapi/setGeoLocation.mustache +0 -12
- package/docs/webapi/switchTo.mustache +0 -9
- package/docs/webapi/switchToNextTab.mustache +0 -10
- package/docs/webapi/switchToPreviousTab.mustache +0 -10
- package/docs/webapi/type.mustache +0 -18
- package/docs/webapi/uncheckOption.mustache +0 -13
- package/docs/webapi/wait.mustache +0 -8
- package/docs/webapi/waitForClickable.mustache +0 -11
- package/docs/webapi/waitForDetached.mustache +0 -10
- package/docs/webapi/waitForElement.mustache +0 -11
- package/docs/webapi/waitForEnabled.mustache +0 -6
- package/docs/webapi/waitForFunction.mustache +0 -17
- package/docs/webapi/waitForInvisible.mustache +0 -10
- package/docs/webapi/waitForText.mustache +0 -13
- package/docs/webapi/waitForValue.mustache +0 -10
- package/docs/webapi/waitForVisible.mustache +0 -10
- package/docs/webapi/waitInUrl.mustache +0 -9
- package/docs/webapi/waitNumberOfVisibleElements.mustache +0 -10
- package/docs/webapi/waitToHide.mustache +0 -10
- package/docs/webapi/waitUrlEquals.mustache +0 -10
- package/docs/webdriver.md +0 -657
- package/docs/wiki/Books-&-Posts.md +0 -27
- package/docs/wiki/Community-Helpers-&-Plugins.md +0 -49
- package/docs/wiki/Converting-Playwright-to-Istanbul-Coverage.md +0 -29
- package/docs/wiki/Examples.md +0 -139
- package/docs/wiki/Google-Summer-of-Code-(GSoC)-2020.md +0 -68
- package/docs/wiki/Home.md +0 -16
- package/docs/wiki/Release-Process.md +0 -24
- package/docs/wiki/Roadmap.md +0 -23
- package/docs/wiki/Tests.md +0 -1393
- package/docs/wiki/Upgrading-to-CodeceptJS-3.md +0 -153
- package/docs/wiki/Videos.md +0 -19
|
@@ -89,8 +89,8 @@ module.exports = function (config) {
|
|
|
89
89
|
const reportDir = config.output ? path.resolve(global.codecept_dir, config.output) : defaultConfig.output;
|
|
90
90
|
|
|
91
91
|
event.dispatcher.on(event.test.before, (test) => {
|
|
92
|
-
const
|
|
93
|
-
dir = path.join(reportDir, `record_${
|
|
92
|
+
const sha256hash = crypto.createHash('sha256').update(test.file + test.title).digest('hex');
|
|
93
|
+
dir = path.join(reportDir, `record_${sha256hash}`);
|
|
94
94
|
mkdirp.sync(dir);
|
|
95
95
|
stepNum = 0;
|
|
96
96
|
error = null;
|
package/lib/plugin/tryTo.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const recorder = require('../recorder');
|
|
2
|
-
const store = require('../store');
|
|
3
2
|
const { debug } = require('../output');
|
|
4
3
|
|
|
5
4
|
const defaultConfig = {
|
|
@@ -9,7 +8,7 @@ const defaultConfig = {
|
|
|
9
8
|
/**
|
|
10
9
|
*
|
|
11
10
|
*
|
|
12
|
-
* Adds global `tryTo` function
|
|
11
|
+
* Adds global `tryTo` function in which all failed steps won't fail a test but will return true/false.
|
|
13
12
|
*
|
|
14
13
|
* Enable this plugin in `codecept.conf.js` (enabled by default for new setups):
|
|
15
14
|
*
|
|
@@ -47,7 +46,7 @@ const defaultConfig = {
|
|
|
47
46
|
* ```js
|
|
48
47
|
* const assert = require('assert');
|
|
49
48
|
* ```
|
|
50
|
-
* Then use the
|
|
49
|
+
* Then use the assertion:
|
|
51
50
|
* const result1 = await tryTo(() => I.see('Hello, user'));
|
|
52
51
|
* const result2 = await tryTo(() => I.seeElement('.welcome'));
|
|
53
52
|
* assert.ok(result1 && result2, 'Assertions were not succesful');
|
|
@@ -70,7 +69,7 @@ const defaultConfig = {
|
|
|
70
69
|
* const tryTo = codeceptjs.container.plugins('tryTo');
|
|
71
70
|
* ```
|
|
72
71
|
*
|
|
73
|
-
*/
|
|
72
|
+
*/
|
|
74
73
|
module.exports = function (config) {
|
|
75
74
|
config = Object.assign(defaultConfig, config);
|
|
76
75
|
|
|
@@ -81,11 +80,10 @@ module.exports = function (config) {
|
|
|
81
80
|
};
|
|
82
81
|
|
|
83
82
|
function tryTo(callback) {
|
|
84
|
-
const mode = store.debugMode;
|
|
85
83
|
let result = false;
|
|
86
84
|
return recorder.add('tryTo', () => {
|
|
87
|
-
store.debugMode = true;
|
|
88
85
|
recorder.session.start('tryTo');
|
|
86
|
+
process.env.TRY_TO = 'true';
|
|
89
87
|
callback();
|
|
90
88
|
recorder.add(() => {
|
|
91
89
|
result = true;
|
|
@@ -100,7 +98,7 @@ function tryTo(callback) {
|
|
|
100
98
|
return result;
|
|
101
99
|
});
|
|
102
100
|
return recorder.add('result', () => {
|
|
103
|
-
|
|
101
|
+
process.env.TRY_TO = undefined;
|
|
104
102
|
return result;
|
|
105
103
|
}, true, false);
|
|
106
104
|
}, false, false);
|
package/lib/plugin/wdio.js
CHANGED
package/lib/recorder.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const debug = require('debug')('codeceptjs:recorder');
|
|
2
2
|
const promiseRetry = require('promise-retry');
|
|
3
|
-
|
|
3
|
+
const { printObjectProperties } = require('./utils');
|
|
4
4
|
const { log } = require('./output');
|
|
5
5
|
|
|
6
6
|
const MAX_TASKS = 100;
|
|
@@ -11,6 +11,7 @@ let errFn;
|
|
|
11
11
|
let queueId = 0;
|
|
12
12
|
let sessionId = null;
|
|
13
13
|
let asyncErr = null;
|
|
14
|
+
let ignoredErrs = [];
|
|
14
15
|
|
|
15
16
|
let tasks = [];
|
|
16
17
|
let oldPromises = [];
|
|
@@ -41,6 +42,7 @@ module.exports = {
|
|
|
41
42
|
* @inner
|
|
42
43
|
*/
|
|
43
44
|
start() {
|
|
45
|
+
debug('Starting recording promises');
|
|
44
46
|
running = true;
|
|
45
47
|
asyncErr = null;
|
|
46
48
|
errFn = null;
|
|
@@ -92,8 +94,10 @@ module.exports = {
|
|
|
92
94
|
promise = Promise.resolve();
|
|
93
95
|
oldPromises = [];
|
|
94
96
|
tasks = [];
|
|
97
|
+
ignoredErrs = [];
|
|
95
98
|
this.session.running = false;
|
|
96
|
-
this
|
|
99
|
+
// reset this retries makes the retryFailedStep plugin won't work if there is Before/BeforeSuit block due to retries is undefined on Scenario
|
|
100
|
+
// this.retries = [];
|
|
97
101
|
},
|
|
98
102
|
|
|
99
103
|
/**
|
|
@@ -161,7 +165,7 @@ module.exports = {
|
|
|
161
165
|
* true: it will retries if `retryOpts` set.
|
|
162
166
|
* false: ignore `retryOpts` and won't retry.
|
|
163
167
|
* @param {number} [timeout]
|
|
164
|
-
* @return {Promise<*>
|
|
168
|
+
* @return {Promise<*>}
|
|
165
169
|
* @inner
|
|
166
170
|
*/
|
|
167
171
|
add(taskName, fn = undefined, force = false, retry = undefined, timeout = undefined) {
|
|
@@ -175,7 +179,7 @@ module.exports = {
|
|
|
175
179
|
return;
|
|
176
180
|
}
|
|
177
181
|
tasks.push(taskName);
|
|
178
|
-
|
|
182
|
+
debug(`${currentQueue()}Queued | ${taskName}`);
|
|
179
183
|
|
|
180
184
|
return promise = Promise.resolve(promise).then((res) => {
|
|
181
185
|
// prefer options for non-conditional retries
|
|
@@ -224,10 +228,12 @@ module.exports = {
|
|
|
224
228
|
* @inner
|
|
225
229
|
*/
|
|
226
230
|
catch(customErrFn) {
|
|
231
|
+
const fnDescription = customErrFn?.toString()?.replace(/\s{2,}/g, ' ').replace(/\n/g, ' ')?.slice(0, 50);
|
|
232
|
+
debug(`${currentQueue()}Queued | catch with error handler ${fnDescription || ''}`);
|
|
227
233
|
return promise = promise.catch((err) => {
|
|
228
|
-
log(`${currentQueue()}Error | ${err}
|
|
234
|
+
log(`${currentQueue()}Error | ${err} ${fnDescription}...`);
|
|
229
235
|
if (!(err instanceof Error)) { // strange things may happen
|
|
230
|
-
err = new Error(`[Wrapped Error] ${
|
|
236
|
+
err = new Error(`[Wrapped Error] ${printObjectProperties(err)}`); // we should be prepared for them
|
|
231
237
|
}
|
|
232
238
|
if (customErrFn) {
|
|
233
239
|
customErrFn(err);
|
|
@@ -244,15 +250,15 @@ module.exports = {
|
|
|
244
250
|
* @inner
|
|
245
251
|
*/
|
|
246
252
|
catchWithoutStop(customErrFn) {
|
|
253
|
+
const fnDescription = customErrFn?.toString()?.replace(/\s{2,}/g, ' ').replace(/\n/g, ' ')?.slice(0, 50);
|
|
247
254
|
return promise = promise.catch((err) => {
|
|
248
|
-
|
|
255
|
+
if (ignoredErrs.includes(err)) return; // already caught
|
|
256
|
+
log(`${currentQueue()}Error (Non-Terminated) | ${err} | ${fnDescription || ''}...`);
|
|
249
257
|
if (!(err instanceof Error)) { // strange things may happen
|
|
250
258
|
err = new Error(`[Wrapped Error] ${JSON.stringify(err)}`); // we should be prepared for them
|
|
251
259
|
}
|
|
252
260
|
if (customErrFn) {
|
|
253
|
-
customErrFn(err);
|
|
254
|
-
} else if (errFn) {
|
|
255
|
-
errFn(err);
|
|
261
|
+
return customErrFn(err);
|
|
256
262
|
}
|
|
257
263
|
});
|
|
258
264
|
},
|
|
@@ -264,12 +270,17 @@ module.exports = {
|
|
|
264
270
|
* @param {*} err
|
|
265
271
|
* @inner
|
|
266
272
|
*/
|
|
273
|
+
|
|
267
274
|
throw(err) {
|
|
268
|
-
return this.add(`throw error ${err}`, () => {
|
|
275
|
+
return this.add(`throw error: ${err.message}`, () => {
|
|
269
276
|
throw err;
|
|
270
277
|
});
|
|
271
278
|
},
|
|
272
279
|
|
|
280
|
+
ignoreErr(err) {
|
|
281
|
+
ignoredErrs.push(err);
|
|
282
|
+
},
|
|
283
|
+
|
|
273
284
|
/**
|
|
274
285
|
* @param {*} err
|
|
275
286
|
* @inner
|
package/lib/secret.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/* eslint-disable max-classes-per-file */
|
|
2
2
|
const { deepClone } = require('./utils');
|
|
3
3
|
|
|
4
|
+
const maskedString = '*****';
|
|
5
|
+
|
|
4
6
|
/** @param {string} secret */
|
|
5
7
|
class Secret {
|
|
6
8
|
constructor(secret) {
|
|
@@ -13,7 +15,7 @@ class Secret {
|
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
getMasked() {
|
|
16
|
-
return
|
|
18
|
+
return maskedString;
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
/**
|
|
@@ -36,12 +38,11 @@ function secretObject(obj, fieldsToHide = []) {
|
|
|
36
38
|
if (prop === 'toString') {
|
|
37
39
|
return function () {
|
|
38
40
|
const maskedObject = deepClone(obj);
|
|
39
|
-
fieldsToHide.forEach(f => maskedObject[f] =
|
|
41
|
+
fieldsToHide.forEach(f => maskedObject[f] = maskedString);
|
|
40
42
|
return JSON.stringify(maskedObject);
|
|
41
43
|
};
|
|
42
44
|
}
|
|
43
|
-
|
|
44
|
-
return obj[prop];
|
|
45
|
+
return fieldsToHide.includes(prop) ? new Secret(obj[prop]) : obj[prop];
|
|
45
46
|
},
|
|
46
47
|
};
|
|
47
48
|
|
package/lib/session.js
CHANGED
|
@@ -19,7 +19,7 @@ const savedSessions = {};
|
|
|
19
19
|
* @param {CodeceptJS.LocatorOrString} sessionName
|
|
20
20
|
* @param {Function | Object<string, *>} config
|
|
21
21
|
* @param {Function} [fn]
|
|
22
|
-
* @return {
|
|
22
|
+
* @return {any}
|
|
23
23
|
*/
|
|
24
24
|
function session(sessionName, config, fn) {
|
|
25
25
|
if (typeof config === 'function') {
|
package/lib/step.js
CHANGED
|
@@ -119,7 +119,9 @@ class Step {
|
|
|
119
119
|
}
|
|
120
120
|
let result;
|
|
121
121
|
try {
|
|
122
|
-
|
|
122
|
+
if (this.helperMethod !== 'say') {
|
|
123
|
+
result = this.helper[this.helperMethod].apply(this.helper, this.args);
|
|
124
|
+
}
|
|
123
125
|
this.setStatus('success');
|
|
124
126
|
} catch (err) {
|
|
125
127
|
this.setStatus('failed');
|
|
@@ -138,13 +140,7 @@ class Step {
|
|
|
138
140
|
|
|
139
141
|
/** @return {string} */
|
|
140
142
|
humanize() {
|
|
141
|
-
return this.name
|
|
142
|
-
// insert a space before all caps
|
|
143
|
-
.replace(/([A-Z])/g, ' $1')
|
|
144
|
-
// _ chars to spaces
|
|
145
|
-
.replace('_', ' ')
|
|
146
|
-
// uppercase the first character
|
|
147
|
-
.replace(/^(.)|\s(.)/g, $1 => $1.toLowerCase());
|
|
143
|
+
return humanizeString(this.name);
|
|
148
144
|
}
|
|
149
145
|
|
|
150
146
|
/** @return {string} */
|
|
@@ -172,7 +168,12 @@ class Step {
|
|
|
172
168
|
} else if (arg.toString && arg.toString() !== '[object Object]') {
|
|
173
169
|
return arg.toString();
|
|
174
170
|
} else if (typeof arg === 'object') {
|
|
175
|
-
|
|
171
|
+
const returnedArg = {};
|
|
172
|
+
for (const [key, value] of Object.entries(arg)) {
|
|
173
|
+
returnedArg[key] = value;
|
|
174
|
+
if (value instanceof Secret) returnedArg[key] = value.getMasked();
|
|
175
|
+
}
|
|
176
|
+
return JSON.stringify(returnedArg);
|
|
176
177
|
}
|
|
177
178
|
return arg;
|
|
178
179
|
}).join(', ');
|
|
@@ -242,12 +243,21 @@ class MetaStep extends Step {
|
|
|
242
243
|
}
|
|
243
244
|
|
|
244
245
|
toString() {
|
|
245
|
-
const actorText =
|
|
246
|
-
|
|
246
|
+
const actorText = this.actor;
|
|
247
|
+
|
|
248
|
+
if (this.isBDD() || this.isWithin()) {
|
|
249
|
+
return `${this.prefix}${actorText} ${this.name} "${this.humanizeArgs()}${this.suffix}"`;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (actorText === 'I') {
|
|
253
|
+
return `${this.prefix}${actorText} ${this.humanize()} ${this.humanizeArgs()}${this.suffix}`;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return `On ${this.prefix}${actorText}: ${this.humanize()} ${this.humanizeArgs()}${this.suffix}`;
|
|
247
257
|
}
|
|
248
258
|
|
|
249
259
|
humanize() {
|
|
250
|
-
return this.name;
|
|
260
|
+
return humanizeString(this.name);
|
|
251
261
|
}
|
|
252
262
|
|
|
253
263
|
setTrace() {
|
|
@@ -311,3 +321,17 @@ function dryRunResolver() {
|
|
|
311
321
|
},
|
|
312
322
|
};
|
|
313
323
|
}
|
|
324
|
+
|
|
325
|
+
function humanizeString(string) {
|
|
326
|
+
// split strings by words, then make them all lowercase
|
|
327
|
+
const _result = string.replace(/([a-z](?=[A-Z]))/g, '$1 ')
|
|
328
|
+
.split(' ')
|
|
329
|
+
.map(word => word.toLowerCase());
|
|
330
|
+
|
|
331
|
+
_result[0] = _result[0] === 'i' ? capitalizeFLetter(_result[0]) : _result[0];
|
|
332
|
+
return _result.join(' ').trim();
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function capitalizeFLetter(string) {
|
|
336
|
+
return (string[0].toUpperCase() + string.slice(1));
|
|
337
|
+
}
|
package/lib/ui.js
CHANGED
|
@@ -23,10 +23,11 @@ const setContextTranslation = (context) => {
|
|
|
23
23
|
/**
|
|
24
24
|
* Codecept-style interface:
|
|
25
25
|
*
|
|
26
|
-
* Feature('login')
|
|
27
|
-
*
|
|
26
|
+
* Feature('login');
|
|
27
|
+
*
|
|
28
|
+
* Scenario('login as regular user', ({I}) {
|
|
28
29
|
* I.fillField();
|
|
29
|
-
* I.click()
|
|
30
|
+
* I.click();
|
|
30
31
|
* I.see('Hello, '+data.login);
|
|
31
32
|
* });
|
|
32
33
|
*
|
|
@@ -167,6 +168,7 @@ module.exports = function (suite) {
|
|
|
167
168
|
context.Scenario.only = function (title, opts, fn) {
|
|
168
169
|
const reString = `^${escapeRe(`${suites[0].title}: ${title}`.replace(/( \| {.+})?$/g, ''))}`;
|
|
169
170
|
mocha.grep(new RegExp(reString));
|
|
171
|
+
process.env.SCENARIO_ONLY = true;
|
|
170
172
|
return addScenario(title, opts, fn);
|
|
171
173
|
};
|
|
172
174
|
|
package/lib/utils.js
CHANGED
|
@@ -11,7 +11,7 @@ function deepMerge(target, source) {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
module.exports.genTestId = (test) => {
|
|
14
|
-
return require('crypto').createHash('
|
|
14
|
+
return require('crypto').createHash('sha256').update(test.fullTitle()).digest('base64')
|
|
15
15
|
.slice(0, -2);
|
|
16
16
|
};
|
|
17
17
|
|
|
@@ -455,3 +455,24 @@ module.exports.isNotSet = function (obj) {
|
|
|
455
455
|
if (obj === undefined) return true;
|
|
456
456
|
return false;
|
|
457
457
|
};
|
|
458
|
+
|
|
459
|
+
module.exports.emptyFolder = async (directoryPath) => {
|
|
460
|
+
require('child_process').execSync(`rm -rf ${directoryPath}/*`);
|
|
461
|
+
};
|
|
462
|
+
|
|
463
|
+
module.exports.printObjectProperties = (obj) => {
|
|
464
|
+
if (typeof obj !== 'object' || obj === null) {
|
|
465
|
+
return obj;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
let result = '';
|
|
469
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
470
|
+
result += `${key}: "${value}"; `;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
return `{${result}}`;
|
|
474
|
+
};
|
|
475
|
+
|
|
476
|
+
module.exports.normalizeSpacesInString = (string) => {
|
|
477
|
+
return string.replace(/\s+/g, ' ');
|
|
478
|
+
};
|
package/lib/workers.js
CHANGED
|
@@ -10,12 +10,14 @@ const MochaFactory = require('./mochaFactory');
|
|
|
10
10
|
const Container = require('./container');
|
|
11
11
|
const { getTestRoot } = require('./command/utils');
|
|
12
12
|
const { isFunction, fileExists } = require('./utils');
|
|
13
|
+
const { replaceValueDeep, deepClone } = require('./utils');
|
|
13
14
|
const mainConfig = require('./config');
|
|
14
15
|
const output = require('./output');
|
|
15
16
|
const event = require('./event');
|
|
16
17
|
const recorder = require('./recorder');
|
|
17
18
|
const runHook = require('./hooks');
|
|
18
19
|
const WorkerStorage = require('./workerStorage');
|
|
20
|
+
const collection = require('./command/run-multiple/collection');
|
|
19
21
|
|
|
20
22
|
const pathToWorker = path.join(__dirname, 'command', 'workers', 'runTests.js');
|
|
21
23
|
|
|
@@ -79,15 +81,60 @@ const repackTest = (test) => {
|
|
|
79
81
|
return test;
|
|
80
82
|
};
|
|
81
83
|
|
|
82
|
-
const createWorkerObjects = (testGroups, config, testRoot, options) => {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
84
|
+
const createWorkerObjects = (testGroups, config, testRoot, options, selectedRuns) => {
|
|
85
|
+
selectedRuns = options && options.all && config.multiple ? Object.keys(config.multiple) : selectedRuns;
|
|
86
|
+
if (selectedRuns === undefined || !selectedRuns.length || config.multiple === undefined) {
|
|
87
|
+
return testGroups.map((tests, index) => {
|
|
88
|
+
const workerObj = new WorkerObject(index);
|
|
89
|
+
workerObj.addConfig(config);
|
|
90
|
+
workerObj.addTests(tests);
|
|
91
|
+
workerObj.setTestRoot(testRoot);
|
|
92
|
+
workerObj.addOptions(options);
|
|
93
|
+
return workerObj;
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
const workersToExecute = [];
|
|
97
|
+
|
|
98
|
+
const currentOutputFolder = config.output;
|
|
99
|
+
let currentMochawesomeReportDir;
|
|
100
|
+
let currentMochaJunitReporterFile;
|
|
101
|
+
|
|
102
|
+
if (config.mocha && config.mocha.reporterOptions) {
|
|
103
|
+
currentMochawesomeReportDir = config.mocha.reporterOptions?.mochawesome.options.reportDir;
|
|
104
|
+
currentMochaJunitReporterFile = config.mocha.reporterOptions['mocha-junit-reporter'].options.mochaFile;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
collection.createRuns(selectedRuns, config).forEach((worker) => {
|
|
108
|
+
const separator = path.sep;
|
|
109
|
+
const _config = { ...config };
|
|
110
|
+
let workerName = worker.name.replace(':', '_');
|
|
111
|
+
_config.output = `${currentOutputFolder}${separator}${workerName}`;
|
|
112
|
+
if (config.mocha && config.mocha.reporterOptions) {
|
|
113
|
+
_config.mocha.reporterOptions.mochawesome.options.reportDir = `${currentMochawesomeReportDir}${separator}${workerName}`;
|
|
114
|
+
|
|
115
|
+
const _tempArray = currentMochaJunitReporterFile.split(separator);
|
|
116
|
+
_tempArray.splice(_tempArray.findIndex(item => item.includes('.xml')), 0, workerName);
|
|
117
|
+
_config.mocha.reporterOptions['mocha-junit-reporter'].options.mochaFile = _tempArray.join(separator);
|
|
118
|
+
}
|
|
119
|
+
workerName = worker.getOriginalName() || worker.getName();
|
|
120
|
+
const workerConfig = worker.getConfig();
|
|
121
|
+
workersToExecute.push(getOverridenConfig(workerName, workerConfig, _config));
|
|
90
122
|
});
|
|
123
|
+
const workers = [];
|
|
124
|
+
let index = 0;
|
|
125
|
+
testGroups.forEach((tests) => {
|
|
126
|
+
const testWorkerArray = [];
|
|
127
|
+
workersToExecute.forEach((finalConfig) => {
|
|
128
|
+
const workerObj = new WorkerObject(index++);
|
|
129
|
+
workerObj.addConfig(finalConfig);
|
|
130
|
+
workerObj.addTests(tests);
|
|
131
|
+
workerObj.setTestRoot(testRoot);
|
|
132
|
+
workerObj.addOptions(options);
|
|
133
|
+
testWorkerArray.push(workerObj);
|
|
134
|
+
});
|
|
135
|
+
workers.push(...testWorkerArray);
|
|
136
|
+
});
|
|
137
|
+
return workers;
|
|
91
138
|
};
|
|
92
139
|
|
|
93
140
|
const indexOfSmallestElement = (groups) => {
|
|
@@ -115,6 +162,28 @@ const convertToMochaTests = (testGroup) => {
|
|
|
115
162
|
return group;
|
|
116
163
|
};
|
|
117
164
|
|
|
165
|
+
const getOverridenConfig = (workerName, workerConfig, config) => {
|
|
166
|
+
// clone config
|
|
167
|
+
const overriddenConfig = deepClone(config);
|
|
168
|
+
|
|
169
|
+
// get configuration
|
|
170
|
+
const browserConfig = workerConfig.browser;
|
|
171
|
+
|
|
172
|
+
for (const key in browserConfig) {
|
|
173
|
+
overriddenConfig.helpers = replaceValueDeep(overriddenConfig.helpers, key, browserConfig[key]);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// override tests configuration
|
|
177
|
+
if (overriddenConfig.tests) {
|
|
178
|
+
overriddenConfig.tests = workerConfig.tests;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (overriddenConfig.gherkin && workerConfig.gherkin && workerConfig.gherkin.features) {
|
|
182
|
+
overriddenConfig.gherkin.features = workerConfig.gherkin.features;
|
|
183
|
+
}
|
|
184
|
+
return overriddenConfig;
|
|
185
|
+
};
|
|
186
|
+
|
|
118
187
|
class WorkerObject {
|
|
119
188
|
/**
|
|
120
189
|
* @param {Number} workerIndex - Unique ID for worker
|
|
@@ -183,7 +252,7 @@ class Workers extends EventEmitter {
|
|
|
183
252
|
|
|
184
253
|
_initWorkers(numberOfWorkers, config) {
|
|
185
254
|
this.splitTestsByGroups(numberOfWorkers, config);
|
|
186
|
-
this.workers = createWorkerObjects(this.testGroups, this.codecept.config, config.testConfig, config.options);
|
|
255
|
+
this.workers = createWorkerObjects(this.testGroups, this.codecept.config, config.testConfig, config.options, config.selectedRuns);
|
|
187
256
|
this.numberOfWorkers = this.workers.length;
|
|
188
257
|
}
|
|
189
258
|
|
|
@@ -290,13 +359,16 @@ class Workers extends EventEmitter {
|
|
|
290
359
|
this.stats.start = new Date();
|
|
291
360
|
recorder.startUnlessRunning();
|
|
292
361
|
event.dispatcher.emit(event.workers.before);
|
|
362
|
+
process.env.RUNS_WITH_WORKERS = 'true';
|
|
293
363
|
recorder.add('starting workers', () => {
|
|
294
364
|
for (const worker of this.workers) {
|
|
295
365
|
const workerThread = createWorker(worker);
|
|
296
366
|
this._listenWorkerEvents(workerThread);
|
|
297
367
|
}
|
|
298
368
|
});
|
|
299
|
-
return new Promise(resolve =>
|
|
369
|
+
return new Promise(resolve => {
|
|
370
|
+
this.on('end', resolve);
|
|
371
|
+
});
|
|
300
372
|
}
|
|
301
373
|
|
|
302
374
|
/**
|
|
@@ -421,6 +493,7 @@ class Workers extends EventEmitter {
|
|
|
421
493
|
}
|
|
422
494
|
|
|
423
495
|
output.result(this.stats.passes, this.stats.failures, this.stats.pending, ms(this.stats.duration));
|
|
496
|
+
process.env.RUNS_WITH_WORKERS = 'false';
|
|
424
497
|
}
|
|
425
498
|
}
|
|
426
499
|
|