Overview:
We all like chrome browser. Whether you like it not, It is the mostly used browser supported by the tech giant Google. I am huge fan of Chrome DevTools which helps me to play with locators, changing element style etc very quickly. Chrome supported headless mode testing from its version 59. Headless mode would be very useful in some cases – particularly in linux/server environments for automated testing.
Puppeteer is a node library with a high-level API to control chrome headless. It uses the DevTools api to interact with chrome. Aim of this article is to introduce puppeteer to you in case you are not aware already!
Installation:
- You need to have node installed. Check here for more info.
- Once installed and everything configured correctly, you should be able to see node version. It should be above 8.
node -v
v8.11.2
- Ensure the npm version also. It should be above 5. You do not have to install it separately as it is bundled with NodeJS. But it can be upgraded.
npm -v
5.6.0
- Lets create an empty directory for playing with puppeteer.
npm init -y
Wrote to testautomationguru@remotehost/package.json:
{
"name": "node-playground",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
- Lets install puppeteer now.
npm install --save puppeteer
Launching Browser Instance:
- Create a test.js file in the directory. At this moment, I am not using js test frameworks like mocha/jest. Our aim here is to just play with puppeteer.
- I add the below code in the test.js
const puppeteer = require('puppeteer');
let config = {
launchOptions: {
headless: false
}
}
puppeteer.launch(config.launchOptions).then(async browser => {
const page = await browser.newPage();
await page.goto('https://www.google.com');
await browser.close();
});
- Edit the package.json file as shown here. [You could simply run the above script ‘node test.js’. But we might add other test frameworks/more commandline options etc. So it is good to invoke via package.json]
"scripts": {
"test": "node test.js"
}
- Run the below command. You could see it launching chrome with Google.com and closes it immediately.
npm run test
> node-playground@1.0.0 test testautomationguru/node-playground
> node test.js
Devices Emulation/View Port:
- Add the below statement in test.js, run and check the console. puppeteer comes with configurations for different devices.
const devices = require('puppeteer/DeviceDescriptors');
console.log(devices)
- Lets see how to emulate iphone. Update test.js as shown here and run the script.
const puppeteer = require('puppeteer');
const devices = require('puppeteer/DeviceDescriptors');
const iPhone = devices['iPhone 6'];
const config = {
launchOptions: {
headless: false
}
}
puppeteer.launch(config.launchOptions).then(async browser => {
const page = await browser.newPage();
await page.emulate(iPhone)
await page.goto('https://www.google.com');
await browser.close();
});
- If we need to control the view port, then we could try something like this.
const config = {
launchOptions: {
headless: false
},
viewport:{width:1920, height:1080}
}
puppeteer.launch(config.launchOptions).then(async browser => {
const page = await browser.newPage();
await page.setViewport(config.viewport)
await page.goto('https://www.google.com');
await browser.close();
});
Interacting With Elements:
- In the above examples, page appears and browser gets closed very quickly before all the elements appear on the page. To wait for an element to appear, try something as shown here. Selector is css selector for the element you would be interested in.
page.waitFor(selector)
- Typing text into textbox/textarea
page.type(selector, text)
- Click on a link/button/image/checkbox/radio button etc
page.click(selector)
- Selecting a dropdown value
page.select(selector, value)
- In all the above examples, we assume the selector returns only one element. if the selector returns multiple elements, only the first element would be used. Lets see how to interact with multiple elements.
page.$$eval('input[type="checkbox"]', checkboxes => {
checkboxes.forEach(chbox => chbox.click())
});
- To extract value/text from an element
let txt = await page.$eval('span.form-checkbox-item', el => el.innerText );
console.log(txt);
- Note the difference here $eval vs $$eval
- $eval returns the first element with the selector expression
- $$eval returns an array of elements matching the selector
- In the below example, Lets see how to wait for an element to appear, enter some text and then submit the page.
const puppeteer = require('puppeteer');
const config = {
launchOptions: {
headless: false
},
viewport:{width:1920, height:1080}
}
//locators
const registrationPage = {
firstname: 'input[name="firstName"]',
lastname: 'input[name="lastName"]',
username: 'input[name="email"]',
password: 'input[name="password"]',
confirmPassword: 'input[name="confirmPassword"]',
submit: 'input[name="register"]'
}
const registrationConfirmation = {
sigin: 'a[href="mercurysignon.php"]'
}
puppeteer.launch(config.launchOptions).then(async browser => {
const page = await browser.newPage();
await page.setViewport(config.viewport)
//mercury tours registration page
await page.goto('http://newtours.demoaut.com/mercuryregister.php');
//wait for the firstname to appear
await page.waitFor(registrationPage.firstname);
//enter the details
await page.type(registrationPage.firstname, 'automation');
await page.type(registrationPage.lastname, 'guru');
await page.type(registrationPage.username, 'guru');
await page.type(registrationPage.password, 'guru');
await page.type(registrationPage.confirmPassword, 'guru');
await page.click(registrationPage.submit);
//after page submission check for the sign-in confirmation
await page.waitFor(registrationConfirmation.sigin);
await page.click(registrationConfirmation.sigin);
await browser.close();
});
Screenshots:
- Taking screenshot & saving in the current directory. Only the current view port is stored.
page.screenshot({ path:'test.png'})
- To take screenshot for full scorllable page.
page.screenshot({ path:'test.png', fullPage: true})
- To take screenshot of an specific element. For this we need to pass the x, y, width, height properties.
const pos = await page.evaluate(selector => {
const element = document.querySelector(selector);
const {x, y, width, height} = element.getBoundingClientRect();
return {x, y, width, height};
}, 'input#username');
await page.screenshot({ path:'test.png', clip: pos})
- Save page as pdf. same like screenshot. But only works if the headless mode is true.
page.pdf({ path:'test.pdf'});
Summary:
Hope you got some idea from this article. As I had mentioned, aim of this article is just to get started with puppeteer. By using puppeteer in headless mode, we can run the tests in server environments without any GUI / docker containers etc. By making use of the Chrome DevTools, we should be able to achieve things like getting HTTP response code, downloading dynamically generated files etc which is not possible in selenium directly. We can take a look at those areas in the upcoming articles.
Happy Testing & Subscribe 🙂