I have a loop checking 40 items. I want to stop my loop, when I am finding the first element, which > 0 This is my code
var genArr = Array.from({ length: 40 }, (v,
break
works only for native for
/while
loops.
To exit early from an .each
loop (as was suggested in the comments), the false
must be returned from the same callback you pass to it, so returning false
from the nested then
callback won't have an effect.
You can't even set a flag in the then
callback and check it in the each
callback, because .each()
command is deep down just a jQuery.fn.each
--- it's synchronous and by the time you'd set up the flag, all iterations will have run (and enqueued the nested commands).
Thus, the only option is not to use .each()
, and use some kind of recursive command. Let's build one.
function walk ( arr, cb, index = 0 ) {
if ( !arr.length ) return;
arr = arr.slice();
const ret = cb(index, arr.shift());
((ret && ret.chainerId) ? ret : cy.wrap(ret))
.then( ret => {
if ( ret === false ) return;
return walk(arr, cb, index + 1);
});
}
/**
* Your callback should return/yield `false` if the loop is to exit early.
*/
Cypress.Commands.add('eachSeries', { prevSubject: 'optional' }, (subject, arr, cb) => {
return subject
// assume `arr` to be `cb`
? walk(subject, arr)
: walk(arr, cb);
});
usage:
describe('test', () => {
it('test', () => {
cy.document().then(doc => {
doc.body.innerHTML = `
0
1
2
3
`;
});
var genArr = Array.from({ length: 40 }, (v, k) => k + 1);
// the command can be chained on an existing subject
cy.wrap(genArr).eachSeries((index) => {
return cy.get('.list-item').eq(index)
.invoke('text')
.then(text => {
if (text > 1) return false;
});
});
// or it can start the chain (the array is passed as 1st arg)
cy.eachSeries(genArr, (index) => {
return cy.get('.list-item').eq(index)
.invoke('text')
.then(text => {
if (text > 1) return false;
});
});
// you can also return a promise
cy.eachSeries(['a', 'b', 'c'], (index, value) => {
return new Promise(resolve => {
setTimeout(() => {
resolve(value === 'b' ? false : true);
}, 500);
});
});
// non-thenable callbacks work too
cy.eachSeries(['a', 'b', 'c'], (index, value) => {
return value === 'b' ? false : true;
});
});
});
In the first two examples above, only the first 3 items are looped through and then the loop exits early.