Puppeteer Sharp - Get element containing textContent - puppeteer

I'm trying to work out how to efficiently grab an element from a page that contains a specific string.
The element is in an <a> tag however it's classes/ids are randomly generated.
The only way I can achieve this is by looping over every <a> tag and checking if the textContent matches.
<a>Match this text foo</a>
I've also tried using the xPath expression however I can figure out how to use the returned elements.
//a[contains(text(),'Match this text')]
Anyone have a better solution?

The page.$x(expression) method returns: <Promise<Array<ElementHandle>>>. So you can get specific element by index or just with the destructuring assignment.
For instance:
const links = await page.$x('//a[text()="Specific Text"]'); // returns: <Promise<Array<ElementHandle>>>
await links[0].click();
or even better with the destructuring assignment:
const [ link ] = await page.$x('//a[text()="Specific Text"]');
await link.click();

Related

Undefined when I try to get Text on a tspan element [WDIO] - typescript

I'm not able to get the text from a Tspan element, at the moment to see the value im getting undefined.
const element = await $("g.highcharts-legend-item.highcharts-line-series.highcharts-color-undefined.highcharts-series-1 tspan");
await testElement.isDisplayed();
await testElement.getText();
undefined
we probably need more context of your issue to give you a better answer.
As far as I can see in your post, you are trying to wait for the element to be displayed with this sentence:
await testElement.isDisplayed();
But this sentence doesn't wait for the element, it only returns the current state of the element.
If you want to wait for the element, you should try with the native wdio waits:
https://webdriver.io/docs/api/element/waitForDisplayed
So that line would turn into:
await testElement.waitForDisplayed();

How to select a button with multiple class names and specific aria-label in puppeteer js?

I am trying to click this button but I keep failing as there is also another button with the same class name with a different aria-name or I am just clicking it wrongly.
<button aria-label="upvote" aria-pressed="false" class="voteButton _2m5vzALl8kQdr9kwIFUo5t" data-click-id="upvote"><span class="_3wVayy5JvIMI67DheMYra2 _3SUsITjKNQ7Tp0Wi2jGxIM _22nWXKAY6OzAfK5GcUqWV2 qW0l8Af61EP35WIG6vnGk _3edNsMs0PNfyQYofMNVhsG"><i class="icon icon-upvote _2Jxk822qXs4DaXwsN7yyHA _39UOLMgvssWenwbRxz_iEn"></i></span></button>
my code looks like this at the moment :
await page.waitForSelector('.voteButton._2m5vzALl8kQdr9kwIFUo5t');
await page.click('.voteButton._2m5vzALl8kQdr9kwIFUo5t');
How can I click an element specifically for aria-label or data-click-id?
You must be independent from hash names like _3wVayy5JvIMI67DheMYra2
This names will be change after rebuild
You need use for your case some fixed classes like
'button[class~="voteButton"]'
And don't forget check your selector on page in console before run puppeteer:
document.querySelector('button[class~="voteButton"]');
then you can run puppeteer:
await page.waitForSelector('button[class~="voteButton"]');
await page.click('button[class~="voteButton"]');
You might have some other problem with your use case as your script should already work as expected: clicks the first element instance with the given selector (if there is a 2nd or 3rd instance: it won't touch them).
It is possible to select elements based on their specific attributes (including aria attributes) with Attribute selectors:
await page.waitForSelector('button[aria-label="upvote"]')
await page.click('button[aria-label="upvote"]')

How to access the style attribute of Primeng table

In an angular project, I need to test that the displayed table width of the primeng data table is set to the maxWidth value i assign to it. To do so, i want to call the [style] attribute to get the width and see if its equal to my maxWidth. However, i do not know how to call attributes like this. How do i go about this? Currently i have no clue if I'm going in the correct direction.
I have tried several things but I am not sure of the syntax for it.
<p-table class="p-table" ... [style] = "{width: maxWidth}" >
it('should implement maxwidth', () => {
const widthDebug: DebugElement = fixture.debugElement;
const tableWidth = widthDebug.query(By.css('.ui-table .ui-widget'));
const ptable: HTMLElement = tableWidth.nativeElement;
expect(ptable.textContent).toContain("width: " + component.maxWidth);
});
expected: success (ptable.textContent contains "width: component.maxWidth")
actual: TypeError: cannot read property 'nativeElement' of null
I see that it's now two months after you asked your question, so it's probably too late for my answer to help, but I stumbled across this post while looking up something else about PrimeNG, so I might as well give it a shot.
The problem here is that nativeElement is defined on Dialog class instances of the Angular p-table component. It's not defined on any particular DOM element.
By.css('.ui-table .ui-widget') is going to find a DOM element for you, not an Angular class instance. In particular what will be found is a <div> inside the <p-dialog> DOM element, and it's this <div> that receives the style set via [style]=....
As your code is written above tableWidth.style.width would contain (as a string) the value of maxWidth that you're expecting to find.

puppeeter selecting bootstrap-select option not val

I will freely admit that with puppeteer I am struggling. I'm using bootstrap-select jquery plugin to do drop downs. Here is an example of one of Jsfiddle
http://jsfiddle.net/9xr5af00/
I have tried numerous different ways of having jest - puppeteer click the dropdown and click an element on the dropdown.
(Not sure how to put puppeteer in a jsfiddle along with an example).
All the examples for puppeteer seem to indicate that I need to use the val html tag, however the bootstrap-select only uses the option tag.
This is one of the many things that I've tried
await page.click('#client-picker')
let value = "A"
await page.select('#client-picker',value)
However putting delays in it seems puppeteer doesn't actually scroll down the list. WHich I guess is right since it's just trying to do a select on an element. How can I make puppeteer scroll the list for an entry?
It create div element and you need to click the button with data-id="client-picker", select the parent and select li a element that match with the value.
await page.evaluate(() => {
let value = "A"
let clientPicker = document.querySelector('button[data-id="client-picker"]')
clientPicker.click();
let listOption = clientPicker.parentNode.querySelectorAll('li a')
Array.from(listOption).find(item => item.textContent == value).click()
});

How can I get the innerText of Dynamic Html tags using Puppeteer.js (node.js) in TripAdvisor?

How would I get all 10 comments located in this page with a loop or a Puppeteer function https://www.tripadvisor.com/Restaurant_Review-g294308-d3937445-Reviews-Maki-Quito_Pichincha_Province.html using innerText property?
The only solution I have come up with is getting the outerHTML of the whole container of comments and then try to substring to get all the comments, but that is not optimal and I think its a more difficult approach. Maybe there is an easier solution in Puppeteer I cant find?
I am doing this for educational purposes. The comments are in class="partial_entry" and I want to get the innerText of a Dynamic Html tag (I want all 10), like the ones you see here:
If I where to open the div that contains <div class="review-container" data-reviewid="606551292" data-collapsed="true" data-deferred="false"><!--trkN:3-->, I would get another with id="review_582693262". Getting to the point, If I get to a <div> that has class="partial_entry" this would be where my comment is located. I have tried a few things but I get null, because it is not found since the parent <div> for each comment has a unique id like id="review_xxxxxxxxx".
Its kind of difficult since the review id is autogenerated like id="review_xxxxxxxxx" and cant iterate with a loop copying the CSS path since I dont have a static parent .
Why not just select those elements which have partial_entry class? This works:
let comments = await page.evaluate(() =>
[...document.querySelectorAll(".partial_entry")].map(item => item.textContent)
);