test: cover SimilarContentCard behaviors

This commit is contained in:
thePR0M3TH3AN committed 2025-10-24 22:07:33 -04:00
1 parent 9e283c1c3a
commit 3b7fea6e7c
2 files changed
+81 -112

No files matched your search

+19
View File
@@ -0,0 +1,19 @@
import { JSDOM } from "jsdom";
export function createUiDom({
html = "<!DOCTYPE html><html><body></body></html>",
url = "https://bitvid.invalid/",
pretendToBeVisual = true,
} = {}) {
const dom = new JSDOM(html, {
url,
pretendToBeVisual,
});
const { window } = dom;
return {
window,
document: window.document,
cleanup: () => window.close(),
};
}
+62 -112
View File
@@ -1,23 +1,9 @@
import test from "node:test";
import assert from "node:assert/strict";
import { JSDOM } from "jsdom";
import { SimilarContentCard } from "../../js/ui/components/SimilarContentCard.js";
import { formatShortNpub } from "../../js/utils/formatters.js";
function createDom() {
const dom = new JSDOM("<!DOCTYPE html><html><body></body></html>", {
pretendToBeVisual: true,
url: "https://example.com/",
});
const { document } = dom.window;
return {
dom,
document,
window: dom.window,
cleanup: () => dom.window.close(),
};
}
import { createUiDom } from "./helpers/jsdom-test-helpers.mjs";
function createVideo(overrides = {}) {
return {
@@ -29,16 +15,26 @@ function createVideo(overrides = {}) {
};
}
test("uses cached thumbnails without lazy-loading and preserves backdrop", (t) => {
const { document, cleanup } = createDom();
function renderCard(t, options = {}) {
const { document, window, cleanup } = createUiDom();
t.after(cleanup);
const cachedSrc = "https://cdn.example.com/thumb.jpg";
const cache = new Map([["video-123", cachedSrc]]);
const { video: videoOverrides, ...rest } = options;
const card = new SimilarContentCard({
document,
video: createVideo(),
video: createVideo(videoOverrides),
...rest,
});
return { card, document, window };
}
test("cached thumbnails reuse existing src without lazy-loading", (t) => {
const cachedSrc = "https://cdn.example.com/thumb.jpg";
const cache = new Map([["video-123", cachedSrc]]);
const { card } = renderCard(t, {
thumbnailCache: cache,
fallbackThumbnailSrc: "https://cdn.example.com/fallback.jpg",
});
@@ -48,43 +44,39 @@ test("uses cached thumbnails without lazy-loading and preserves backdrop", (t) =
assert(img, "thumbnail element should exist");
assert.equal(img.src, cachedSrc);
assert.equal(img.hasAttribute("data-lazy"), false);
assert.equal(img.dataset.lazy, undefined);
assert.equal(
root.style.getPropertyValue("--similar-card-thumb-url"),
`url("${cachedSrc}")`,
);
});
test("lazy loads uncached thumbnails, caches on load, and keeps blur state", (t) => {
const { document, window, cleanup } = createDom();
t.after(cleanup);
const fallback = "https://cdn.example.com/fallback.jpg";
test("uncached thumbnails use fallback, cache on load, and retain blur state", (t) => {
const fallbackSrc = "https://cdn.example.com/fallback.jpg";
const remoteThumb = "https://cdn.example.com/remote.jpg";
const cache = new Map();
const card = new SimilarContentCard({
document,
video: createVideo({
const { card, window } = renderCard(t, {
video: {
id: "video-456",
thumbnail: remoteThumb,
moderation: { blurThumbnail: true },
}),
},
thumbnailCache: cache,
fallbackThumbnailSrc: fallback,
fallbackThumbnailSrc: fallbackSrc,
});
const root = card.getRoot();
const img = root.querySelector("img[data-video-thumbnail]");
assert(img);
assert.equal(img.getAttribute("src"), fallback);
assert.equal(img.getAttribute("src"), fallbackSrc);
assert.equal(img.dataset.fallbackSrc, fallbackSrc);
assert.equal(img.dataset.lazy, remoteThumb);
assert.equal(img.dataset.fallbackSrc, fallback);
assert.equal(img.dataset.thumbnailState, "blurred");
assert.equal(
root.style.getPropertyValue("--similar-card-thumb-url"),
`url("${fallback}")`,
`url("${fallbackSrc}")`,
);
img.src = remoteThumb;
@@ -98,63 +90,53 @@ test("lazy loads uncached thumbnails, caches on load, and keeps blur state", (t)
assert.equal(img.dataset.thumbnailState, "blurred");
});
test("primary clicks trigger onPlay, modifiers and right clicks do not", (t) => {
const { document, window, cleanup } = createDom();
t.after(cleanup);
const card = new SimilarContentCard({
document,
video: createVideo({ id: "video-play" }),
test("primary clicks trigger onPlay while modifiers and right clicks do not", (t) => {
const { card, window } = renderCard(t, {
video: { id: "video-play" },
});
let callCount = 0;
let lastPayload = null;
card.onPlay = (payload) => {
callCount += 1;
lastPayload = payload;
assert.equal(payload.video.id, "video-play");
};
const mediaLink = card.getRoot().querySelector("a[data-primary-action=play]");
assert(mediaLink);
mediaLink.dispatchEvent(
new window.MouseEvent("click", { bubbles: true, button: 0 })
);
assert.equal(callCount, 1);
assert.equal(lastPayload?.video?.id, "video-play");
mediaLink.dispatchEvent(
new window.MouseEvent("click", { bubbles: true, button: 0, metaKey: true })
);
mediaLink.dispatchEvent(
new window.MouseEvent("click", { bubbles: true, button: 2 })
);
assert.equal(callCount, 1);
const titleLink = card.getRoot().querySelector(
".player-modal__similar-card-title"
".player-modal__similar-card-title",
);
assert(mediaLink);
assert(titleLink);
mediaLink.dispatchEvent(
new window.MouseEvent("click", { bubbles: true, button: 0 }),
);
assert.equal(callCount, 1);
mediaLink.dispatchEvent(
new window.MouseEvent("click", { bubbles: true, button: 0, metaKey: true }),
);
mediaLink.dispatchEvent(
new window.MouseEvent("click", { bubbles: true, button: 2 }),
);
assert.equal(callCount, 1);
titleLink.dispatchEvent(
new window.MouseEvent("click", { bubbles: true, button: 0 })
new window.MouseEvent("click", { bubbles: true, button: 0 }),
);
assert.equal(callCount, 2);
});
test("renders author identity fields with provided datasets", (t) => {
const { document, cleanup } = createDom();
t.after(cleanup);
test("author identity fields render supplied values and datasets", (t) => {
const identity = {
name: "Satoshi",
name: "Satoshi Nakamoto",
npub: "npub1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
pubkey: "pubkey-satoshi",
picture: "https://cdn.example.com/avatar.png",
};
const card = new SimilarContentCard({
document,
video: createVideo({ id: "identity" }),
const { card } = renderCard(t, {
video: { id: "identity" },
identity,
});
@@ -164,6 +146,7 @@ test("renders author identity fields with provided datasets", (t) => {
const avatarEl = root.querySelector(
".player-modal__similar-card-avatar-img",
);
assert(nameEl);
assert(npubEl);
assert(avatarEl);
@@ -174,27 +157,24 @@ test("renders author identity fields with provided datasets", (t) => {
const expectedShort = formatShortNpub(identity.npub);
assert.equal(npubEl.textContent, expectedShort);
assert.equal(npubEl.dataset.pubkey, identity.pubkey);
assert.equal(npubEl.dataset.npub, identity.npub);
assert.equal(npubEl.getAttribute("title"), identity.npub);
assert.equal(npubEl.getAttribute("aria-hidden"), "false");
assert.equal(npubEl.hidden, false);
assert.equal(npubEl.getAttribute("aria-hidden"), "false");
assert.equal(avatarEl.dataset.pubkey, identity.pubkey);
assert.equal(avatarEl.src, identity.picture);
assert.match(avatarEl.alt, /Satoshi/);
});
test("exposes view count element wired to pointer info", (t) => {
const { document, cleanup } = createDom();
t.after(cleanup);
test("view counter wiring exposes pointer datasets", (t) => {
const pointerInfo = {
key: "views:123",
pointer: ["a", "b", "wss://relay.example"],
pointer: ["a", "kind:views", "wss://relay.example"],
};
const card = new SimilarContentCard({
document,
video: createVideo({ id: "views" }),
const { card } = renderCard(t, {
video: { id: "views" },
pointerInfo,
});
@@ -203,40 +183,10 @@ test("exposes view count element wired to pointer info", (t) => {
assert.equal(viewEl.dataset.viewPointer, pointerInfo.key);
assert.equal(viewEl.dataset.viewCount, "");
assert.equal(viewEl.textContent, "– views");
});
test("hides duplicate npub pill and falls back to default avatar", (t) => {
const { document, cleanup } = createDom();
t.after(cleanup);
const npub = "npub1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq";
const card = new SimilarContentCard({
document,
video: createVideo({ id: "duplicates" }),
identity: { npub },
});
const root = card.getRoot();
const nameEl = root.querySelector(".author-name");
const npubEl = root.querySelector(".author-npub");
const avatarEl = root.querySelector(
".player-modal__similar-card-avatar-img",
);
assert(nameEl);
assert(npubEl);
assert(avatarEl);
const expectedShort = formatShortNpub(npub);
assert.equal(nameEl.textContent, expectedShort);
assert.equal(npubEl.textContent, expectedShort);
assert.equal(npubEl.hidden, true);
assert.equal(npubEl.getAttribute("aria-hidden"), "true");
assert.equal(npubEl.hasAttribute("title"), false);
assert.ok(
avatarEl.src.endsWith("/assets/svg/default-profile.svg"),
"avatar should fall back to default profile icon",
);
assert.match(avatarEl.alt, /avatar$/i);
assert.equal(root.dataset.pointerKey, pointerInfo.key);
assert.equal(root.dataset.pointerType, pointerInfo.pointer[0]);
assert.equal(root.dataset.pointerValue, pointerInfo.pointer[1]);
assert.equal(root.dataset.pointerRelay, pointerInfo.pointer[2]);
});