What exactly is "Viewport"? - puppeteer

I have troubles understanding what exactly "Viewport" is. The docs say it defines the "width" and the "height" in a "page". And what exactly was "page", again? I used to think of it as a browser tab, but this is also wrong, see below...
My tests fail because I seem to misunderstand "Viewport":
page.setViewport({ width: 640, height: 480 })
expect(window.innerWidth).toBe(640) // FAIL, it's 1366, Puppeteers default
From googling around, I know that there are options to launch Puppeteer in another window size. But this is not what I'm looking for, out of two reasons:
it still doesn't explain what "Viewport" is
I can't "restart" Puppeteer in every single test (I'm testing responsive behavior)
https://puppeteer.github.io/puppeteer/docs/puppeteer.page.viewport

You should expect the page.evaluate result of window.innerWidth.
Remember that the execution context inside of the page itself is different with puppeteer context.
import puppeteer, { Browser, BrowserContext, Page } from 'puppeteer'
const start = async () => {
const browser: Browser = await puppeteer.launch({ headless: false })
const page: Page = await browser.newPage()
page.setViewport({ width: 640, height: 480 })
await page.goto('http://www.samisite.com/test-csb2nf/id43.htm', { waitUntil: 'networkidle0' })
expect(await page.evaluate(() => window.innerWidth)).toBe(640)
console.log(await page.evaluate(() => window.innerWidth))
await page.close()
await browser.close()
}
;(async () => await start())()

Related

puppeteer: Different response from the puppeteer browser and the user browser

I use my own browser to get the result page I want. Everything is correct. Page link is below.
https://parcelsapp.com/en/tracking/016-35294405
img for working
I want to use puppeteer to help me to load the result page. The page shows differently.
I use options headless=false to debug. I found the browser pop up from puppeteer can not load the url correctly. I guess it is because the different environments. How can I solve the problem? Thank you.
img for not working
My code is below:
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({
headless: false,
slowMo: 250, // slow down by 250ms
executablePath: '/usr/bin/google-chrome-stable',
});
const page = await browser.newPage();
await page.on("request", (request) => {
request.abort();
});
await page.goto('https://parcelsapp.com/en/tracking/016-35294405');
await page.waitForNavigation()
await page.screenshot({ path: 'result.png' });
await browser.close();
})();

Avoid puppeteer detection

Is there any way to avoid being detected by a website that I am using puppeteer? I just can't navigate around the https://www.footlocker.ca/ website using puppeteer. I have tried using stealth plugin and random user-agents to no avail.
Any advice on what else I can try?
This website use navigator.webdriver to check if you are real user or bot. so you can use the code below to delete navigator.webdriver value. docs.
const puppeteer = require("puppeteer");
(async () => {
const browser = await puppeteer.launch({
headless: false,
});
const page = await browser.newPage();
await page.evaluateOnNewDocument(() => {
delete navigator.__proto__.webdriver;
});
await page.goto("https://www.footlocker.ca", {
waitUntil: "domcontentloaded",
});
})();

Using puppeteer get a selector from an input label

So, I have a front end in React.js or Ember.js - not sure. I'm just trying to automate some testing for it. When looking at the HTML in the Chrome Dev Tools, I see
<label class="MuiFormLabel-root-16 MuiInputLabel-root-5 MuiInputLabel-formControl-10 MuiInputLabel-animated-13 MuiInputLabel-outlined-15" data-shrink="false">Username</label>
This is set in an iframe (which isn't too important for this issue). I'm trying to get the ElementHandler using the puppeteer function
frame.$(selector)
How do I get the selector given
Username
I've tried a few things, but with little success.
If I understand correctly, you need to find an element by its text content. If so, these are at least two ways:
const puppeteer = require('puppeteer');
(async function main() {
try {
const browser = await puppeteer.launch(); // { headless: false, defaultViewport: null, args: ['--lang=en'] }
const [page] = await browser.pages();
await page.goto('https://example.org/');
const element1 = await page.evaluateHandle(() => {
return [...document.querySelectorAll('h1')].find(h1 => h1.innerText === 'Example Domain');
});
console.log(await (await element1.getProperty('outerHTML')).jsonValue());
const [element2] = await page.$x('//h1[text()="Example Domain"]');
console.log(await (await element2.getProperty('outerHTML')).jsonValue());
await browser.close();
} catch (err) {
console.error(err);
}
})();
My solution was to place HTML data attributes in the front end code so that I can easily select them.

issue with puppeteer console.log

i just want to use XPath to get innerText using Puppeteer. This is code
import * as puppeteer from 'puppeteer-core';
(async () => {
// Make the browser visible by default, extend the timeout, and set a default viewport size
const browser = await puppeteer.launch({
executablePath: 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe',
userDataDir: 'C:\\ctvbanhang\\browserData',
defaultViewport: { width: 1920, height: 1080 },
headless: false, // true = hide screen, false = show screen
timeout: 60000, // 60 seconds
});
// The browser automatically opens a page, so use that
const page = (await browser.pages())[0];
await page.goto('https://example.com/');
var XPath = "//h1/text()";// //'div.product-briefing > div > div > div > span';
// //await page.waitForSelector(selector);
await page.waitForXPath(XPath);
let result = await page.evaluate(element => {
console.log(element); //log in browser
console.log(typeof element); //log in browser
console.log(JSON.stringify(element)); //log in browser
return element;
}, (await page.$x(XPath))[0]);
console.log(result); //log in terminal
await page.waitFor(100000);
await browser.close();
})()
.then(() => {
console.log('Browser scans complete!');
})
Why the result is not the same?
this is result log in browser
and in terminal
According to the docs, various eval functions can transfer only serializable data (roughly, the data JSON can handle, with some additions). Your code returns a DOM element (Text node), which is not serializable (it has methods and circular references). Try to retrieve the data in the browser context and returns only serializable data. For example:
return element.wholeText;

UI seems different on puppeteer

Even though most of the process of my end-to-end test with puppeteer works fine ( which is a rather simply a series of page.select/type/waitfor/etc) the UI seems skewed.
When the process is over, at the very end of it the UI readjusts to what it should look like but only after everything has concluded. I tried firing up a plain Chromium instance and it looks as it should be as well.
test code looks like so
beforeAll(async () => {
browser = await puppeteer.launch(
{
headless: false,
slowMo: 250,
}
)
page = await browser.newPage()
await page.goto('http://localhost:3000/');
})
describe('on page load', () => {
test('MessageLists loads', async () => {
await page.waitForSelector('.MessageList', { timeout: 3000 })
await page.waitForSelector('.messageOuterContainer', { timeout: 10000 })
},
16000
);
test('Post Question', async () => {
await page.waitForSelector('.messageOuterContainer', { timeout: 10000 })
await page.focus('.input');
await page.keyboard.type('test');
await page.$('.AnswerList');
await page.screenshot({ path: 'screenshot1.png' });
}, 20000)
})
afterAll(() => {
// browser.close()
})
Im on MacOS Mojave 10.14 though i imagine this isnt the culprit here.
Even if you launch puppeteer in headless: false mode, the page will be run with a given viewport. By default that viewport size is 800x600. If you resize the window to something bigger it might indeed look like the page is run inside an iframe. You cannot resize the viewport by resizing the browser window. You have to rely on functions for that.
Code sample
To change the default viewport, you can add an argument when calling puppeteer.launch:
const browser = await puppeteer.launch({
defaultViewport: { // example: 1600x800
width: 1600,
height: 800
},
headless: false,
slowMo: 250,
})
You can also change it by calling the function page.setViewport.