Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/improsocial/impro
An extensible Bluesky client for web impro.social
Something went wrong. Try again.
6.4 kB · 209 lines
JavaScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210import { describe, it, beforeEach } from "node:test";import assert from "node:assert/strict";import "/js/components/plugin-blob-image.js";import { CDN_URL } from "/js/config.js";
describe("plugin-blob-image", () => { const VALID_CID = "bafkreigh2akiscaildcqabsyg3dfr6chu3fgpregiymsck7e7aqa4s52zy"; let didCounter = 0;
function uniqueDid() { didCounter++; return `did:plc:test${didCounter.toString().padStart(6, "0")}xxxxxxx`; }
async function flush() { await new Promise((resolve) => setTimeout(resolve, 0)); }
function makeElement({ did, cid, alt, cdnPrefix }) { const element = document.createElement("plugin-blob-image"); if (did !== undefined) element.setAttribute("did", did); if (cid !== undefined) element.setAttribute("cid", cid); if (alt !== undefined) element.setAttribute("alt", alt); if (cdnPrefix !== undefined) element.setAttribute("cdn-prefix", cdnPrefix); document.body.appendChild(element); return element; }
beforeEach(() => { document.body.innerHTML = ""; });
describe("input validation", () => { it("renders the alt fallback when did is missing", async () => { const element = makeElement({ cid: VALID_CID, alt: ":blobcat:", cdnPrefix: "feed_thumbnail", }); await flush(); assert(element.querySelector("img") === null); const fallback = element.querySelector(".blob-image-fallback"); assert(fallback !== null); assert.deepEqual(fallback.textContent, ":blobcat:"); });
it("renders the alt fallback when cid is malformed", async () => { const element = makeElement({ did: uniqueDid(), cid: "not-a-cid", alt: ":x:", cdnPrefix: "feed_thumbnail", }); await flush(); assert(element.querySelector("img") === null); assert(element.querySelector(".blob-image-fallback") !== null); });
it("renders the alt fallback for a bogus DID method", async () => { const element = makeElement({ did: "did:evil:x", cid: VALID_CID, alt: ":x:", cdnPrefix: "feed_thumbnail", }); await flush(); assert(element.querySelector("img") === null); assert(element.querySelector(".blob-image-fallback") !== null); });
it("falls back when cdn-prefix is missing", async () => { const element = makeElement({ did: uniqueDid(), cid: VALID_CID, alt: ":x:", }); await flush(); assert(element.querySelector("img") === null); assert(element.querySelector(".blob-image-fallback") !== null); });
it("falls back when cdn-prefix is not allowlisted", async () => { const element = makeElement({ did: uniqueDid(), cid: VALID_CID, alt: ":x:", cdnPrefix: "../secrets", }); await flush(); assert(element.querySelector("img") === null); assert(element.querySelector(".blob-image-fallback") !== null); }); });
describe("URL construction", () => { it("builds a bsky CDN URL from did/cid/cdn-prefix", async () => { const did = uniqueDid(); const element = makeElement({ did, cid: VALID_CID, alt: "avatar", cdnPrefix: "avatar_thumbnail", }); await flush(); const img = element.querySelector("img"); assert(img !== null); assert.deepEqual( img.getAttribute("src"), `${CDN_URL}/img/avatar_thumbnail/plain/${did}/${VALID_CID}@jpeg`, ); assert.deepEqual(img.getAttribute("alt"), "avatar"); }); });
describe("error handling", () => { it("shows fallback on image error", async () => { const element = makeElement({ did: uniqueDid(), cid: VALID_CID, alt: ":x:", cdnPrefix: "feed_thumbnail", }); await flush();
const img = element.querySelector("img"); assert(img !== null); img.dispatchEvent(new window.Event("error")); await flush(); assert(element.querySelector("img") === null); assert(element.querySelector(".blob-image-fallback") !== null); }); });
describe("attribute changes", () => { it("re-renders when did changes", async () => { const didA = uniqueDid(); const didB = uniqueDid(); const element = makeElement({ did: didA, cid: VALID_CID, alt: ":x:", cdnPrefix: "feed_thumbnail", }); await flush(); assert(element.querySelector("img").getAttribute("src").includes(didA));
element.setAttribute("did", didB); await flush(); assert(element.querySelector("img").getAttribute("src").includes(didB)); });
it("updates the rendered alt text when alt changes", async () => { const element = makeElement({ did: uniqueDid(), cid: VALID_CID, alt: ":old:", cdnPrefix: "feed_thumbnail", }); await flush();
element.setAttribute("alt", ":new:"); await flush(); assert.deepEqual( element.querySelector("img").getAttribute("alt"), ":new:", ); });
it("keeps the fallback when only alt changes after a load error", async () => { const element = makeElement({ did: uniqueDid(), cid: VALID_CID, alt: ":old:", cdnPrefix: "feed_thumbnail", }); await flush();
element.querySelector("img").dispatchEvent(new window.Event("error")); await flush(); assert(element.querySelector("img") === null);
element.setAttribute("alt", ":new:"); await flush(); assert(element.querySelector("img") === null); const fallback = element.querySelector(".blob-image-fallback"); assert(fallback !== null); assert.deepEqual(fallback.textContent, ":new:"); });
it("clears the error state so a fixed cid stops showing the fallback", async () => { const element = makeElement({ did: uniqueDid(), cid: VALID_CID, alt: ":x:", cdnPrefix: "feed_thumbnail", }); await flush();
element.querySelector("img").dispatchEvent(new window.Event("error")); await flush(); assert(element.querySelector("img") === null);
element.setAttribute("cid", VALID_CID.replace("bafk", "bafy")); await flush(); assert(element.querySelector("img") !== null); }); });});