I have the following code:
<li id="ecf43e6a-0a99-4b88-9927-7f6b681bc18d" class="checked">
<input type="button">
<span>Green</span>
</li>
I'm trying to click on the button by doing this.
const btnWrap = await page.$('#ecf43e6a-0a99-4b88-9927-7f6b681bc18d');
await btnWrap.$eval('input', el => el.click());
I'm getting an error on this any idea why it's not working?
For me your script works just fine.
You may need to wait for the element to be appeared:
await page.waitForSelector('#ecf43e6a-0a99-4b88-9927-7f6b681bc18d')
I think that will do the job as well:
await page.$eval('#ecf43e6a-0a99-4b88-9927-7f6b681bc18d > input', el => el.click());
Related
Given the following markup:
<label for="name">Name</label>
<input type="text" id="name" />
I want to fill the input value in a Playwright test. However, I prefer to follow a paradigm similar to Testing Library, which is using selectors like a real user would (usually visible text content). Therefore, I would like my Playwright selector to use the label text.
When I attempt the following I get an error element is not an <input> because it selects the actual label element:
await page.fill('"Name"')
Is there another way to achieve this?
Note: I'm not keen on using the Playwright Testing Library package because it simply isn't mature enough. Also, my understanding is that Puppeteer and Playwright are virtually the same, hence why this question applies to both frameworks.
You could .click() the label to set focus on the input, then use page.keyboard.type to type into the input.
Here's a minimal example:
const puppeteer = require("puppeteer");
let browser;
(async () => {
browser = await puppeteer.launch({headless: true});
const [page] = await browser.pages();
await page.setContent(`
<label for="name">Name</label>
<input type="text" id="name" />
`);
await page.click("label[for='name']");
await page.keyboard.type("hello world");
console.log(await page.$eval("#name", e => e.value)); // => hello world
console.log(await page.evaluate(() => document.activeElement.value)); // same
})()
.catch(err => console.error(err))
.finally(() => browser?.close())
;
When an input field and a label are correctly connected.
For example like this (using the for attribute:
<label for="name">Name</label>
<input type="text" id="name" name="name" />
Then it's really easy to fill the input field using the label.
It works like this for example:
await page.fill('label:has-text("name")', 'Peter');
The feature to fill an input via a selected label was added to Playwright in this pull request: https://github.com/microsoft/playwright/issues/3466
To expand on #ggorlen answer, and to make it even more similar to Testing Library, you can use the :has-text() pseudo-class to select the label by its accessible name:
await page.click('label:has-text("Name")');
await page.keyboard.type('hello world');
Playwright has an exact locator for this page.getByLabel
Allows locating input elements by the text of the associated label. For example, this method will find the input by label text Password in the following DOM:
<label for="password-input">Password:</label>
<input id="password-input">
#paramtext — Text to locate the element for.
Trying to automate selection of a dropdown item in the Wunderground/wundermap (https://www.wunderground.com/wundermap) and struggling a bit. The selection item isn't named, and gets a random ID every page load (common element to the ID, but new numbers). The element is:
<select aria-label="Map Types" class="header-select ng-pristine ng-valid ng-touched" style="width: 200px;" id="mapTypes0.3556425555390934"><option title="Show street map with terrain" value="terrain" selected="selected">Terrain</option><option title="Show Dark Map" value="darkmap">Dark Map</option><option title="Show Light Map" value="lightmap">Light Map</option><option title="Show satellite imagery" value="satellite">Satellite</option><option title="Show imagery with street names" value="hybrid">Hybrid</option></select>
Trying to select darkmap using puppeteer.
I've tried a couple of page eval options but they don't seem to be finding the element. Any suggestions?
This seems working:
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({ headless: false, defaultViewport: null });
try {
const [page] = await browser.pages();
await page.goto('https://www.wunderground.com/wundermap');
const select = await page.waitForSelector('select[aria-label="Map Types"]');
await select.select('darkmap');
} catch (err) { console.error(err); }
so im trying to create a link shortener for me and my friend
to use on our small service center
but im having a small problem.
i set up an express server to get this done, whilst creating a fileuploader
which i used postman to test.
both work fine, but this is where im getting the problem.
whenever i use the snippet below to try and send data to the 'api'
it doesnt even post/touch the website yes i debugged to see if it touched
its only when i use form post/get method that the code doesnt work
HTML code snippet
<form method="POST" action="/shorten" enctype="application/x-www-form-urlencoded">
<label for="fUrl" class="sronly">URL</label>
<input class="input"
required
placeholder="URL"
type="url"
name="fUrl"
id="fUrl"
/>
<button type="submit">Shrink This!</button>
</form>
ive tried many things, i dont know if its because im rendering it with EJS or what
i tested it on its own with an HTML file but to no avail
if theres anything in this post i missed to go over let me know!
It looks like there is some issue with mapping between client and server. Try changing action value to the your API endpoint.
<form method="POST" action="http://myserver.com/shorten" enctype="application/x-www-form-urlencoded">
<label for="fUrl" class="sronly">URL</label>
<input class="input"
required
placeholder="URL"
type="url"
name="fUrl"
id="fUrl"
/>
<button type="submit">Shrink This!</button>
</form>
It was a problem of browsers being a tad too fast/slow
fix is here
// thanks to Vikasdeep Singh for this oddly specific url regex test
function isValidURL(string) {
var res = string.match(/(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9#:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9#:%_\+.~#?&//=]*)/g);
return (res !== null)
};
var el = document.getElementById("yourButtonID");
el.addEventListener("click", avoidNSErrorWithFirefox, false); //Firefox
function avoidNSErrorWithFirefox() {
ElementInterval = setInterval(function() {
var url = document.getElementById("inputURL").value; // input tag
if (isValidURL(url)) {
var xhr = new XMLHttpRequest();
xhr.open("POST", "https://your-url.com/shorten", true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({
"url": url
}));
}
clearInterval(ElementInterval);
}, 0);
};
works like a charm on all browsers ive tested
edge chrome opera firefox
Hopefully me and my friends fix saves you some trouble with form / express problems!
I have this function to create a search bar using the Express Framework in Node.JS, Handlebars and MySQL. The connection to MySQL is already functional, body parser already installed, and i already checked the query hardcoded straight inside phpmyadmin (without the req.body) and it worked, but it doesn't work when i applied it to Node.JS
inside the handlebars :
<form role="form" action="naskah_form/search" method="get">
<input type='text' name='titlesearch' id='q' placeholder='Enter a keyword...' required autocomplete='off'>
<input type='submit' value='Search' id='submit'>
</form>
inside naskah_form.js :
router.get('/search', (req,res)=>{
let sql = "SELECT * FROM upload_test where title LIKE '% "+
req.body.titlesearch + "%'"
conn.query(sql, (err,results)=>{
if (err) throw err
res.json(results[0])
})
})
module.exports = router
I expect the result would be to at least show a list of json of the searched word let's say 'q'. The url is http://localhost:3000/naskah_form/search?titlesearch=q but inside it is blank.
Can anyone guide me on how to approach this issue?
if you are using the GET method to submit the form then use req.query.titlesearch :
router.get('/search', (req, res) => {
console.log(req.query);
})
if you are using the POST method to submit the form then req.body.titlesearch
router.post('/search', (req, res) => {
console.log(req.body);
})
I have 2 button one of them of type file -which is hidden- if the user click the first button a confirmation dialog opens if user click Ok the second button must be clicked.
The problem is that all the logic is subscribe method -of confirmation dialog - are execute expect clickEvent for the second button.
Can anyone explain why and provide me with a solution?
#ViewChild('fileBrowser') fileInput: ElementRef;
dialogRef: MdDialogRef<ConfirmationDialog>;
clickUpload(){
this.dialogRef = this.dialog.open(ConfirmationDialog);
this.dialogRef.afterClosed().subscribe((result) => {
if (result) {
// some code
this.fileInput.nativeElement.click();
}
this.dialogRef = null;
});}
//HTML Code
<button md-button (click)="clickUpload()" > upload</button>
<input #fileBrowser id="fileBrowser" type="file" hidden="true">
"this.fileInput.nativeElement.click();" this is the problem line
I found the solution, i changed dialogRef's method from afterClosed to beforeClose
The new code
this.dialogRef.beforeClose().subscribe((result) => {
if (result) {
// some code
this.fileInput.nativeElement.click();
}
this.dialogRef = null;
});}