Reputation: 1879
Goal Be able to perform multiple retries of an entire test suite until all tests succeed.
Instead of configuring retries allowed for every test within a test suite, as defined by Configure Test Retries: Global Configuration
How to provide test suite retries?
If any test fails within a test suite, then start over and retry the entire test suite again until all tests within a test suite succeed or stop when the entire test suite retry attempts exceed the requested retry attempts.
In the following code, configures retry attempts applicable for every test within a test suite.
The desired goal for this test suite, test 'TEST counter'
is expected to fail until incrementing _counter
equals _runModeRetries
and only then is it expected to succeed. Repeat the entire test suite means re-run every test prior to test 'TEST counter'
until it succeeds.
However, what happens is that only test 'TEST counter'
is retried _runModeRetries
times, and _counter
is not incremented because test 'TEST increment'
is called only once.
Why do I want this?
I have test suites that have a series of tests the required to run in sequence, and if a test fails, then retries require restarting the sequence. For example, _counter
can only be incremented if test 'TEST increment'
is called again with a full test suite retry.
How can I do test suite retries?
let _counter = 0;
const _runModeRetries = 3;
context(
'CONTEXT Cypress Retries',
{
retries: {
runMode: _runModeRetries,
openMode: 0
}
},
() => {
it('TEST increment', () => {
_counter++;
expect(_counter).to.be.a('number').gt(0);
});
it('TEST true', () => {
expect(true).to.be.a('boolean').to.be.true;
});
it('TEST false', () => {
expect(false).to.be.a('boolean').to.be.false;
});
it('TEST counter', () => {
if (_counter < _runModeRetries) {
assert.fail();
} else {
assert.isTrue(true);
}
});
}
);
Upvotes: 5
Views: 1488
Reputation: 32108
This is really hacky, I'm but posting it in case you can improve on it
_runModeRetries
timesskip
variable to control if tests runfunction()
so that this.skip()
can be calledafter()
within the suite to set skip
true after first passskip
when a fail occurslet _counter = 0;
const _runModeRetries = 3;
let skip = false
Cypress.on('fail', (error, test) => {
skip = false
throw error // behave as normal
})
Cypress._.times(_runModeRetries, () => {
context('CONTEXT', {retries: {runMode: _runModeRetries}}, () => {
it('TEST increment', function() {
if (skip) this.skip()
_counter++;
expect(_counter).to.be.a('number').gt(0);
});
it('TEST true', function() {
if (skip) this.skip()
expect(true).to.be.a('boolean').to.be.true;
});
it('TEST false', function() {
if (skip) this.skip()
expect(false).to.be.a('boolean').to.be.false;
});
it('TEST counter', function() {
if (skip) this.skip()
assert.isTrue(_counter < _runModeRetries ? false :true);
});
}
);
after(() => skip = true) // any fail, this does not run
})
There may be some improvements available by adjusting the suite inside the onFail (suite = test.parent) and avoiding adding the changes to individual tests.
A cleaner way is to use the Module API which would allow you to run the test suite, examine the results and run again if there's any fail. Sort of manual-retry.
Upvotes: 6