Test Chrome Extensions with Puppeteer

Puppeteer provides a framework for building automated tests of websites, which also includes the ability to test Chrome Extensions. These are high-level end-to-end tests that test the functionality of a website or extension once it has been built into the final product. In this tutorial, we demonstrate how to write a basic test for an extension from our samples repository.

Before you start

Clone or download the chrome-extensions-samples repository. We'll use the history API demo in api-samples/history/showHistory as our test extension.

You'll also need to install Node.JS which is the runtime Puppeteer is built on.

Writing your test

Step 1: Start your Node.JS project

We need to set up a basic Node.JS project. In a new folder, create a package.json file with the following:

pacakge.json:

{
  "name": "puppeteer-demo",
  "version": "1.0"
}

Similar to an extension's manifest.json file, this file is required by all Node projects.

Step 2: Install Puppeteer and Jest

Run npm install puppeteer jest to add Puppeteer and Jest as dependencies. They will be automatically added to your package.json file.

It is possible to write standalone Puppeteer tests, but we'll use Jest as a test runner to provide some additional structure to our code.

Step 3: Create an entry point

Create a new file called index.test.js and add the following code:

index.test.js:

const puppeteer = require('puppeteer');

const EXTENSION_PATH = '../../api-samples/history/showHistory';
const EXTENSION_ID = 'jkomgjfbbjocikdmilgaehbfpllalmia';

let browser;

beforeEach(async () => {
  // TODO: Launch the browser.
});

afterEach(async () => {
  // TODO: Close the browser.
});

Step 4: Launch the browser

Update beforeEach and afterEach to launch and close the browser. When running many tests, you may wish to consider using the same browser. However, this is generally discouraged as it reduces the isolation between your tests and may cause one test to impact the outcome of another.

index.test.js:

beforeEach(async () => {
  browser = await puppeteer.launch({
    headless: false,
    args: [
      `--disable-extensions-except=${EXTENSION_PATH}`,
      `--load-extension=${EXTENSION_PATH}`
    ]
  });
});

afterEach(async () => {
  await browser.close();
  browser = undefined;
});

Step 5: Add an alias

To make running the tests easier, add an alias to your package.json file:

package.json:

{
  "name": "puppeteer-demo",
  "version": "1.0",
  "dependencies": {
    "puppeteer": "^21.3.6"
  },
  "scripts": {
    "start": "jest ."
  }
}

This will run all files ending in .test.js in the current directory.

Step 6: Open the popup

Let's add a basic test that opens the popup in a new page. We need to do this because Puppeteer does not support accessing an extension popup from the popup window. Add the following code:

index.test.js:

test('popup renders correctly', async () => {
  const page = await browser.newPage();
  await page.goto(`chrome-extension://${EXTENSION_ID}/popup.html`);
});

Step 7: Assert the current state

Let's assert something, so that our test can fail if the extension isn't behaving as expected. We know that our popup should show recently visited pages, so let's check that we see one:

index.test.js:

test('popup renders correctly', async () => {
  const page = await browser.newPage();
  await page.goto(`chrome-extension://${EXTENSION_ID}/popup.html`);

  const list = await page.$('ul');
  const children = await list.$$('li');

  expect(children.length).toBe(1);
});

Step 8: Run your test

To run the test, use npm start. You should see output indicating that your test passed.

You can see the full project in our chrome-extensions-samples repository.

Next Steps

After mastering the basics, try building a test suite for your own extension. The Puppeteer API reference contains more information about what's possible - there are many capabilities not described here.