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