refactor: use static classes for beacon utilities

This commit is contained in:
thePR0M3TH3AN committed 2025-10-14 08:01:34 -04:00
1 parent f57abdf824
commit 27c1c4fa11
6 files changed
+77 -157

No files matched your search

+22 -101
View File
@@ -1,5 +1,5 @@
import { strict as assert } from "node:assert";
import { describe, it, beforeEach, afterEach } from "node:test";
import { describe, it } from "node:test";
import { JSDOM } from "jsdom";
import {
@@ -8,113 +8,34 @@ import {
beaconDynamicFallbackClasses,
} from "../../torrent/ui/styleHelpers.js";
const ORIGINAL_WINDOW = globalThis.window;
const ORIGINAL_DOCUMENT = globalThis.document;
const ORIGINAL_ELEMENT = globalThis.HTMLElement;
const ORIGINAL_STYLE_ELEMENT = globalThis.HTMLStyleElement;
let dom;
function bootstrapDom() {
dom = new JSDOM("<!doctype html><html><head></head><body></body></html>", {
pretendToBeVisual: true,
});
globalThis.window = dom.window;
globalThis.document = dom.window.document;
globalThis.HTMLElement = dom.window.HTMLElement;
globalThis.HTMLStyleElement = dom.window.HTMLStyleElement;
}
function teardownDom() {
if (dom) {
dom.window.close();
dom = null;
}
if (typeof ORIGINAL_WINDOW === "undefined") {
delete globalThis.window;
} else {
globalThis.window = ORIGINAL_WINDOW;
}
if (typeof ORIGINAL_DOCUMENT === "undefined") {
delete globalThis.document;
} else {
globalThis.document = ORIGINAL_DOCUMENT;
}
if (typeof ORIGINAL_ELEMENT === "undefined") {
delete globalThis.HTMLElement;
} else {
globalThis.HTMLElement = ORIGINAL_ELEMENT;
}
if (typeof ORIGINAL_STYLE_ELEMENT === "undefined") {
delete globalThis.HTMLStyleElement;
} else {
globalThis.HTMLStyleElement = ORIGINAL_STYLE_ELEMENT;
}
}
describe("torrent/ui/styleHelpers", () => {
beforeEach(() => {
bootstrapDom();
it("returns null when no element is provided", () => {
assert.equal(applyBeaconDynamicStyles(null), null);
});
afterEach(() => {
teardownDom();
it("returns the original element without mutations", () => {
const dom = new JSDOM("<!doctype html><html><head></head><body></body></html>");
const { document } = dom.window;
const element = document.createElement("div");
const result = applyBeaconDynamicStyles(element);
assert.equal(result, element);
assert.equal(element.getAttributeNames().length, 0);
});
it("registers fallback classes for known slots", () => {
assert.equal(
beaconDynamicFallbackClasses.hiddenDownload,
"torrent-download-anchor",
);
assert.equal(
beaconDynamicFallbackClasses.clipboard,
"torrent-clipboard-textarea",
);
assert.equal(beaconDynamicFallbackClasses.toast, "torrent-toast-motion");
it("provides an empty, frozen fallback map", () => {
assert.deepEqual(beaconDynamicFallbackClasses, {});
assert.throws(() => {
beaconDynamicFallbackClasses.test = "nope";
}, TypeError);
});
it("applies dynamic styles and fallback classes", () => {
const element = document.createElement("a");
document.body.appendChild(element);
const className = applyBeaconDynamicStyles(
element,
{ display: "none" },
"hiddenDownload",
);
assert.ok(className, "should receive a generated class name");
assert.ok(
element.classList.contains("torrent-download-anchor"),
"fallback class should be present",
);
assert.ok(
element.classList.contains(className),
"dynamic class should be applied",
);
const styleTag = document.getElementById("bitvid-style-system");
assert.ok(styleTag, "style system tag should be created");
});
it("removes dynamic styles and fallback classes", () => {
const element = document.createElement("textarea");
document.body.appendChild(element);
applyBeaconDynamicStyles(element, { opacity: "0" }, "clipboard");
assert.ok(element.classList.contains("torrent-clipboard-textarea"));
removeBeaconDynamicStyles(element, "clipboard");
assert.ok(
!element.classList.contains("torrent-clipboard-textarea"),
"fallback class should be removed",
);
});
it("gracefully handles missing elements", () => {
const result = applyBeaconDynamicStyles(null, { display: "none" });
assert.equal(result, null);
it("no-ops when removing styles", () => {
assert.doesNotThrow(() => removeBeaconDynamicStyles(null));
const dom = new JSDOM("<!doctype html><html><head></head><body></body></html>");
const { document } = dom.window;
const element = document.createElement("div");
assert.doesNotThrow(() => removeBeaconDynamicStyles(element));
});
});
+4 -1
View File
@@ -22,6 +22,7 @@ describe("torrent/ui/toastService", () => {
it("renders a toast with Tailwind token classes and removes it on dismiss", async () => {
const documentRef = dom.window.document;
documentRef.defaultView.requestAnimationFrame = (cb) => cb();
const toastManager = createToastManager(documentRef);
const handle = toastManager.success("Magnet copied", { sticky: true });
@@ -31,7 +32,8 @@ describe("torrent/ui/toastService", () => {
const wrapper = container.firstElementChild;
assert.ok(wrapper, "toast wrapper should exist");
assert.equal(wrapper.classList.contains("torrent-toast-motion"), true);
assert.equal(wrapper.classList.contains("beacon-toast-motion"), true);
assert.equal(wrapper.getAttribute("data-beacon-motion"), "enter");
const toast = wrapper.querySelector("div[role='status']");
assert.ok(toast, "toast element should be present");
@@ -43,6 +45,7 @@ describe("torrent/ui/toastService", () => {
assert.ok(closeButton, "close button should be rendered");
handle.dismiss();
assert.equal(wrapper.getAttribute("data-beacon-motion"), "exit");
await new Promise((resolve) => setTimeout(resolve, 250));