chromium support
Release Firefox and Chromium extensions / Package and attach browser extensions (release) Successful in 54s
Release Firefox and Chromium extensions / Package and attach browser extensions (release) Successful in 54s
This commit is contained in:
@@ -4,12 +4,14 @@ const test = require("node:test");
|
||||
const assert = require("node:assert/strict");
|
||||
const { createBackgroundController } = require("../background.js");
|
||||
|
||||
function makeBrowser(initialStorage = {}) {
|
||||
function makeBrowser(initialStorage = {}, initialSessionStorage = {}) {
|
||||
let messageListener;
|
||||
let removedListener;
|
||||
const broadcasts = [];
|
||||
const stored = { ...initialStorage };
|
||||
const sessionStored = { ...initialSessionStorage };
|
||||
const storageWrites = [];
|
||||
const sessionWrites = [];
|
||||
const api = {
|
||||
runtime: {
|
||||
onMessage: {
|
||||
@@ -27,6 +29,15 @@ function makeBrowser(initialStorage = {}) {
|
||||
storageWrites.push({ ...values });
|
||||
Object.assign(stored, values);
|
||||
}
|
||||
},
|
||||
session: {
|
||||
async get(key) {
|
||||
return { [key]: sessionStored[key] };
|
||||
},
|
||||
async set(values) {
|
||||
sessionWrites.push(structuredClone(values));
|
||||
Object.assign(sessionStored, structuredClone(values));
|
||||
}
|
||||
}
|
||||
},
|
||||
tabs: {
|
||||
@@ -45,13 +56,24 @@ function makeBrowser(initialStorage = {}) {
|
||||
return {
|
||||
api,
|
||||
broadcasts,
|
||||
sessionStored,
|
||||
sessionWrites,
|
||||
stored,
|
||||
storageWrites,
|
||||
send(message, sender = {}) {
|
||||
return messageListener(message, sender);
|
||||
return new Promise((resolve) => {
|
||||
let responded = false;
|
||||
const keepChannelOpen = messageListener(message, sender, (response) => {
|
||||
responded = true;
|
||||
resolve(response);
|
||||
});
|
||||
if (!keepChannelOpen && !responded) {
|
||||
resolve(undefined);
|
||||
}
|
||||
});
|
||||
},
|
||||
remove(tabId) {
|
||||
removedListener(tabId);
|
||||
return removedListener(tabId);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -91,10 +113,41 @@ test("owns absolute state per tab and supplies it to new frames", async () => {
|
||||
{ enabled: false, fontStyle: "round" }
|
||||
);
|
||||
|
||||
fake.remove(17);
|
||||
await fake.remove(17);
|
||||
assert.equal(controller.tabStates.has(17), false);
|
||||
});
|
||||
|
||||
test("restores tab state after an MV3 background worker restart", async () => {
|
||||
const firstWorker = makeBrowser();
|
||||
createBackgroundController(firstWorker.api);
|
||||
await firstWorker.send({
|
||||
type: "glagolify:set-tab-enabled",
|
||||
tabId: 23,
|
||||
enabled: true
|
||||
});
|
||||
|
||||
assert.deepEqual(firstWorker.sessionStored, {
|
||||
glagolifyTabStates: { 23: true }
|
||||
});
|
||||
|
||||
const restartedWorker = makeBrowser({}, firstWorker.sessionStored);
|
||||
createBackgroundController(restartedWorker.api);
|
||||
assert.deepEqual(
|
||||
await restartedWorker.send(
|
||||
{ type: "glagolify:document-ready" },
|
||||
{ tab: { id: 23 } }
|
||||
),
|
||||
{ enabled: true, fontStyle: "round" }
|
||||
);
|
||||
assert.deepEqual(
|
||||
await restartedWorker.send({
|
||||
type: "glagolify:get-tab-state",
|
||||
tabId: 23
|
||||
}),
|
||||
{ enabled: true, available: true, fontStyle: "round" }
|
||||
);
|
||||
});
|
||||
|
||||
test("keeps states isolated between tabs and reports protected tabs", async () => {
|
||||
const fake = makeBrowser();
|
||||
createBackgroundController(fake.api);
|
||||
|
||||
@@ -8,7 +8,8 @@ const os = require("node:os");
|
||||
const path = require("node:path");
|
||||
const { inflateRawSync } = require("node:zlib");
|
||||
const {
|
||||
ARCHIVE_FILES,
|
||||
CHROMIUM_ARCHIVE_FILES,
|
||||
FIREFOX_ARCHIVE_FILES,
|
||||
normalizeVersion,
|
||||
packageExtension
|
||||
} = require("../scripts/package-extension.js");
|
||||
@@ -72,8 +73,12 @@ test("builds a deterministic unsigned XPI with the release version and runtime f
|
||||
const entries = readZipEntries(firstArchive);
|
||||
|
||||
assert.equal(first.archiveName, "glagolify-9.8.7.xpi");
|
||||
assert.deepEqual([...entries.keys()], [...ARCHIVE_FILES]);
|
||||
assert.equal(JSON.parse(entries.get("manifest.json")).version, "9.8.7");
|
||||
assert.deepEqual([...entries.keys()], [...FIREFOX_ARCHIVE_FILES]);
|
||||
const manifest = JSON.parse(entries.get("manifest.json"));
|
||||
assert.equal(manifest.version, "9.8.7");
|
||||
assert.equal(manifest.manifest_version, 2);
|
||||
assert.equal(manifest.background.persistent, true);
|
||||
assert.equal(manifest.browser_action.default_popup, "popup.html");
|
||||
assert.equal(entries.has("package.json"), false);
|
||||
assert.equal(entries.has("tests/package-extension.test.js"), false);
|
||||
assert.deepEqual(firstArchive, secondArchive);
|
||||
@@ -84,3 +89,76 @@ test("builds a deterministic unsigned XPI with the release version and runtime f
|
||||
`${digest} glagolify-9.8.7.xpi\n`
|
||||
);
|
||||
});
|
||||
|
||||
test("builds a Chromium MV3 ZIP with Chromium manifest fields and raster icons", async (context) => {
|
||||
const rootDirectory = path.resolve(__dirname, "..");
|
||||
const outputDirectory = await mkdtemp(path.join(os.tmpdir(), "glagolify-chromium-"));
|
||||
context.after(() => rm(outputDirectory, { recursive: true, force: true }));
|
||||
|
||||
const result = await packageExtension({
|
||||
rootDirectory,
|
||||
outputDirectory,
|
||||
target: "chromium",
|
||||
version: "v4.5.6"
|
||||
});
|
||||
const archive = await readFile(result.archivePath);
|
||||
const entries = readZipEntries(archive);
|
||||
const manifest = JSON.parse(entries.get("manifest.json"));
|
||||
|
||||
assert.equal(result.archiveName, "glagolify-4.5.6-chromium.zip");
|
||||
assert.deepEqual([...entries.keys()], [...CHROMIUM_ARCHIVE_FILES]);
|
||||
assert.equal(manifest.manifest_version, 3);
|
||||
assert.equal(manifest.minimum_chrome_version, "102");
|
||||
assert.equal(manifest.version, "4.5.6");
|
||||
assert.deepEqual(manifest.permissions, ["activeTab", "storage"]);
|
||||
assert.deepEqual(manifest.host_permissions, ["<all_urls>"]);
|
||||
assert.deepEqual(manifest.background, { service_worker: "background.js" });
|
||||
assert.equal(manifest.action.default_popup, "popup.html");
|
||||
assert.equal("browser_action" in manifest, false);
|
||||
assert.equal("browser_specific_settings" in manifest, false);
|
||||
assert.deepEqual(manifest.web_accessible_resources, [
|
||||
{
|
||||
resources: [
|
||||
"fonts/NotoSansGlagolitic-Regular.ttf",
|
||||
"fonts/Shafarik-Regular.ttf"
|
||||
],
|
||||
matches: ["<all_urls>"]
|
||||
}
|
||||
]);
|
||||
assert.equal(manifest.icons["128"], "icons/icon-128.png");
|
||||
|
||||
for (const relativePath of CHROMIUM_ARCHIVE_FILES.filter((name) =>
|
||||
name.endsWith(".png")
|
||||
)) {
|
||||
assert.deepEqual(
|
||||
entries.get(relativePath).subarray(0, 8),
|
||||
Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a])
|
||||
);
|
||||
}
|
||||
const popup = entries.get("popup.html").toString("utf8");
|
||||
for (const [, relativePath] of popup.matchAll(/\b(?:href|src)="([^"]+)"/g)) {
|
||||
assert.equal(
|
||||
entries.has(relativePath),
|
||||
true,
|
||||
`${relativePath} referenced by popup.html should be packaged`
|
||||
);
|
||||
}
|
||||
|
||||
const digest = createHash("sha256").update(archive).digest("hex");
|
||||
assert.equal(
|
||||
await readFile(result.checksumPath, "utf8"),
|
||||
`${digest} glagolify-4.5.6-chromium.zip\n`
|
||||
);
|
||||
});
|
||||
|
||||
test("rejects Chromium version components outside the MV3 manifest range", async () => {
|
||||
await assert.rejects(
|
||||
packageExtension({
|
||||
rootDirectory: path.resolve(__dirname, ".."),
|
||||
outputDirectory: os.tmpdir(),
|
||||
target: "chromium",
|
||||
version: "65536"
|
||||
}),
|
||||
/cannot exceed 65535/
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user