pikabo loads your unpacked extension into a real Chromium and drives all of it — popup, options page, content scripts, and the MV3 service worker — then writes a report with a screenshot of every step.
npm install -D pikabo
$ pikabo explore --ext ./my-extension my-extension v2.1.0 · MV3 popup: popup.html · options: options.html · service worker · 5 permissions Generated 5 smoke test(s) → tests/smoke.generated.yaml my-extension smoke tests ✓ service worker starts without errors 12ms ✓ popup renders 431ms ✓ options page renders 318ms ✓ content script injects on github.com 772ms 4 passed · 3.8s html pikabo-results/report.html
Ordinary browser automation can’t reach it. The popup is browser chrome, the MV3 background is a service worker with no tab, and stable Chrome 137+ refuses --load-extension outright.
So you test it by hand — and repeat after every change.
Drive the popup, options page, content scripts, MV3 service worker, side panel, devtools, and offscreen documents — each by name.
pikabo explore reads manifest.json, generates a smoke suite, and runs it — no hand-written test required.
Click through your extension in a real browser and pikabo writes a runnable YAML suite — a first draft you finish with assertions.
Service-worker startup crashes, silent popup failures, and selector drift are caught and reported with file and line.
Every run compares the chrome.* namespaces your code actually reaches against what manifest.json declares.
assertPdf and assertFile check the PDFs and images your extension downloads — page count, geometry, byte size and all.
A test step is one action; in: chooses which part of the extension it acts on. This is most of the point of the tool.
pagethe web page under test, where content scripts run
popupthe extension popup, as a real document
optionsthe options page
workerthe MV3 service worker — storage, runtime, alarms, messaging
sidepanelthe manifest-declared side-panel document
devtoolsthe DevTools extension page
backgroundan MV2 persistent background page
offscreenan MV3 offscreen document
An MV3 service worker’s console is invisible unless its inspector happens to be open the moment it starts. pikabo attaches over the DevTools protocol before assertions run and picks up the buffered output.
✗ service worker starts without errors assertNoConsoleErrors: 2 console error(s): [worker] ReferenceError: initialise is not defined at chrome-extension://abc…/background.js:4:1 [worker] Error: storage quota exceeded at chrome-extension://abc…/background.js:31:16 Expected "#save-pdf" to be visible in popup. Elements present: #save, #cancel, #status.
A step is one action. Already have a Playwright suite? Extend your own test once and keep every locator, assertion and reporter you have.
name: PageSaver tests: - name: popup saves a PDF steps: - navigate: https://example.com - openPopup - click: "#save-pdf" - waitForDownload: "*.pdf" - assertStorage: key: lastSave exists: true - assertNoConsoleErrors - name: options page persists the theme steps: - openOptions - select: { selector: "#theme", value: dark } - click: "#save" - assertStorage: { key: theme, equals: dark }
// fixtures.ts import { test as base, expect } from '@playwright/test'; import { createExtensionTest } from 'pikabo/playwright'; export const test = createExtensionTest(base); test.use({ extensionPath: 'dist/extension' }); // popup.spec.ts test('popup changes the current page', async ({ extensionPage, extensionPopup }) => { await extensionPage.goto('https://example.com/'); await extensionPopup.getByRole('button', { name: 'Apply' }).click(); await expect(extensionPage.locator('[data-extension-applied]')).toBeVisible(); });
The bundled skill teaches an agent the workflow and the non-obvious parts, and installs into whichever convention your agent already reads. pikabo mcp serves the same primitives over MCP, so an agent can drive the browser and then freeze what worked into a YAML suite.
# install the skill everywhere pikabo skill install --global # or just this repo pikabo skill install --dir . # serve the runner over MCP pikabo mcp
Point pikabo at your unpacked build and let it drive every surface, catch the invisible errors, and drop straight into CI.
Runs on Chromium, Chrome for Testing, and Edge — not stable Google Chrome, which no longer loads unpacked extensions from the command line. Needs Node 22+. MIT licensed.