【问题标题】:Cypress.io: How to send a trigger out of cy.then or cy.each function?Cypress.io:如何从 cy.then 或 cy.each 函数中发送触发器?
【发布时间】:2019-09-19 08:26:48
【问题描述】:

如果页面元素之间有我想要的商店关键字,我会尝试验证天气。

例如:

商店关键字 = “苹果”

页面的部分结构:

<tbody>
  <tr>
    <td class="store">
      <img class="offer-store" ... alt="amazon store" .../></td>
    <td ...
    ...</td>
  </tr>
  ...
  <tr>
    <td class="store">
      <img class="offer-store" ... alt="apple store" .../></td>
    <td ...
    ...</td>
  </tr>
</tbody>

我有 3 个产品,需要验证每个产品都有 store 包含 store 关键字。

一个产品可能有 10 个页面,每个页面有 10 个商店。

进入产品页面,开始查找店铺关键词。

如果我在第三页的第二个商店中找到商店关键字,则转到另一个产品页面。

我的策略:

for(var i = 0; i < 3; i++) // three product
{
  //assume I can go to store page of a product here(using var i)
  for(var j = 1; j < 10; j++) //search 10 store pages of the product
  { 
    cy.get(".offer-store").each(($item)=>{  
    cy.get($item).its('context').invoke('attr','alt').then((store)=>{
      if(store.indexOf('apple')!=-1)
        cy.log("found store!!")
        //send trigger to break cy.then, cy.each and a for loop
      })
    })
    cy.get('.btn-group').contains('>').click({force: true}) 
    //go to next page if not found in this page
  }
}

一开始,我用一个变量作为触发器来做break命令。

我后来知道不能改变外部变量作为触发器,需要在 cy.then() 或 cy.each() 的末尾使用 cy.then() 来做进一步的操作。

我尝试使用 except() 代替 if() 进行验证,但是当它在第一个元素中没有找到关键字时会出现断言错误(但我想找到下一个)。而且我还尝试制作一个 uncaught:exception 来忽略错误:

Cypress.on('uncaught:exception', (err, runnable) => {
    return false
})

我将这段代码放在 cypress/support/commands.js 中,但没有用。

我尝试的另一种方法是在cy.then()/cy.each()中返回一个值作为触发器,我得到了

CypressError: cy.then() failed because you are mixing up async and sync code.

我的问题:

1.在这种情况下如何发送触发来中断cy.then、cy.each和for循环?

2.如何忽略断言错误?

【问题讨论】:

  • 正确的做法是在cypress/support/index.js中添加uncaught:exception。但是我认为即使添加了断言错误也不会被忽略。
  • @Pigbrainflower 感谢您的回答,但我想知道这个未捕获的主要目的是什么:异常?

标签: javascript cypress


【解决方案1】:

您所追求的可能最好通过递归命令/帮助程序来解决,该命令/帮助程序抓取页面直到找到商店或直到没有其他页面/商店。

下面,findStore 是一个调用 _walkStores 的函数,它是递归的。它爬取当前页面,如果没有找到则尝试加载下一页。

describe('test', () => {
    function _walkStores ( store ) {
        let found = false;
        return cy.get('.store').each( elem => {
            if ( Cypress.$(elem).find(`[data-store="${store}"]`).length ) {
                found = true;
                return false; // exit early (not required)
            }
        }).then(() => {
            if ( found ) {
                return true;
            } else {
                if ( Cypress.$('.nextPage').length ) {
                    cy.get('.nextPage').click();

                    // if your `.nextPage` button doesn't immediately repaint 
                    //  DOM as my mock helper does, you should assert url
                    //  change or something similar, before calling _walkStores,
                    //  so as to ensure the _walkStores doesn't retrieve the
                    //  same old DOM nodes
                    return _walkStores(store);
                }
                return false;
            }
        });
    }

    function findStore ( store ) {
        return _walkStores(store).then( found => {
            expect(found, `store "${store}"`).to.true;
        });
    }

    function loadProduct ( name ) {
        cy.window().then(win => {
            const pages = [
                `
                    <div class="store">
                        <div class="offer-store" data-store="apple">Apple</div>
                    </div>
                    <div class="store">
                        <div class="offer-store" data-store="amazon">Amazon</div>
                    </div>
                    <button class="nextPage" onclick="nextPage()">next</button>
                `,
                `
                    <div class="store">
                        <div class="offer-store" data-store="microsoft">Microsoft</div>
                    </div>
                    <div class="store">
                        <div class="offer-store" data-store="dell">Dell</div>
                    </div>
                    <button class="nextPage" onclick="nextPage()">next</button>
                `,
                `
                    <div class="store">
                        <div class="offer-store" data-store="ibm">IBM</div>
                    </div>
                    <div class="store">
                        <div class="offer-store" data-store="lenovo">Lenovo</div>
                    </div>
                `,
            ];

            const doc = win.document;

            win.nextPage = () => {
                const page = pages.shift();
                if ( !page ) return;
                doc.querySelector('.content').innerHTML = 'loading...';
                setTimeout(() => {
                    doc.querySelector('.content').innerHTML = page;
                }, 1000 );
            };
            doc.body.innerHTML = `
                <h1>${name}</h1>
                <div class="content">
                    ${pages.shift()}
                </div>
            `;
        });
    }

    it('test', () => {
        ['Laptop A', 'Laptop B'].forEach( name => {
            loadProduct(name);
            // will pass
            findStore('ibm');
        });

        // will fail
        findStore('xx');
    });
});

【讨论】:

  • 我得到 CypressError: cy.then() failed 因为你混淆了异步和同步代码。
  • 似乎 cy.then() 试图同步返回一个值(false)。不过谢谢你的回答
  • 运行我发布的确切代码,还是您自己改编的代码?
猜你喜欢
  • 2011-03-20
  • 2018-03-08
  • 1970-01-01
  • 1970-01-01
  • 2019-10-09
  • 2012-08-13
  • 2019-08-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多