I am testing two websites that are linked between each other. I starts on website one where there is a link (_blank) to the second website. And I want to continue my test on that tab.
test('test', async ({ page }) => {
const browser = await chromium.launch();
const context = await browser.newContext();
await page.goto('https://example.io/');
const [newPage] = await Promise.all([
context.waitForEvent('page'),
page.locator('a.browser-button').first().click() // Opens tab
])
await newPage.waitForLoadState();
console.log(await newPage.title());
await page.screenshot({ path: 'test.png', fullPage: true });
await browser.close();
});
So I click on the button, a new tab opens. And then I want to continue from there.
Instead I get the error:
Timeout of 30000ms exceeded.
context.waitForEvent('page')
I have tried as in documentation as well, dont get it to work either:
https://playwright.dev/docs/pages
Handling new pages is documented here
You can capture the new page from the click event.
const [newPage] = await Promise.all([
context.waitForEvent('page'),
page.locator('a[target="_blank"]').click() // Opens a new tab
])
await newPage.waitForLoadState();
console.log(await newPage.title());
I'd remove the target=_blank attribute on the element and then click it.
await page.$eval("a.browser-button", el => el.removeAttribute("target"))
Then click it and it will open in the same window. Unless you're really determined to test it as is.
Related
I was wondering if there is a way to verify using playwright that there are 2 web tabs open...
In the code below I click on a button and verify that google has opened.
BUT!
I also would like to verify that there are now 2 tabs open and wanted to know if it can be done with some thing like .toHaveCount(2)
OR
would you guys recommend something better?
test('Click button link test using blank target', async () => {
const browser = await chromium.launch();
const context = await browser.newContext();
const page = await context.newPage();
await page.goto(<my weblink>);
const newPagePromise = new Promise((resolve) => context.once('page', resolve));
// Button locator used to click the button to open the link
const buttonLocator = page.locator('.MuiButton-root');
// Click the button
await buttonLocator.click();
// Verify that after clicking on the page that the correct URL is present
const newPage = await newPagePromise;
expect(newPage.url()).toContain('https://www.google.ca');
});
You can use browserContext.pages() to get all the pages opened in the context. You can then use length and assert the values like this
const totPages = context.pages().length
expect(totPages).toHaveCount(2);
First time using Puppeteer and trying to simply click this button
after clicking the deny cookies button. That's my code:
await page.goto('https://myurl.com');
await page.click('a.cc-btn.cc-deny');
// await page.waitForNavigation();
await page.waitForSelector("#detailview_btn_order", {visible: true});
await page.click("#detailview_btn_order");
Clicking the deny cookies button works like a charm. However, it seems the second button can't be identified by Puppeteer. If I don't use waitForSelector it just says it can't find it. If I use it, I get a timeout after 30 seconds even though the website finishes loading after 5 seconds. If I uncomment waitForNavigation (regardless of what options I use) I get a timeout there, even thoug the site loads within seconds. What am I doing wrong? Thanks!
Can you try this:
await page.goto('https://myurl.com');
await Promise.all([
page.click('a.cc-btn.cc-deny'),
page.waitForNavigation(),
]);
const iframeElement = await page.waitForSelector("#my-iframe");
const frame = await iframeElement.contentFrame();
await frame.waitForSelector("#detailview_btn_order", {visible: true});
await frame.click("#detailview_btn_order");
Sometimes there is a race condition between a click and navigation.
I want to make a scraper with puppeteer, that opens a site, uses its search bar and opens the first link.
That is the code:
const puppeteer = require('puppeteer');
(async () => {
let browser = await puppeteer.launch();
let page = await browser.newPage();
await page.goto('https://example.com', {waitUntil: 'networkidle2'});
await page.click('[name=query]');
await page.keyboard.type("(Weapon)");
await page.keyboard.press('Enter');
await page.waitForSelector('div[class="search-results"]', {timeout: 100000});
});
The problem is I can't make it open the first link from the search results, I tried to use page.click() But all of the search results are the same except the URL.
What I want to know is how can I make it open the first link from search results.
There're more ways to solve this. I recommend experimenting with it a bit, so you learn different ways of doing this.
await page.click('.search-results a');
it turns out Puppeteer always click on the first element it finds, so if you want the first one, this will be enough.
Or you can select all the links and then click on the first one:
const resultLinks = await page.$$('.search-results a');
resultLinks[0].click();
It'd be better to include a condition here as well, so you don't end up with an error because no element was found:
const resultLinks = await page.$$('.search-results a');
if (resultLinks.length) resultLinks[0].click();
There're more ways, so if you want to learn more, please refer to the API documenttion.
I run the following test which works using playwright, however sometimes I got a certificate popup like below, if I click on cancel button the test proceed and pass,
How can I avoid this pop-up, I click on inspect button for the cancel button but noting happen.
Any idea how to avoid it? as this is my certificate... and it shouldn't be used on the tests.
How can I overcome this?
(async () => {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
await page.goto('https://app.com');
await page.fill('input[type="text"]', 'user#test.com');
await page.fill('input[type="password"]', 'Abcd1234!');
page.click('button[id="logOnFormSubmit"]');
}
)();
I am using this code in Try Puppeteer:
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://www.barchart.com/futures/quotes/ESM19/interactive-chart/fullscreen');
const linkHandlers = await page.$x("//li[contains(text(), '1D')]");
if (linkHandlers.length > 0) {
await linkHandlers[0].click();
} else {
throw new Error("Link not found");
}
await page.$eval('input[name="fieldInput"]', el => el.value = '1');
console.log(await page.content())
// const text = page.evaluate(() => document.querySelector('rect'))
// text.then((r) => {console.log(r[0])})
await page.screenshot({path: 'screenshot.png'});
await browser.close();
The same page loaded in the Chrome browser shows the bars indicating price movements, but in the screenshot obtained in Puppeteer the chart is empty.
Also page.content() gives an html that is completely different from the one I see when inspecting the element in Chrome.
Problem
You are not waiting for the request to resolve when the input is changed. As a change will trigger a request, you should use page.waitForResponse to wait until the data is loaded.
In addition, this is an Angular application, which does not seem to like it if you simply change the value of the field via el.value = '1'. Instead you need to try to behave more like a human (and hit backspace and type the input value).
Solution
First, you get the element handle (input[name="fieldInput") from the document. Then, you focus the element, remove the value inside by pressing backspace. After that you type the desired input value.
The input field now has the correct value, now we need to trigger the blur event by calling blur() on the element. In parallel, we wait for the request to the server to finish. After the request finishes, we should give the page a few milliseconds to render the data.
All together, the resulting code looks like this:
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://www.barchart.com/futures/quotes/ESM19/interactive-chart/fullscreen');
// wait until the element appears
const linkHandler = await page.waitForXPath("//li[contains(text(), '1D')]");
await linkHandler.click();
// get the input field, focus it, remove what's inside, then type the value
const elementHandle = await page.$('input[name="fieldInput"]');
await elementHandle.focus();
await elementHandle.press('Backspace');
await elementHandle.type('1');
// trigger the blur event and wait for the response from the server
await Promise.all([
page.waitForResponse(response => response.url().includes('https://www.barchart.com/proxies/timeseries/queryminutes.ashx')),
page.evaluate(el => el.blur(), elementHandle)
]);
// give the page a few milliseconds to render the diagram
await page.waitFor(100);
await page.screenshot({path: 'screenshot.png'});
await browser.close();
Code improvement
I also removed the page.$x function and replaced it with the page.waitForXPath function. This makes sure that your scripts waits until the page is loaded and the element you want to click is available before the script continues.