# Browser Extension Testing

> Browser-Daemon Extension Testing

- Skill: `lucadominguez/browser-extension-testing` (Agent Skill)
- Install (CLI): `npx skillmds@latest add lucadominguez/browser-extension-testing`
- Raw SKILL.md: https://api.skillmd.com/api/skills/lucadominguez/browser-extension-testing/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: lucadominguez (https://skillmd.com/u/lucadominguez)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/lucadominguez/browser-extension-testing

---

# Browser-Daemon Extension Testing

Test the Chrome extension at `/mnt/c/Users/Lenovo/Desktop/AI/Browser-Daemon/extension`.
Extension ID: `jbncedmlekgiomcopmhakilindpbmfdg`.

## Prerequisites

- Playwright Python installed (`python3 -m playwright install chromium`)
- `PLAYWRIGHT_BROWSERS_PATH=/tmp/pw-browsers` (reinstall Chromium if /tmp was cleared between WSL sessions)
- WSL2 with WSLg (provides display for headful Chrome)

## Run Tests

```bash
# Core extension tests (SW boot, blocking, interception, popup, standalone mode)
cd /mnt/c/Users/Lenovo/Desktop/AI/Browser-Daemon
PLAYWRIGHT_BROWSERS_PATH=/tmp/pw-browsers python3 tests/extension_test.py

# Custom rule pipeline tests (create, inject, toggle, delete)
PLAYWRIGHT_BROWSERS_PATH=/tmp/pw-browsers python3 tests/custom_rule_test.py
```

Timeout: 120s for core suite, 90s for custom rule suite.

## Key Quirks

- **headless mode**: Must use `headless=False` in Playwright. `headless=True` + `--headless=new` *silently prevents extension loading* — the browser launches but the extension never registers. No error is raised; the symptom is zero service workers and no extension ID in Preferences.
- **`--disable-extensions-except`**: ESSENTIAL flag — without it, Playwright launches Chrome but the extension loads lazily and the service worker may never register during the test window. Always pair with `--load-extension`.
- **full Chrome binary**: Must set `executable_path` to the Chrome for Testing binary, not the headless shell (`chromium-*/chrome-linux64/chrome`). The headless shell doesn't support extensions at all.
- **Browser cache**: `/tmp/pw-browsers` gets wiped between WSL sessions. Reinstall with `PLAYWRIGHT_BROWSERS_PATH=/tmp/pw-browsers python3 -m playwright install chromium`. The patch in `coreBundle.js` that maps Ubuntu 24.x to ubuntu24.04 must also be re-applied if Playwright was reinstalled.
- **Extension ID discovery**: When loaded via `--load-extension`, Chrome does NOT create an `Extensions/` directory in the profile. Find the ID via: (1) `context.service_workers` scanning for `chrome-extension://` URLs, (2) regex on `Default/Preferences` filtering out known Chrome component IDs, (3) `context.pages` for `chrome-extension://` URLs.
- **chrome://extensions unavailable**: Navigating to `chrome://extensions` in Playwright headless returns `net::ERR_INVALID_URL` — don't rely on it.

## Test Files

### `tests/extension_test.py` — 7 core tests
1. Service worker boot (extension ID discovery, no console errors)
2. Element blocking (YouTube Shorts CSS injection, TikTok FYP)
3. URL interception (shorts URL redirect to origin — ERR_ABORTED = PASS)
4. Content script idle after page load
5. Popup rendering (brand, rules, diag rows, version)
6. Standalone mode indicator (cyan dot)
7. Daemon integration (HTTP /extension/status — SKIP if daemon not running)

### `tests/custom_rule_test.py` — 6 pipeline tests
A. Rule creation via `create:rule` message → storage
B. Rule persistence in chrome.storage.local
C. CSS injection on target domain (verify elements hidden)
D. Rule visibility in popup UI rules list
E. Rule toggle: off removes CSS, on restores it
F. Rule deletion via `delete:rule` message → cleanup

## Extension Code Quality Checks

When modifying the extension, verify these before running tests:

- **`manifest.json` permissions**: Every `chrome.*` API call in background.js must have a matching permission. Run `grep -n 'chrome\.' extension/background.js | grep -v 'chrome\.\(storage\|tabs\|webNavigation\|scripting\|alarms\|runtime\|action\|i18n\)'` and cross-check with manifest.json. Missing permissions cause silent service worker crashes.
- **urlPatterns in rules**: Check that no urlPattern matches the site's homepage itself (e.g., `'*://www.tiktok.com/'` on the tiktok-fyp rule), or the extension will redirect the homepage to itself, making the site unreachable. urlPatterns should target specific sub-paths like `'*://*.youtube.com/shorts/*'`.
- **Custom rule handler coverage**: The extension should handle `create:rule`, `toggle:rule`, and `delete:rule` messages. If any is missing, add both the message handler case and the implementation function.

## Debugging Extension Loading

If the service worker isn't visible, launch Chrome directly with verbose logging to isolate Playwright issues:

```bash
CHROME=/tmp/pw-browsers/chromium-1223/chrome-linux64/chrome
"$CHROME" --headless=new --enable-logging=stderr --v=1 \
  --load-extension=/mnt/c/Users/Lenovo/Desktop/AI/Browser-Daemon/extension \
  --user-data-dir=/tmp/pw-ext-debug --no-sandbox about:blank 2>/tmp/chrome.log
```

Then check: `grep -i "extension\|manifest\|ERR\|background.js" /tmp/chrome.log`. Look for JavaScript errors in the service worker — they appear as `CONSOLE` errors with `chrome-extension://` source URLs.

## Known Limitations

- TikTok.com blocks headless browsers. Test 2 may time out on TikTok navigation — this is expected, not an extension bug. The YouTube portion passes independently.
- Test 7 always fails when daemon isn't running (expected in standalone mode).
- The AI chat (✦ button) requires an OpenRouter API key or the daemon to be running. Without either, conversational rule creation is unavailable. The programmatic `create:rule` message works regardless.

See `references/pitfalls.md` for detailed debugging transcripts from this session.
