What is Visual testing and how to automate visual testing using puppeteer and jest? In this puppeteer and jest tutorial. We will see how to automate and verify the visuals of an application.
As you know Google Introduce puppeteer with lots of amazing features like a screenshot or page to PDF conversion. We can take a screenshot of the application at any stage and compare it with the existing image. before dive into the code let’s understand what is Visual or Visual regression testing.
Visual testing
These days software technology is on the boom and you can see many devices and the application in the market. Have you ever notice all the applications working fine with all the sizes of devices. Like desktop or mobile apps.
Did the developer write code for all the devices?
My answer is NO. This is called a responsive design It means the developer will write the code only once and the view will modify automatically according to the device size.
So Now as QA your job is to verify the application is working properly in all the types of devices. All the images text each and everything display properly. So you have to verify web pages by mockups designs or PSD.
When It comes to large scale projects or multiple devices it really hard and time-consuming to verify all the pages with every build or every regression test.
What if we can automate visual testing?
Yes, We can automate them using puppeteer and Jest. The automation script will help to verify all the pages and any kind of device. It’s really awesome and time-saving.
Automate Visual Testing using Puppeteer and jest.
Let’s write a puppeteer script to automate the visual testing.
Step 1) Install puppeteer, Jest and Jest-image-snapshot
npm install puppeteer jest jest-image-snapshot
Step 2) Setup setup jest config.
Create a jest.config.js file and write the below code for the root directory.
module.exports = { rootDir:"./tests-snapshots", testTimeout: 30000, bail:0 }
Step 3) Write the Node script to run the script under the package.json
"test-snapshot": "jest --config=jest.config.js --detectOpenHandles --forceExit", "test-snapshots-update": "jest --config=jest.config.js --updateSnapshot --detectOpenHandles --forceExit"
Step 4) Write the script (visual.test.js).
const puppeteer = require('puppeteer') const {toMatchImageSnapshot} = require('jest-image-snapshot') expect.extend({toMatchImageSnapshot}) describe("visual regression testing",()=>{ let browser let page beforeAll(async function(){ browser = await puppeteer.launch({ headless:false, slowMo:100 }) page = await browser.newPage() }) test('Full page Screenshot', async function(){ await page.goto("https://devexpress.github.io/testcafe/example/") await page.waitForSelector('h1') const image = await page.screenshot(); expect(image).toMatchImageSnapshot({ failureThresholdType:'pixel', failureThreshold:500 }) }) test('Screenshot of the single element', async function() { await page.goto("https://devexpress.github.io/testcafe/example/") const h1 = await page.waitForSelector('h1') const image = await h1.screenshot() expect(image).toMatchImageSnapshot({ failureTresholdType: 'percent', failureTreshold: 0.01, }) }) test('Screenshot of Mobile view', async function() { await page.goto("https://devexpress.github.io/testcafe/example/") await page.waitForSelector('h1') await page.emulate(puppeteer.devices['iPhone X']) const image = await page.screenshot() expect(image).toMatchImageSnapshot({ failureTresholdType: 'percent', failureTreshold: 0.01, }) }) test('Screenshot of Tablet view', async function() { await page.goto("https://devexpress.github.io/testcafe/example/") await page.waitForSelector('h1') await page.emulate(puppeteer.devices['iPad landscape']) const image = await page.screenshot() expect(image).toMatchImageSnapshot({ failureTresholdType: 'percent', failureTreshold: 0.01, }) }) test('Remove Element Before Snapshot', async function() { await page.evaluate(() => { (document.querySelectorAll('h1') || []).forEach(el => el.remove()) }) await page.waitFor(5000) }) afterAll(async function(){ await browser.close() }) });
Run: npm run test-snapshot
Output:
Alos It will take a screenshot and store them into your project root directory or at the path that you specify in the jest.config.js file. Again the challenge about the storage. In case there are 1000s of images it will take lots of space in the drive to store the image. so Percy provides the solution to the problem. Now let’s understand what is Percy and how to automate the visual testing using puppeteer, jest, and Percy.
Device emulation using puppeteer
Devices emulation is processed to run an automation script on any specific device or size of the devices. Yes, We can modify the screen size according to the requirement. Puppeteer provides two ways to achieve this.
- Viewport.
- Use a direct device name.
We can use dynamic viewports to run puppeteer script on any size of device where we just need to pass the height and width of the screen. If you notice the above example we are using multiple devices to run every test case. Like Mobile, Tablet, Or desktop.
Device emulation is also a way to perform responsive testing where we can verify all the functionality and elements are working or not. Read more about puppeteer in detail.
Integrate puppeteer with percy
Percy is a web platform to manage the visual testing and snapshots. Let’s follow some steps to integrate Percy with puppeteer.
- Create a project at “percy.io”.
- Generate key and pass the key in your project using NPM terminal by using command “$env:PERCY_TOKEN = “Key””.
- Node command to run the script. “percy-test”: “percy exec — jest ./tests-snapshots/__tests__/percy.test.js”.
- Write script percy.test.js
const puppeteer = require('puppeteer') const { percySnapshot } = require('@percy/puppeteer') describe("Visual testing with puppeteer and percy",()=>{ let browser let page beforeAll(async function(){ browser = await puppeteer.launch({ headless:true, slowMo:0 }) page = await browser.newPage() }) test('Percy test', async function (){ await page.goto("https://devexpress.github.io/testcafe/example/") await page.waitForSelector('h1') await percySnapshot(page, "Snapshot1"); }) afterAll(async function(){ await browser.close() }) });
runtest:
npm run percy-test