With the Global Setup/Teardown and Async Test Environment APIs, Jest can work smoothly with puppeteer.

Generating code coverage for test files using Puppeteer is currently not possible if your test uses page.$eval, page.$$eval or page.evaluate as the passed function is executed outside of Jest's scope. Check out issue #7962 on GitHub for a workaround.

Use jest-puppeteer Preset

Jest Puppeteer provides all required configuration to run your tests using Puppeteer.

  • First install jest-puppeteer
  1. yarn add --dev jest-puppeteer
  • Specify preset in your Jest configuration:
  1. {
  2. "preset": "jest-puppeteer"
  3. }
  • Write your test
  1. describe('Google', () => {
  2. beforeAll(async () => {
  3. await page.goto('https://google.com');
  4. });
  5. it('should be titled "Google"', async () => {
  6. await expect(page.title()).resolves.toMatch('Google');
  7. });
  8. });

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

See documentation.

Custom example without jest-puppeteer preset

You can also hook up puppeteer from scratch. The basic idea is to:

  • launch & file the websocket endpoint of puppeteer with Global Setup
  • connect to puppeteer from each Test Environment
  • close puppeteer with Global TeardownHere's an example of the GlobalSetup script
  1. // setup.js
  2. const puppeteer = require('puppeteer');
  3. const mkdirp = require('mkdirp');
  4. const path = require('path');
  5. const fs = require('fs');
  6. const os = require('os');
  7. const DIR = path.join(os.tmpdir(), 'jest_puppeteer_global_setup');
  8. module.exports = async function() {
  9. const browser = await puppeteer.launch();
  10. // store the browser instance so we can teardown it later
  11. // this global is only available in the teardown but not in TestEnvironments
  12. global.__BROWSER_GLOBAL__ = browser;
  13. // use the file system to expose the wsEndpoint for TestEnvironments
  14. mkdirp.sync(DIR);
  15. fs.writeFileSync(path.join(DIR, 'wsEndpoint'), browser.wsEndpoint());
  16. };

Then we need a custom Test Environment for puppeteer

  1. // puppeteer_environment.js
  2. const NodeEnvironment = require('jest-environment-node');
  3. const fs = require('fs');
  4. const path = require('path');
  5. const puppeteer = require('puppeteer');
  6. const os = require('os');
  7. const DIR = path.join(os.tmpdir(), 'jest_puppeteer_global_setup');
  8. class PuppeteerEnvironment extends NodeEnvironment {
  9. constructor(config) {
  10. super(config);
  11. }
  12. async setup() {
  13. await super.setup();
  14. // get the wsEndpoint
  15. const wsEndpoint = fs.readFileSync(path.join(DIR, 'wsEndpoint'), 'utf8');
  16. if (!wsEndpoint) {
  17. throw new Error('wsEndpoint not found');
  18. }
  19. // connect to puppeteer
  20. this.global.__BROWSER__ = await puppeteer.connect({
  21. browserWSEndpoint: wsEndpoint,
  22. });
  23. }
  24. async teardown() {
  25. await super.teardown();
  26. }
  27. runScript(script) {
  28. return super.runScript(script);
  29. }
  30. }
  31. module.exports = PuppeteerEnvironment;

Finally we can close the puppeteer instance and clean-up the file

  1. // teardown.js
  2. const os = require('os');
  3. const rimraf = require('rimraf');
  4. const path = require('path');
  5. const DIR = path.join(os.tmpdir(), 'jest_puppeteer_global_setup');
  6. module.exports = async function() {
  7. // close the browser instance
  8. await global.__BROWSER_GLOBAL__.close();
  9. // clean-up the wsEndpoint file
  10. rimraf.sync(DIR);
  11. };

With all the things set up, we can now write our tests like this:

  1. // test.js
  2. const timeout = 5000;
  3. describe(
  4. '/ (Home Page)',
  5. () => {
  6. let page;
  7. beforeAll(async () => {
  8. page = await global.__BROWSER__.newPage();
  9. await page.goto('https://google.com');
  10. }, timeout);
  11. it('should load without error', async () => {
  12. const text = await page.evaluate(() => document.body.textContent);
  13. expect(text).toContain('google');
  14. });
  15. },
  16. timeout,
  17. );

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

  1. module.exports = {
  2. globalSetup: './setup.js',
  3. globalTeardown: './teardown.js',
  4. testEnvironment: './puppeteer_environment.js',
  5. };

Here's the code of full working example.