Jest and Puppeteer

Consider the following scenario:

I’m using the javascript library puppeteer to do a bunch of browser related operations. However, these operations are ad-hoc and I would like to re-use the same browser and page instance to runs the jobs whenever they are called. Therefore, I don’t open 1,000,000 new browsers if I’m running the function 1,000,000 times, that’ll probably freeze the machine.

Here’s my simple logic in pseudocode:

import puppeteer;

browser = null;
page = null;

initialize() {
    browser = puppeteer.createBrowser();
    page = browser.createPage();
}

operate(arg) {
    page.go_to('www.google.com');
    page.evaluate(arg);
    page.do_something_else(arg);
}

shutdown() {
    page.close();
    browser.close();
}

then in jest, I would have something like this:

import module as sut; // subject under test

beforeAll do sut.initialize;
afterAll do sut.shutdown;

test sut.operate(348972349);
test sut.operate(Error);
test sut.operate('blah3');
test sut.operate(['dsfjsklj', {blah:'blahblah'}]);

And you would expect it to just work, right?

Wrong.

Apparently jest has trouble working with puppeteer when the browser and page instances are not immediately closed within the same function call. Therefore, an additional member needs to be introduced in order to make it work, and that is jest-environment-puppeteer. It’s usage is demonstrated here: https://www.npmjs.com/package/jest-environment-puppeteer

After proper setup, the function calls in jest is now clean and simple, since the global variables browser and page are now defined as part of jest setup.

it('should blah', async () => {
    await browser.blah();
    await page.evaluate();
    await page.do_something_else();
})

But this causes problems with eslint, since it doesn’t see a declaration being used for page and browser, and it will tell you that you have written proper code by using something that has not been declared. So you gotta do this in order to bypass it, according to docs from https://github.com/smooth-code/jest-puppeteer

// .eslintrc.js
module.exports = {
  env: {
    jest: true,
  },
  globals: {
    page: true,
    browser: true,
    context: true,
    jestPuppeteer: true,
  },
}

Afterwards, jest and puppeteer should be able to happily co-exist.

See the original Issue and PR for source inspiration of this post:

Issue: https://github.com/Seneca-CDOT/telescope/issues/388

PR: https://github.com/Seneca-CDOT/telescope/pull/488

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Create your website at WordPress.com
Get started
%d bloggers like this: