P15 min read

Testing a Chrome extension before shipping it

The test plan I ran on my own Manifest V3 extension before sending it to the Chrome Web Store: permissions, blocking rules, time counting, strict mode, updates and the review checklist.

Ready with known risks3 min read · recommendation first

I recently shipped a small Chrome extension of my own: TimeFence, a website blocker with daily time limits. Most of my working life is spent testing other people’s products, so this was the first release where I wrote the code, the test plan and the readiness decision myself. Here is the plan I used. It applies to most Manifest V3 extensions that block, redirect or count anything.

A browser extension has a different risk profile from a web app. It runs on every page the user opens, it keeps working when no window of its own is visible, and the store reviews it before anyone can install it. A defect does not stay on one screen. It follows the user around the web.

Review the permissions before testing anything else

The manifest is the first thing I test, because it decides what the user is warned about at install time and what the store reviewer asks about. TimeFence asks for storage, declarativeNetRequest, alarms and idle, plus host access to all sites. For each one I wrote down a single sentence: why it is needed and what would break without it.

PermissionWhy it is neededWhat I checked
storageKeeps the site list and today’s minutesSettings survive a browser restart; nothing is written anywhere else
declarativeNetRequestRedirects a blocked site to the block pageRules are added and removed as the list changes
alarmsWakes the extension once a minute to count timeCounting continues after the service worker is shut down
idleStops counting when the user walks awayNo minutes are added while the machine is idle or locked
Host access to all sitesNeeded to redirect any site the user chooses and to see the active tab’s siteNo content script reads page content

Host access to every site produces the most alarming install warning Chrome shows. If a permission cannot be justified in one sentence, I remove it and test again before going further. One fewer permission is one fewer question in review and one fewer reason for a user to hesitate.

Blocking rules: declarativeNetRequest under real conditions

With declarativeNetRequest, the extension hands Chrome a set of rules and Chrome applies them. The extension never sees the request itself. That makes blocking fast, but it also means a wrong rule fails silently. My checks:

  • A blocked domain is blocked with and without www., on subdomains such as m.youtube.com, and over both http and https.
  • A domain that merely contains the blocked name is not blocked: blocking x.com must not touch example.com.
  • Tabs that are already open on a site get redirected when it becomes blocked, not only new navigations.
  • Rules are rebuilt from saved settings after a browser restart and after the extension is reloaded, with no duplicate rule IDs left behind.
  • Removing a site from the list unblocks it straight away.

The substring case is the one I would expect to slip through a quick manual pass, so I wrote it down as an explicit check.

Time counting with idle detection and alarms

Daily limits are where most of the logic lives, and where most of my test time went. In Manifest V3 the background script is a service worker that Chrome stops when it is not needed, so nothing can rely on a timer kept in memory. TimeFence wakes on an alarm once a minute, asks the idle API whether the user has been active, and adds a minute to the site in the active tab.

  • Leave a limited site open in a background tab: no minutes should count.
  • Leave it in the active tab and walk away from the keyboard: counting should stop once the idle threshold passes.
  • Lock the screen: no counting.
  • Cross midnight with the browser open: the minutes reset and the site unblocks without a restart.
  • Use up the limit while on the site: the open tab moves to the block page instead of waiting for the next navigation.

TimeFence keeps the date and schedule logic in plain functions with no Chrome APIs, so most of these cases can run as fast unit tests with a fixed date. The checks in a real browser then confirm the wiring, not the arithmetic.

Strict mode and schedule edge cases

Strict mode prevents removing sites or pausing while a block is active. A lock like this tends to have side doors, so I tried to get round it the way an impatient user would: from the options page, from the toolbar popup, by turning the schedule off, by pausing first and enabling strict mode second. Then the opposite failure: the lock must release on its own when the focus hours end or the limits reset at midnight, or the user is stuck with a list they cannot edit.

Schedules that cross midnight, such as 22:00 to 06:00, need their own cases. The early-morning part belongs to the previous day’s schedule, so a schedule set for Friday night must still block at 01:00 on Saturday.

Updates, uninstall and saved data

An update is a release for users who already have data. The test: install the previous version, add sites and limits, use up some minutes, then load the new version over it. The list, limits and today’s minutes must survive, and settings added in the new version must get sensible defaults instead of breaking the old ones. On uninstall Chrome removes the extension’s local storage, and the TimeFence privacy policy promises exactly that, so the check is to reinstall and expect an empty list.

The store review checklist I used

  1. Single-purpose statement written, and every feature fits under it.
  2. Each permission justified in the submission form with the same sentence as in my notes.
  3. Data-use answers match the code: if nothing is collected, nothing leaves the device, including from the payment code.
  4. Privacy policy published at a public URL and linked from the listing.
  5. No remotely hosted code: every script is in the package.
  6. Screenshots show the current build, and every claim in the description can be checked against it.

The last item is the one I would expect to slip. Listing copy tends to be written early and features change after, so before submitting I read the description line by line against the build. The result is live in the Chrome Web Store, and the same plan will run before every update.

Questions I get asked

How do you test a Manifest V3 extension’s background logic if the service worker can stop at any time?

Keep nothing important in memory. Store state, wake on alarms, and test the cases where the worker has been stopped: after a restart, after an idle period and across midnight. Logic that does not need Chrome APIs can be unit tested on its own with fixed dates.

What does the Chrome Web Store check in review?

Among other things, that the extension has a single clear purpose, that each permission is justified, that the data-use answers and privacy policy match what the code does, and that no code is loaded from a remote server.

Filed under Release readiness and regression.