feat: scaffold Firefox extension skeleton with manifest validation tests

Manifest V3 (Firefox keys: background.scripts, host_permissions), a
background event page that opens a standalone list page on toolbar
click, and the placeholder list page (HTML/CSS/JS vanilla). No build
step. extension.test.ts validates manifest shape and referenced files.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Pierre Martin
2026-06-29 23:40:48 +02:00
co-authored by Claude Opus 4.8
parent 328df2d181
commit 0b1c022247
7 changed files with 132 additions and 0 deletions
+45
View File
@@ -0,0 +1,45 @@
import { describe, expect, test } from "bun:test";
import { existsSync } from "node:fs";
import { join } from "node:path";
const extensionDir = join(import.meta.dir, "extension");
const manifest = await Bun.file(join(extensionDir, "manifest.json")).json();
describe("manifest.json", () => {
test("est en Manifest V3", () => {
expect(manifest.manifest_version).toBe(3);
});
test("déclare background.js comme script d'arrière-plan", () => {
expect(manifest.background.scripts).toContain("background.js");
});
test("demande les host_permissions des deux sources", () => {
expect(manifest.host_permissions).toEqual([
"https://atelier-huit.frama.space/*",
"https://www.ville-cugnaux.fr/*",
]);
});
test("ne définit PAS default_popup (sinon onClicked devient muet)", () => {
expect(manifest.action.default_popup).toBeUndefined();
});
test("porte un identifiant gecko", () => {
expect(manifest.browser_specific_settings.gecko.id).toBeDefined();
});
});
describe("ressources référencées", () => {
test("background.js existe", () => {
expect(existsSync(join(extensionDir, "background.js"))).toBe(true);
});
test("liste.html existe", () => {
expect(existsSync(join(extensionDir, "liste.html"))).toBe(true);
});
test("l'icône référencée existe", () => {
expect(existsSync(join(extensionDir, manifest.action.default_icon))).toBe(true);
});
});
+5
View File
@@ -0,0 +1,5 @@
// Listener enregistré au niveau racine (synchrone) : l'event page peut être
// déchargée, le clic toolbar doit toujours la réveiller et être capté.
browser.action.onClicked.addListener(() => {
browser.tabs.create({ url: browser.runtime.getURL("liste.html") });
});
+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 96" width="96" height="96" role="img" aria-label="Écho du Huit">
<rect width="96" height="96" rx="20" fill="#1d4ed8" />
<text x="48" y="50" font-family="system-ui, sans-serif" font-size="60" font-weight="700"
fill="#ffffff" text-anchor="middle" dominant-baseline="central">8</text>
</svg>

After

Width:  |  Height:  |  Size: 358 B

+29
View File
@@ -0,0 +1,29 @@
:root {
color-scheme: light dark;
font-family: system-ui, sans-serif;
}
body {
margin: 0;
}
main {
max-width: 48rem;
margin: 0 auto;
padding: 2rem 1.5rem;
}
h1 {
margin-top: 0;
}
#liste {
list-style: none;
margin: 0;
padding: 0;
}
.liste-vide {
color: #666;
font-style: italic;
}
+16
View File
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Écho du Huit</title>
<link rel="stylesheet" href="liste.css" />
</head>
<body>
<main>
<h1>Écho du Huit</h1>
<ul id="liste"></ul>
</main>
<script type="module" src="liste.js"></script>
</body>
</html>
+8
View File
@@ -0,0 +1,8 @@
// Squelette : la récupération des deux sources (Atelier du Huit, ville de
// Cugnaux) arrivera dans des tâches ultérieures. Pour l'instant, état vide.
const liste = document.querySelector("#liste");
const vide = document.createElement("li");
vide.className = "liste-vide";
vide.textContent = "Aucune donnée pour l'instant.";
liste.append(vide);
+24
View File
@@ -0,0 +1,24 @@
{
"manifest_version": 3,
"name": "Écho du Huit",
"version": "0.1.0",
"description": "Liste autonome agrégeant les infos de l'Atelier du Huit et de la ville de Cugnaux.",
"browser_specific_settings": {
"gecko": {
"id": "echo-du-huit@atelier-huit",
"strict_min_version": "127.0"
}
},
"background": {
"scripts": ["background.js"]
},
"action": {
"default_title": "Ouvrir la liste de l'Écho du Huit",
"default_icon": "icons/icon.svg"
},
"host_permissions": [
"https://atelier-huit.frama.space/*",
"https://www.ville-cugnaux.fr/*"
],
"icons": { "48": "icons/icon.svg", "96": "icons/icon.svg" }
}