Using puppeteer to access react event handlers - javascript

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

Related

How to target the selector on new tab after clicking a[target="_blank"] - Failing to activate the new tab created

After clicking a[target="_blank"] new tab opens. How to get code to get new page object so I can access password input field?
Using NodeJS, JavaScript, Puppeteer.
Navigation is working up to the point included below.
EDIT: I used the page.url() method to retrieve current URL and the URL of the newly created tab does not log to console, previous page logs.
I tried adjusting the script and received following errors
Cannot read properties of undefined (reading 'page') - I thought adding a time delay would solve this but no go.
I was having this error but as the code is below I do not get this error: No node found for selector: #Password
I have looked at related issues
I came across dheerajbhaskar GitHub issue and read up on related issues
#386
#3535
#978
and more
I tried to implement code from an accepted answer without any success.
Using Puppeteer to get a handle to the new page after "_blank" click?
try {
await sleep(2300)
// This block creates a new tab
// I was previously using a selector and not mouse click API
await Promise.all([
page.mouse.click(xToolsBtn, yToolsBtn, { delay: 2000 }),
])
// NEW TARGET CREATED
// Below is a snippet from an accepted answer but the the type method
// does not work
// Seems like page is still not activated
const [newTarget] = await Promise.all([
// Await new target to be created with the proper opener
new Promise((x) =>
browser.on("targetcreated", (target) => {
if (target.opener() !== page.target()) return
browser.removeListener("targetcreated", arguments.callee)
x()
})
),
// page.click('link')
])
// Trying to input password without success
const newPage = await newTarget.newPage()
await newPage.type("#Password", process.env.PASSWORD, {
delay: randomGenerator,
})
} catch (err) {
console.error(
"LOGIN BUTTON FAIL",
err.message
)
}
Alternatively atempt#1: I tried to select the input via mouse x, y co-ordinates which activates the input field but this returns the following error"
No node found for selector: #Password
Alternatively atempt#2:
//* WAIT FOR TARGET
try {
await sleep(2300)
await Promise.all([
page.mouse.click(xToolsBtn, yToolsBtn, { delay: 2000 }),
])
sleep(5000)
await page.evaluate(() => window.open(`${loginUrl3}`))
const newWindowTarget = await browser.waitForTarget(
(target) => target.url() === `${loginUrl3}`
)
console.log("GOT TARGET")
await newWindowTarget.type("#Password", process.env.PASSWORD, {
delay: randomGenerator,
})
} catch (err) {
console.log("WAIT FOR TARGET FAILED")
}
Note: URLS are randomly generated so I would be curious what if any work around there is to use current URL. I would assume the new tab created would still need to be activated...
managed to solve this together (Linker :)
Process
First, we mapped the target being created to check for focus
browser.on('targetcreated', function (target) {
console.log('New tab:');
console.log(target);
});
We saw the URL is trying to open - for some reason the URLs in the target were empty. We re-installed stuff to rule out weird dependency bugs, then figured there's a focus issue.
Workaround
To solve it, we need to wait for the .newPage() to open before goto'ing to the URL, calling bringToFront() and then waiting for it to load (short sleep is the easy way). Once we did that, we had a working POC to start from.
Relevant part from the solution:
let mappedURL = tabs
.map((e, index) => e.url())
.filter((e, idx) => idx == 2)
console.log("MAPPED URL ", mappedURL)
sleep(2500)
const page3 = await browser.newPage()
await page3.goto(`${mappedURL}`)
await page3.bringToFront()
Ref
Here's a cool SO Answer showing how to use once syntax to test the event. Happy we were able to solve it, and I hope the process helps other people out.
Addressing just the question in the title, "How to target the selector on new tab after clicking a[target="_blank"]" -
Handling newly opened tabs in Playwright is far from intuitive if you're not used to it. A summary of how they work:
If you click a link in your test with target="_blank", which opens a new tab, the page object you're working with still refers to the original page/tab you opened the link on.
To get ahold of the new page, you have to:
const [newPage] = await Promise.all([
context.waitForEvent('page'), // get `context` by destructuring with `page` in the test params; 'page' is a built-in event, and **you must wait for this like this,**, or `newPage` will just be the response object, rather than an actual Playwright page object.
page.locator('text=Click me').click() // note that, like all waiting in Playwright, this is somewhat unintuitive. This is the action which is *causing the navigation*; you have to set up the wait *before* it happens, hence the use of Promise.all().
])
await newPage.waitForLoadState(); // wait for the new tab to fully load
// now, use `newPage` to access the newly opened tab, rather than `page`, which will still refer to the original page/tab.
await expect(newPage).toHaveURL('http://www.someURL.com');
await newPage.locator('text=someText');

react-select-event doesn't trigger the onChange function to set the value during testing

It's been a couple of days that I'm struggling with a test I'm trying to write and thought this would be a good place to ask for some tips. I'm trying to fill a form that uses react-select dropdowns, and these forms are inside a map that renders 4 of them. However when trying to run the code below on the selectors of each form in a loop, after the first iteration which runs fine, the input element found in the form to perform the onChange doesn't have the onChange handler and doesn't trigger the change function to select the option I need. The package I am using for the selection is react-select-event as per the documentation here. I am still a beginner with react-testing-library and testing in general so it's quite probable that I missed something. Any tips or ideas are welcome! Thank you 🙂
const selectOptionAndAssertValue = async (indicator, field, element, option, inputForm) => {
await selectEvent.select(element, option.label, {
container: document.body,
});
await waitFor(
async () => {
expect(inputForm).toHaveFormValues({
[${indicator.short_alias}-${field}]: option.value,
});
},
{
onTimeout: error => console.log(error),
}
);
};
Note: to find the inputForm, I am using findByLabelText and it does find the element.
EDIT: Issue replicated in this repo https://github.com/ildaballiu/select-testing-demo
The issue was solved by changing the container to
container: () => document.body.querySelector('[class$=-menu]')

Using Event Target to return specific data in the console

I'm trying to use an event listener to return specific data from the console made from an API call and apply it to a variable to make another API call.
The calls are made through functions that return the data in JSON format.
The console data is as follows:
href: "https://api.spotify.com/v1/tracks/7f0vVL3xi4i78Rv5Ptn2s1"
id: "7f0vVL3xi4i78Rv5Ptn2s1"
I'm trying to only access the id portion to use it in a new API call. I have an event listener that I would like to use which receives the id on click.
DOMInputs.tracks.addEventListener('click', async (e) => {
const trackId = e.target.id;
}
However, the variable trackId contains the href instead of the id. Resulting in:
app.js:74 GET https://api.spotify.com/v1/audio-analysis/https://api.spotify.com/v1/tracks/7f0vVL3xi4i78Rv5Ptn2s1 404
Where the second link is contained in ${trackId} Is there a work around or am I missing something?
For those wanting to know the same thing. I simply used const trackEndPoint = e.target.id.replace('https://api.spotify.com/v1/tracks/', '');

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

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

Is there a way in protractor, by which we can iterate through the webelement having the same css and click on the element with matching text

PageObject.js(Select_Organization.js)
this.selectOrganization = function() {
organizationLocator.each(function(element) {
FunctionLibrary.getText(element, organizationName).then(function(text) {
logger.info(text);
if (text.includes('ImageResizingOrg')) {
FunctionLibrary.click(element, organizationName);
}
})
})
};
Spec.js
it('should be able to select the required organization', function() {
Select_Organization.selectOrganization();
});
Scenario:
I want to store all the elements having the same class name in a list and then iterate through it using for-each loop and click on the element if the text of the elementFinder is same as that required.
Issue I am facing: Due to async nature of the javascript this is not getting handled properly as sometimes stale element exception is getting thrown. I know the reason which is because all the actions are getting stored in control flow queue.
I just need a solution for this :) Any help will be highly appreciated

Categories