Cypress.io: How to send a trigger out of cy.then or cy.each function?

独自空忆成欢 提交于 2021-01-29 07:56:57

问题


I try to verify weather if there have store keyword I want between the elements of pages.

For example:

store keyword = "apple"

the part structure of a page:

<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>

I have 3 products,need to verify that every product have a store contains store keyword.

One product may have 10 pages,and have 10 stores per page.

Go to a product page,and start to find store keyword.

If I find store keyword in second store on third page,then go to another product page.

My strategy:

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
  }
}

At the beginning,I use a variable as a trigger to do break command.

I know later that you can't change outer variable as a trigger,need to use cy.then() at the end of cy.then() or cy.each() to do further operation.

I have tried to use except() to do verification instead of if(),but it will get assertion error when it did not find keyword in first element(but I want to find next one). And I also tried to make a uncaught:exception to ignore error:

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

I put this code at cypress/support/commands.js,and it didn't work.

Another way I tried is that return a value as a trigger in cy.then()/cy.each(),and I got

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

My question:

1.How to send trigger to break cy.then, cy.each and a for loop in this case?

2.How to ignore assertion error?


回答1:


What you're after is probably best solved by a recursive command/helper that crawls the pages until a store is found or until no other page/stores are left.

Below, the findStore is a function that calls _walkStores which is recursive. It crawls current page, and tries to load next page if nothing is found.

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');
    });
});


来源:https://stackoverflow.com/questions/58006776/cypress-io-how-to-send-a-trigger-out-of-cy-then-or-cy-each-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!