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:
package.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';
let browser;
let worker;
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 want 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,
pipe: true,
enableExtensions: [EXTENSION_PATH]
});
});
afterEach(async () => {
await browser.close();
browser = undefined;
});
Step 5: Wait for the extension service worker
We need to wait for the extension service worker to start so that we can use it
later to open the popup. Update your beforeEach function with the following
code:
beforeEach(async () => {
browser = await puppeteer.launch({
headless: false,
pipe: true,
enableExtensions: [EXTENSION_PATH]
});
const workerTarget = await browser.waitForTarget(
// Assumes that there is only one service worker created by the extension
// and its URL ends with service-worker.js.
(target) =>
target.type() === 'service_worker' &&
target.url().endsWith('service-worker.js')
);
worker = await workerTarget.worker();
});
Step 6: 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": "^24.8.1"
},
"scripts": {
"start": "jest ."
}
}
This will run all files ending in .test.js in the current directory.
Step 7: Open the popup
Add a basic test. We will first open a new page so that there is an item in the browser history. Then, we will open the popup to see the history contents. Add the following code:
index.test.js:
test('popup renders correctly', async () => {
// Open a page to add a history item.
const page = await browser.newPage();
await page.goto('https://example.com');
// Open the extension popup.
await worker.evaluate('chrome.action.openPopup();');
const popupTarget = await browser.waitForTarget(
// Assumes that there is only one page with the URL ending with popup.html
// and that is the popup created by the extension.
(target) => target.type() === 'page' && target.url().endsWith('popup.html')
);
});
Step 8: Assert the current state
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 check that we see one:
index.test.js:
test('popup renders correctly', async () => {
// Open a page to add a history item.
const page = await browser.newPage();
await page.goto('https://example.com');
// Open the extension popup.
await worker.evaluate('chrome.action.openPopup();');
const popupTarget = await browser.waitForTarget(
// Assumes that there is only one page with the URL ending with popup.html
// and that is the popup created by the extension.
(target) => target.type() === 'page' && target.url().endsWith('popup.html')
);
const popup = await popupTarget.asPage();
const list = await page.$('ul');
const children = await list.$$('li');
expect(children.length).toBe(1);
});
Step 9: 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.