codeceptjs 4.0.0-beta.1 → 4.0.0-beta.10.esm-aria
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +133 -120
- package/bin/codecept.js +107 -96
- package/bin/test-server.js +64 -0
- package/docs/webapi/clearCookie.mustache +1 -1
- package/docs/webapi/click.mustache +5 -1
- package/lib/actor.js +71 -103
- package/lib/ai.js +159 -188
- package/lib/assert/empty.js +22 -24
- package/lib/assert/equal.js +30 -37
- package/lib/assert/error.js +14 -14
- package/lib/assert/include.js +43 -48
- package/lib/assert/throws.js +11 -11
- package/lib/assert/truth.js +22 -22
- package/lib/assert.js +20 -18
- package/lib/codecept.js +238 -162
- package/lib/colorUtils.js +50 -52
- package/lib/command/check.js +206 -0
- package/lib/command/configMigrate.js +56 -51
- package/lib/command/definitions.js +96 -109
- package/lib/command/dryRun.js +77 -79
- package/lib/command/generate.js +234 -194
- package/lib/command/gherkin/init.js +42 -33
- package/lib/command/gherkin/snippets.js +76 -74
- package/lib/command/gherkin/steps.js +20 -17
- package/lib/command/info.js +74 -38
- package/lib/command/init.js +300 -290
- package/lib/command/interactive.js +41 -32
- package/lib/command/list.js +28 -27
- package/lib/command/run-multiple/chunk.js +51 -48
- package/lib/command/run-multiple/collection.js +5 -5
- package/lib/command/run-multiple/run.js +5 -1
- package/lib/command/run-multiple.js +97 -97
- package/lib/command/run-rerun.js +19 -25
- package/lib/command/run-workers.js +68 -92
- package/lib/command/run.js +39 -27
- package/lib/command/utils.js +80 -64
- package/lib/command/workers/runTests.js +388 -226
- package/lib/config.js +124 -50
- package/lib/container.js +751 -260
- package/lib/data/context.js +60 -61
- package/lib/data/dataScenarioConfig.js +47 -47
- package/lib/data/dataTableArgument.js +32 -32
- package/lib/data/table.js +22 -22
- package/lib/effects.js +307 -0
- package/lib/element/WebElement.js +327 -0
- package/lib/els.js +160 -0
- package/lib/event.js +173 -163
- package/lib/globals.js +141 -0
- package/lib/heal.js +89 -85
- package/lib/helper/AI.js +131 -41
- package/lib/helper/ApiDataFactory.js +107 -75
- package/lib/helper/Appium.js +542 -404
- package/lib/helper/FileSystem.js +100 -79
- package/lib/helper/GraphQL.js +44 -43
- package/lib/helper/GraphQLDataFactory.js +52 -52
- package/lib/helper/JSONResponse.js +126 -88
- package/lib/helper/Mochawesome.js +54 -29
- package/lib/helper/Playwright.js +2547 -1316
- package/lib/helper/Puppeteer.js +1578 -1181
- package/lib/helper/REST.js +209 -68
- package/lib/helper/WebDriver.js +1482 -1342
- package/lib/helper/errors/ConnectionRefused.js +6 -6
- package/lib/helper/errors/ElementAssertion.js +11 -16
- package/lib/helper/errors/ElementNotFound.js +5 -9
- package/lib/helper/errors/RemoteBrowserConnectionRefused.js +5 -5
- package/lib/helper/extras/Console.js +11 -11
- package/lib/helper/extras/PlaywrightLocator.js +110 -0
- package/lib/helper/extras/PlaywrightPropEngine.js +18 -18
- package/lib/helper/extras/PlaywrightReactVueLocator.js +17 -8
- package/lib/helper/extras/PlaywrightRestartOpts.js +25 -11
- package/lib/helper/extras/Popup.js +22 -22
- package/lib/helper/extras/React.js +27 -28
- package/lib/helper/network/actions.js +36 -42
- package/lib/helper/network/utils.js +78 -84
- package/lib/helper/scripts/blurElement.js +5 -5
- package/lib/helper/scripts/focusElement.js +5 -5
- package/lib/helper/scripts/highlightElement.js +8 -8
- package/lib/helper/scripts/isElementClickable.js +34 -34
- package/lib/helper.js +2 -3
- package/lib/history.js +23 -19
- package/lib/hooks.js +8 -8
- package/lib/html.js +94 -104
- package/lib/index.js +38 -27
- package/lib/listener/config.js +30 -23
- package/lib/listener/emptyRun.js +54 -0
- package/lib/listener/enhancedGlobalRetry.js +110 -0
- package/lib/listener/exit.js +16 -18
- package/lib/listener/globalRetry.js +70 -0
- package/lib/listener/globalTimeout.js +181 -0
- package/lib/listener/helpers.js +76 -51
- package/lib/listener/mocha.js +10 -11
- package/lib/listener/result.js +11 -0
- package/lib/listener/retryEnhancer.js +85 -0
- package/lib/listener/steps.js +71 -59
- package/lib/listener/store.js +20 -0
- package/lib/locator.js +214 -197
- package/lib/mocha/asyncWrapper.js +274 -0
- package/lib/mocha/bdd.js +167 -0
- package/lib/mocha/cli.js +341 -0
- package/lib/mocha/factory.js +163 -0
- package/lib/mocha/featureConfig.js +89 -0
- package/lib/mocha/gherkin.js +231 -0
- package/lib/mocha/hooks.js +121 -0
- package/lib/mocha/index.js +21 -0
- package/lib/mocha/inject.js +46 -0
- package/lib/{interfaces → mocha}/scenarioConfig.js +58 -34
- package/lib/mocha/suite.js +89 -0
- package/lib/mocha/test.js +184 -0
- package/lib/mocha/types.d.ts +42 -0
- package/lib/mocha/ui.js +242 -0
- package/lib/output.js +141 -71
- package/lib/parser.js +47 -44
- package/lib/pause.js +173 -145
- package/lib/plugin/analyze.js +403 -0
- package/lib/plugin/{autoLogin.js → auth.js} +178 -79
- package/lib/plugin/autoDelay.js +36 -40
- package/lib/plugin/coverage.js +131 -78
- package/lib/plugin/customLocator.js +22 -21
- package/lib/plugin/customReporter.js +53 -0
- package/lib/plugin/enhancedRetryFailedStep.js +99 -0
- package/lib/plugin/heal.js +101 -110
- package/lib/plugin/htmlReporter.js +3648 -0
- package/lib/plugin/pageInfo.js +140 -0
- package/lib/plugin/pauseOnFail.js +12 -11
- package/lib/plugin/retryFailedStep.js +82 -47
- package/lib/plugin/screenshotOnFail.js +111 -92
- package/lib/plugin/stepByStepReport.js +159 -101
- package/lib/plugin/stepTimeout.js +20 -25
- package/lib/plugin/subtitles.js +38 -38
- package/lib/recorder.js +193 -130
- package/lib/rerun.js +94 -49
- package/lib/result.js +238 -0
- package/lib/retryCoordinator.js +207 -0
- package/lib/secret.js +20 -18
- package/lib/session.js +95 -89
- package/lib/step/base.js +239 -0
- package/lib/step/comment.js +10 -0
- package/lib/step/config.js +50 -0
- package/lib/step/func.js +46 -0
- package/lib/step/helper.js +50 -0
- package/lib/step/meta.js +99 -0
- package/lib/step/record.js +74 -0
- package/lib/step/retry.js +11 -0
- package/lib/step/section.js +55 -0
- package/lib/step.js +18 -329
- package/lib/steps.js +54 -0
- package/lib/store.js +38 -7
- package/lib/template/heal.js +3 -12
- package/lib/template/prompts/generatePageObject.js +31 -0
- package/lib/template/prompts/healStep.js +13 -0
- package/lib/template/prompts/writeStep.js +9 -0
- package/lib/test-server.js +334 -0
- package/lib/timeout.js +60 -0
- package/lib/transform.js +8 -8
- package/lib/translation.js +34 -21
- package/lib/utils/mask_data.js +47 -0
- package/lib/utils.js +411 -228
- package/lib/workerStorage.js +37 -34
- package/lib/workers.js +532 -296
- package/package.json +115 -95
- package/translations/de-DE.js +5 -3
- package/translations/fr-FR.js +5 -4
- package/translations/index.js +22 -12
- package/translations/it-IT.js +4 -3
- package/translations/ja-JP.js +4 -3
- package/translations/nl-NL.js +76 -0
- package/translations/pl-PL.js +4 -3
- package/translations/pt-BR.js +4 -3
- package/translations/ru-RU.js +4 -3
- package/translations/utils.js +10 -0
- package/translations/zh-CN.js +4 -3
- package/translations/zh-TW.js +4 -3
- package/typings/index.d.ts +546 -185
- package/typings/promiseBasedTypes.d.ts +150 -879
- package/typings/types.d.ts +547 -996
- package/lib/cli.js +0 -249
- package/lib/dirname.js +0 -5
- package/lib/helper/Expect.js +0 -425
- package/lib/helper/ExpectHelper.js +0 -399
- package/lib/helper/MockServer.js +0 -223
- package/lib/helper/Nightmare.js +0 -1411
- package/lib/helper/Protractor.js +0 -1835
- package/lib/helper/SoftExpectHelper.js +0 -381
- package/lib/helper/TestCafe.js +0 -1410
- package/lib/helper/clientscripts/nightmare.js +0 -213
- package/lib/helper/testcafe/testControllerHolder.js +0 -42
- package/lib/helper/testcafe/testcafe-utils.js +0 -63
- package/lib/interfaces/bdd.js +0 -98
- package/lib/interfaces/featureConfig.js +0 -69
- package/lib/interfaces/gherkin.js +0 -195
- package/lib/listener/artifacts.js +0 -19
- package/lib/listener/retry.js +0 -68
- package/lib/listener/timeout.js +0 -109
- package/lib/mochaFactory.js +0 -110
- package/lib/plugin/allure.js +0 -15
- package/lib/plugin/commentStep.js +0 -136
- package/lib/plugin/debugErrors.js +0 -67
- package/lib/plugin/eachElement.js +0 -127
- package/lib/plugin/fakerTransform.js +0 -49
- package/lib/plugin/retryTo.js +0 -121
- package/lib/plugin/selenoid.js +0 -371
- package/lib/plugin/standardActingHelpers.js +0 -9
- package/lib/plugin/tryTo.js +0 -105
- package/lib/plugin/wdio.js +0 -246
- package/lib/scenario.js +0 -222
- package/lib/ui.js +0 -238
- package/lib/within.js +0 -70
package/lib/plugin/coverage.js
CHANGED
|
@@ -1,21 +1,25 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { CoverageReport } from 'monocart-coverage-reports'
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
import
|
|
1
|
+
import debugModule from 'debug'
|
|
2
|
+
import { CoverageReport } from 'monocart-coverage-reports'
|
|
3
|
+
import Container from '../container.js'
|
|
4
|
+
|
|
5
|
+
import recorder from '../recorder.js'
|
|
6
|
+
|
|
7
|
+
import event from '../event.js'
|
|
8
|
+
|
|
9
|
+
import output from '../output.js'
|
|
10
|
+
|
|
11
|
+
import { deepMerge } from '../utils.js'
|
|
8
12
|
|
|
9
13
|
const defaultConfig = {
|
|
10
14
|
name: 'CodeceptJS Coverage Report',
|
|
11
15
|
outputDir: 'output/coverage',
|
|
12
|
-
}
|
|
16
|
+
}
|
|
13
17
|
|
|
14
|
-
const supportedHelpers = ['Puppeteer', 'Playwright']
|
|
18
|
+
const supportedHelpers = ['Puppeteer', 'Playwright', 'WebDriver']
|
|
15
19
|
|
|
16
20
|
const v8CoverageHelpers = {
|
|
17
21
|
Playwright: {
|
|
18
|
-
startCoverage: async
|
|
22
|
+
startCoverage: async page => {
|
|
19
23
|
await Promise.all([
|
|
20
24
|
page.coverage.startJSCoverage({
|
|
21
25
|
resetOnNavigation: false,
|
|
@@ -23,19 +27,16 @@ const v8CoverageHelpers = {
|
|
|
23
27
|
page.coverage.startCSSCoverage({
|
|
24
28
|
resetOnNavigation: false,
|
|
25
29
|
}),
|
|
26
|
-
])
|
|
30
|
+
])
|
|
27
31
|
},
|
|
28
32
|
takeCoverage: async (page, coverageReport) => {
|
|
29
|
-
const [jsCoverage, cssCoverage] = await Promise.all([
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
]);
|
|
33
|
-
const coverageList = [...jsCoverage, ...cssCoverage];
|
|
34
|
-
await coverageReport.add(coverageList);
|
|
33
|
+
const [jsCoverage, cssCoverage] = await Promise.all([page.coverage.stopJSCoverage(), page.coverage.stopCSSCoverage()])
|
|
34
|
+
const coverageList = [...jsCoverage, ...cssCoverage]
|
|
35
|
+
await coverageReport.add(coverageList)
|
|
35
36
|
},
|
|
36
37
|
},
|
|
37
38
|
Puppeteer: {
|
|
38
|
-
startCoverage: async
|
|
39
|
+
startCoverage: async page => {
|
|
39
40
|
await Promise.all([
|
|
40
41
|
page.coverage.startJSCoverage({
|
|
41
42
|
resetOnNavigation: false,
|
|
@@ -44,24 +45,51 @@ const v8CoverageHelpers = {
|
|
|
44
45
|
page.coverage.startCSSCoverage({
|
|
45
46
|
resetOnNavigation: false,
|
|
46
47
|
}),
|
|
47
|
-
])
|
|
48
|
+
])
|
|
48
49
|
},
|
|
49
50
|
takeCoverage: async (page, coverageReport) => {
|
|
50
|
-
const [jsCoverage, cssCoverage] = await Promise.all([
|
|
51
|
-
page.coverage.stopJSCoverage(),
|
|
52
|
-
page.coverage.stopCSSCoverage(),
|
|
53
|
-
]);
|
|
51
|
+
const [jsCoverage, cssCoverage] = await Promise.all([page.coverage.stopJSCoverage(), page.coverage.stopCSSCoverage()])
|
|
54
52
|
// to raw V8 script coverage
|
|
55
|
-
const coverageList = [
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
53
|
+
const coverageList = [
|
|
54
|
+
...jsCoverage.map(it => {
|
|
55
|
+
return {
|
|
56
|
+
source: it.text,
|
|
57
|
+
...it.rawScriptCoverage,
|
|
58
|
+
}
|
|
59
|
+
}),
|
|
60
|
+
...cssCoverage,
|
|
61
|
+
]
|
|
62
|
+
await coverageReport.add(coverageList)
|
|
62
63
|
},
|
|
63
64
|
},
|
|
64
|
-
|
|
65
|
+
WebDriver: {
|
|
66
|
+
startCoverage: async page => {
|
|
67
|
+
await Promise.all([
|
|
68
|
+
page.coverage.startJSCoverage({
|
|
69
|
+
resetOnNavigation: false,
|
|
70
|
+
includeRawScriptCoverage: true,
|
|
71
|
+
}),
|
|
72
|
+
page.coverage.startCSSCoverage({
|
|
73
|
+
resetOnNavigation: false,
|
|
74
|
+
}),
|
|
75
|
+
])
|
|
76
|
+
},
|
|
77
|
+
takeCoverage: async (page, coverageReport) => {
|
|
78
|
+
const [jsCoverage, cssCoverage] = await Promise.all([page.coverage.stopJSCoverage(), page.coverage.stopCSSCoverage()])
|
|
79
|
+
// to raw V8 script coverage
|
|
80
|
+
const coverageList = [
|
|
81
|
+
...jsCoverage.map(it => {
|
|
82
|
+
return {
|
|
83
|
+
source: it.text,
|
|
84
|
+
...it.rawScriptCoverage,
|
|
85
|
+
}
|
|
86
|
+
}),
|
|
87
|
+
...cssCoverage,
|
|
88
|
+
]
|
|
89
|
+
await coverageReport.add(coverageList)
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
}
|
|
65
93
|
|
|
66
94
|
/**
|
|
67
95
|
* Dumps code coverage from Playwright/Puppeteer after every test.
|
|
@@ -89,67 +117,92 @@ const v8CoverageHelpers = {
|
|
|
89
117
|
* * `sourcePath`: option to resolve a custom path.
|
|
90
118
|
*
|
|
91
119
|
*/
|
|
92
|
-
|
|
93
120
|
export default function (config) {
|
|
94
|
-
config = deepMerge(defaultConfig, config)
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
const
|
|
121
|
+
config = deepMerge(defaultConfig, config)
|
|
122
|
+
|
|
123
|
+
if (config.debug) config.logging = 'debug'
|
|
124
|
+
|
|
125
|
+
const helpers = Container.helpers()
|
|
126
|
+
let coverageRunning = false
|
|
127
|
+
|
|
128
|
+
const v8Names = Object.keys(v8CoverageHelpers)
|
|
129
|
+
const helperName = Object.keys(helpers).find(it => v8Names.includes(it))
|
|
102
130
|
if (!helperName) {
|
|
103
|
-
console.error(`Coverage is only supported in ${supportedHelpers.join(' or ')}`)
|
|
131
|
+
console.error(`Coverage is only supported in ${supportedHelpers.join(' or ')}`)
|
|
104
132
|
// no helpers for screenshot
|
|
105
|
-
return
|
|
133
|
+
return
|
|
106
134
|
}
|
|
107
135
|
|
|
108
|
-
config.name = `${config.name} - in ${helperName}
|
|
109
|
-
const
|
|
136
|
+
config.name = `${config.name} - in ${helperName}`
|
|
137
|
+
const debug = debugModule(`codeceptjs:plugin:${helperName.toLowerCase()}Coverage`)
|
|
138
|
+
|
|
139
|
+
const helper = helpers[helperName]
|
|
110
140
|
|
|
111
|
-
const
|
|
112
|
-
const v8Helper = v8CoverageHelpers[helperName];
|
|
141
|
+
const v8Helper = v8CoverageHelpers[helperName]
|
|
113
142
|
|
|
114
143
|
const coverageOptions = {
|
|
115
144
|
...config,
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (helperName === 'WebDriver') coverageOptions.coverageProvider = 'v8'
|
|
148
|
+
|
|
149
|
+
const coverageReport = new CoverageReport(coverageOptions)
|
|
150
|
+
coverageReport.cleanCache()
|
|
119
151
|
|
|
120
|
-
event.dispatcher.on(event.all.after,
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
152
|
+
event.dispatcher.on(event.all.after, () => {
|
|
153
|
+
// Add coverage generation to recorder to ensure it completes before process exit
|
|
154
|
+
recorder.add(
|
|
155
|
+
'generate coverage report',
|
|
156
|
+
async () => {
|
|
157
|
+
try {
|
|
158
|
+
output.print(`writing ${coverageOptions.outputDir}`)
|
|
159
|
+
await coverageReport.generate()
|
|
160
|
+
} catch (error) {
|
|
161
|
+
output.print(`Failed to generate coverage report: ${error.message}`)
|
|
162
|
+
// Don't throw - coverage failure shouldn't fail tests
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
true,
|
|
166
|
+
false,
|
|
167
|
+
)
|
|
168
|
+
})
|
|
124
169
|
|
|
125
170
|
// we're going to try to "start" coverage before each step because this is
|
|
126
171
|
// when the browser is already up and is ready to start coverage.
|
|
127
172
|
event.dispatcher.on(event.step.before, () => {
|
|
128
|
-
recorder.add(
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
173
|
+
recorder.add(
|
|
174
|
+
'start coverage',
|
|
175
|
+
async () => {
|
|
176
|
+
if (coverageRunning) {
|
|
177
|
+
return
|
|
178
|
+
}
|
|
179
|
+
if (!helper.page || !helper.page.coverage) {
|
|
180
|
+
return
|
|
181
|
+
}
|
|
182
|
+
coverageRunning = true
|
|
183
|
+
debug('--> starting coverage <--')
|
|
184
|
+
await v8Helper.startCoverage(helper.page)
|
|
185
|
+
},
|
|
186
|
+
true,
|
|
187
|
+
)
|
|
188
|
+
})
|
|
140
189
|
|
|
141
190
|
// Save coverage data after every test run
|
|
142
|
-
event.dispatcher.on(event.test.after,
|
|
143
|
-
recorder.add(
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
191
|
+
event.dispatcher.on(event.test.after, test => {
|
|
192
|
+
recorder.add(
|
|
193
|
+
'take coverage',
|
|
194
|
+
async () => {
|
|
195
|
+
if (!coverageRunning) {
|
|
196
|
+
return
|
|
197
|
+
}
|
|
198
|
+
if (!helper.page || !helper.page.coverage) {
|
|
199
|
+
return
|
|
200
|
+
}
|
|
201
|
+
coverageRunning = false
|
|
202
|
+
debug('--> stopping coverage <--')
|
|
203
|
+
await v8Helper.takeCoverage(helper.page, coverageReport)
|
|
204
|
+
},
|
|
205
|
+
true,
|
|
206
|
+
)
|
|
207
|
+
})
|
|
155
208
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import Locator from '../locator.js'
|
|
2
|
-
import { xpathLocator } from '../utils.js'
|
|
1
|
+
import Locator from '../locator.js'
|
|
2
|
+
import { xpathLocator } from '../utils.js'
|
|
3
3
|
|
|
4
4
|
const defaultConfig = {
|
|
5
5
|
prefix: '$',
|
|
6
6
|
attribute: 'data-test-id',
|
|
7
7
|
strategy: 'xpath',
|
|
8
8
|
showActual: false,
|
|
9
|
-
}
|
|
9
|
+
}
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Creates a [custom locator](https://codecept.io/locators#custom-locators) by using special attributes in HTML.
|
|
@@ -111,34 +111,35 @@ const defaultConfig = {
|
|
|
111
111
|
* I.click('=sign-up'); // matches => [data-qa=sign-up],[data-test=sign-up]
|
|
112
112
|
* ```
|
|
113
113
|
*/
|
|
114
|
-
export default (config)
|
|
115
|
-
config = { ...defaultConfig, ...config }
|
|
114
|
+
export default function (config) {
|
|
115
|
+
config = { ...defaultConfig, ...config }
|
|
116
116
|
|
|
117
117
|
Locator.addFilter((value, locatorObj) => {
|
|
118
|
-
if (typeof value !== 'string') return
|
|
119
|
-
if (!value.startsWith(config.prefix)) return
|
|
118
|
+
if (typeof value !== 'string') return
|
|
119
|
+
if (!value.startsWith(config.prefix)) return
|
|
120
120
|
|
|
121
|
-
if (!['String', 'Array'].includes(config.attribute.constructor.name)) return
|
|
121
|
+
if (!['String', 'Array'].includes(config.attribute.constructor.name)) return
|
|
122
122
|
|
|
123
|
-
const val = value.substr(config.prefix.length)
|
|
123
|
+
const val = value.substr(config.prefix.length)
|
|
124
124
|
|
|
125
125
|
if (config.strategy.toLowerCase() === 'xpath') {
|
|
126
|
-
locatorObj.value = `.//*[${
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
locatorObj.type = 'xpath'
|
|
126
|
+
locatorObj.value = `.//*[${[]
|
|
127
|
+
.concat(config.attribute)
|
|
128
|
+
.map(attr => `@${attr}=${xpathLocator.literal(val)}`)
|
|
129
|
+
.join(' or ')}]`
|
|
130
|
+
locatorObj.type = 'xpath'
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
if (config.strategy.toLowerCase() === 'css') {
|
|
134
|
-
locatorObj.value = []
|
|
135
|
-
.
|
|
136
|
-
.
|
|
137
|
-
|
|
134
|
+
locatorObj.value = []
|
|
135
|
+
.concat(config.attribute)
|
|
136
|
+
.map(attr => `[${attr}=${val}]`)
|
|
137
|
+
.join(',')
|
|
138
|
+
locatorObj.type = 'css'
|
|
138
139
|
}
|
|
139
140
|
|
|
140
141
|
if (config.showActual) {
|
|
141
|
-
locatorObj.output = locatorObj.value
|
|
142
|
+
locatorObj.output = locatorObj.value
|
|
142
143
|
}
|
|
143
|
-
})
|
|
144
|
-
}
|
|
144
|
+
})
|
|
145
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import event from '../event.js'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Sample custom reporter for CodeceptJS.
|
|
6
|
+
*/
|
|
7
|
+
export default function (config) {
|
|
8
|
+
event.dispatcher.on(event.hook.finished, hook => {
|
|
9
|
+
if (config.onHookFinished) {
|
|
10
|
+
config.onHookFinished(hook)
|
|
11
|
+
}
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
event.dispatcher.on(event.test.before, test => {
|
|
15
|
+
if (config.onTestBefore) {
|
|
16
|
+
config.onTestBefore(test)
|
|
17
|
+
}
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
event.dispatcher.on(event.test.failed, (test, err) => {
|
|
21
|
+
if (config.onTestFailed) {
|
|
22
|
+
config.onTestFailed(test, err)
|
|
23
|
+
}
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
event.dispatcher.on(event.test.passed, test => {
|
|
27
|
+
if (config.onTestPassed) {
|
|
28
|
+
config.onTestPassed(test)
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
event.dispatcher.on(event.test.skipped, test => {
|
|
33
|
+
if (config.onTestSkipped) {
|
|
34
|
+
config.onTestSkipped(test)
|
|
35
|
+
}
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
event.dispatcher.on(event.test.finished, test => {
|
|
39
|
+
if (config.onTestFinished) {
|
|
40
|
+
config.onTestFinished(test)
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
event.dispatcher.on(event.all.result, result => {
|
|
45
|
+
if (config.onResult) {
|
|
46
|
+
config.onResult(result)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (config.save) {
|
|
50
|
+
result.save()
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import event from '../event.js'
|
|
2
|
+
import recorder from '../recorder.js'
|
|
3
|
+
import store from '../store.js'
|
|
4
|
+
import output from '../output.js'
|
|
5
|
+
import { RETRY_PRIORITIES } from '../retryCoordinator.js'
|
|
6
|
+
|
|
7
|
+
const defaultConfig = {
|
|
8
|
+
retries: 3,
|
|
9
|
+
defaultIgnoredSteps: ['amOnPage', 'wait*', 'send*', 'execute*', 'run*', 'have*'],
|
|
10
|
+
factor: 1.5,
|
|
11
|
+
ignoredSteps: [],
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Enhanced retryFailedStep plugin that coordinates with other retry mechanisms
|
|
16
|
+
*
|
|
17
|
+
* This plugin provides step-level retries and coordinates with global retry settings
|
|
18
|
+
* to avoid conflicts and provide predictable behavior.
|
|
19
|
+
*/
|
|
20
|
+
export default config => {
|
|
21
|
+
config = Object.assign({}, defaultConfig, config)
|
|
22
|
+
config.ignoredSteps = config.ignoredSteps.concat(config.defaultIgnoredSteps)
|
|
23
|
+
const customWhen = config.when
|
|
24
|
+
|
|
25
|
+
let enableRetry = false
|
|
26
|
+
|
|
27
|
+
const when = err => {
|
|
28
|
+
if (!enableRetry) return false
|
|
29
|
+
if (store.debugMode) return false
|
|
30
|
+
if (!store.autoRetries) return false
|
|
31
|
+
if (customWhen) return customWhen(err)
|
|
32
|
+
return true
|
|
33
|
+
}
|
|
34
|
+
config.when = when
|
|
35
|
+
|
|
36
|
+
event.dispatcher.on(event.step.started, step => {
|
|
37
|
+
// if a step is ignored - return
|
|
38
|
+
for (const ignored of config.ignoredSteps) {
|
|
39
|
+
if (step.name === ignored) return
|
|
40
|
+
if (ignored instanceof RegExp) {
|
|
41
|
+
if (step.name.match(ignored)) return
|
|
42
|
+
} else if (ignored.indexOf('*') && step.name.startsWith(ignored.slice(0, -1))) return
|
|
43
|
+
}
|
|
44
|
+
enableRetry = true // enable retry for a step
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
event.dispatcher.on(event.step.finished, () => {
|
|
48
|
+
enableRetry = false
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
event.dispatcher.on(event.test.before, test => {
|
|
52
|
+
// pass disableRetryFailedStep is a preferred way to disable retries
|
|
53
|
+
// test.disableRetryFailedStep is used for backward compatibility
|
|
54
|
+
if (test.opts.disableRetryFailedStep || test.disableRetryFailedStep) {
|
|
55
|
+
store.autoRetries = false
|
|
56
|
+
output.log(`[Step Retry] Disabled for test: ${test.title}`)
|
|
57
|
+
return // disable retry when a test is not active
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Check if step retries should be disabled due to higher priority scenario retries
|
|
61
|
+
const scenarioRetries = test.retries()
|
|
62
|
+
const stepRetryPriority = RETRY_PRIORITIES.STEP_PLUGIN
|
|
63
|
+
const scenarioPriority = test.opts.retryPriority || 0
|
|
64
|
+
|
|
65
|
+
if (scenarioRetries > 0 && config.deferToScenarioRetries !== false) {
|
|
66
|
+
// Scenario retries are configured with higher or equal priority
|
|
67
|
+
// Option 1: Disable step retries (conservative approach)
|
|
68
|
+
store.autoRetries = false
|
|
69
|
+
output.log(`[Step Retry] Deferred to scenario retries (${scenarioRetries} retries)`)
|
|
70
|
+
return
|
|
71
|
+
|
|
72
|
+
// Option 2: Reduce step retries to avoid excessive total retries
|
|
73
|
+
// const reducedStepRetries = Math.max(1, Math.floor(config.retries / scenarioRetries))
|
|
74
|
+
// config.retries = reducedStepRetries
|
|
75
|
+
// output.log(`[Step Retry] Reduced to ${reducedStepRetries} retries due to scenario retries (${scenarioRetries})`)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// this option is used to set the retries inside _before() block of helpers
|
|
79
|
+
store.autoRetries = true
|
|
80
|
+
test.opts.conditionalRetries = config.retries
|
|
81
|
+
test.opts.stepRetryPriority = stepRetryPriority
|
|
82
|
+
|
|
83
|
+
recorder.retry(config)
|
|
84
|
+
|
|
85
|
+
output.log(`[Step Retry] Enabled with ${config.retries} retries for test: ${test.title}`)
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
// Add coordination info for debugging
|
|
89
|
+
event.dispatcher.on(event.test.finished, test => {
|
|
90
|
+
if (test.state === 'passed' && test.opts.conditionalRetries && store.autoRetries) {
|
|
91
|
+
const stepRetries = test.opts.conditionalRetries || 0
|
|
92
|
+
const scenarioRetries = test.retries() || 0
|
|
93
|
+
|
|
94
|
+
if (stepRetries > 0 && scenarioRetries > 0) {
|
|
95
|
+
output.log(`[Retry Coordination] Test used both step retries (${stepRetries}) and scenario retries (${scenarioRetries})`)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
})
|
|
99
|
+
}
|