One day with Puppeteer ❤ and cookies

Aleks
3 min readApr 1, 2018

Have you see and integration testing approach that doesn’t make throw up? at least not for the JS planet, because I think during this years I crossed paths with phantom and karma, with selenium and Nightwatch, I had some hopes for CasperJS and slimerJS, even sometimes I pretend that jsdom is reliable and then I realize what I’ve done and cried myself to sleep; until Saturday I found puppeteer is not new I tell you this as a disclaimer but just recently I had the chance to try it.

One day so far so good

How hard can be when running yarn add -D ava puppeteer already brings to your country a headless browser. The first challenge was actually tolaunch a browser .. const browser = await puppeteer.launch({ headless:false }) believe me, is not that hard, what about a new page navigating to localhost not hard at all either, so let me summarize

import test from 'ava'
import puppeteer from 'puppeteer'
let browser, page
test.beforeEach(async () => {
browser = await puppeteer.launch({ headless: false, slowMo: 300 })
page = await browser.newPage()
await page.goto('http://localhost:3000')
})
test.afterEach(async () => {
await browser.close()
})

For the example I used headless: false and slowMo: 300 just to see what’s going on finally I was amazed by the simplicity of the process, but it works with no difference at all without the options.

Testing Time

My main goal was to test a cookie modal, one of those regular modals that create a cookie if the user accepts the cookie’s policy, nothing fancy but it was not reliable to test just with the false positives from phantomJS or the mock implementations of jsdom.

That’s when puppeter comes into play. First, the test is so simple that is almost as easy as aunit test, so this is how you can access the HTML of an element

test('Link to policy', async (t) => {
const anchorText = await page.$eval('.terms', el => el.innerHTML)
t.is(anchorText, 'Cookies policy', 'policy anchor text')
})

$eval is some kind of “selector evaluation” that returns the element on a callback, pretty useful to start but sometimes you need to execute more than that on the browser, for those more complex times you still have theevaluate function and I did it for a casual CSS test to check the zIndex and position

test('Cookie banner is on top of everything', async (t) => {
const banner = await page.evaluate(() => {
const dialog = document.querySelector('.js_banner')
return JSON.parse(JSON.stringify(getComputedStyle(dialog)))
})
t.is(banner.position, 'fixed', 'position is fixed')
t.is(banner.zIndex, '6000001', 'z index is on top')
})

Last but not least I’m glad that the API is so similar to the browser and you can check what’s going on inside, my main goal as I told you was to test a cookie and here is the result

test('Cookie banner is not visible after reload', async (t) => {
await page.waitForSelector('button.js_accept')
await page.click('button.js_accept')
await page.reload()
await page.waitForSelector('.ck_cookie_unrendered')
const classes = await page.$eval('.ck_hidden', el => el.className) t.true(classes.indexOf('ck_hidden') !== -1, 'span without banner') const [ returnedCookie ] = await page.cookies() t.is(returnedCookie.name, 'Cookie_Consent', 'name is ok')
t.is(returnedCookie.value, 'Accepted', 'value is ok')
})

Not only I was able to reload the page without any issues at all after the button clicked but also being able to test cookie name, value, expiration date and all other significant properties of the cookie was the real deal to start using puppeteer more and more inside my projects.

--

--