我有这样的HTML代码。
<div id ='pages'>
<div id='wrapper'>1 </div>
<div id='wrapper'>2 </div>
</div>
我想找到带有id包装器的元素数。 我使用赛普拉斯。我开始学习赛普拉斯。 如果我尝试:
cy.get('div#wrapper').should('have.length', 2)
我收到AssertionError:
CypressError: Timed out retrying: expected 1 to equal 2
答案 0 :(得分:0)
正如jonrsharpe所指出的那样,具有多个具有相同id
属性的元素是无效的HTML。
话说回来,DOM非常聪明,即使使用无效的HTML也可以恢复和工作。重复的id
元素不会造成太大麻烦。
例如尝试执行document.querySelectorAll('#wrapper')
,它应该返回2个元素的列表(在您的情况下)。
问题是,赛普拉斯正在使用jQuery来查询DOM而不是使用本机DOM方法,而且我猜想jQuery并不那么聪明(或者更时髦)。
话虽如此,我在运行时无法重现该错误:
// succeeds
cy.get('div#wrapper').should('have.length', 2)
仅在直接查询#wrapper
时(没有前面的div
时):
// fails
cy.get('#wrapper').should('have.length', 2)
我认为这是因为当选择器字符串(#wrapper
)仅包含一个id时,jQuery使用了一种提前退出的启发式方法(这就是div#wrapper
返回两个元素的原因)。
此外,您在注释(cy.get('#pages') .find('div#wrapper') .should(($div) => { expect($div).to.have.length(2) })
)中的解决方案在运行时也不理想,因为它不会重试。让我演示一下:
在下面的代码中,第二#wrapper
仅在1秒后才会出现在DOM中。
describe( 'test', () => {
beforeEach(() => {
cy.document().then( doc => {
doc.body.innerHTML = `
<div id='pages'>
<div id='wrapper'>1</div>
</div>
`;
setTimeout(() => {
doc.body.innerHTML = `
<div id='pages'>
<div id='wrapper'>1</div>
<div id='wrapper'>2</div>
</div>
`;
}, 1000 );
});
});
// will fail
it('solution A', () => {
cy.get('#pages') // <- won't be retried
.find('div#wrapper') // <- only this command will be retried
.should( $div => expect($div).to.have.length(2) );
});
// will pass
it('solution B', () => {
cy.get('#pages #wrapper') // <- will be retried and succeed in 1sec
.should( $div => {
expect($div).to.have.length(2);
});
});
// will pass
it('solution C', () => {
cy.get('#pages')
.should($pages => {
// using native DOM querying
expect($pages[0].querySelectorAll('#wrapper').length).to.eq(2);
});
});
});
因此,您应该采用类似于B
或C
的解决方案。