Files
return-youtube-dislike/Extensions/combined/ryd.background-changelog.spec.js
T
Anarios e500088e65 Prepare 4.0.5 Firefox update and Shorts fixes
Add Firefox data consent, repair contributor sign-in, and introduce optional Hide clutter buttons. Harden video navigation, voting, and action layouts with shared browser regression coverage and reproducible release packaging.
2026-09-06 12:51:12 +02:00

173 lines
6.9 KiB
JavaScript

jest.mock("../common/vote-client", () => ({ createVoteClient: jest.fn() }));
jest.mock("./src/data-collection-permissions", () => ({
hasAuthenticationDataPermission: jest.fn(),
onAuthenticationDataPermissionRemoved: jest.fn(),
usesFirefoxDataCollectionConsent: jest.fn(),
}));
const flushCallbacks = () => new Promise((resolve) => setTimeout(resolve, 0));
const VERSION = "4.0.5";
const CHANGELOG_URL = "moz-extension://test/changelog/4/changelog_4.0.html";
describe("background changelog lifecycle", () => {
let installedListener;
let startupListener;
let stored;
beforeEach(() => {
jest.resetModules();
stored = {};
require("../common/vote-client").createVoteClient.mockReturnValue({ ensureRegistered: () => Promise.resolve({}) });
global.__RYD_LIVE_TEST_BUILD__ = false;
global.chrome = {
runtime: {
getManifest: () => ({ version: VERSION }),
getURL: (relativePath) => `moz-extension://test/${relativePath}`,
onMessage: { addListener: jest.fn() },
onInstalled: { addListener: (listener) => (installedListener = listener) },
onStartup: { addListener: (listener) => (startupListener = listener) },
},
storage: {
sync: { get: jest.fn(), set: jest.fn(), remove: jest.fn() },
local: {
get: jest.fn((keys, callback) => queueMicrotask(() => callback({ ...stored }))),
set: jest.fn((values, callback) =>
queueMicrotask(() => {
Object.assign(stored, values);
callback?.();
}),
),
remove: jest.fn((keys, callback) =>
queueMicrotask(() => {
for (const key of [].concat(keys)) delete stored[key];
callback?.();
}),
),
},
onChanged: { addListener: jest.fn() },
},
tabs: {
create: jest.fn((properties, callback) => queueMicrotask(() => callback?.({ id: 1, ...properties }))),
},
};
// Firefox exposes the chrome callback namespace alongside browser.
global.browser = global.chrome;
jest.spyOn(console, "debug").mockImplementation(() => {});
require("./ryd.background");
});
afterEach(() => {
jest.restoreAllMocks();
delete global.chrome;
delete global.browser;
delete global.__RYD_LIVE_TEST_BUILD__;
});
test.each([false, true])("opens the changelog on a fresh install (temporary=%s)", async (temporary) => {
installedListener({ reason: "install", temporary });
await flushCallbacks();
expect(chrome.tabs.create).toHaveBeenCalledTimes(1);
expect(chrome.tabs.create).toHaveBeenCalledWith({ url: CHANGELOG_URL }, expect.any(Function));
expect(stored).toEqual({ lastShownChangelogVersion: VERSION });
});
test.each(["install", "update"])("preserves already-seen suppression on %s", async (reason) => {
stored.lastShownChangelogVersion = "4.0.4";
installedListener({ reason, temporary: true, previousVersion: "4.0.4" });
await flushCallbacks();
expect(chrome.tabs.create).not.toHaveBeenCalled();
expect(stored).toEqual({ lastShownChangelogVersion: "4.0.4" });
});
test("queues an unseen update and opens it on browser startup", async () => {
installedListener({ reason: "update", previousVersion: "4.0.4" });
await flushCallbacks();
expect(chrome.tabs.create).not.toHaveBeenCalled();
expect(stored).toEqual({ pendingChangelogVersion: VERSION });
startupListener();
await flushCallbacks();
expect(chrome.tabs.create).toHaveBeenCalledTimes(1);
expect(stored).toEqual({ lastShownChangelogVersion: VERSION });
startupListener();
await flushCallbacks();
expect(chrome.tabs.create).toHaveBeenCalledTimes(1);
});
test("opens an unseen temporary update immediately after the shown marker is cleared", async () => {
installedListener({ reason: "update", temporary: true, previousVersion: VERSION });
await flushCallbacks();
expect(chrome.tabs.create).toHaveBeenCalledTimes(1);
expect(chrome.tabs.create).toHaveBeenCalledWith({ url: CHANGELOG_URL }, expect.any(Function));
expect(stored).toEqual({ lastShownChangelogVersion: VERSION });
});
test("consumes an existing pending changelog when a temporary update opens it", async () => {
stored.pendingChangelogVersion = VERSION;
installedListener({ reason: "update", temporary: true, previousVersion: VERSION });
await flushCallbacks();
expect(chrome.tabs.create).toHaveBeenCalledTimes(1);
expect(stored).toEqual({ lastShownChangelogVersion: VERSION });
});
test("does not reopen the changelog on the next already-seen temporary reload", async () => {
const details = { reason: "update", temporary: true, previousVersion: VERSION };
installedListener(details);
await flushCallbacks();
expect(chrome.tabs.create).toHaveBeenCalledTimes(1);
installedListener(details);
await flushCallbacks();
expect(chrome.tabs.create).toHaveBeenCalledTimes(1);
expect(stored).toEqual({ lastShownChangelogVersion: VERSION });
});
test("opens a previously persisted pending version on startup", async () => {
stored.pendingChangelogVersion = VERSION;
startupListener();
await flushCallbacks();
expect(chrome.tabs.create).toHaveBeenCalledWith({ url: CHANGELOG_URL }, expect.any(Function));
expect(stored).toEqual({ lastShownChangelogVersion: VERSION });
});
test("clears a redundant pending update when the changelog was already shown", async () => {
stored.lastShownChangelogVersion = "4.0.4";
stored.pendingChangelogVersion = VERSION;
startupListener();
await flushCallbacks();
expect(chrome.tabs.create).not.toHaveBeenCalled();
expect(stored).toEqual({ lastShownChangelogVersion: "4.0.4" });
});
test("does not mark the changelog as shown when tabs.create reports a callback error", async () => {
chrome.tabs.create.mockImplementationOnce((properties, callback) =>
queueMicrotask(() => {
chrome.runtime.lastError = { message: "No browser window is available" };
try {
callback(undefined);
} finally {
delete chrome.runtime.lastError;
}
}),
);
installedListener({ reason: "install", temporary: true });
await flushCallbacks();
expect(chrome.tabs.create).toHaveBeenCalledTimes(1);
expect(stored.lastShownChangelogVersion).toBeUndefined();
expect(chrome.storage.local.set).not.toHaveBeenCalledWith(
expect.objectContaining({ lastShownChangelogVersion: expect.anything() }),
expect.any(Function),
);
installedListener({ reason: "install", temporary: true });
await flushCallbacks();
expect(chrome.tabs.create).toHaveBeenCalledTimes(2);
expect(stored).toEqual({ lastShownChangelogVersion: VERSION });
const shownWrites = chrome.storage.local.set.mock.calls.filter(([values]) =>
Object.prototype.hasOwnProperty.call(values, "lastShownChangelogVersion"),
);
expect(shownWrites).toHaveLength(1);
});
});