w3resource

Using with puppeteer


With the Async Test Environment and Global Setup/Teardown APIs, Jest will be able to work smoothly with puppeteer.

Trying to generate code coverage for test files using Puppeteer is not possible currently if your test uses page.$eval, page.$$eval or page.evaluate because the passed function will be executed outside of Jest's scope.

Use jest-puppeteer Preset

Jest Puppeteer will provide all required configuration to run your tests using Puppeteer.

1. First you need to install jest-puppeteer

yarn add --dev jest-puppeteer

2. You need to specify preset in your Jest configuration:

{
  "preset": "jest-puppeteer"
   }

3. You should write your test

describe('w3resource', () => {
  beforeAll(async () => {
    await page.goto('https://w3resource.com');
  });

  it('should be titled "w3resource"', async () => {
    await expect(page.title()).resolves.toMatch('w3resource');
  });
});

There is no need to load any dependencies. Puppeteer's page and browser classes are automatically exposed

Custom example without jest-puppeteer preset

You can equally hook up puppeteer from scratch. The basic idea is that you have to:

  1. launch & file puppeter's websocket endpoint with Global Setup
  2. connect to puppeteer from each of the Test Environment
  3. use Global Teardown to close puppeter

An example of the GlobalSetup script is shown below:

// setup.js

const puppeteer = require('puppeteer');
const mkdirp = require('mkdirp');
const path = require('path');
const fs = require('fs');
const os = require('os');

const DIR = path.join(os.tmpdir(), 'jest_puppeteer_global_setup');

module.exports = async function() {
  const browser = await puppeteer.launch();
  // stores the browser instance so we can teardown it later
  // this global will only be available in the teardown but not in TestEnvironments
  global.__BROWSER_GLOBAL__ = browser;

  // uses the file system to expose the wsEndpoint for TestEnvironments
  mkdirp.sync(DIR);
  fs.writeFileSync(path.join(DIR, 'wsEndpoint'), browser.wsEndpoint());
};

Then you will need a custom Test Environment for puppeteer

// puppeteer_environment.js

const NodeEnvironment = require('jest-environment-node');
const fs = require('fs');
const path = require('path');
const puppeteer = require('puppeteer');
const os = require('os');

const DIR = path.join(os.tmpdir(), 'jest_puppeteer_global_setup');

class PuppeteerEnvironment extends NodeEnvironment {
  constructor(config) {
    super(config);
  }

  async setup() {
    await super.setup();
    // get the wsEndpoint
    const wsEndpoint = fs.readFileSync(path.join(DIR, 'wsEndpoint'), 'utf8');
    if (!wsEndpoint) {
      throw new Error('wsEndpoint not found');
    }

// connect to puppeteer

this.global.__BROWSER__ = await puppeteer.connect({
      browserWSEndpoint: wsEndpoint,
    });
  }

  async teardown() {
    await super.teardown();
  }

  runScript(script) {
    return super.runScript(script);
  }
}

module.exports = PuppeteerEnvironment;

Finally, you can close the puppeteer instance and clean-up the file

// teardown.js

const os = require('os');
const rimraf = require('rimraf');
const path = require('path');

const DIR = path.join(os.tmpdir(), 'jest_puppeteer_global_setup');
module.exports = async function() {
  // close the browser instance
  await global.__BROWSER_GLOBAL__.close();

  // clean-up the wsEndpoint file
  rimraf.sync(DIR);
};

Having set up everything, you can now write your tests as shown in the example below:

// test.js

const timeout = 5000;

describe(
  '/ (Home Page)',
  () => {
    let page;
    beforeAll(async () => {
      page = await global.__BROWSER__.newPage();
      await page.goto('https://google.com');
    }, timeout);

    it('should load without error', async () => {
      const text = await page.evaluate(() => document.body.textContent);
      expect(text).toContain('google');
    });
  },
  timeout,
);

Then, you need to set jest.config.js to read from these files. (The jest-puppeteer preset does something like this under the hood.)

module.exports = {
  globalSetup: './setup.js',
  globalTeardown: './teardown.js',
  testEnvironment: './puppeteer_environment.js',
};

Previous: Using Jest with MongoDB and DynamoDB
Next: DOM Manipulation