Playwright test library - parent element for selector - e2e-testing

please, how to get a parent element for a text selector by the Playwright E2E library.
Is better to modify the selector (it is string by something like >> //:parent) or evaluate the selector and then call the DOM element?
(The selector content is unknown)
Thank you.

You can call .$ to start searching from the element:
const elem = await page.$(anySelector)
const parent = await elem.$('xpath=..')
Doc: https://playwright.dev/docs/api/class-elementhandle#elementhandleselector

Using the new Locator you can do:
const elementParent = await page.locator(`${childSelector} >> xpath=..`)
https://playwright.dev/docs/api/class-locator
https://playwright.dev/docs/selectors#xpath-selectors

Related

How to get element attribute by xpath in pyppeteer

I'm trying to use ElementHandle.Jeval() to get element style attribute through Pyppeteer. But the problem is I can only address the element by xpath since the element class is dynamically generated.
However, the ElementHandle.Jeval() requries selector as one of the parameters.
I've tried:
element = await iframe.Jx('//*[#id="root"]/main/div[1]/div/div[9]/div[1]/div[2]/div[2]/div/div[2]')
style = await element[0].Jeval(pageFunction='node => node.getAttribute("style")')
It still requires selector. And I tried to find a way to get selector from the ElementHandle I addressed through xpath, but didn't find out a method allow me to do so.
and:
xpath = '//*[#id="root"]/main/div[1]/div/div[9]/div[1]/div[2]/div[2]/div/div[2]'
style = await iframe.Jeval(xpath, pageFunction='node => node.getAttribute("style")')
-------------------------------
raise ElementHandleError('Evaluation failed: {}'.format(
pyppeteer.errors.ElementHandleError: Evaluation failed: DOMException: Failed to execute 'querySelector' on 'Document': '//*[#id="root"]/main/div[1]/div/div[9]/div[1]/div[2]/div[2]/div/div[2]' is not a valid selector.
at __pyppeteer_evaluation_script__:1:33
If anyone can figure this out, please let me know. Thanks.
-----------------update---------------
I figured out through editing the source code:
#!element_handle.py
# elementHandle = await self.querySelector(selector)
elementHandle = selector
if not elementHandle:
raise ElementHandleError(
f'Error: failed to find element matching selector "{selector}"'
)
result = await self.executionContext.evaluate(
pageFunction, elementHandle, *args)
await elementHandle.dispose()
return result
However, I don't want to do so. If anyone have a better way, let me know. Thanks.

How to click element in Puppeteer using xPath

I want to click on an element without using css selectors.
await page.click()
uses selectors to identify the element.
So how can I do something like this?
await page.click('/*[#id="toc"]/ul/li[1]/a')
First I had to get the element by using
await page.$x('<xPath>')
It returns an array with elements. To click I had to choose the first element in the array.
const elements = await page.$x('<xPath>')
await elements[0].click()
You can use the xpath prefix with puppeteer 19 and newer
await page.click('xpath/' + xpathExpression)
e.g.
await page.click('xpath//*[#id="toc"]/ul/li[1]/a')

Malformed attribute selector Cheerio

I'm Requesting to a website and getting the html successfully and loading it with cheerio.
The problem is that its erroring
const res = await axios.get(download_url);
const $ = cheerio.load(res.data);
let result = $('div[class=w-full mt-6 sm:mt-8 lg:mt-0 lg:w-1/3]').html()
So what I think is causing the error is the spaces but what would I have to replace them with?
Thanks,
You would either quote the value:
div[class="w-full mt-6 sm:mt-8 lg:mt-0 lg:w-1/3"]
or use . style:
div.w-full.mt-6.sm:mt-8.lg:mt-0.lg:w-1/3
Also chances are you don't need to full class:
div.w-full.mt-6.sm:mt

What's the expected behavior of puppeteer's ElementHandle.getProperty()?

Puppeteer 1.0.0-post. The getProperty() method seems somewhat magical. For example, if your page contains:
link
Then this will return not a relative but an absolute URL:
const propertyHandle = await elementHandle.getProperty('href');
const href = await propertyHandle.jsonValue();
// href is 'https://localhost:8080/foo/bar.html'
On the other hand, if you were to do the more roundabout:
const hrefHandle = await page.evaluateHandle(element => element.getAttribute('href'), elementHandle);
const href = await hrefHandle.jsonValue();
// href is '/foo/bar.html'
As far as I can tell, the puppeteer documentation doesn't mention this behavior of getProperty()?
It gets uglier, for instance if you want to get the style attribute of an element. It looks like puppeteer's getProperty() actually tries to parse the style in some way, which parsing is buggy/incomplete. The only way to get the raw text is with the roundabout call to evaluateHandle(...).
Is this an intended feature and simply a documentation bug? Or is it just, outright, a puppeteer bug?
Thanks.
See HTML - attributes vs properties for difference between HTML attributes and DOM properties.
You can easily see the difference without Puppeteer, too. For example, on this page:
document.getElementById('nav-questions').href
// returns "https://stackoverflow.com/questions"
document.getElementById('nav-questions').getAttribute('href')
// returns "/questions"

How to get updated html after changing page element values using puppeteer?

I'm at a loss. I'm typing into an input element on the page using this:
await page.type('#username', 'test');
Then I'd like to retrieve the newly updated, which I'm trying using this:
let html = await page.content();
But the username field does not include the word 'test' in it - it is empty. If I take a screenshot, it has the word 'test' in it. What am I missing?
Typing in an <input> element updates the value property but leaves the value attribute unchanged. This is why you don't see the text in the rendered HTML.
To get the value property:
await page.type('#username', 'test');
let value = await page.$('#username').getProperty('value');

Resources