break 仅适用于原生 for/while 循环。
要提前退出 .each 循环(如 cmets 中所建议的那样),false 必须从您传递给它的同一个回调中返回,因此从嵌套的 then 回调中返回 false 获胜'没有效果。
你甚至不能在then 回调中设置一个标志并在each 回调中检查它,因为.each() 命令在深处只是一个jQuery.fn.each --- 它是同步的,当你'd 设置标志,所有迭代都将运行(并将嵌套命令排入队列)。
因此,唯一的选择是不使用.each(),而使用某种递归命令。让我们建立一个。
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);
});
用法:
describe('test', () => {
it('test', () => {
cy.document().then(doc => {
doc.body.innerHTML = `
<div class="list-item">0</div>
<div class="list-item">1</div>
<div class="list-item">2</div>
<div class="list-item">3</div>
`;
});
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;
});
});
});
在上面的前两个示例中,只有前 3 个项目被循环通过,然后循环提前退出。