codeceptjs 3.7.5-beta.8 → 3.7.5
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 +0 -23
- package/lib/helper/Playwright.js +3 -0
- package/lib/helper/Puppeteer.js +5 -1
- package/lib/helper/WebDriver.js +6 -3
- package/lib/helper/network/actions.js +4 -2
- package/lib/listener/enhancedGlobalRetry.js +110 -0
- package/lib/mocha/test.js +0 -1
- package/lib/plugin/enhancedRetryFailedStep.js +99 -0
- package/lib/recorder.js +19 -3
- package/lib/retryCoordinator.js +207 -0
- package/lib/utils.js +54 -4
- package/package.json +24 -21
- package/typings/promiseBasedTypes.d.ts +49 -12
- package/typings/types.d.ts +60 -12
- package/lib/command/run-failed-tests.js +0 -218
- package/lib/plugin/failedTestsTracker.js +0 -360
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeceptjs",
|
|
3
|
-
"version": "3.7.5
|
|
3
|
+
"version": "3.7.5",
|
|
4
4
|
"description": "Supercharged End 2 End Testing Framework for NodeJS",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"acceptance",
|
|
@@ -78,12 +78,12 @@
|
|
|
78
78
|
"@codeceptjs/configure": "1.0.6",
|
|
79
79
|
"@codeceptjs/helper": "2.0.4",
|
|
80
80
|
"@cucumber/cucumber-expressions": "18",
|
|
81
|
-
"@cucumber/gherkin": "
|
|
82
|
-
"@cucumber/messages": "
|
|
81
|
+
"@cucumber/gherkin": "35.1.0",
|
|
82
|
+
"@cucumber/messages": "29.0.1",
|
|
83
83
|
"@xmldom/xmldom": "0.9.8",
|
|
84
|
-
"acorn": "8.
|
|
84
|
+
"acorn": "8.15.0",
|
|
85
85
|
"arrify": "3.0.0",
|
|
86
|
-
"axios": "1.
|
|
86
|
+
"axios": "1.12.2",
|
|
87
87
|
"chalk": "4.1.2",
|
|
88
88
|
"cheerio": "^1.0.0",
|
|
89
89
|
"chokidar": "^4.0.3",
|
|
@@ -95,20 +95,20 @@
|
|
|
95
95
|
"escape-string-regexp": "4.0.0",
|
|
96
96
|
"figures": "3.2.0",
|
|
97
97
|
"fn-args": "4.0.0",
|
|
98
|
-
"fs-extra": "11.3.
|
|
98
|
+
"fs-extra": "11.3.2",
|
|
99
99
|
"fuse.js": "^7.0.0",
|
|
100
100
|
"glob": ">=9.0.0 <12",
|
|
101
101
|
"html-minifier-terser": "7.2.0",
|
|
102
102
|
"inquirer": "^8.2.7",
|
|
103
103
|
"invisi-data": "^1.0.0",
|
|
104
|
-
"joi": "
|
|
104
|
+
"joi": "18.0.1",
|
|
105
105
|
"js-beautify": "1.15.4",
|
|
106
106
|
"lodash.clonedeep": "4.5.0",
|
|
107
107
|
"lodash.merge": "4.6.2",
|
|
108
108
|
"lodash.shuffle": "4.2.0",
|
|
109
109
|
"mkdirp": "3.0.1",
|
|
110
|
-
"mocha": "11.
|
|
111
|
-
"monocart-coverage-reports": "2.12.
|
|
110
|
+
"mocha": "11.7.2",
|
|
111
|
+
"monocart-coverage-reports": "2.12.9",
|
|
112
112
|
"ms": "2.1.3",
|
|
113
113
|
"multer": "^2.0.2",
|
|
114
114
|
"ora-classic": "5.4.2",
|
|
@@ -120,20 +120,20 @@
|
|
|
120
120
|
"uuid": "11.1.0"
|
|
121
121
|
},
|
|
122
122
|
"optionalDependencies": {
|
|
123
|
-
"@codeceptjs/detox-helper": "1.1.
|
|
123
|
+
"@codeceptjs/detox-helper": "1.1.12"
|
|
124
124
|
},
|
|
125
125
|
"devDependencies": {
|
|
126
|
-
"@apollo/server": "^
|
|
126
|
+
"@apollo/server": "^5",
|
|
127
127
|
"@codeceptjs/expect-helper": "^1.0.2",
|
|
128
128
|
"@codeceptjs/mock-request": "0.3.1",
|
|
129
129
|
"@eslint/eslintrc": "3.3.1",
|
|
130
|
-
"@eslint/js": "9.
|
|
130
|
+
"@eslint/js": "9.36.0",
|
|
131
131
|
"@faker-js/faker": "9.8.0",
|
|
132
132
|
"@pollyjs/adapter-puppeteer": "6.0.6",
|
|
133
133
|
"@pollyjs/core": "6.0.6",
|
|
134
134
|
"@types/chai": "5.2.2",
|
|
135
|
-
"@types/inquirer": "9.0.
|
|
136
|
-
"@types/node": "24.
|
|
135
|
+
"@types/inquirer": "9.0.9",
|
|
136
|
+
"@types/node": "24.5.2",
|
|
137
137
|
"@wdio/sauce-service": "9.12.5",
|
|
138
138
|
"@wdio/selenium-standalone-service": "8.15.0",
|
|
139
139
|
"@wdio/utils": "9.15.0",
|
|
@@ -142,13 +142,13 @@
|
|
|
142
142
|
"chai-as-promised": "7.1.2",
|
|
143
143
|
"chai-subset": "1.6.0",
|
|
144
144
|
"documentation": "14.0.3",
|
|
145
|
-
"electron": "
|
|
146
|
-
"eslint": "^9.
|
|
145
|
+
"electron": "38.1.2",
|
|
146
|
+
"eslint": "^9.36.0",
|
|
147
147
|
"eslint-plugin-import": "2.32.0",
|
|
148
148
|
"eslint-plugin-mocha": "11.1.0",
|
|
149
|
-
"expect": "30.
|
|
149
|
+
"expect": "30.1.2",
|
|
150
150
|
"express": "^5.1.0",
|
|
151
|
-
"globals": "16.
|
|
151
|
+
"globals": "16.4.0",
|
|
152
152
|
"graphql": "16.11.0",
|
|
153
153
|
"graphql-tag": "^2.12.6",
|
|
154
154
|
"husky": "9.1.7",
|
|
@@ -157,7 +157,7 @@
|
|
|
157
157
|
"jsdoc-typeof-plugin": "1.0.0",
|
|
158
158
|
"json-server": "0.17.4",
|
|
159
159
|
"mochawesome": "^7.1.3",
|
|
160
|
-
"playwright": "1.
|
|
160
|
+
"playwright": "1.55.0",
|
|
161
161
|
"prettier": "^3.3.2",
|
|
162
162
|
"puppeteer": "24.15.0",
|
|
163
163
|
"qrcode-terminal": "0.12.0",
|
|
@@ -171,8 +171,8 @@
|
|
|
171
171
|
"ts-node": "10.9.2",
|
|
172
172
|
"tsd": "^0.33.0",
|
|
173
173
|
"tsd-jsdoc": "2.5.0",
|
|
174
|
-
"typedoc": "0.28.
|
|
175
|
-
"typedoc-plugin-markdown": "4.
|
|
174
|
+
"typedoc": "0.28.13",
|
|
175
|
+
"typedoc-plugin-markdown": "4.9.0",
|
|
176
176
|
"typescript": "5.8.3",
|
|
177
177
|
"wdio-docker-service": "3.2.1",
|
|
178
178
|
"webdriverio": "9.12.5",
|
|
@@ -189,5 +189,8 @@
|
|
|
189
189
|
"compilerOptions": {
|
|
190
190
|
"strict": false
|
|
191
191
|
}
|
|
192
|
+
},
|
|
193
|
+
"overrides": {
|
|
194
|
+
"tmp": "0.2.5"
|
|
192
195
|
}
|
|
193
196
|
}
|
|
@@ -2735,9 +2735,6 @@ declare namespace CodeceptJS {
|
|
|
2735
2735
|
* @property [testIdAttribute = data-testid] - locate elements based on the testIdAttribute. See more of [locate by test id](https://playwright.dev/docs/locators#locate-by-test-id).
|
|
2736
2736
|
* @property [customLocatorStrategies] - custom locator strategies. An object with keys as strategy names and values as JavaScript functions. Example: `{ byRole: (selector, root) => { return root.querySelector(\`[role="\${selector}\"]\`) } }`
|
|
2737
2737
|
*/
|
|
2738
|
-
// @ts-ignore
|
|
2739
|
-
// @ts-ignore
|
|
2740
|
-
// @ts-ignore
|
|
2741
2738
|
type PlaywrightConfig = {
|
|
2742
2739
|
url?: string;
|
|
2743
2740
|
browser?: 'chromium' | 'firefox' | 'webkit' | 'electron';
|
|
@@ -6115,9 +6112,6 @@ declare namespace CodeceptJS {
|
|
|
6115
6112
|
* @property [chrome] - pass additional [Puppeteer run options](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#puppeteerlaunchoptions).
|
|
6116
6113
|
* @property [highlightElement] - highlight the interacting elements. Default: false. Note: only activate under verbose mode (--verbose).
|
|
6117
6114
|
*/
|
|
6118
|
-
// @ts-ignore
|
|
6119
|
-
// @ts-ignore
|
|
6120
|
-
// @ts-ignore
|
|
6121
6115
|
type PuppeteerConfig = {
|
|
6122
6116
|
url: string;
|
|
6123
6117
|
basicAuth?: any;
|
|
@@ -6541,6 +6535,17 @@ declare namespace CodeceptJS {
|
|
|
6541
6535
|
* {{ react }}
|
|
6542
6536
|
*/
|
|
6543
6537
|
_locate(): Promise<any>;
|
|
6538
|
+
/**
|
|
6539
|
+
* Get single element by different locator types, including strict locator
|
|
6540
|
+
* Should be used in custom helpers:
|
|
6541
|
+
*
|
|
6542
|
+
* ```js
|
|
6543
|
+
* const element = await this.helpers['Puppeteer']._locateElement({name: 'password'});
|
|
6544
|
+
* ```
|
|
6545
|
+
*
|
|
6546
|
+
* {{ react }}
|
|
6547
|
+
*/
|
|
6548
|
+
_locateElement(): Promise<any>;
|
|
6544
6549
|
/**
|
|
6545
6550
|
* Find a checkbox by providing human-readable text:
|
|
6546
6551
|
* NOTE: Assumes the checkable element exists
|
|
@@ -6577,6 +6582,17 @@ declare namespace CodeceptJS {
|
|
|
6577
6582
|
* @returns WebElement of being used Web helper
|
|
6578
6583
|
*/
|
|
6579
6584
|
grabWebElements(locator: CodeceptJS.LocatorOrString): Promise<any>;
|
|
6585
|
+
/**
|
|
6586
|
+
* Grab WebElement for given locator
|
|
6587
|
+
* Resumes test execution, so **should be used inside an async function with `await`** operator.
|
|
6588
|
+
*
|
|
6589
|
+
* ```js
|
|
6590
|
+
* const webElement = await I.grabWebElement('#button');
|
|
6591
|
+
* ```
|
|
6592
|
+
* @param locator - element located by CSS|XPath|strict locator.
|
|
6593
|
+
* @returns WebElement of being used Web helper
|
|
6594
|
+
*/
|
|
6595
|
+
grabWebElement(locator: CodeceptJS.LocatorOrString): Promise<any>;
|
|
6580
6596
|
/**
|
|
6581
6597
|
* Switch focus to a particular tab by its number. It waits tabs loading and then switch tab
|
|
6582
6598
|
*
|
|
@@ -7912,6 +7928,22 @@ declare namespace CodeceptJS {
|
|
|
7912
7928
|
*/
|
|
7913
7929
|
flushWebSocketMessages(): Promise<any>;
|
|
7914
7930
|
}
|
|
7931
|
+
/**
|
|
7932
|
+
* Find elements using Puppeteer's native element discovery methods
|
|
7933
|
+
* Note: Unlike Playwright, Puppeteer's Locator API doesn't have .all() method for multiple elements
|
|
7934
|
+
* @param matcher - Puppeteer context to search within
|
|
7935
|
+
* @param locator - Locator specification
|
|
7936
|
+
* @returns Array of ElementHandle objects
|
|
7937
|
+
*/
|
|
7938
|
+
function findElements(matcher: any, locator: any | string): Promise<any[]>;
|
|
7939
|
+
/**
|
|
7940
|
+
* Find a single element using Puppeteer's native element discovery methods
|
|
7941
|
+
* Note: Puppeteer Locator API doesn't have .first() method like Playwright
|
|
7942
|
+
* @param matcher - Puppeteer context to search within
|
|
7943
|
+
* @param locator - Locator specification
|
|
7944
|
+
* @returns Single ElementHandle object
|
|
7945
|
+
*/
|
|
7946
|
+
function findElement(matcher: any, locator: any | string): Promise<object>;
|
|
7915
7947
|
/**
|
|
7916
7948
|
* ## Configuration
|
|
7917
7949
|
* @property [endpoint] - API base URL
|
|
@@ -7924,9 +7956,6 @@ declare namespace CodeceptJS {
|
|
|
7924
7956
|
* @property [onResponse] - an async function which can update response object.
|
|
7925
7957
|
* @property [maxUploadFileSize] - set the max content file size in MB when performing api calls.
|
|
7926
7958
|
*/
|
|
7927
|
-
// @ts-ignore
|
|
7928
|
-
// @ts-ignore
|
|
7929
|
-
// @ts-ignore
|
|
7930
7959
|
type RESTConfig = {
|
|
7931
7960
|
endpoint?: string;
|
|
7932
7961
|
prettyPrintJson?: boolean;
|
|
@@ -9072,9 +9101,6 @@ declare namespace CodeceptJS {
|
|
|
9072
9101
|
* @property [highlightElement] - highlight the interacting elements. Default: false. Note: only activate under verbose mode (--verbose).
|
|
9073
9102
|
* @property [logLevel = silent] - level of logging verbosity. Default: silent. Options: trace | debug | info | warn | error | silent. More info: https://webdriver.io/docs/configuration/#loglevel
|
|
9074
9103
|
*/
|
|
9075
|
-
// @ts-ignore
|
|
9076
|
-
// @ts-ignore
|
|
9077
|
-
// @ts-ignore
|
|
9078
9104
|
type WebDriverConfig = {
|
|
9079
9105
|
url: string;
|
|
9080
9106
|
browser: string;
|
|
@@ -9545,6 +9571,17 @@ declare namespace CodeceptJS {
|
|
|
9545
9571
|
* @returns WebElement of being used Web helper
|
|
9546
9572
|
*/
|
|
9547
9573
|
grabWebElements(locator: CodeceptJS.LocatorOrString): Promise<any>;
|
|
9574
|
+
/**
|
|
9575
|
+
* Grab WebElement for given locator
|
|
9576
|
+
* Resumes test execution, so **should be used inside an async function with `await`** operator.
|
|
9577
|
+
*
|
|
9578
|
+
* ```js
|
|
9579
|
+
* const webElement = await I.grabWebElement('#button');
|
|
9580
|
+
* ```
|
|
9581
|
+
* @param locator - element located by CSS|XPath|strict locator.
|
|
9582
|
+
* @returns WebElement of being used Web helper
|
|
9583
|
+
*/
|
|
9584
|
+
grabWebElement(locator: CodeceptJS.LocatorOrString): Promise<any>;
|
|
9548
9585
|
/**
|
|
9549
9586
|
* Set [WebDriver timeouts](https://webdriver.io/docs/timeouts.html) in realtime.
|
|
9550
9587
|
*
|
package/typings/types.d.ts
CHANGED
|
@@ -2825,9 +2825,6 @@ declare namespace CodeceptJS {
|
|
|
2825
2825
|
* @property [testIdAttribute = data-testid] - locate elements based on the testIdAttribute. See more of [locate by test id](https://playwright.dev/docs/locators#locate-by-test-id).
|
|
2826
2826
|
* @property [customLocatorStrategies] - custom locator strategies. An object with keys as strategy names and values as JavaScript functions. Example: `{ byRole: (selector, root) => { return root.querySelector(\`[role="\${selector}\"]\`) } }`
|
|
2827
2827
|
*/
|
|
2828
|
-
// @ts-ignore
|
|
2829
|
-
// @ts-ignore
|
|
2830
|
-
// @ts-ignore
|
|
2831
2828
|
type PlaywrightConfig = {
|
|
2832
2829
|
url?: string;
|
|
2833
2830
|
browser?: 'chromium' | 'firefox' | 'webkit' | 'electron';
|
|
@@ -6356,9 +6353,6 @@ declare namespace CodeceptJS {
|
|
|
6356
6353
|
* @property [chrome] - pass additional [Puppeteer run options](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#puppeteerlaunchoptions).
|
|
6357
6354
|
* @property [highlightElement] - highlight the interacting elements. Default: false. Note: only activate under verbose mode (--verbose).
|
|
6358
6355
|
*/
|
|
6359
|
-
// @ts-ignore
|
|
6360
|
-
// @ts-ignore
|
|
6361
|
-
// @ts-ignore
|
|
6362
6356
|
type PuppeteerConfig = {
|
|
6363
6357
|
url: string;
|
|
6364
6358
|
basicAuth?: any;
|
|
@@ -6798,6 +6792,17 @@ declare namespace CodeceptJS {
|
|
|
6798
6792
|
* {{ react }}
|
|
6799
6793
|
*/
|
|
6800
6794
|
_locate(): void;
|
|
6795
|
+
/**
|
|
6796
|
+
* Get single element by different locator types, including strict locator
|
|
6797
|
+
* Should be used in custom helpers:
|
|
6798
|
+
*
|
|
6799
|
+
* ```js
|
|
6800
|
+
* const element = await this.helpers['Puppeteer']._locateElement({name: 'password'});
|
|
6801
|
+
* ```
|
|
6802
|
+
*
|
|
6803
|
+
* {{ react }}
|
|
6804
|
+
*/
|
|
6805
|
+
_locateElement(): void;
|
|
6801
6806
|
/**
|
|
6802
6807
|
* Find a checkbox by providing human-readable text:
|
|
6803
6808
|
* NOTE: Assumes the checkable element exists
|
|
@@ -6834,6 +6839,17 @@ declare namespace CodeceptJS {
|
|
|
6834
6839
|
* @returns WebElement of being used Web helper
|
|
6835
6840
|
*/
|
|
6836
6841
|
grabWebElements(locator: CodeceptJS.LocatorOrString): Promise<any>;
|
|
6842
|
+
/**
|
|
6843
|
+
* Grab WebElement for given locator
|
|
6844
|
+
* Resumes test execution, so **should be used inside an async function with `await`** operator.
|
|
6845
|
+
*
|
|
6846
|
+
* ```js
|
|
6847
|
+
* const webElement = await I.grabWebElement('#button');
|
|
6848
|
+
* ```
|
|
6849
|
+
* @param locator - element located by CSS|XPath|strict locator.
|
|
6850
|
+
* @returns WebElement of being used Web helper
|
|
6851
|
+
*/
|
|
6852
|
+
grabWebElement(locator: CodeceptJS.LocatorOrString): Promise<any>;
|
|
6837
6853
|
/**
|
|
6838
6854
|
* Switch focus to a particular tab by its number. It waits tabs loading and then switch tab
|
|
6839
6855
|
*
|
|
@@ -8289,6 +8305,22 @@ declare namespace CodeceptJS {
|
|
|
8289
8305
|
*/
|
|
8290
8306
|
flushWebSocketMessages(): void;
|
|
8291
8307
|
}
|
|
8308
|
+
/**
|
|
8309
|
+
* Find elements using Puppeteer's native element discovery methods
|
|
8310
|
+
* Note: Unlike Playwright, Puppeteer's Locator API doesn't have .all() method for multiple elements
|
|
8311
|
+
* @param matcher - Puppeteer context to search within
|
|
8312
|
+
* @param locator - Locator specification
|
|
8313
|
+
* @returns Array of ElementHandle objects
|
|
8314
|
+
*/
|
|
8315
|
+
function findElements(matcher: any, locator: any | string): Promise<any[]>;
|
|
8316
|
+
/**
|
|
8317
|
+
* Find a single element using Puppeteer's native element discovery methods
|
|
8318
|
+
* Note: Puppeteer Locator API doesn't have .first() method like Playwright
|
|
8319
|
+
* @param matcher - Puppeteer context to search within
|
|
8320
|
+
* @param locator - Locator specification
|
|
8321
|
+
* @returns Single ElementHandle object
|
|
8322
|
+
*/
|
|
8323
|
+
function findElement(matcher: any, locator: any | string): Promise<object>;
|
|
8292
8324
|
/**
|
|
8293
8325
|
* ## Configuration
|
|
8294
8326
|
* @property [endpoint] - API base URL
|
|
@@ -8301,9 +8333,6 @@ declare namespace CodeceptJS {
|
|
|
8301
8333
|
* @property [onResponse] - an async function which can update response object.
|
|
8302
8334
|
* @property [maxUploadFileSize] - set the max content file size in MB when performing api calls.
|
|
8303
8335
|
*/
|
|
8304
|
-
// @ts-ignore
|
|
8305
|
-
// @ts-ignore
|
|
8306
|
-
// @ts-ignore
|
|
8307
8336
|
type RESTConfig = {
|
|
8308
8337
|
endpoint?: string;
|
|
8309
8338
|
prettyPrintJson?: boolean;
|
|
@@ -9509,9 +9538,6 @@ declare namespace CodeceptJS {
|
|
|
9509
9538
|
* @property [highlightElement] - highlight the interacting elements. Default: false. Note: only activate under verbose mode (--verbose).
|
|
9510
9539
|
* @property [logLevel = silent] - level of logging verbosity. Default: silent. Options: trace | debug | info | warn | error | silent. More info: https://webdriver.io/docs/configuration/#loglevel
|
|
9511
9540
|
*/
|
|
9512
|
-
// @ts-ignore
|
|
9513
|
-
// @ts-ignore
|
|
9514
|
-
// @ts-ignore
|
|
9515
9541
|
type WebDriverConfig = {
|
|
9516
9542
|
url: string;
|
|
9517
9543
|
browser: string;
|
|
@@ -9982,6 +10008,17 @@ declare namespace CodeceptJS {
|
|
|
9982
10008
|
* @returns WebElement of being used Web helper
|
|
9983
10009
|
*/
|
|
9984
10010
|
grabWebElements(locator: CodeceptJS.LocatorOrString): Promise<any>;
|
|
10011
|
+
/**
|
|
10012
|
+
* Grab WebElement for given locator
|
|
10013
|
+
* Resumes test execution, so **should be used inside an async function with `await`** operator.
|
|
10014
|
+
*
|
|
10015
|
+
* ```js
|
|
10016
|
+
* const webElement = await I.grabWebElement('#button');
|
|
10017
|
+
* ```
|
|
10018
|
+
* @param locator - element located by CSS|XPath|strict locator.
|
|
10019
|
+
* @returns WebElement of being used Web helper
|
|
10020
|
+
*/
|
|
10021
|
+
grabWebElement(locator: CodeceptJS.LocatorOrString): Promise<any>;
|
|
9985
10022
|
/**
|
|
9986
10023
|
* Set [WebDriver timeouts](https://webdriver.io/docs/timeouts.html) in realtime.
|
|
9987
10024
|
*
|
|
@@ -11526,6 +11563,13 @@ declare namespace CodeceptJS {
|
|
|
11526
11563
|
* Loads tests by pattern or by config.tests
|
|
11527
11564
|
*/
|
|
11528
11565
|
loadTests(pattern?: string): void;
|
|
11566
|
+
/**
|
|
11567
|
+
* Apply sharding to test files based on shard configuration
|
|
11568
|
+
* @param testFiles - Array of test file paths
|
|
11569
|
+
* @param shardConfig - Shard configuration in format "index/total" (e.g., "1/4")
|
|
11570
|
+
* @returns - Filtered array of test files for this shard
|
|
11571
|
+
*/
|
|
11572
|
+
_applySharding(testFiles: string[], shardConfig: string): string[];
|
|
11529
11573
|
/**
|
|
11530
11574
|
* Run a specific test or all loaded tests.
|
|
11531
11575
|
*/
|
|
@@ -12019,6 +12063,10 @@ declare namespace CodeceptJS {
|
|
|
12019
12063
|
* Get a state of current queue and tasks
|
|
12020
12064
|
*/
|
|
12021
12065
|
toString(): string;
|
|
12066
|
+
/**
|
|
12067
|
+
* Get current session ID
|
|
12068
|
+
*/
|
|
12069
|
+
getCurrentSessionId(): string | null;
|
|
12022
12070
|
}
|
|
12023
12071
|
interface RecorderSession {
|
|
12024
12072
|
running: boolean;
|
|
@@ -1,218 +0,0 @@
|
|
|
1
|
-
const fs = require('fs')
|
|
2
|
-
const path = require('path')
|
|
3
|
-
const { getConfig, printError, getTestRoot, createOutputDir } = require('./utils')
|
|
4
|
-
const Config = require('../config')
|
|
5
|
-
const store = require('../store')
|
|
6
|
-
const Codecept = require('../codecept')
|
|
7
|
-
const output = require('../output')
|
|
8
|
-
const Workers = require('../workers')
|
|
9
|
-
const { tryOrDefault } = require('../utils')
|
|
10
|
-
|
|
11
|
-
module.exports = async function (options) {
|
|
12
|
-
// registering options globally to use in config
|
|
13
|
-
if (options.profile) {
|
|
14
|
-
process.env.profile = options.profile
|
|
15
|
-
}
|
|
16
|
-
if (options.verbose || options.debug) store.debugMode = true
|
|
17
|
-
|
|
18
|
-
const configFile = options.config
|
|
19
|
-
let config = getConfig(configFile)
|
|
20
|
-
|
|
21
|
-
if (options.override) {
|
|
22
|
-
config = Config.append(JSON.parse(options.override))
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const testRoot = getTestRoot(configFile)
|
|
26
|
-
createOutputDir(config, testRoot)
|
|
27
|
-
|
|
28
|
-
// Determine failed tests file path - respect CodeceptJS output directory
|
|
29
|
-
const failedTestsFile = options.file || 'failed-tests.json'
|
|
30
|
-
const failedTestsPath = path.isAbsolute(failedTestsFile)
|
|
31
|
-
? failedTestsFile
|
|
32
|
-
: path.resolve(global.output_dir || './output', failedTestsFile)
|
|
33
|
-
|
|
34
|
-
// Check if failed tests file exists
|
|
35
|
-
if (!fs.existsSync(failedTestsPath)) {
|
|
36
|
-
output.error(`Failed tests file not found: ${failedTestsPath}`)
|
|
37
|
-
output.print('Run tests first to generate a failed tests file, or specify a different file with --file option')
|
|
38
|
-
process.exitCode = 1
|
|
39
|
-
return
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
let failedTestsData
|
|
43
|
-
try {
|
|
44
|
-
const fileContent = fs.readFileSync(failedTestsPath, 'utf8')
|
|
45
|
-
failedTestsData = JSON.parse(fileContent)
|
|
46
|
-
} catch (error) {
|
|
47
|
-
output.error(`Failed to read or parse failed tests file: ${error.message}`)
|
|
48
|
-
process.exitCode = 1
|
|
49
|
-
return
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (!failedTestsData.tests || failedTestsData.tests.length === 0) {
|
|
53
|
-
output.print('No failed tests found in the file')
|
|
54
|
-
return
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
output.print(`Found ${failedTestsData.tests.length} failed tests from ${failedTestsData.timestamp}`)
|
|
58
|
-
|
|
59
|
-
// Build test patterns from failed tests
|
|
60
|
-
const testPatterns = []
|
|
61
|
-
const testsByFile = new Map()
|
|
62
|
-
|
|
63
|
-
// Group tests by file for more efficient execution
|
|
64
|
-
failedTestsData.tests.forEach(test => {
|
|
65
|
-
if (test.file) {
|
|
66
|
-
if (!testsByFile.has(test.file)) {
|
|
67
|
-
testsByFile.set(test.file, [])
|
|
68
|
-
}
|
|
69
|
-
testsByFile.get(test.file).push(test)
|
|
70
|
-
}
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
// If we have specific test files, use them
|
|
74
|
-
if (testsByFile.size > 0) {
|
|
75
|
-
for (const [file, tests] of testsByFile) {
|
|
76
|
-
if (options.grep) {
|
|
77
|
-
// If grep is specified, combine with file pattern
|
|
78
|
-
testPatterns.push(file)
|
|
79
|
-
} else {
|
|
80
|
-
// Try to be more specific with test titles if possible
|
|
81
|
-
testPatterns.push(file)
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
} else {
|
|
85
|
-
// Fallback: use test titles with grep
|
|
86
|
-
const testTitles = failedTestsData.tests.map(test => test.title).filter(Boolean)
|
|
87
|
-
if (testTitles.length > 0) {
|
|
88
|
-
// Create a regex pattern to match any of the failed test titles
|
|
89
|
-
const grepPattern = testTitles.map(title => title.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|')
|
|
90
|
-
options.grep = grepPattern
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Check if user wants to run with workers
|
|
95
|
-
if (options.workers) {
|
|
96
|
-
await runWithWorkers(config, options, testPatterns, failedTestsData)
|
|
97
|
-
} else {
|
|
98
|
-
await runWithoutWorkers(config, options, testPatterns, failedTestsData, testRoot)
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
async function runWithWorkers(config, options, testPatterns, failedTestsData) {
|
|
103
|
-
const numberOfWorkers = parseInt(options.workers, 10)
|
|
104
|
-
const overrideConfigs = tryOrDefault(() => JSON.parse(options.override || '{}'), {})
|
|
105
|
-
|
|
106
|
-
// Determine test split strategy
|
|
107
|
-
let by = 'test' // default for failed tests
|
|
108
|
-
if (options.by) {
|
|
109
|
-
by = options.by
|
|
110
|
-
} else if (options.suites) {
|
|
111
|
-
by = 'suite'
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Validate the by option
|
|
115
|
-
const validStrategies = ['test', 'suite', 'pool']
|
|
116
|
-
if (!validStrategies.includes(by)) {
|
|
117
|
-
throw new Error(`Invalid --by strategy: ${by}. Valid options are: ${validStrategies.join(', ')}`)
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const workerConfig = {
|
|
121
|
-
by,
|
|
122
|
-
testConfig: options.config,
|
|
123
|
-
options,
|
|
124
|
-
selectedRuns: undefined,
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
output.print(`CodeceptJS v${require('../codecept').version()}`)
|
|
128
|
-
output.print(`Re-running ${failedTestsData.tests.length} failed tests in ${output.styles.bold(numberOfWorkers)} workers...`)
|
|
129
|
-
output.print()
|
|
130
|
-
store.hasWorkers = true
|
|
131
|
-
|
|
132
|
-
const workers = new Workers(numberOfWorkers, workerConfig)
|
|
133
|
-
workers.overrideConfig(overrideConfigs)
|
|
134
|
-
|
|
135
|
-
// Set up event listeners for worker output
|
|
136
|
-
workers.on('test.failed', test => {
|
|
137
|
-
output.test.failed(test)
|
|
138
|
-
})
|
|
139
|
-
|
|
140
|
-
workers.on('test.passed', test => {
|
|
141
|
-
output.test.passed(test)
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
workers.on('test.skipped', test => {
|
|
145
|
-
output.test.skipped(test)
|
|
146
|
-
})
|
|
147
|
-
|
|
148
|
-
workers.on('all.result', result => {
|
|
149
|
-
workers.printResults()
|
|
150
|
-
})
|
|
151
|
-
|
|
152
|
-
try {
|
|
153
|
-
if (options.verbose || options.debug) store.debugMode = true
|
|
154
|
-
|
|
155
|
-
if (options.verbose) {
|
|
156
|
-
output.print('\nFailed tests to re-run with workers:')
|
|
157
|
-
failedTestsData.tests.forEach((test, index) => {
|
|
158
|
-
output.print(` ${index + 1}. ${test.fullTitle || test.title} (${test.file || 'unknown file'})`)
|
|
159
|
-
if (test.error && test.error.message) {
|
|
160
|
-
output.print(` Error: ${test.error.message}`)
|
|
161
|
-
}
|
|
162
|
-
})
|
|
163
|
-
output.print('')
|
|
164
|
-
|
|
165
|
-
const { getMachineInfo } = require('./info')
|
|
166
|
-
await getMachineInfo()
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
await workers.bootstrapAll()
|
|
170
|
-
await workers.run()
|
|
171
|
-
} catch (err) {
|
|
172
|
-
printError(err)
|
|
173
|
-
process.exitCode = 1
|
|
174
|
-
} finally {
|
|
175
|
-
await workers.teardownAll()
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
async function runWithoutWorkers(config, options, testPatterns, failedTestsData, testRoot) {
|
|
180
|
-
const codecept = new Codecept(config, options)
|
|
181
|
-
|
|
182
|
-
try {
|
|
183
|
-
codecept.init(testRoot)
|
|
184
|
-
await codecept.bootstrap()
|
|
185
|
-
|
|
186
|
-
// Load tests - if we have specific patterns, use them, otherwise load all and filter with grep
|
|
187
|
-
if (testPatterns.length > 0) {
|
|
188
|
-
codecept.loadTests(testPatterns.join(' '))
|
|
189
|
-
} else {
|
|
190
|
-
codecept.loadTests()
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
if (options.verbose) {
|
|
194
|
-
global.debugMode = true
|
|
195
|
-
const { getMachineInfo } = require('./info')
|
|
196
|
-
await getMachineInfo()
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// Display information about what we're running
|
|
200
|
-
if (options.verbose) {
|
|
201
|
-
output.print('\nFailed tests to re-run:')
|
|
202
|
-
failedTestsData.tests.forEach((test, index) => {
|
|
203
|
-
output.print(` ${index + 1}. ${test.fullTitle || test.title} (${test.file || 'unknown file'})`)
|
|
204
|
-
if (test.error && test.error.message) {
|
|
205
|
-
output.print(` Error: ${test.error.message}`)
|
|
206
|
-
}
|
|
207
|
-
})
|
|
208
|
-
output.print('')
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
await codecept.run()
|
|
212
|
-
} catch (err) {
|
|
213
|
-
printError(err)
|
|
214
|
-
process.exitCode = 1
|
|
215
|
-
} finally {
|
|
216
|
-
await codecept.teardown()
|
|
217
|
-
}
|
|
218
|
-
}
|