codeceptjs
Version:
Modern Era Acceptance Testing Framework for NodeJS
118 lines (110 loc) • 3.35 kB
JavaScript
const event = require('../event');
const recorder = require('../recorder');
const defaultConfig = {
retries: 5,
defaultIgnoredSteps: [
'amOnPage',
'wait*',
'send*',
'execute*',
'run*',
'have*',
],
ignoredSteps: [],
};
/**
* Retries each failed step in a test.
*
* Add this plugin to config file:
*
* ```js
* plugins: {
* retryFailedStep: {
* enabled: true
* }
* }
* ```
*
*
* Run tests with plugin enabled:
*
* ```
* npx codeceptjs run --plugins retryFailedStep
* ```
*
* ##### Configuration:
*
* * `retries` - number of retries (by default 5),
* * `when` - function, when to perform a retry (accepts error as parameter)
* * `factor` - The exponential factor to use. Default is 2.
* * `minTimeout` - The number of milliseconds before starting the first retry. Default is 1000.
* * `maxTimeout` - The maximum number of milliseconds between two retries. Default is Infinity.
* * `randomize` - Randomizes the timeouts by multiplying with a factor between 1 to 2. Default is false.
* * `defaultIgnoredSteps` - an array of steps to be ignored for retry. Includes:
* * `amOnPage`
* * `wait*`
* * `send*`
* * `execute*`
* * `run*`
* * `have*`
* * `ignoredSteps` - an array for custom steps to ignore on retry. Use it to append custom steps to ignored list.
* You can use step names or step prefixes ending with `*`. As such, `wait*` will match all steps starting with `wait`.
* To append your own steps to ignore list - copy and paste a default steps list. Regexp values are accepted as well.
*
* ##### Example
*
* ```js
* plugins: {
* retryFailedStep: {
* enabled: true,
* ignoreSteps: [
* 'scroll*', // ignore all scroll steps
* /Cookie/, // ignore all steps with a Cookie in it (by regexp)
* ]
* }
* }
* ```
*
* ##### Disable Per Test
*
* This plugin can be disabled per test. In this case you will need to stet `I.retry()` to all flaky steps:
*
* Use scenario configuration to disable plugin for a test
*
* ```js
* Scenario('scenario tite', () => {
* // test goes here
* }).config(test => test.disableRetryFailedStep = true)
* ```
*
*/
module.exports = (config) => {
config = Object.assign(defaultConfig, config);
config.ignoredSteps = config.ignoredSteps.concat(config.defaultIgnoredSteps);
const customWhen = config.when;
let enableRetry = false;
const when = (err) => {
if (!enableRetry) return;
const store = require('../store');
if (store.debugMode) return false;
if (customWhen) return customWhen(err);
return true;
};
config.when = when;
event.dispatcher.on(event.step.started, (step) => {
// if a step is ignored - return
for (const ignored of config.ignoredSteps) {
if (step.name === ignored) return;
if (ignored instanceof RegExp && step.name.match(ignored)) return;
if (ignored.indexOf('*') && step.name.startsWith(ignored.slice(0, -1))) return;
}
enableRetry = true; // enable retry for a step
});
event.dispatcher.on(event.step.finished, (step) => {
enableRetry = false;
});
event.dispatcher.on(event.test.before, (test) => {
if (test && test.disableRetryFailedStep) return; // disable retry when a test is not active
recorder.retry(config);
});
};