Files
speeder/tests/popup.spec.js
T

299 lines
8.7 KiB
JavaScript

const {
createChromeMock,
evaluateScript,
fireDOMContentLoaded,
flushAsyncWork,
installCommonWindowMocks,
loadHtmlFile
} = require("./helpers/extension-test-utils");
const manifest = require("../extension/manifest.json");
function bootPopup(options) {
const config = options || {};
loadHtmlFile("extension/popup/popup.html");
installCommonWindowMocks();
const chrome = createChromeMock({
manifest: { version: "9.9.9-test" },
syncData: config.syncData,
localData: config.localData,
runtimeSendMessageImpl: config.runtimeSendMessageImpl,
tabsQueryResult: [
config.activeTab || { id: 99, active: true, url: "https://example.com/" }
]
});
chrome.tabs.executeScript.mockImplementation(
config.executeScriptImpl ||
((tabId, details, callback) => {
if (callback) callback([{ speed: 1.0, preferred: true }]);
})
);
chrome.tabs.sendMessage.mockImplementation(
config.sendMessageImpl ||
((tabId, message, callback) => {
if (message.action === "get_speed") {
callback({ speed: 1.0 });
return;
}
if (message.action === "rescan_page") {
callback({ status: "complete" });
return;
}
callback({ speed: 1.0 });
})
);
global.chrome = chrome;
window.chrome = chrome;
evaluateScript("extension/shared/settings-core.js");
evaluateScript("extension/shared/site-rules.js");
evaluateScript("extension/shared/popup-controls.js");
evaluateScript("extension/shared/ui-icons.js");
evaluateScript("extension/popup/popup.js");
fireDOMContentLoaded();
return chrome;
}
describe("popup.js", () => {
afterEach(() => {
vi.useRealTimers();
vi.unstubAllGlobals();
delete global.chrome;
});
it("declares activeTab for the popup all-frame speed snapshot", () => {
expect(manifest.permissions).toContain("activeTab");
});
it("renders the popup disabled state when a site rule disables Speeder", async () => {
bootPopup({
syncData: {
enabled: true,
siteRules: [
{
pattern: "youtube.com",
enabled: false
}
]
},
activeTab: {
id: 10,
active: true,
url: "https://www.youtube.com/watch?v=abc123"
}
});
await flushAsyncWork();
expect(document.querySelector("#app-version").textContent).toBe("9.9.9-test");
expect(document.querySelector("#status").textContent).toContain(
"disabled for this site"
);
expect(document.querySelector("#popupSpeed").textContent).toBe("1.00");
expect(document.querySelector("#popupControlBar").style.display).toBe("none");
});
it("builds sanitized popup buttons and refreshes speed after an action", async () => {
let speedQueryCount = 0;
const chrome = bootPopup({
syncData: {
enabled: true,
controllerButtons: ["faster", "settings", "rewind", "faster"],
popupMatchHoverControls: true
},
executeScriptImpl: (tabId, details, callback) => {
speedQueryCount += 1;
callback(
speedQueryCount === 1
? [
{ speed: 1.25, preferred: false },
{ speed: 1.5, frameToken: "playing-frame", preferred: true }
]
: [{ speed: 1.75, preferred: true }]
);
}
});
chrome.tabs.sendMessage.mockImplementation((tabId, message, callback) => {
if (message.action === "run_action") {
callback({ speed: 1.75 });
return;
}
callback({ speed: 1.0 });
});
await flushAsyncWork();
const buttons = Array.from(
document.querySelectorAll("#popupControlBar button[data-action]")
).map((button) => button.dataset.action);
expect(buttons).toEqual(["faster", "rewind"]);
expect(document.querySelector("#popupSpeed").textContent).toBe("1.50");
document.querySelector('#popupControlBar button[data-action="faster"]').click();
await flushAsyncWork();
expect(chrome.tabs.sendMessage).toHaveBeenCalledWith(
99,
{
action: "run_action",
actionName: "faster",
targetFrameToken: "playing-frame"
},
expect.any(Function)
);
expect(document.querySelector("#popupSpeed").textContent).toBe("1.75");
});
it("keeps all-video popup actions intentionally untargeted", async () => {
const chrome = bootPopup({
syncData: { shortcutTargetMode: "all" },
executeScriptImpl: (tabId, details, callback) => {
callback([{ speed: 1.5, frameToken: "playing-frame", preferred: true }]);
}
});
await flushAsyncWork();
chrome.tabs.sendMessage.mockClear();
document.querySelector("#popupControlBar button").click();
expect(chrome.tabs.sendMessage).toHaveBeenCalledWith(
99,
{ action: "run_action", actionName: "rewind" },
expect.any(Function)
);
});
it("copies redacted diagnostics for the active media frame", async () => {
bootPopup({
activeTab: {
id: 12,
active: true,
url: "https://video.example/watch?private_token=secret"
},
executeScriptImpl: (tabId, details, callback) => {
callback([
{
speed: 1.5,
preferred: true,
diagnostics: {
mediaType: "video",
fullscreen: { active: true, element: "div", ownsMedia: true },
controller: { present: true, hidden: false }
}
}
]);
}
});
const writeText = vi.fn(() => Promise.resolve());
Object.defineProperty(navigator, "clipboard", {
configurable: true,
value: { writeText }
});
await flushAsyncWork();
document.querySelector("#copyDiagnostics").click();
await flushAsyncWork();
expect(writeText).toHaveBeenCalled();
const reportText = writeText.mock.calls.at(-1)[0];
const report = JSON.parse(reportText);
expect(report.page).toEqual({
protocol: "https:",
hostname: "video.example"
});
expect(report.frame.mediaType).toBe("video");
expect(reportText).not.toContain("private_token");
expect(reportText).not.toContain("secret");
expect(document.querySelector("#status").textContent).toContain("copied");
});
it("adds one safe origin rule for the current site", async () => {
const chrome = bootPopup({
activeTab: {
id: 18,
active: true,
url: "https://courses.example:8443/watch/lesson?token=private"
}
});
await flushAsyncWork();
document.querySelector("#addSiteRule").click();
await flushAsyncWork();
document.querySelector("#addSiteRule").click();
await flushAsyncWork();
const rules = window.vscExpandStoredSettings(
chrome.storage.sync._dump()
).siteRules.filter(function(rule) {
return rule.pattern === "https://courses.example:8443";
});
expect(rules).toEqual([
{
title: "courses.example:8443",
pattern: "https://courses.example:8443",
enabled: true
}
]);
expect(window.open).toHaveBeenCalledWith(
"moz-extension://options/options.html"
);
});
it("pauses only the active tab for the browser session", async () => {
let paused = false;
const chrome = bootPopup({
runtimeSendMessageImpl: (message, callback) => {
if (message.action === "set_tab_paused") paused = message.paused === true;
callback({ paused });
}
});
await flushAsyncWork();
document.querySelector("#pauseTab").click();
expect(chrome.runtime.sendMessage).toHaveBeenCalledWith(
{ action: "set_tab_paused", tabId: 99, paused: true },
expect.any(Function)
);
expect(document.querySelector("#pauseTab").textContent).toBe(
"Resume on this tab"
);
expect(document.querySelector("#popupControlBar").style.display).toBe(
"none"
);
expect(document.querySelector("#status").textContent).toContain("paused");
});
it("toggles enablement and closes after a successful refresh", async () => {
const chrome = bootPopup({
syncData: {
enabled: false
}
});
await flushAsyncWork();
vi.useFakeTimers();
expect(document.querySelector("#enable").classList.contains("hide")).toBe(false);
expect(document.querySelector("#disable").classList.contains("hide")).toBe(true);
document.querySelector("#enable").click();
expect(chrome.storage.sync._dump()).not.toHaveProperty("enabled");
expect(
window.vscExpandStoredSettings(chrome.storage.sync._dump()).enabled
).toBe(true);
expect(chrome.browserAction.setIcon).not.toHaveBeenCalled();
document.querySelector("#refresh").click();
expect(document.querySelector("#status").textContent).toContain("Closing");
vi.advanceTimersByTime(500);
expect(window.close).toHaveBeenCalled();
});
});