Recommended Free Tools
To test a Chrome extension with Puppeteer, launch Chrome with the built, unpacked extension enabled, then interact with the right extension context: a service worker for Manifest V3 (MV3), a background page for Manifest V2 (MV2), a popup target for its action UI, or an extension realm for content scripts. The examples below use Puppeteer’s documented extension APIs and are written for repeatable tests.
Set up Puppeteer and build the extension
Use the extension’s built output directory—the unpacked folder containing its manifest—not a source directory that still needs compiling. Build it before launching the test. Puppeteer’s Chrome Extensions guide, displayed as version 25.12.0, documents loading unpacked extensions with enableExtensions: Puppeteer Chrome Extensions guide.
As an Amazon Associate I earn from qualifying purchases.
Install Puppeteer in your project if it is not already installed:
npm install puppeteer
The following examples use ECMAScript modules. In a Node.js project, set "type": "module" in package.json, or save the test as an .mjs file. Replace my-extension with the path to your built extension.
#1 Best Overall
- SLIM. LIGHTWEIGHT. READY TO GO: The all-new slim design is perfect for busy lives on the go.
- SKILLFULLY DESIGNED. MILITARY TOUGH: Built with premium craftsmanship to withstand the occasional drop or ding.
- ALL-DAY, ALL-IN-ONE CHARGING: Power through your school day – and beyond – with a long-lasting 12-hour battery.¹
- 3X FASTER THAN THE PREVIOUS GENERATION OF WIFI: Crush your schoolwork in record time with Wi-Fi that’s three times faster than the previous generation of Wi-Fi.
- YOUR PHONE AND CHROMEBOOK WORK BETTER TOGETHER: Easily transfer files between devices, and control your phone right from your Chromebook.
Load an unpacked extension when launching Chrome
Pass the extension directory to enableExtensions. This is the simplest choice when the test always uses the same extension:
import puppeteer from 'puppeteer';
import path from 'node:path';
const extensionPath = path.join(process.cwd(), 'my-extension');
const browser = await puppeteer.launch({
enableExtensions: [extensionPath],
});
try {
console.log(await browser.extensions());
// Run extension checks here.
} finally {
await browser.close();
}
The path must point to an unpacked, built extension. The enableExtensions launch option accepts either a boolean or an array of extension paths; setting it avoids Puppeteer’s default arguments that prevent extensions from being enabled. See the LaunchOptions interface.
Install the extension at runtime instead
If the test needs the extension ID returned directly, enable extensions at launch and install the path afterward:
import puppeteer from 'puppeteer';
import path from 'node:path';
const extensionPath = path.join(process.cwd(), 'my-extension');
const browser = await puppeteer.launch({ enableExtensions: true });
try {
const extensionId = await browser.installExtension(extensionPath);
console.log('Installed extension:', extensionId);
console.log(await browser.extensions());
// Run extension checks here.
} finally {
await browser.close();
}
Puppeteer also provides browser.uninstallExtension(extensionId) to remove an installed extension. The browser extension APIs are documented in the Chrome Extensions guide.
Rank #2
- FOR HOME, WORK, & SCHOOL – With an Intel processor, 14-inch display, custom-tuned stereo speakers, and long battery life, this Chromebook laptop lets you knock out any assignment or binge-watch your favorite shows..Voltage:5.0 volts
- HD DISPLAY, PORTABLE DESIGN – See every bit of detail on this micro-edge, anti-glare, 14-inch HD (1366 x 768) display (1); easily take this thin and lightweight laptop PC from room to room, on trips, or in a backpack.
- ALL-DAY PERFORMANCE – Reliably tackle all your assignments at once with the quad-core, Intel Celeron N4120—the perfect processor for performance, power consumption, and value (2).
- 4K READY – Smoothly stream 4K content and play your favorite next-gen games with Intel UHD Graphics 600 (3) (4).
- MEMORY AND STORAGE – Enjoy a boost to your system’s performance with 4 GB of RAM while saving more of your favorite memories with 64 GB of reliable flash-based eMMC storage (5).
Find the background context for the manifest version
Do not assume all extensions have the same background target. MV3 uses a service worker; MV2 uses a background page. Match both the target type and a URL condition that identifies your extension. Puppeteer’s guide shows a worker URL ending in background.js as an example, but that filename is not universal.
Manifest V3: service worker
const workerTarget = await browser.waitForTarget(target =>
target.type() === 'service_worker' &&
target.url().endsWith('background.js')
);
if (!workerTarget) {
throw new Error('Extension service worker was not found');
}
const worker = await workerTarget.worker();
if (!worker) {
throw new Error('Could not get the extension service worker');
}
const result = await worker.evaluate(() => {
// Replace with a check appropriate to your background code.
return typeof chrome !== 'undefined' && Boolean(chrome.runtime?.id);
});
if (!result) {
throw new Error('Extension runtime is unavailable in the service worker');
}
For a suite with multiple extensions or workers, make the predicate more specific: check the expected extension ID in the target URL and the worker script path used by your build. A broad predicate can attach the test to another extension’s worker.
Manifest V2: background page
const backgroundTarget = await browser.waitForTarget(target =>
target.type() === 'background_page' &&
target.url().includes(expectedExtensionId)
);
if (!backgroundTarget) {
throw new Error('Extension background page was not found');
}
const backgroundPage = await backgroundTarget.page();
if (!backgroundPage) {
throw new Error('Could not get the extension background page');
}
const result = await backgroundPage.evaluate(() =>
typeof chrome !== 'undefined' && Boolean(chrome.runtime?.id)
);
Define expectedExtensionId from the installed extension or your known test configuration. The MV2 background-page flow and MV3 worker flow are distinct in Puppeteer’s extension documentation.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Test the toolbar action and popup
Puppeteer provides page.triggerExtensionAction(extension) and extension.triggerAction(page) to trigger an extension’s default action for a page. If the action opens a popup, wait for the popup target and convert it to a page before asserting on its contents.
Rank #3
- Storage: 16GB Flash Memory
- OS: Chrome OS
- Screen Size: 11.6"
const page = await browser.newPage();
await page.goto('https://example.com');
const [extension] = await browser.extensions();
if (!extension) {
throw new Error('No extension is installed');
}
await page.triggerExtensionAction(extension);
const popupTarget = await browser.waitForTarget(target =>
target.type() === 'page' &&
target.url().startsWith(`chrome-extension://${extension.id}/`) &&
target.url().endsWith('/popup.html')
);
if (!popupTarget) {
throw new Error('Extension popup did not open');
}
const popup = await popupTarget.asPage();
const heading = await popup.locator('h1').textContent();
if (heading !== 'Expected popup heading') {
throw new Error(`Unexpected popup heading: ${heading}`);
}
await browser.close();
Change the extension selection, popup path, and assertion to match your project. If a test suite can open more than one extension popup, include the specific extension ID and expected popup path in the target predicate; the official guide’s simpler popup.html suffix example assumes a single match. The guide also demonstrates opening a popup with chrome.action.openPopup() through the MV3 service worker.
Test content-script behavior on a normal web page
Navigate to a page where the extension’s content-script match rules apply. Then inspect the page’s extension realms, find the realm associated with your extension ID, and evaluate the assertion there. A content script runs in an extension realm, so evaluating only in the ordinary page context may not test the extension code.
const page = await browser.newPage();
await page.goto('https://example.com');
const [extension] = await browser.extensions();
if (!extension) {
throw new Error('No extension is installed');
}
const realms = await page.extensionRealms();
const extensionRealm = realms.find(realm =>
realm.extension?.id === extension.id
);
if (!extensionRealm) {
throw new Error(`No content-script realm found for ${extension.id}`);
}
const result = await extensionRealm.evaluate(() => {
// Replace this with an observable effect of your content script.
return document.documentElement.hasAttribute('data-my-extension-ready');
});
if (!result) {
throw new Error('Content-script behavior was not observed');
}
Use a URL that satisfies the extension’s host permissions and content-script match patterns, and make the assertion specific to the behavior under test. Failing clearly when the realm is missing prevents an accidental pass from evaluating in the page’s regular JavaScript context. See the Puppeteer extension guide for page.extensionRealms().
Free tools Windows power users keep installed
One-click scans. No signup required.
Choose a browser mode that matches the assertion
Puppeteer launches headless by default. Use headless: false when the test needs a visible Chrome window or depends on extension UI behavior that must be checked in regular Chrome:
Rank #4
- Intel Celeron N4120: 4 Cores & Threads, 1.1GHz Base Clock, Up to 2.6GHz Boost Clock, 4MB Cache, Intel UHD Graphics 600. The perfect combination of performance, power consumption, and value helps your device handle multitasking smoothly and reliably with four processing cores to divide up the work.
const browser = await puppeteer.launch({
enableExtensions: [extensionPath],
headless: false,
});
Puppeteer distinguishes regular headless Chrome from headless: 'shell', which selects the separate chrome-headless-shell binary. The shell can be faster when its reduced feature set is sufficient, but it does not completely match regular Chrome. Validate the exact mode used in CI when popup or toolbar behavior matters. Details are in Puppeteer’s Headless mode guide.
For reproducible runs, prefer the Chrome for Testing build Puppeteer downloads by default. Puppeteer says it works best with that version and does not guarantee operation with another Chrome version; if your environment requires an independently installed browser, validate that pairing. See PuppeteerNode.launch().
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Troubleshoot common failures
- The extension is missing. Confirm that
enableExtensionsis set and that the path points to the built, unpacked extension directory. Puppeteer’s defaults can disable extensions; the launch option avoids the default arguments that prevent this. On Windows, Puppeteer’s troubleshooting guide also identifies Chrome policies as a possible launch issue and describesenableExtensions: trueas a workaround. See LaunchOptions and Troubleshooting. - The background target never appears. Check the manifest version and wait for the matching target type:
service_workerfor MV3 orbackground_pagefor MV2. Tighten the URL predicate so it matches the extension and script or page actually used by your build. - The popup wait times out. Confirm that the action is configured to open a popup, trigger the action on the intended page, and match the actual popup path as well as extension ID. A suffix-only predicate may be ambiguous in a larger suite.
- No content-script realm is found. Check that the navigated URL matches the content script’s configured patterns and that the extension has been installed. Do not fall back silently to evaluating in the page’s ordinary context.
- Extension behavior differs in headless CI. Try regular headful Chrome with
headless: false, especially for UI assertions; the separate headless shell is not fully equivalent to regular Chrome. See Headless mode. - Chrome fails to launch on Linux. Check for missing system dependencies using Puppeteer’s troubleshooting guide. It strongly discourages running Chrome without its sandbox, so do not treat
--no-sandboxas a routine fix. - A separately installed Chrome behaves differently. Reproduce with Puppeteer’s downloaded Chrome for Testing first, then validate the separately managed browser and Puppeteer pairing in the same environment.
Or skip the browser setup
For capturing a web page as an image or PDF—not for testing extension internals—ScreenshotNeo provides a website screenshot API and MCP server. One GET request returns a PNG, JPEG, WebP, or PDF. Here is a cURL example; see the API documentation for request options:
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Repair Windows errors before they cause bigger problems3Scan for outdated or missing drivers - takes under a minutecurl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
- Cookie and consent banners, newsletter popups, and chat widgets are handled before capture; each step can be turned off.
- Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing; response headers indicate the page verdict and billing status.
- An MCP server provides
take_screenshot,get_page_info, andcapture_pdftools for AI agents and MCP clients. - The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots.
Sign up free for 1,000 screenshots a month—no card required.
Frequently asked questions
Can Puppeteer test a Chrome extension without opening Chrome visibly?
Yes. Puppeteer is headless by default, but extension tests that rely on visible UI should be validated in the exact browser mode used for the test, including headful mode where needed.
Can Puppeteer test extension background logic and page-injected behavior in the same run?
Yes. Use the background target appropriate to the manifest version for background checks, then navigate a page and evaluate in the extension realm for content-script checks.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →




