codeceptjs 4.0.0-beta.2 → 4.0.0-beta.3
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 +84 -81
- package/lib/actor.js +13 -13
- package/lib/ai.js +10 -13
- package/lib/assert/empty.js +20 -21
- package/lib/assert/equal.js +37 -39
- package/lib/assert/error.js +14 -14
- package/lib/assert/include.js +46 -47
- package/lib/assert/throws.js +13 -11
- package/lib/assert/truth.js +19 -22
- package/lib/assert.js +4 -2
- package/lib/cli.js +57 -49
- package/lib/codecept.js +142 -155
- package/lib/colorUtils.js +3 -3
- package/lib/command/configMigrate.js +58 -52
- package/lib/command/definitions.js +88 -89
- package/lib/command/dryRun.js +71 -68
- package/lib/command/generate.js +197 -188
- package/lib/command/gherkin/init.js +27 -16
- package/lib/command/gherkin/snippets.js +20 -20
- package/lib/command/gherkin/steps.js +8 -8
- package/lib/command/info.js +40 -38
- package/lib/command/init.js +290 -288
- 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 +6 -2
- package/lib/command/run-multiple.js +113 -93
- package/lib/command/run-rerun.js +20 -25
- package/lib/command/run-workers.js +64 -66
- package/lib/command/run.js +26 -29
- package/lib/command/utils.js +80 -65
- package/lib/command/workers/runTests.js +10 -10
- package/lib/config.js +10 -9
- package/lib/container.js +40 -48
- package/lib/data/context.js +60 -59
- package/lib/data/dataScenarioConfig.js +47 -47
- package/lib/data/dataTableArgument.js +29 -29
- package/lib/data/table.js +26 -20
- package/lib/event.js +163 -167
- package/lib/heal.js +13 -17
- package/lib/helper/AI.js +130 -41
- package/lib/helper/ApiDataFactory.js +73 -69
- package/lib/helper/Appium.js +413 -382
- package/lib/helper/ExpectHelper.js +40 -48
- package/lib/helper/FileSystem.js +80 -79
- package/lib/helper/GraphQL.js +44 -43
- package/lib/helper/GraphQLDataFactory.js +50 -50
- package/lib/helper/JSONResponse.js +65 -62
- package/lib/helper/Mochawesome.js +28 -28
- package/lib/helper/MockServer.js +12 -14
- package/lib/helper/Nightmare.js +662 -566
- package/lib/helper/Playwright.js +1361 -1216
- package/lib/helper/Protractor.js +663 -627
- package/lib/helper/Puppeteer.js +1231 -1128
- package/lib/helper/REST.js +159 -68
- package/lib/helper/SoftExpectHelper.js +2 -2
- package/lib/helper/TestCafe.js +490 -484
- package/lib/helper/WebDriver.js +1297 -1156
- 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 +21 -18
- package/lib/helper/extras/Popup.js +1 -1
- package/lib/helper/extras/React.js +3 -3
- package/lib/helper/network/actions.js +14 -7
- package/lib/helper/network/utils.js +3 -2
- 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 +6 -7
- package/lib/helper.js +1 -3
- package/lib/history.js +6 -5
- package/lib/hooks.js +6 -6
- package/lib/html.js +7 -7
- package/lib/index.js +25 -41
- package/lib/interfaces/bdd.js +47 -64
- package/lib/interfaces/featureConfig.js +19 -19
- package/lib/interfaces/gherkin.js +124 -118
- 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 +32 -30
- package/lib/listener/steps.js +50 -53
- package/lib/listener/timeout.js +54 -54
- package/lib/locator.js +6 -10
- package/lib/mochaFactory.js +18 -15
- package/lib/output.js +6 -10
- package/lib/parser.js +15 -12
- package/lib/pause.js +40 -33
- package/lib/plugin/allure.js +15 -15
- package/lib/plugin/autoDelay.js +29 -37
- package/lib/plugin/autoLogin.js +70 -65
- package/lib/plugin/commentStep.js +18 -18
- package/lib/plugin/coverage.js +115 -67
- package/lib/plugin/customLocator.js +21 -20
- 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 +67 -108
- package/lib/plugin/pauseOnFail.js +11 -11
- package/lib/plugin/retryFailedStep.js +32 -39
- package/lib/plugin/retryTo.js +46 -40
- package/lib/plugin/screenshotOnFail.js +109 -87
- package/lib/plugin/selenoid.js +131 -118
- package/lib/plugin/standardActingHelpers.js +2 -8
- package/lib/plugin/stepByStepReport.js +110 -91
- package/lib/plugin/stepTimeout.js +24 -23
- package/lib/plugin/subtitles.js +34 -35
- package/lib/plugin/tryTo.js +40 -30
- package/lib/plugin/wdio.js +78 -75
- package/lib/recorder.js +14 -17
- package/lib/rerun.js +11 -10
- package/lib/scenario.js +25 -23
- package/lib/secret.js +4 -2
- package/lib/session.js +10 -10
- package/lib/step.js +12 -9
- package/lib/store.js +2 -3
- package/lib/transform.js +1 -1
- package/lib/translation.js +7 -8
- package/lib/ui.js +12 -14
- package/lib/utils.js +70 -72
- package/lib/within.js +10 -10
- package/lib/workerStorage.js +27 -25
- package/lib/workers.js +29 -32
- package/package.json +56 -57
- package/translations/de-DE.js +1 -1
- package/translations/fr-FR.js +1 -1
- package/translations/index.js +9 -13
- 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 +415 -65
- package/typings/promiseBasedTypes.d.ts +32 -0
- package/typings/types.d.ts +32 -0
- package/lib/dirname.js +0 -5
- package/lib/helper/Expect.js +0 -425
package/lib/plugin/heal.js
CHANGED
|
@@ -1,19 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
import supportedHelpers from './standardActingHelpers.js';
|
|
9
|
-
|
|
10
|
-
debug('codeceptjs:heal');
|
|
11
|
-
const heal = require('../heal');
|
|
12
|
-
const store = require('../store');
|
|
1
|
+
const debug = require('debug')('codeceptjs:heal')
|
|
2
|
+
const colors = require('chalk')
|
|
3
|
+
const recorder = require('../recorder')
|
|
4
|
+
const event = require('../event')
|
|
5
|
+
const output = require('../output')
|
|
6
|
+
const heal = require('../heal')
|
|
7
|
+
const store = require('../store')
|
|
13
8
|
|
|
14
9
|
const defaultConfig = {
|
|
15
10
|
healLimit: 2,
|
|
16
|
-
}
|
|
11
|
+
}
|
|
17
12
|
|
|
18
13
|
/**
|
|
19
14
|
* Self-healing tests with AI.
|
|
@@ -33,130 +28,94 @@ const defaultConfig = {
|
|
|
33
28
|
* * `healLimit` - how many steps can be healed in a single test (default: 2)
|
|
34
29
|
*
|
|
35
30
|
*/
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (store.store.debugMode && !process.env.DEBUG) {
|
|
31
|
+
module.exports = function (config = {}) {
|
|
32
|
+
if (store.debugMode && !process.env.DEBUG) {
|
|
39
33
|
event.dispatcher.on(event.test.failed, () => {
|
|
40
|
-
output.
|
|
41
|
-
|
|
42
|
-
|
|
34
|
+
output.plugin(
|
|
35
|
+
'heal',
|
|
36
|
+
'Healing is disabled in --debug mode, use DEBUG="codeceptjs:heal" to enable it in debug mode',
|
|
37
|
+
)
|
|
38
|
+
})
|
|
39
|
+
return
|
|
43
40
|
}
|
|
44
41
|
|
|
45
|
-
let currentTest = null
|
|
46
|
-
let currentStep = null
|
|
47
|
-
let healedSteps = 0
|
|
48
|
-
let caughtError
|
|
49
|
-
let healTries = 0
|
|
50
|
-
let isHealing = false
|
|
42
|
+
let currentTest = null
|
|
43
|
+
let currentStep = null
|
|
44
|
+
let healedSteps = 0
|
|
45
|
+
let caughtError
|
|
46
|
+
let healTries = 0
|
|
47
|
+
let isHealing = false
|
|
51
48
|
|
|
52
|
-
config = Object.assign(defaultConfig, config)
|
|
49
|
+
config = Object.assign(defaultConfig, config)
|
|
53
50
|
|
|
54
51
|
event.dispatcher.on(event.test.before, (test) => {
|
|
55
|
-
currentTest = test
|
|
56
|
-
healedSteps = 0
|
|
57
|
-
caughtError = null
|
|
58
|
-
})
|
|
52
|
+
currentTest = test
|
|
53
|
+
healedSteps = 0
|
|
54
|
+
caughtError = null
|
|
55
|
+
})
|
|
59
56
|
|
|
60
|
-
event.dispatcher.on(event.step.started, step => currentStep = step)
|
|
57
|
+
event.dispatcher.on(event.step.started, (step) => (currentStep = step))
|
|
61
58
|
|
|
62
59
|
event.dispatcher.on(event.step.after, (step) => {
|
|
63
|
-
if (isHealing) return
|
|
64
|
-
if (
|
|
65
|
-
if (healTries >= config.healLimit) return; // out of limit
|
|
60
|
+
if (isHealing) return
|
|
61
|
+
if (healTries >= config.healLimit) return // out of limit
|
|
66
62
|
|
|
67
|
-
if (!heal.hasCorrespondingRecipes(step)) return
|
|
63
|
+
if (!heal.hasCorrespondingRecipes(step)) return
|
|
68
64
|
|
|
69
65
|
recorder.catchWithoutStop(async (err) => {
|
|
70
|
-
isHealing = true
|
|
71
|
-
if (caughtError === err) throw err
|
|
72
|
-
caughtError = err
|
|
66
|
+
isHealing = true
|
|
67
|
+
if (caughtError === err) throw err // avoid double handling
|
|
68
|
+
caughtError = err
|
|
73
69
|
|
|
74
|
-
const test = currentTest
|
|
70
|
+
const test = currentTest
|
|
75
71
|
|
|
76
|
-
recorder.session.start('heal')
|
|
72
|
+
recorder.session.start('heal')
|
|
77
73
|
|
|
78
|
-
debug('Self-healing started', step.toCode())
|
|
74
|
+
debug('Self-healing started', step.toCode())
|
|
79
75
|
|
|
80
|
-
await heal.healStep(step, err, { test })
|
|
76
|
+
await heal.healStep(step, err, { test })
|
|
81
77
|
|
|
82
|
-
healTries
|
|
78
|
+
healTries++
|
|
83
79
|
|
|
84
80
|
recorder.add('close healing session', () => {
|
|
85
|
-
recorder.reset()
|
|
86
|
-
recorder.session.restore('heal')
|
|
87
|
-
recorder.ignoreErr(err)
|
|
88
|
-
})
|
|
89
|
-
await recorder.promise()
|
|
81
|
+
recorder.reset()
|
|
82
|
+
recorder.session.restore('heal')
|
|
83
|
+
recorder.ignoreErr(err)
|
|
84
|
+
})
|
|
85
|
+
await recorder.promise()
|
|
90
86
|
|
|
91
|
-
isHealing = false
|
|
92
|
-
})
|
|
93
|
-
})
|
|
87
|
+
isHealing = false
|
|
88
|
+
})
|
|
89
|
+
})
|
|
94
90
|
|
|
95
91
|
event.dispatcher.on(event.all.result, () => {
|
|
96
|
-
if (!heal.fixes?.length) return
|
|
92
|
+
if (!heal.fixes?.length) return
|
|
97
93
|
|
|
98
|
-
const { print } = output
|
|
94
|
+
const { print } = output
|
|
99
95
|
|
|
100
|
-
print('')
|
|
101
|
-
print('===================')
|
|
102
|
-
print(colors.bold.green('Self-Healing Report:'))
|
|
96
|
+
print('')
|
|
97
|
+
print('===================')
|
|
98
|
+
print(colors.bold.green('Self-Healing Report:'))
|
|
103
99
|
|
|
104
|
-
print(`${colors.bold(heal.fixes.length)} ${heal.fixes.length === 1 ? 'step was' : 'steps were'} healed`)
|
|
100
|
+
print(`${colors.bold(heal.fixes.length)} ${heal.fixes.length === 1 ? 'step was' : 'steps were'} healed`)
|
|
105
101
|
|
|
106
|
-
const suggestions = heal.fixes.filter(fix => fix.recipe && heal.recipes[fix.recipe].suggest)
|
|
102
|
+
const suggestions = heal.fixes.filter((fix) => fix.recipe && heal.recipes[fix.recipe].suggest)
|
|
107
103
|
|
|
108
|
-
if (!suggestions.length) return
|
|
104
|
+
if (!suggestions.length) return
|
|
109
105
|
|
|
110
|
-
let i = 1
|
|
111
|
-
print('')
|
|
112
|
-
print('Suggested changes:')
|
|
113
|
-
print('')
|
|
106
|
+
let i = 1
|
|
107
|
+
print('')
|
|
108
|
+
print('Suggested changes:')
|
|
109
|
+
print('')
|
|
114
110
|
|
|
115
111
|
for (const suggestion of suggestions) {
|
|
116
|
-
print(`${i}. To fix ${colors.bold.magenta(suggestion.test?.title)}`)
|
|
117
|
-
print(' Replace the failed code:', colors.gray(`(suggested by ${colors.bold(suggestion.recipe)})`))
|
|
118
|
-
print(colors.red(`- ${suggestion.step.toCode()}`))
|
|
119
|
-
print(colors.green(`+ ${suggestion.snippet}`))
|
|
120
|
-
print(suggestion.step.line())
|
|
121
|
-
print('')
|
|
122
|
-
i
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
async function tryToHeal(failedStep, err) {
|
|
127
|
-
output.output.debug(`Running OpenAI to heal ${failedStep.toCode()} step`);
|
|
128
|
-
|
|
129
|
-
const codeSnippets = await AiAssistant.healFailedStep(failedStep, err, currentTest);
|
|
130
|
-
|
|
131
|
-
output.output.debug(`Received ${codeSnippets.length} suggestions from OpenAI`);
|
|
132
|
-
const I = Container.support('I'); // eslint-disable-line
|
|
133
|
-
|
|
134
|
-
for (const codeSnippet of codeSnippets) {
|
|
135
|
-
try {
|
|
136
|
-
debug('Executing', codeSnippet);
|
|
137
|
-
recorder.catch((e) => {
|
|
138
|
-
console.log(e);
|
|
139
|
-
});
|
|
140
|
-
await eval(codeSnippet); // eslint-disable-line
|
|
141
|
-
|
|
142
|
-
let healSuggestions = [];
|
|
143
|
-
healSuggestions.push({
|
|
144
|
-
test: currentTest,
|
|
145
|
-
step: failedStep,
|
|
146
|
-
snippet: codeSnippet,
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
recorder.add('healed', () => output.print(colors.bold.green(' Code healed successfully')));
|
|
150
|
-
healedSteps++;
|
|
151
|
-
return;
|
|
152
|
-
} catch (err) {
|
|
153
|
-
debug('Failed to execute code', err);
|
|
154
|
-
recorder.ignoreErr(err); // healing ded not help
|
|
155
|
-
// recorder.catch(() => output.print(colors.bold.red(' Failed healing code')));
|
|
156
|
-
}
|
|
112
|
+
print(`${i}. To fix ${colors.bold.magenta(suggestion.test?.title)}`)
|
|
113
|
+
print(' Replace the failed code:', colors.gray(`(suggested by ${colors.bold(suggestion.recipe)})`))
|
|
114
|
+
print(colors.red(`- ${suggestion.step.toCode()}`))
|
|
115
|
+
print(colors.green(`+ ${suggestion.snippet}`))
|
|
116
|
+
print(suggestion.step.line())
|
|
117
|
+
print('')
|
|
118
|
+
i++
|
|
157
119
|
}
|
|
158
|
-
|
|
159
|
-
output.output.debug(`Couldn't heal the code for ${failedStep.toCode()}`);
|
|
160
|
-
}
|
|
161
|
-
return recorder.promise();
|
|
120
|
+
})
|
|
162
121
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
const event = require('../event')
|
|
2
|
+
const pause = require('../pause')
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Automatically launches [interactive pause](/basics/#pause) when a test fails.
|
|
@@ -21,18 +21,18 @@ import pause from '../pause';
|
|
|
21
21
|
* ```
|
|
22
22
|
*
|
|
23
23
|
*/
|
|
24
|
-
|
|
25
|
-
let failed = false
|
|
24
|
+
module.exports = () => {
|
|
25
|
+
let failed = false
|
|
26
26
|
|
|
27
27
|
event.dispatcher.on(event.test.started, () => {
|
|
28
|
-
failed = false
|
|
29
|
-
})
|
|
28
|
+
failed = false
|
|
29
|
+
})
|
|
30
30
|
|
|
31
31
|
event.dispatcher.on(event.step.failed, () => {
|
|
32
|
-
failed = true
|
|
33
|
-
})
|
|
32
|
+
failed = true
|
|
33
|
+
})
|
|
34
34
|
|
|
35
35
|
event.dispatcher.on(event.test.after, () => {
|
|
36
|
-
if (failed) pause()
|
|
37
|
-
})
|
|
38
|
-
}
|
|
36
|
+
if (failed) pause()
|
|
37
|
+
})
|
|
38
|
+
}
|
|
@@ -1,22 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import { store } from '../store.js';
|
|
1
|
+
const event = require('../event')
|
|
2
|
+
const recorder = require('../recorder')
|
|
3
|
+
const container = require('../container')
|
|
4
|
+
const { log } = require('../output')
|
|
6
5
|
|
|
7
6
|
const defaultConfig = {
|
|
8
7
|
retries: 3,
|
|
9
|
-
defaultIgnoredSteps: [
|
|
10
|
-
'amOnPage',
|
|
11
|
-
'wait*',
|
|
12
|
-
'send*',
|
|
13
|
-
'execute*',
|
|
14
|
-
'run*',
|
|
15
|
-
'have*',
|
|
16
|
-
],
|
|
8
|
+
defaultIgnoredSteps: ['amOnPage', 'wait*', 'send*', 'execute*', 'run*', 'have*'],
|
|
17
9
|
factor: 1.5,
|
|
18
10
|
ignoredSteps: [],
|
|
19
|
-
}
|
|
11
|
+
}
|
|
20
12
|
|
|
21
13
|
/**
|
|
22
14
|
* Retries each failed step in a test.
|
|
@@ -84,45 +76,46 @@ const defaultConfig = {
|
|
|
84
76
|
* ```
|
|
85
77
|
*
|
|
86
78
|
*/
|
|
87
|
-
|
|
88
|
-
config = Object.assign(defaultConfig, config)
|
|
89
|
-
config.ignoredSteps = config.ignoredSteps.concat(config.defaultIgnoredSteps)
|
|
90
|
-
const customWhen = config.when
|
|
79
|
+
module.exports = (config) => {
|
|
80
|
+
config = Object.assign(defaultConfig, config)
|
|
81
|
+
config.ignoredSteps = config.ignoredSteps.concat(config.defaultIgnoredSteps)
|
|
82
|
+
const customWhen = config.when
|
|
91
83
|
|
|
92
|
-
let enableRetry = false
|
|
84
|
+
let enableRetry = false
|
|
93
85
|
|
|
94
86
|
const when = (err) => {
|
|
95
|
-
if (!enableRetry) return
|
|
96
|
-
|
|
97
|
-
if (
|
|
98
|
-
return
|
|
99
|
-
|
|
100
|
-
|
|
87
|
+
if (!enableRetry) return
|
|
88
|
+
const store = require('../store')
|
|
89
|
+
if (store.debugMode) return false
|
|
90
|
+
if (customWhen) return customWhen(err)
|
|
91
|
+
return true
|
|
92
|
+
}
|
|
93
|
+
config.when = when
|
|
101
94
|
|
|
102
95
|
event.dispatcher.on(event.step.started, (step) => {
|
|
103
96
|
if (process.env.TRY_TO === 'true') {
|
|
104
|
-
|
|
105
|
-
return
|
|
97
|
+
log('Info: RetryFailedStep plugin is disabled inside tryTo block')
|
|
98
|
+
return
|
|
106
99
|
}
|
|
107
100
|
|
|
108
101
|
// if a step is ignored - return
|
|
109
102
|
for (const ignored of config.ignoredSteps) {
|
|
110
|
-
if (step.name === ignored) return
|
|
103
|
+
if (step.name === ignored) return
|
|
111
104
|
if (ignored instanceof RegExp) {
|
|
112
|
-
if (step.name.match(ignored)) return
|
|
113
|
-
} else if (ignored.indexOf('*') && step.name.startsWith(ignored.slice(0, -1))) return
|
|
105
|
+
if (step.name.match(ignored)) return
|
|
106
|
+
} else if (ignored.indexOf('*') && step.name.startsWith(ignored.slice(0, -1))) return
|
|
114
107
|
}
|
|
115
|
-
enableRetry = true
|
|
116
|
-
})
|
|
108
|
+
enableRetry = true // enable retry for a step
|
|
109
|
+
})
|
|
117
110
|
|
|
118
111
|
event.dispatcher.on(event.step.finished, () => {
|
|
119
|
-
enableRetry = false
|
|
120
|
-
})
|
|
112
|
+
enableRetry = false
|
|
113
|
+
})
|
|
121
114
|
|
|
122
115
|
event.dispatcher.on(event.test.before, (test) => {
|
|
123
|
-
if (test && test.disableRetryFailedStep) return
|
|
116
|
+
if (test && test.disableRetryFailedStep) return // disable retry when a test is not active
|
|
124
117
|
// this env var is used to set the retries inside _before() block of helpers
|
|
125
|
-
process.env.FAILED_STEP_RETRIES = config.retries
|
|
126
|
-
recorder.retry(config)
|
|
127
|
-
})
|
|
128
|
-
}
|
|
118
|
+
process.env.FAILED_STEP_RETRIES = config.retries
|
|
119
|
+
recorder.retry(config)
|
|
120
|
+
})
|
|
121
|
+
}
|
package/lib/plugin/retryTo.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
const recorder = require('../recorder')
|
|
2
|
+
const { debug } = require('../output')
|
|
3
3
|
|
|
4
4
|
const defaultConfig = {
|
|
5
5
|
registerGlobal: true,
|
|
6
6
|
pollInterval: 200,
|
|
7
|
-
}
|
|
7
|
+
}
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
*
|
|
@@ -72,50 +72,56 @@ const defaultConfig = {
|
|
|
72
72
|
* const retryTo = codeceptjs.container.plugins('retryTo');
|
|
73
73
|
* ```
|
|
74
74
|
*
|
|
75
|
-
*/
|
|
76
|
-
|
|
77
|
-
config = Object.assign(defaultConfig, config)
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
global.retryTo = retryTo;
|
|
82
|
-
}
|
|
83
|
-
return retryTo;
|
|
84
|
-
|
|
85
|
-
function retryTo(callback, maxTries, pollInterval = undefined) {
|
|
86
|
-
let tries = 1;
|
|
87
|
-
if (!pollInterval) pollInterval = config.pollInterval;
|
|
75
|
+
*/
|
|
76
|
+
module.exports = function (config) {
|
|
77
|
+
config = Object.assign(defaultConfig, config)
|
|
78
|
+
function retryTo(callback, maxTries, pollInterval = config.pollInterval) {
|
|
79
|
+
return new Promise((done, reject) => {
|
|
80
|
+
let tries = 1
|
|
88
81
|
|
|
89
|
-
|
|
82
|
+
function handleRetryException(err) {
|
|
83
|
+
recorder.throw(err)
|
|
84
|
+
reject(err)
|
|
85
|
+
}
|
|
90
86
|
|
|
91
|
-
return new Promise((done) => {
|
|
92
87
|
const tryBlock = async () => {
|
|
93
|
-
|
|
94
|
-
|
|
88
|
+
tries++
|
|
89
|
+
recorder.session.start(`retryTo ${tries}`)
|
|
90
|
+
try {
|
|
91
|
+
await callback(tries)
|
|
92
|
+
} catch (err) {
|
|
93
|
+
handleRetryException(err)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Call done if no errors
|
|
95
97
|
recorder.add(() => {
|
|
96
|
-
recorder.session.restore(`retryTo ${tries}`)
|
|
97
|
-
done(null)
|
|
98
|
-
})
|
|
99
|
-
recorder.session.catch((e) => {
|
|
100
|
-
err = e;
|
|
101
|
-
recorder.session.restore(`retryTo ${tries}`);
|
|
102
|
-
tries++;
|
|
103
|
-
if (tries <= maxTries) {
|
|
104
|
-
output.output.debug(`Error ${err}... Retrying`);
|
|
105
|
-
err = null;
|
|
98
|
+
recorder.session.restore(`retryTo ${tries}`)
|
|
99
|
+
done(null)
|
|
100
|
+
})
|
|
106
101
|
|
|
107
|
-
|
|
102
|
+
// Catch errors and retry
|
|
103
|
+
recorder.session.catch((err) => {
|
|
104
|
+
recorder.session.restore(`retryTo ${tries}`)
|
|
105
|
+
if (tries <= maxTries) {
|
|
106
|
+
debug(`Error ${err}... Retrying`)
|
|
107
|
+
recorder.add(`retryTo ${tries}`, () => setTimeout(tryBlock, pollInterval))
|
|
108
108
|
} else {
|
|
109
|
-
|
|
109
|
+
// if maxTries reached
|
|
110
|
+
handleRetryException(err)
|
|
110
111
|
}
|
|
111
|
-
})
|
|
112
|
-
}
|
|
112
|
+
})
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
recorder.add('retryTo', tryBlock).catch((err) => {
|
|
116
|
+
console.error('An error occurred:', err)
|
|
117
|
+
done(null)
|
|
118
|
+
})
|
|
119
|
+
})
|
|
120
|
+
}
|
|
113
121
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
});
|
|
117
|
-
}).then(() => {
|
|
118
|
-
if (err) recorder.throw(err);
|
|
119
|
-
});
|
|
122
|
+
if (config.registerGlobal) {
|
|
123
|
+
global.retryTo = retryTo
|
|
120
124
|
}
|
|
125
|
+
|
|
126
|
+
return retryTo
|
|
121
127
|
}
|