在赛普拉斯中如何找到计数具有相同ID的选择并获得长度?

时间:2019-03-20 20:58:26

标签: testing cypress

我有这样的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

1 个答案:

答案 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);
            });
    });
});

因此,您应该采用类似于BC的解决方案。