How to click on each payment method in cypress using iteration? - javascript

My requirement is to click on each and every payment method (pay-safe, visa, bit-pay etc.)
and then validate using assert method by comparing URL.
Problem : Unable to click on element. I'm getting null value in variable. Tried using val() as well as html() method.
I tried below code.
//cy.get('.real-money--providers-list') = allPaymentMethods
depositFiat.allPaymentMethods().find('[src*="providers/logo"]').each(($element, index, $list) => {
var namePaymentProvider = $element.find('[alt*="safe"]').text()
cy.log(namePaymentProvider)
cy.wait(1000)
if(namePaymentProvider.includes('class')){
$element.find('.provider-content--choice').click()
//cy.get('.provider-content').invoke('removeAttr','src').click()
//depositFiat.secureCheckout().click()
//cy.back()
}
})
As cypress unable to handle child windows I tried to use invoke method but no luck.
Find HTML here

<div class="provider-img"><img alt="safecharge_paysafecard" class="style__Logo-a3ugi5-2 fAwRoV visible" src="https://static.xyz.com/1234123463/img/providers/logo_safecharge_paysafecard.svg"></div>
As per your HTML fiddle, I could see that for every payment provider you can use the css selector img[class*="style__Logo"]
For one payment method you can use:
cy.get('img[class*="style__Logo"]').eq(0).invoke('attr', 'src').should('contain', 'https: //static.xyz.com/')

You are finding an image, then trying to click on it.
Most likely the click-event sits on the button
Instead try to click on the button:
cy.get('.provider-content').each($element => {
cy.wrap($element).click()
// Assert something here
})
If the click action opens up a new tab/window, and you want to assert that it moved you do this new link, then Cypress does not support this directly.
Instead, you would either get the url that should be opened by the click and verify that.
Or
Stub the browser window so that the new tab opens up in the same tab you are currently in.

You can use Recursion and Jquery .removeAttr :
cy.get('[src*="providers/logo"]') //You need to make sure here is the correct selector that covers all methods here
.then(methods => {
checkPaymentMethod
function checkPaymentMethod(methodNumber = 0) {
if(methodNumber < methods.length) {
Cypress.$(methods[methodNumber]).removeAttr("target");
cy.get(methods[methodNumber])
.click()
.should('not.exist')
cy.url().should('eq', 'targetUrl')
cy.visit('yourPageUrl')
cy.url().should('eq', 'yourPageUrl')
methodNumber ++
checkPaymentMethod(methodNumber)
}
}
})

Related

How to click in a select element with several options with Cypress?

I have a problem in clicking in a select element using cypress.
This is the element to click:
And i receive this error.
cy.click() cannot be called on a <select> element. Use the cy.select() command instead to change the value.
This is my code:
cy.get('[name^=shopveg]').click()
After searching some people advise using the trigger command.
Changed the code to:
cy.get('[name^=shopveg]').trigger('click')
The step pass in the cypress execution but the click was not executed.
As the message says, .select() is the command to use
cy.get('[name^=shopveg]').select('Bananas')
That's because <select> behavior is implemented by a web component (see slot tag), not javascript, so there's no click handler available.
Given the select looks like a "special" implementation, i.e a web component with slots, you may need to click it open to see the option values (lazy loading).
If so, try with cypress-real-events plugin
Install
npm install cypress-real-events
// or
yarn add cypress-real-events
In /cypress/suport/e2e.js
import "cypress-real-events";
Test
cy.get('[name^=shopveg]')
.should('have.value', '1') // confirm initial value
.realClick() // click open
cy.contains('option', 'Batatas') // this option exists
cy.contains('option', 'Arroz') // this option exists
cy.contains('option', 'Bananas') // this option exists
// etc
cy.get('[name^=shopveg]')
.select('Bananas') // select new option
.should('have.value', '3') // confirm new value
To validate the values in the select menu, you can iterate through them with cy.each().
const options = [ "Batatas", "Arroz", "Bananas", "Tomates", "Macaz" ];
cy.get('[name^=shopveg]').find('option').each(($el, index) => {
cy.wrap($el).should('have.text', options[index]);
});
As #Grainger answered, you can then use cy.select() to pick a value.

Using puppeteer to access react event handlers

I am trying to use puppeteer to access properties of an element. Specifically I need the key or listingId from the react event handler object
__reactEventHandlers$(the rest is dynamically generated) > children[0] > key
screenshot from devtools on page
So far await page.$(".RoyalTicketListPanel"); or await page.$(".RoyalTicketListPanel__0"); the first being a ul element and the second being the first list item, returns a lot of data for the element, but not the event handler object.
I've tried
await page.evaluate((selector) => {
return document.querySelector(selector);
}, selector);
as well and it just returns undefined.
Someone posted a similar question here How to access React Event Handlers with Puppeteer
But the answer also returns undefined in my case.
I'm stumped at this point, if anyone can help me out with this it would be greatly appreciated.
Also, if anyone wants to try to recreate what I'm doing, I'm using puppeteer to go to an event on stubhub then trying to get the ticket's listing ids from the ticket list.
var abc=document.querySelector('.RoyalTicketListPanel');
var reactHandlerKey=Object.keys(abc).filter(function(item){
return item.indexOf('__reactEventHandlers')>=0
});
var reactHandler=abc[reactHandlerKey[0]];
console.log(reactHandler);

How to test relative positioning of elements in cypress?

I am currently new to cypress and wants to test that Forgot Password should be below Login button in Facebook page? Is there a way to do that?
Is there a way to test relative positioning of elements in cypress?
I think you can use jQuery .position()
cy.get('#element1')
.then($el => $el.position().top) // get 1st top value
.then(top1 => {
cy.get('#element2')
.then($el => $el.position().top) // get 2nd top value
.then(top2 => {
expect(top1).to.be.gt(top2)
})
})
Notes
Cypress use jQuery to find elements. Chaining .then($el => ... exposes the jQuery object containing the element, so now you can apply other jQuery functions that are not part of the Cypress commands.
In fact, any other Javascript functions you want.
You can also make reusable functions
const getTop = ($el) = $el.position().top;
cy.get('#element1').then(getTop)
.then(top1 => {
cy.get('#element2').then(getTop)
.then(top2 => {
expect(top1).to.be.gt(top2)
})
})
You can use the cypress method next() to determine the element next to Log in button like this. next() gets the immediately following sibling of each DOM element within a set of DOM elements.
cy.get('div[type="submit"]').next().should('have.text', 'Forgot password?')

How to open different popups with the same title in CasperJS?

I'm trying to automate some tasks using casperJS, and I need to open multiple popups. However, all popups have the exact same url (http://.../printit.aspx/...), so that whenever I use
this.withPopup(/printit/, function() {...});
it always opens the first popup. I can't access the other ones.
I suppose there are two possibilities :
close each popup after visiting it, but I can't find how to do this
accessing popups using another way than the URL regex /printit/. Maybe using casper.popups, but the documentation is very vague about this.
There is no easy and documented way of disambiguating two popups. The documentation says that casper.popups is an array-like property. So you could iterate over it. Judging by the code, the popups property itself is a pagestack. One can easily modify the pagestack.findByRegExp() function to do this kind of thing.
It seems that the casper.popups property contains duplicate entries, so one can filter them out.
casper.findAllPopupsByRegExp = function(regexp){
var popups = this.popups.filter(function(popupPage) {
return regexp.test(popupPage.url);
});
if (!popups) {
throw new CasperError(f("Couldn't find popup with url matching pattern %s", regexp));
}
// remove duplicates
var uniquePopups = [];
popups.forEach(function(p){
if (uniquePopups.indexOf(p) === -1) {
uniquePopups.push(p);
}
});
return uniquePopups;
}
casper.withPopup() accepts three types of inputs to identify a popup page. The third one is a the page object itself. So you can retrieve the matching popup page objects with findAllPopupsByRegExp(), select the one that you want and pass that to withPopup() to change into its context:
casper.then(function(){
var popups = this.findAllPopupsByRegExp(/printit/);
this.withPopup(popups[1], function(){
...
});
});
In my case i have a list of links. Every link calls some javascript that opens a new tab(=popup in casperjs), always with the same url (...\View.aspx).
Inside the tab i have to click a button that changes the url in the tab (...\List.aspx).
on("popup.loaded"...) is called twice, pushing every new page in the casper.popups array. They usually alternate, but for some reason (i guess asyncrony) not always: sometimes casper.popups[/*LAST*/].url matches /View\.aspx/, sometimes it matches /List\.aspx/.
I always had to use casper.withPopup( /*LAST VIEW.ASPX LOADED*/, ...); that was not always the last popup loaded and neither the one matching /View.aspx/ (it could be one of the oldes), so i had to find the latest loaded matching /View\.aspx/.
Here's my solution:
var is_view_loaded=false;
casper.on('popup.loaded', function(page) {
if(page.url.match(/View\.aspx/)) {
is_view_loaded=true;
}
}
// return last popup which url matches the required regexp
casper.getLastRegExPopup=function(regex) {
var l=casper.popups.length;
var i=l-1;
while(!regex.test(casper.popups[i].url)) {
i--;
if(i<0) return null;
}
return casper.popups[i];
}
Then in my core steps:
.
.
// clicked the link, must wait for popup (but which?!)
casper.waitFor(
function test() {
return is_view_loaded;
},
function then() {
var popup=casper.getLastRegExPopup(/View\.aspx/);
casper.withPopup(popup, function() {
// do things with "this"
});
is_view_loaded=false;
}
//, timeout
);
.
.

Chrome Extension Notifications Not Always Created - Reuse?

Let's say I want to show the same notification each time something happens. That's what I currently use:
chrome.notifications.create(id, {
type:"basic",
title:"Title",
message:"My message",
iconUrl: "icon.png",
}, notificationResult);
But sometimes the notification doesn't appear.
Is that an id thing ? Do I need to reuse an already created notification ? Can I not create a new notification with the same id ?
I tried to do a var notification = chrome.notifications.create(id .... ) and do a notification.show() in case I already created one with the same id but that also didn't solve it.
So - do I need to recreate an existing notification each time I want to show the same one (which currently doesn't work for me), or is there a different way? How to make sure it pops every time?
The id in the create function is specifically for reusing. IDs must be unique. If you use create with an ID of an existing notification, it basically behaves like an update.
If a notification exists, it may no longer be shown but only be visible in the Message Center. In this case, the notification IS updated - but not shown again.
The API docs specify that you can pass an empty string to the notification to get a unique new id. If you need it, it is passed to the callback.
But if you do want to reuse the ID (ensuring that the notification is unique), you can use priority trick to make it show again.
You can clear the notification if its not use and if you want to use the same id.
For example :
function Notify(){
var my_notif_id="some_id";
//This will clear your previous notifcation with the same ID
chrome.notifications.clear(my_notif_id,function(){});
chrome.notifications.create(my_notif_id,options,function(){});
}
Now each time you call the notify function to display notification it will clear the old notification before displaying new notification and gets displayed.
UPDATED
As #Xan suggested, Its good to incorporate the create() method inside callback function of clear()
So here is the complete example :
function Notify(id, options){
//This will clear your previous notifcation with the same ID
chrome.notifications.clear(id, function() {
//inside callback function
chrome.notifications.create(id, options, function(){});
});
}

Categories