惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Jina AI
Jina AI
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
有赞技术团队
有赞技术团队
罗磊的独立博客
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
U
Unit 42
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Recent Announcements
Recent Announcements
Y
Y Combinator Blog
Vercel News
Vercel News
Martin Fowler
Martin Fowler
V
V2EX
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
L
LangChain Blog
云风的 BLOG
云风的 BLOG
H
Hackread – Cybersecurity News, Data Breaches, AI and More
aimingoo的专栏
aimingoo的专栏
G
Google Developers Blog
The GitHub Blog
The GitHub Blog
N
Netflix TechBlog - Medium
Google DeepMind News
Google DeepMind News
雷峰网
雷峰网
阮一峰的网络日志
阮一峰的网络日志
F
Fortinet All Blogs

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
How to Test Firefox Extensions Without Publishing: Local ...
Weather Cloc · 2026-05-04 · via DEV Community

How to Test Firefox Extensions Without Publishing: Local Development Tips

Publishing to AMO every time you want to test a change is slow and painful. Here's the full toolkit for local development.

Temporary Add-on Loading

The fastest way to load your extension:

  1. Open Firefox and go to about:debugging
  2. Click This Firefox in the left sidebar
  3. Click Load Temporary Add-on...
  4. Navigate to your extension folder and select manifest.json

The extension is loaded immediately. It disappears when Firefox restarts, but stays active during the session.

Auto-Reload on File Changes

Manually clicking "Reload" in about:debugging is tedious. Use web-ext for auto-reload:

npm install --save-dev web-ext

# Auto-reload on any file change
npx web-ext run --source-dir . --watch

# Or add to package.json scripts

Enter fullscreen mode Exit fullscreen mode

{
  "scripts": {
    "dev": "web-ext run --source-dir .",
    "build": "web-ext build --source-dir . --artifacts-dir dist"
  }
}

Enter fullscreen mode Exit fullscreen mode

web-ext opens a new Firefox profile with your extension loaded, and reloads it automatically when you save any file.

Inspecting the Extension's DevTools

Each extension context has its own DevTools:

For new tab page / popup:

  • Right-click anywhere on the new tab → Inspect
  • Or open DevTools on the popup while it's visible

For background scripts/service workers:

  1. Go to about:debugging#/runtime/this-firefox
  2. Click Inspect next to your extension
  3. This opens a dedicated DevTools window for the background context

Testing storage.sync

Simulate sync changes in DevTools console:

// In the extension's background context DevTools
await browser.storage.sync.set({ theme: 'dark' });
await browser.storage.sync.get(null); // Get all stored values
await browser.storage.sync.clear();   // Clear everything (for fresh testing)

Enter fullscreen mode Exit fullscreen mode

Testing Across Multiple Firefox Profiles

To simulate sync across devices, use two Firefox profiles:

# Create two profiles
firefox --createprofile profile1
firefox --createprofile profile2

# Launch both simultaneously
firefox --profile profile1 &
firefox --profile profile2 &

Enter fullscreen mode Exit fullscreen mode

Log into the same Firefox Account on both, install the extension on both via temporary loading, and watch changes sync.

Debugging the New Tab Override

New tab pages are special — they can't be right-clicked and inspected directly from the tab. Workarounds:

// Option 1: Open the new tab page as a regular page
// Navigate to moz-extension://YOUR-EXTENSION-ID/newtab.html

// Option 2: Log the extension ID
console.log(browser.runtime.id);
// Then navigate to moz-extension://<id>/newtab.html

Enter fullscreen mode Exit fullscreen mode

Or from about:debugging, click Inspect on your extension and look for the new tab URL.

Mock browser.storage for Unit Tests

For unit testing without a real browser:

// mock-browser-storage.js
const storage = {
  local: { _data: {} },
  sync: { _data: {} },
};

for (const area of ['local', 'sync']) {
  storage[area].get = async (keys) => {
    if (!keys) return { ...storage[area]._data };
    if (typeof keys === 'string') return { [keys]: storage[area]._data[keys] };
    const result = {};
    for (const key of Object.keys(keys)) {
      result[key] = key in storage[area]._data ? storage[area]._data[key] : keys[key];
    }
    return result;
  };
  storage[area].set = async (items) => {
    Object.assign(storage[area]._data, items);
  };
  storage[area].clear = async () => {
    storage[area]._data = {};
  };
}

global.browser = { storage };

Enter fullscreen mode Exit fullscreen mode

Then in your tests:

require('./mock-browser-storage');
const { loadPreferences } = require('./preferences');

test('loads defaults on first run', async () => {
  const prefs = await loadPreferences();
  expect(prefs.theme).toBe('auto');
  expect(prefs.temperatureUnit).toBe('celsius');
});

Enter fullscreen mode Exit fullscreen mode

web-ext lint

Catch issues before submitting to AMO:

npx web-ext lint --source-dir .

Enter fullscreen mode Exit fullscreen mode

This checks:

  • Manifest validity
  • Deprecated APIs
  • Common mistakes
  • Permission warnings

Run this before every AMO submission.

Testing the Install/First-Run Flow

To test how your extension behaves on first install:

# Launch with a clean profile every time
npx web-ext run --source-dir . --firefox-profile temp-test --profile-create-if-missing

Enter fullscreen mode Exit fullscreen mode

This creates a fresh profile, so storage is always empty — you see exactly what a new user sees.

Summary

Task Tool
Quick load about:debugging temporary add-on
Auto-reload dev web-ext run
Production build web-ext build
Linting web-ext lint
Storage debugging DevTools console
Fresh install test web-ext run --profile-create-if-missing

The web-ext tool is genuinely excellent — it's the official Mozilla CLI and makes extension development feel like normal web dev with hot reload.


Weather & Clock Dashboard — free Firefox new tab extension. Built and tested using all these techniques.