Something went wrong. Try again.
Mirror of https://github.com/improsocial/improAn extensible Bluesky client for web
Something went wrong. Try again.
JavaScript
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363import { describe, it } from "node:test";import assert from "node:assert/strict";import { avatarThumbnailUrl, getRKey, getIsLiked, isListFeed, getQuotedPost, getImagesFromDraftPost, getLocalRefsFromDraft, getBlockedQuote, createEmbedFromPost, embedViewRecordToPostView, replaceTopParent, isAutomatedAccount, isLabelerProfile, getLabelNameAndDescription, getLabelerForLabel, getDefinitionForLabel, isBadgeLabel, addFeedItemToFeed, pinPostInFeed, unpinPostInFeed, getDisplayName, getThreadgateAllowSettings, isEmptyPost, hasValidHandle, INVALID_HANDLE, MISSING_HANDLE, canReplyToPost, transformNestedQuotes, getInteractionTimestamp, getConvoPreviewText, getInteractionProfileDids, getGroupConvoDetails, getGroupConvoOwner, getSystemMessageDisplayText, groupReactions, isGroupConvo, isInviteLinkUrl, getInviteCodeFromUrl, isVideoLink, isAvailableJoinLinkPreview, getJoinLinkCodeFromEmbed, getJoinLinkCodesFromPosts, getJoinLinkCodesFromMessages, attachJoinLinkPreviewToEmbed, getPostsFromPostThread, getPostsFromFeed,} from "/js/dataHelpers.js";
describe("avatarThumbnailUrl", () => { it("should convert plain avatar URL to thumbnail URL", () => { const avatarUrl = "https://cdn.bsky.app/img/avatar/plain/did:plc:123/image@jpeg"; const expected = "https://cdn.bsky.app/img/avatar_thumbnail/plain/did:plc:123/image@jpeg"; assert.deepEqual(avatarThumbnailUrl(avatarUrl), expected); });
it("should handle URL without /img/avatar/plain/", () => { const avatarUrl = "https://cdn.bsky.app/img/other/plain/image.jpg"; assert.deepEqual(avatarThumbnailUrl(avatarUrl), avatarUrl); });
it("should handle empty string", () => { assert.deepEqual(avatarThumbnailUrl(""), ""); });});
describe("getRKey", () => { it("should extract rkey from post URI", () => { const post = { uri: "at://did:plc:123/app.bsky.feed.post/3l7q2wm5ws22k" }; assert.deepEqual(getRKey(post), "3l7q2wm5ws22k"); });
it("should handle URI with different path structure", () => { const post = { uri: "at://did:plc:456/collection/another-rkey" }; assert.deepEqual(getRKey(post), "another-rkey"); });
it("should handle URI with single path segment", () => { const post = { uri: "single-segment" }; assert.deepEqual(getRKey(post), "single-segment"); });});
describe("isListFeed", () => { it("should return true for a list URI", () => { assert.deepEqual( isListFeed("at://did:plc:123/app.bsky.graph.list/3ltcvl4ver723"), true, ); });
it("should return false for a feed generator URI", () => { assert.deepEqual( isListFeed("at://did:plc:123/app.bsky.feed.generator/whats-hot"), false, ); });
it("should return false for the following feed", () => { assert.deepEqual(isListFeed("following"), false); });});
describe("getIsLiked", () => { it("should return true when post has viewer like", () => { const post = { viewer: { like: "at://did:plc:123/like/abc123" } }; assert.deepEqual(getIsLiked(post), true); });
it("should return false when viewer like is empty string", () => { const post = { viewer: { like: "" } }; assert.deepEqual(getIsLiked(post), false); });
it("should return false when viewer like is null", () => { const post = { viewer: { like: null } }; assert.deepEqual(getIsLiked(post), false); });
it("should return false when viewer like is undefined", () => { const post = { viewer: { like: undefined } }; assert.deepEqual(getIsLiked(post), false); });
it("should return false when viewer is undefined", () => { const post = {}; assert.deepEqual(getIsLiked(post), false); });
it("should return false when post has no viewer property", () => { const post = { uri: "test" }; assert.deepEqual(getIsLiked(post), false); });});
describe("getQuotedPost", () => { it("should return record for app.bsky.embed.record#view", () => { const post = { embed: { $type: "app.bsky.embed.record#view", record: { uri: "quoted-post-uri", author: { displayName: "Test" } }, }, }; assert.deepEqual(getQuotedPost(post), post.embed.record); });
it("should return nested record for app.bsky.embed.recordWithMedia#view", () => { const post = { embed: { $type: "app.bsky.embed.recordWithMedia#view", record: { record: { uri: "quoted-post-uri", author: { displayName: "Test" } }, }, }, }; assert.deepEqual(getQuotedPost(post), post.embed.record.record); });
it("should return null for embed with different $type", () => { const post = { embed: { $type: "app.bsky.embed.images#view", images: [], }, }; assert.deepEqual(getQuotedPost(post), null); });
it("should return null when embed is undefined", () => { const post = {}; assert.deepEqual(getQuotedPost(post), null); });
it("should return null when embed is null", () => { const post = { embed: null }; assert.deepEqual(getQuotedPost(post), null); });
it("should return null when post has no embed property", () => { const post = { uri: "test" }; assert.deepEqual(getQuotedPost(post), null); });
it("should use embeds array when available", () => { const post = { embeds: [ { $type: "app.bsky.embed.record#view", record: { uri: "quoted-post-uri", author: { displayName: "Test" } }, }, ], }; assert.deepEqual(getQuotedPost(post), post.embeds[0].record); });
it("should use embeds array for recordWithMedia", () => { const post = { embeds: [ { $type: "app.bsky.embed.recordWithMedia#view", record: { record: { uri: "quoted-post-uri", author: { displayName: "Test" }, }, }, }, ], }; assert.deepEqual(getQuotedPost(post), post.embeds[0].record.record); });
it("should prefer embeds array over embed property", () => { const post = { embeds: [ { $type: "app.bsky.embed.record#view", record: { uri: "from-embeds-array" }, }, ], embed: { $type: "app.bsky.embed.record#view", record: { uri: "from-embed-prop" }, }, }; assert.deepEqual(getQuotedPost(post), post.embeds[0].record); });
it("should fall back to embed when embeds is empty", () => { const post = { embeds: [], embed: { $type: "app.bsky.embed.record#view", record: { uri: "from-embed-prop" }, }, }; assert.deepEqual(getQuotedPost(post), null); });});
describe("getBlockedQuote", () => { it("should return blocked quote when quoted post is blocked", () => { const post = { embed: { $type: "app.bsky.embed.record#view", record: { $type: "app.bsky.embed.record#viewBlocked", uri: "blocked-uri", blocked: true, }, }, }; assert.deepEqual(getBlockedQuote(post), post.embed.record); });
it("should return null when quoted post is not blocked", () => { const post = { embed: { $type: "app.bsky.embed.record#view", record: { $type: "app.bsky.embed.record#view", uri: "normal-uri", }, }, }; assert.deepEqual(getBlockedQuote(post), null); });
it("should return null when no quoted post exists", () => { const post = { embed: { $type: "app.bsky.embed.images#view", images: [], }, }; assert.deepEqual(getBlockedQuote(post), null); });
it("should return null when post has no embed", () => { const post = {}; assert.deepEqual(getBlockedQuote(post), null); });});
describe("createEmbedFromPost", () => { it("should create embed from post with all required fields", () => { const post = { author: { did: "did:plc:123", displayName: "Test User" }, record: { text: "Hello world", createdAt: "2024-01-01" }, uri: "at://did:plc:123/app.bsky.feed.post/abc123", cid: "cid123", indexedAt: "2024-01-01T00:00:00Z", labels: [{ val: "test" }], likeCount: 5, replyCount: 2, repostCount: 1, quoteCount: 3, };
const result = createEmbedFromPost(post);
assert.deepEqual(result, { $type: "app.bsky.embed.record#viewRecord", author: { did: "did:plc:123", displayName: "Test User" }, value: { text: "Hello world", createdAt: "2024-01-01" }, uri: "at://did:plc:123/app.bsky.feed.post/abc123", cid: "cid123", indexedAt: "2024-01-01T00:00:00Z", labels: [{ val: "test" }], likeCount: 5, replyCount: 2, repostCount: 1, quoteCount: 3, }); });
it("should create separate copies of author and record objects", () => { const post = { author: { did: "did:plc:123" }, record: { text: "Hello" }, uri: "test-uri", };
const result = createEmbedFromPost(post);
assert(result.author !== post.author); assert(result.value !== post.record); assert.deepEqual(result.author, post.author); assert.deepEqual(result.value, post.record); });
it("should handle post with minimal data", () => { const post = { author: {}, record: {}, uri: "minimal-uri", };
const result = createEmbedFromPost(post);
assert.deepEqual(result, { $type: "app.bsky.embed.record#viewRecord", author: {}, value: {}, uri: "minimal-uri", cid: undefined, indexedAt: undefined, labels: undefined, likeCount: undefined, replyCount: undefined, repostCount: undefined, quoteCount: undefined, }); });
it("should include embeds when post has an embed", () => { const post = { author: { did: "did:plc:123" }, record: { text: "Hello" }, uri: "test-uri", cid: "cid456", indexedAt: "2024-02-01T00:00:00Z", labels: [], likeCount: 0, replyCount: 0, repostCount: 0, quoteCount: 0, embed: { $type: "app.bsky.embed.images#view", images: [{ thumb: "thumb.jpg" }], }, };
const result = createEmbedFromPost(post);
assert.deepEqual(result, { $type: "app.bsky.embed.record#viewRecord", author: { did: "did:plc:123" }, value: { text: "Hello" }, uri: "test-uri", cid: "cid456", indexedAt: "2024-02-01T00:00:00Z", labels: [], likeCount: 0, replyCount: 0, repostCount: 0, quoteCount: 0, embeds: [ { $type: "app.bsky.embed.images#view", images: [{ thumb: "thumb.jpg" }], }, ], }); });
it("should not include embeds when post has no embed", () => { const post = { author: { did: "did:plc:456" }, record: { text: "No embed" }, uri: "no-embed-uri", };
const result = createEmbedFromPost(post);
assert(!("embeds" in result)); });});
describe("embedViewRecordToPostView", () => { it("should convert a ViewRecord to a PostView", () => { const viewRecord = { uri: "at://did:plc:123/app.bsky.feed.post/abc", cid: "cid123", author: { did: "did:plc:123", handle: "test.user" }, value: { text: "Hello world", createdAt: "2024-01-01" }, embeds: [{ $type: "app.bsky.embed.images#view", images: [] }], labels: [{ val: "test" }], likeCount: 5, replyCount: 2, repostCount: 1, quoteCount: 3, indexedAt: "2024-01-01T00:00:00Z", };
const result = embedViewRecordToPostView(viewRecord);
assert.deepEqual(result, { uri: "at://did:plc:123/app.bsky.feed.post/abc", cid: "cid123", author: { did: "did:plc:123", handle: "test.user" }, record: { text: "Hello world", createdAt: "2024-01-01" }, embed: { $type: "app.bsky.embed.images#view", images: [] }, labels: [{ val: "test" }], likeCount: 5, replyCount: 2, repostCount: 1, quoteCount: 3, indexedAt: "2024-01-01T00:00:00Z", }); });
it("should map value to record and embeds[0] to embed", () => { const viewRecord = { uri: "test-uri", cid: "test-cid", author: {}, value: { text: "test" }, embeds: [{ $type: "embed1" }, { $type: "embed2" }], indexedAt: "2024-01-01T00:00:00Z", };
const result = embedViewRecordToPostView(viewRecord);
assert.deepEqual(result.record, viewRecord.value); assert.deepEqual(result.embed, viewRecord.embeds[0]); });
it("should handle missing embeds", () => { const viewRecord = { uri: "test-uri", cid: "test-cid", author: {}, value: { text: "test" }, indexedAt: "2024-01-01T00:00:00Z", };
const result = embedViewRecordToPostView(viewRecord);
assert.deepEqual(result.embed, undefined); });
it("should handle empty embeds array", () => { const viewRecord = { uri: "test-uri", cid: "test-cid", author: {}, value: { text: "test" }, embeds: [], indexedAt: "2024-01-01T00:00:00Z", };
const result = embedViewRecordToPostView(viewRecord);
assert.deepEqual(result.embed, undefined); });
it("should handle missing optional count fields", () => { const viewRecord = { uri: "test-uri", cid: "test-cid", author: {}, value: {}, indexedAt: "2024-01-01T00:00:00Z", };
const result = embedViewRecordToPostView(viewRecord);
assert.deepEqual(result.likeCount, undefined); assert.deepEqual(result.replyCount, undefined); assert.deepEqual(result.repostCount, undefined); assert.deepEqual(result.quoteCount, undefined); });});
describe("replaceTopParent", () => { it("should throw error when postThread has no parent", () => { const postThread = { post: { uri: "post-uri" } }; let threw = false; try { replaceTopParent(postThread, { post: { uri: "new-parent" } }); } catch (e) { threw = true; assert.deepEqual(e.message, "No parent found"); } assert(threw, "Expected replaceTopParent to throw"); });
it("should replace immediate parent when it is the top", () => { const postThread = { post: { uri: "child-uri" }, parent: { post: { uri: "parent-uri" } }, }; const newParent = { post: { uri: "new-parent-uri" } };
const result = replaceTopParent(postThread, newParent);
assert.deepEqual(result.parent, newParent); assert.deepEqual(result.post, postThread.post); });
it("should return new object when immediate parent is the top", () => { const postThread = { post: { uri: "child-uri" }, parent: { post: { uri: "parent-uri" } }, }; const newParent = { post: { uri: "new-parent-uri" } };
const result = replaceTopParent(postThread, newParent);
assert(result !== postThread, "Should return a new object"); });
it("should replace top parent when there are multiple levels", () => { const postThread = { post: { uri: "child-uri" }, parent: { post: { uri: "parent-uri" }, parent: { post: { uri: "grandparent-uri" }, }, }, }; const newParent = { post: { uri: "new-grandparent-uri" } };
const result = replaceTopParent(postThread, newParent);
assert.deepEqual(result.parent.parent, newParent); assert.deepEqual(result.parent.post.uri, "parent-uri"); });
it("should replace top parent when there are three levels", () => { const postThread = { post: { uri: "child-uri" }, parent: { post: { uri: "parent-uri" }, parent: { post: { uri: "grandparent-uri" }, parent: { post: { uri: "great-grandparent-uri" }, }, }, }, }; const newParent = { post: { uri: "new-top-uri" } };
const result = replaceTopParent(postThread, newParent);
assert.deepEqual(result.parent.parent.parent, newParent); assert.deepEqual(result.parent.parent.post.uri, "grandparent-uri"); });});
describe("isAutomatedAccount", () => { it("should return false for profile without labels", () => { const profile = { did: "did:plc:123", handle: "user.bsky.social" }; assert.deepEqual(isAutomatedAccount(profile), false); });
it("should return false for profile with empty labels", () => { const profile = { did: "did:plc:123", labels: [] }; assert.deepEqual(isAutomatedAccount(profile), false); });
it("should return false for profile with non-bot labels", () => { const profile = { did: "did:plc:123", labels: [{ val: "!no-unauthenticated" }], }; assert.deepEqual(isAutomatedAccount(profile), false); });
it("should return true for profile with bot label", () => { const profile = { did: "did:plc:123", labels: [{ val: "bot" }], }; assert.deepEqual(isAutomatedAccount(profile), true); });
it("should return true when bot label is among other labels", () => { const profile = { did: "did:plc:123", labels: [{ val: "!no-unauthenticated" }, { val: "bot" }], }; assert.deepEqual(isAutomatedAccount(profile), true); });});
describe("isLabelerProfile", () => { it("should return true when profile has associated labeler", () => { const profile = { associated: { labeler: true } }; assert.deepEqual(isLabelerProfile(profile), true); });
it("should return false when profile has no associated labeler", () => { const profile = { associated: { labeler: false } }; assert.deepEqual(isLabelerProfile(profile), false); });
it("should return undefined when profile has no associated property", () => { const profile = {}; assert.deepEqual(isLabelerProfile(profile), undefined); });
it("should return undefined when associated has no labeler property", () => { const profile = { associated: {} }; assert.deepEqual(isLabelerProfile(profile), undefined); });});
describe("getLabelNameAndDescription", () => { it("should return identifier as name when no locales", () => { const labelDefinition = { identifier: "test-label" }; const result = getLabelNameAndDescription(labelDefinition);
assert.deepEqual(result.name, "test-label"); assert.deepEqual(result.description, ""); });
it("should return identifier as name when locales is empty", () => { const labelDefinition = { identifier: "test-label", locales: [] }; const result = getLabelNameAndDescription(labelDefinition);
assert.deepEqual(result.name, "test-label"); assert.deepEqual(result.description, ""); });
it("should return preferred language locale", () => { const labelDefinition = { identifier: "test-label", locales: [ { lang: "es", name: "Etiqueta", description: "Descripción" }, { lang: "en", name: "Label", description: "Description" }, ], }; const result = getLabelNameAndDescription(labelDefinition, "en");
assert.deepEqual(result.name, "Label"); assert.deepEqual(result.description, "Description"); });
it("should fall back to first locale when preferred not found", () => { const labelDefinition = { identifier: "test-label", locales: [ { lang: "es", name: "Etiqueta", description: "Descripción" }, { lang: "fr", name: "Étiquette", description: "La description" }, ], }; const result = getLabelNameAndDescription(labelDefinition, "en");
assert.deepEqual(result.name, "Etiqueta"); assert.deepEqual(result.description, "Descripción"); });
it("should use identifier when locale name is missing", () => { const labelDefinition = { identifier: "test-label", locales: [{ lang: "en", description: "Description only" }], }; const result = getLabelNameAndDescription(labelDefinition, "en");
assert.deepEqual(result.name, "test-label"); assert.deepEqual(result.description, "Description only"); });
it("should default to en as preferred language", () => { const labelDefinition = { identifier: "test-label", locales: [ { lang: "es", name: "Etiqueta", description: "Descripción" }, { lang: "en", name: "Label", description: "Description" }, ], }; const result = getLabelNameAndDescription(labelDefinition);
assert.deepEqual(result.name, "Label"); assert.deepEqual(result.description, "Description"); });});
describe("getLabelerForLabel", () => { it("should return matching labeler by src did", () => { const label = { src: "did:plc:labeler1", val: "nsfw" }; const labelers = [ { creator: { did: "did:plc:labeler1" }, policies: {} }, { creator: { did: "did:plc:labeler2" }, policies: {} }, ];
const result = getLabelerForLabel(label, labelers);
assert.deepEqual(result.creator.did, "did:plc:labeler1"); });
it("should return null when no matching labeler", () => { const label = { src: "did:plc:unknown", val: "nsfw" }; const labelers = [{ creator: { did: "did:plc:labeler1" }, policies: {} }];
const result = getLabelerForLabel(label, labelers);
assert.deepEqual(result, null); });
it("should return null when labelers is empty", () => { const label = { src: "did:plc:labeler1", val: "nsfw" };
const result = getLabelerForLabel(label, []);
assert.deepEqual(result, null); });});
describe("getDefinitionForLabel", () => { it("should return matching label definition", () => { const label = { src: "did:plc:labeler1", val: "nsfw" }; const labeler = { creator: { did: "did:plc:labeler1" }, policies: { labelValueDefinitions: [ { identifier: "spam", blurs: "none" }, { identifier: "nsfw", blurs: "media" }, ], }, };
const result = getDefinitionForLabel(label, labeler);
assert.deepEqual(result.identifier, "nsfw"); assert.deepEqual(result.blurs, "media"); });
it("should return undefined when no matching definition", () => { const label = { src: "did:plc:labeler1", val: "unknown" }; const labeler = { creator: { did: "did:plc:labeler1" }, policies: { labelValueDefinitions: [{ identifier: "nsfw", blurs: "media" }], }, };
const result = getDefinitionForLabel(label, labeler);
assert.deepEqual(result, undefined); });});
describe("isBadgeLabel", () => { it("should return true when blurs is none", () => { const labelDefinition = { blurs: "none" }; assert.deepEqual(isBadgeLabel(labelDefinition), true); });
it("should return true when blurs is undefined", () => { const labelDefinition = {}; assert.deepEqual(isBadgeLabel(labelDefinition), true); });
it("should return false when blurs is media", () => { const labelDefinition = { blurs: "media" }; assert.deepEqual(isBadgeLabel(labelDefinition), false); });
it("should return false when blurs is content", () => { const labelDefinition = { blurs: "content" }; assert.deepEqual(isBadgeLabel(labelDefinition), false); });});
describe("addFeedItemToFeed", () => { it("should add item to empty feed", () => { const feedItem = { post: { uri: "post-1" } }; const result = addFeedItemToFeed(feedItem, []);
assert.deepEqual(result.length, 1); assert.deepEqual(result[0], feedItem); });
it("should add item to beginning of feed without pinned post", () => { const existingItem = { post: { uri: "post-1" } }; const newItem = { post: { uri: "post-2" } };
const result = addFeedItemToFeed(newItem, [existingItem]);
assert.deepEqual(result.length, 2); assert.deepEqual(result[0], newItem); assert.deepEqual(result[1], existingItem); });
it("should add item after pinned post", () => { const pinnedItem = { post: { uri: "pinned-post" }, reason: { $type: "app.bsky.feed.defs#reasonPin" }, }; const existingItem = { post: { uri: "post-1" } }; const newItem = { post: { uri: "post-2" } };
const result = addFeedItemToFeed(newItem, [pinnedItem, existingItem]);
assert.deepEqual(result.length, 3); assert.deepEqual(result[0], pinnedItem); assert.deepEqual(result[1], newItem); assert.deepEqual(result[2], existingItem); });
it("should handle pinned post not at first position", () => { const pinnedItem = { post: { uri: "pinned-post" }, reason: { $type: "app.bsky.feed.defs#reasonPin" }, }; const existingItem = { post: { uri: "post-1" } }; const newItem = { post: { uri: "post-2" } };
const result = addFeedItemToFeed(newItem, [existingItem, pinnedItem]);
assert.deepEqual(result.length, 3); assert.deepEqual(result[0], pinnedItem); assert.deepEqual(result[1], newItem); assert.deepEqual(result[2], existingItem); });
it("should handle repost feed items", () => { const repostItem = { post: { uri: "post-1" }, reason: { $type: "app.bsky.feed.defs#reasonRepost", by: { did: "did:plc:123" }, uri: "at://did:plc:123/app.bsky.feed.repost/abc", indexedAt: "2024-01-01T00:00:00Z", }, };
const result = addFeedItemToFeed(repostItem, []);
assert.deepEqual(result.length, 1); assert.deepEqual(result[0].reason.$type, "app.bsky.feed.defs#reasonRepost"); });});
describe("pinPostInFeed", () => { const pinReason = { $type: "app.bsky.feed.defs#reasonPin" };
it("should add a pinned item to an empty feed", () => { const post = { uri: "post-1", cid: "cid-1" }; const result = pinPostInFeed([], post); assert.deepEqual(result.length, 1); assert.deepEqual(result[0].post, post); assert.deepEqual(result[0].reason.$type, pinReason.$type); });
it("should move an existing post to the top and mark it pinned", () => { const post = { uri: "post-2", cid: "cid-2" }; const feed = [ { post: { uri: "post-1" } }, { post }, { post: { uri: "post-3" } }, ]; const result = pinPostInFeed(feed, post); assert.deepEqual(result.length, 3); assert.deepEqual(result[0].post.uri, "post-2"); assert.deepEqual(result[0].reason.$type, pinReason.$type); assert.deepEqual(result[1].post.uri, "post-1"); assert.deepEqual(result[2].post.uri, "post-3"); });
it("should unpin a previously pinned item when pinning a new one", () => { const oldPinned = { post: { uri: "post-1" }, reason: pinReason }; const other = { post: { uri: "post-2" } }; const newPost = { uri: "post-3", cid: "cid-3" }; const result = pinPostInFeed([oldPinned, other], newPost); assert.deepEqual(result.length, 3); assert.deepEqual(result[0].post.uri, "post-3"); assert.deepEqual(result[0].reason.$type, pinReason.$type); // Old pinned item is still present, but no longer carries the pin reason. const oldInResult = result.find((item) => item.post.uri === "post-1"); assert.deepEqual(oldInResult.reason, undefined); });
it("should not duplicate the post when it is already pinned", () => { const post = { uri: "post-1", cid: "cid-1" }; const feed = [{ post, reason: pinReason }, { post: { uri: "post-2" } }]; const result = pinPostInFeed(feed, post); assert.deepEqual(result.length, 2); assert.deepEqual(result[0].post.uri, "post-1"); assert.deepEqual(result[0].reason.$type, pinReason.$type); assert.deepEqual(result[1].post.uri, "post-2"); });
it("should not mutate the input feed", () => { const post = { uri: "post-1" }; const feed = [{ post: { uri: "post-2" } }]; const before = [...feed]; pinPostInFeed(feed, post); assert.deepEqual(feed.length, before.length); assert.deepEqual(feed[0], before[0]); });});
describe("unpinPostInFeed", () => { const pinReason = { $type: "app.bsky.feed.defs#reasonPin" };
it("should clear the pin reason on the matching item but keep it in place", () => { const post = { uri: "post-1", cid: "cid-1" }; const feed = [{ post, reason: pinReason }, { post: { uri: "post-2" } }]; const result = unpinPostInFeed(feed, post); assert.deepEqual(result.length, 2); assert.deepEqual(result[0].post.uri, "post-1"); assert.deepEqual(result[0].reason, undefined); assert.deepEqual(result[1].post.uri, "post-2"); });
it("should leave a non-pinned occurrence of the post unchanged", () => { const post = { uri: "post-1", cid: "cid-1" }; const feed = [{ post }, { post: { uri: "post-2" } }]; const result = unpinPostInFeed(feed, post); assert.deepEqual(result.length, 2); assert.deepEqual(result[0].post.uri, "post-1"); assert.deepEqual(result[0].reason, undefined); });
it("should not affect another pinned item with a different uri", () => { const post = { uri: "post-1" }; const otherPinned = { post: { uri: "post-2" }, reason: pinReason }; const result = unpinPostInFeed([otherPinned], post); assert.deepEqual(result.length, 1); assert.deepEqual(result[0].post.uri, "post-2"); assert.deepEqual(result[0].reason.$type, pinReason.$type); });
it("should return an empty feed when given one", () => { assert.deepEqual(unpinPostInFeed([], { uri: "post-1" }).length, 0); });});
describe("getDisplayName", () => { it("should return displayName when present", () => { const profile = { displayName: "Alice", handle: "alice.bsky.social" }; assert.deepEqual(getDisplayName(profile), "Alice"); });
it("should trim whitespace from displayName", () => { const profile = { displayName: " Alice ", handle: "alice.bsky.social" }; assert.deepEqual(getDisplayName(profile), "Alice"); });
it("should strip check mark characters", () => { const profile = { displayName: "Alice \u2705\u2713\u2714\u2611", handle: "alice.bsky.social", }; assert.deepEqual(getDisplayName(profile), "Alice"); });
it("should strip control characters", () => { const profile = { displayName: "Ali\u0000ce\u001F", handle: "alice.bsky.social", }; assert.deepEqual(getDisplayName(profile), "Alice"); });
it("should strip bidirectional override characters", () => { const profile = { displayName: "Ali\u202Ace\u202E", handle: "alice.bsky.social", }; assert.deepEqual(getDisplayName(profile), "Alice"); });
it("should collapse multiple spaces into one", () => { const profile = { displayName: "Alice Bob", handle: "alice.bsky.social", }; assert.deepEqual(getDisplayName(profile), "Alice Bob"); });
it("should collapse spaces with zero-width spaces", () => { const profile = { displayName: "Alice \u200B Bob", handle: "alice.bsky.social", }; assert.deepEqual(getDisplayName(profile), "Alice Bob"); });
it("should handle all sanitizations together", () => { const profile = { displayName: " \u2705Alice\u0000 Bob\u202E ", handle: "alice.bsky.social", }; assert.deepEqual(getDisplayName(profile), "Alice Bob"); });
it("should return 'Deleted Account' for missing.invalid handle", () => { const profile = { handle: "missing.invalid" }; assert.deepEqual(getDisplayName(profile), "Deleted Account"); });
it("should return 'Invalid Handle' for handle.invalid handle", () => { const profile = { handle: "handle.invalid" }; assert.deepEqual(getDisplayName(profile), "Invalid Handle"); });
it("should return handle when no displayName", () => { const profile = { handle: "alice.bsky.social" }; assert.deepEqual(getDisplayName(profile), "alice.bsky.social"); });
it("should prefer displayName over special handle fallbacks", () => { const profile = { displayName: "Still Here", handle: "missing.invalid" }; assert.deepEqual(getDisplayName(profile), "Still Here"); });});
describe("hasValidHandle", () => { it("returns true for a normal handle", () => { assert(hasValidHandle({ handle: "alice.bsky.social" })); });
it("returns false for the invalid sentinel", () => { assert(!hasValidHandle({ handle: INVALID_HANDLE })); });
it("returns false for the missing sentinel", () => { assert(!hasValidHandle({ handle: MISSING_HANDLE })); });
it("returns false when handle is absent", () => { assert(!hasValidHandle({ did: "did:plc:bob" })); });});
describe("getThreadgateAllowSettings", () => { it("returns everybody when post has no threadgate", () => { assert.deepEqual(getThreadgateAllowSettings({}), { type: "everybody" }); });
it("returns everybody when allow is undefined", () => { const post = { threadgate: { record: { $type: "app.bsky.feed.threadgate" } }, }; assert.deepEqual(getThreadgateAllowSettings(post), { type: "everybody" }); });
it("returns nobody when allow is empty array", () => { const post = { threadgate: { record: { allow: [] } } }; assert.deepEqual(getThreadgateAllowSettings(post), { type: "nobody" }); });
it("maps a mention rule", () => { const post = { threadgate: { record: { allow: [{ $type: "app.bsky.feed.threadgate#mentionRule" }] }, }, }; assert.deepEqual(getThreadgateAllowSettings(post), [{ type: "mention" }]); });
it("maps follower and following rules", () => { const post = { threadgate: { record: { allow: [ { $type: "app.bsky.feed.threadgate#followerRule" }, { $type: "app.bsky.feed.threadgate#followingRule" }, ], }, }, }; assert.deepEqual(getThreadgateAllowSettings(post), [ { type: "followers" }, { type: "following" }, ]); });
it("resolves a list rule against threadgate.lists", () => { const listUri = "at://did:plc:abc/app.bsky.graph.list/123"; const list = { uri: listUri, name: "Cool people" }; const post = { threadgate: { lists: [list], record: { allow: [ { $type: "app.bsky.feed.threadgate#listRule", list: listUri }, ], }, }, }; assert.deepEqual(getThreadgateAllowSettings(post), [ { type: "list", list }, ]); });
it("returns null list when list rule references missing list", () => { const post = { threadgate: { lists: [], record: { allow: [ { $type: "app.bsky.feed.threadgate#listRule", list: "at://did:plc:abc/app.bsky.graph.list/zzz", }, ], }, }, }; assert.deepEqual(getThreadgateAllowSettings(post), [ { type: "list", list: null }, ]); });
it("marks unknown rule types", () => { const post = { threadgate: { record: { allow: [{ $type: "app.bsky.feed.threadgate#futureRule" }] }, }, }; assert.deepEqual(getThreadgateAllowSettings(post), [{ type: "unknown" }]); });});
describe("isEmptyPost", () => { it("should return true for blocked posts", () => { const post = { $type: "app.bsky.feed.defs#blockedPost", uri: "at://x" }; assert.deepEqual(isEmptyPost(post), true); });
it("should return true for not-found posts", () => { const post = { $type: "app.bsky.feed.defs#notFoundPost", uri: "at://x" }; assert.deepEqual(isEmptyPost(post), true); });
it("should return true for unavailable posts", () => { const post = { $type: "social.impro.feed.defs#unavailablePost", uri: "at://x", }; assert.deepEqual(isEmptyPost(post), true); });
it("should return false for normal post views", () => { const post = { $type: "app.bsky.feed.defs#postView", uri: "at://x" }; assert.deepEqual(isEmptyPost(post), false); });});
describe("canReplyToPost", () => { it("should return true for a normal post view with no restrictions", () => { const post = { $type: "app.bsky.feed.defs#postView", uri: "at://x", viewer: {}, }; assert.deepEqual(canReplyToPost(post), true); });
it("should return false for a blocked post", () => { const post = { $type: "app.bsky.feed.defs#blockedPost", uri: "at://x" }; assert.deepEqual(canReplyToPost(post), false); });
it("should return false for a not-found post", () => { const post = { $type: "app.bsky.feed.defs#notFoundPost", uri: "at://x" }; assert.deepEqual(canReplyToPost(post), false); });
it("should return false for an unavailable post", () => { const post = { $type: "social.impro.feed.defs#unavailablePost", uri: "at://x", }; assert.deepEqual(canReplyToPost(post), false); });
it("should return false when viewer.replyDisabled is true", () => { const post = { $type: "app.bsky.feed.defs#postView", uri: "at://x", viewer: { replyDisabled: true }, }; assert.deepEqual(canReplyToPost(post), false); });
it("should return true when viewer is missing", () => { const post = { $type: "app.bsky.feed.defs#postView", uri: "at://x" }; assert.deepEqual(canReplyToPost(post), true); });});
describe("transformNestedQuotes", () => { const makeQuote = (uri, nestedQuote) => { const quote = { uri }; if (nestedQuote) { quote.embeds = [ { $type: "app.bsky.embed.record#view", record: nestedQuote }, ]; } return quote; };
it("returns the post unchanged when there is no quote", () => { const post = { uri: "post" }; const result = transformNestedQuotes(post, () => ({ touched: true })); assert.deepEqual(result, post); });
it("leaves the root post untouched but transforms the direct quote", () => { const post = { uri: "post", flag: "root", embed: { $type: "app.bsky.embed.record#view", record: makeQuote("quote"), }, }; const result = transformNestedQuotes(post, (quotedPost) => ({ ...quotedPost, touched: true, })); assert.deepEqual(result.uri, "post"); assert.deepEqual(result.flag, "root"); assert.deepEqual(result.embed.record, { uri: "quote", touched: true }); });
it("transforms both the direct and nested quote (two levels)", () => { const post = { uri: "post", embed: { $type: "app.bsky.embed.record#view", record: makeQuote("quote", makeQuote("nested")), }, }; const calls = []; const result = transformNestedQuotes(post, (quotedPost) => { calls.push(quotedPost.uri); return { ...quotedPost, touched: true }; }); assert.deepEqual(calls, ["quote", "nested"]); assert.deepEqual(result.embed.record.touched, true); assert.deepEqual(result.embed.record.embeds[0].record, { uri: "nested", touched: true, }); });
it("does not recurse into a third level of nesting", () => { const deepest = makeQuote("deepest"); const nested = makeQuote("nested", deepest); const post = { uri: "post", embed: { $type: "app.bsky.embed.record#view", record: makeQuote("quote", nested), }, }; const seen = []; transformNestedQuotes(post, (quotedPost) => { seen.push(quotedPost.uri); return quotedPost; }); assert.deepEqual(seen, ["quote", "nested"]); });
it("returns the same post when the transform leaves quotes unchanged", () => { const post = { uri: "post", embed: { $type: "app.bsky.embed.record#view", record: makeQuote("quote", makeQuote("nested")), }, }; const result = transformNestedQuotes(post, (quotedPost) => quotedPost); assert(result === post); });
it("does not mutate the input post", () => { const originalNested = { uri: "nested" }; const originalQuote = { uri: "quote", embeds: [{ $type: "app.bsky.embed.record#view", record: originalNested }], }; const post = { uri: "post", embed: { $type: "app.bsky.embed.record#view", record: originalQuote }, }; transformNestedQuotes(post, (quotedPost) => ({ ...quotedPost, touched: true, })); assert.deepEqual(originalQuote.touched, undefined); assert.deepEqual(originalNested.touched, undefined); assert.deepEqual(post.embed.record, originalQuote); });});
describe("getInteractionTimestamp", () => { it("should return sentAt for message views", () => { const timestamp = getInteractionTimestamp({ $type: "chat.bsky.convo.defs#messageView", sentAt: "2026-06-11T01:00:00.000Z", }); assert.deepEqual(timestamp, "2026-06-11T01:00:00.000Z"); });
it("should return sentAt for system message views", () => { const timestamp = getInteractionTimestamp({ $type: "chat.bsky.convo.defs#systemMessageView", sentAt: "2026-06-11T02:00:00.000Z", }); assert.deepEqual(timestamp, "2026-06-11T02:00:00.000Z"); });
it("should return reaction createdAt for message-and-reaction views", () => { const timestamp = getInteractionTimestamp({ $type: "chat.bsky.convo.defs#messageAndReactionView", reaction: { createdAt: "2026-06-11T03:00:00.000Z" }, }); assert.deepEqual(timestamp, "2026-06-11T03:00:00.000Z"); });});
describe("getGroupConvoDetails", () => { const groupKind = { $type: "chat.bsky.convo.defs#groupConvo", name: "Test Group", memberCount: 3, memberLimit: 10, lockStatus: "unlocked", createdAt: "2026-06-01T00:00:00.000Z", };
it("should return the kind object for group convos", () => { assert.deepEqual( getGroupConvoDetails({ id: "c1", kind: groupKind }), groupKind, ); });
it("should return null for direct convos", () => { const directConvo = { id: "c2", kind: { $type: "chat.bsky.convo.defs#directConvo" }, }; assert.deepEqual(getGroupConvoDetails(directConvo), null); });
it("should return null when kind is missing", () => { assert.deepEqual(getGroupConvoDetails({ id: "c3" }), null); });});
describe("isGroupConvo", () => { it("should detect group convos", () => { const convo = { id: "c1", kind: { $type: "chat.bsky.convo.defs#groupConvo", name: "Test Group" }, }; assert.deepEqual(isGroupConvo(convo), true); });
it("should reject direct and untyped convos", () => { assert.deepEqual( isGroupConvo({ kind: { $type: "chat.bsky.convo.defs#directConvo" } }), false, ); assert.deepEqual(isGroupConvo({}), false); });});
describe("getGroupConvoOwner", () => { function groupMember(did, role) { return { did, handle: `${did.split(":").pop()}.bsky.social`, kind: { $type: "chat.bsky.actor.defs#groupConvoMember", role }, }; }
it("should find the member with the owner role", () => { const owner = groupMember("did:plc:alice", "owner"); const convo = { members: [groupMember("did:plc:me", "standard"), owner], }; assert.deepEqual(getGroupConvoOwner(convo), owner); });
it("should return null when the owner has left", () => { const convo = { members: [ groupMember("did:plc:me", "standard"), groupMember("did:plc:bob", "standard"), ], }; assert.deepEqual(getGroupConvoOwner(convo), null); });
it("should ignore members without a group member kind", () => { const convo = { members: [ { did: "did:plc:me", handle: "me.bsky.social" }, { did: "did:plc:bob", handle: "bob.bsky.social", kind: { role: "owner" }, }, ], }; assert.deepEqual(getGroupConvoOwner(convo), null); });});
describe("getSystemMessageDisplayText", () => { function systemMessage(dataType, data = {}) { return { $type: "chat.bsky.convo.defs#systemMessageView", id: "sys-1", data: { $type: `chat.bsky.convo.defs#${dataType}`, ...data }, }; }
it("should use the member name for member events when provided", () => { assert.deepEqual( getSystemMessageDisplayText(systemMessage("systemMessageDataAddMember"), { memberName: "Alice", }), "Alice was added to the group", ); assert.deepEqual( getSystemMessageDisplayText( systemMessage("systemMessageDataMemberLeave"), { memberName: "Alice" }, ), "Alice left the group", ); });
it("should fall back to anonymous copy for member events without a name", () => { assert.deepEqual( getSystemMessageDisplayText(systemMessage("systemMessageDataAddMember")), "Someone was added to the group", ); });
it("should include the new name for edit-group events", () => { assert.deepEqual( getSystemMessageDisplayText( systemMessage("systemMessageDataEditGroup", { oldName: "Old Club", newName: "Book Club", }), ), "Chat title changed to Book Club", ); });
it("should use generic copy for edit-group events without a new name", () => { assert.deepEqual( getSystemMessageDisplayText(systemMessage("systemMessageDataEditGroup")), "Chat title changed", ); });
it("should ignore memberName for non-member events", () => { assert.deepEqual( getSystemMessageDisplayText(systemMessage("systemMessageDataLockConvo"), { memberName: "Alice", }), "Chat locked", ); });
it("should fall back to generic copy for unknown kinds", () => { assert.deepEqual( getSystemMessageDisplayText(systemMessage("systemMessageDataFuture")), "Chat updated", ); });});
describe("getConvoPreviewText", () => { const currentUser = { did: "did:plc:me", handle: "me.bsky.social" }; const alice = { did: "did:plc:alice", handle: "alice.bsky.social", displayName: "Alice", }; const groupConvo = { id: "group-1", members: [currentUser, alice], kind: { $type: "chat.bsky.convo.defs#groupConvo", name: "Book Club" }, }; const directConvo = { id: "convo-1", members: [currentUser, alice] };
function messageView({ text, senderDid }) { return { $type: "chat.bsky.convo.defs#messageView", id: "msg-1", text, sender: { did: senderDid }, }; }
it("should prefix group messages with the sender name", () => { assert.deepEqual( getConvoPreviewText(messageView({ text: "hi", senderDid: alice.did }), { currentUser, convo: groupConvo, profiles: groupConvo.members, }), "Alice: hi", ); assert.deepEqual( getConvoPreviewText( messageView({ text: "hi", senderDid: currentUser.did }), { currentUser, convo: groupConvo, profiles: groupConvo.members }, ), "You: hi", ); });
it("should fall back to Someone for unknown group senders", () => { assert.deepEqual( getConvoPreviewText( messageView({ text: "hi", senderDid: "did:plc:stranger" }), { currentUser, convo: groupConvo, profiles: groupConvo.members }, ), "Someone: hi", ); });
it("should resolve senders from the passed profiles", () => { assert.deepEqual( getConvoPreviewText( messageView({ text: "hi", senderDid: "did:plc:stranger" }), { currentUser, convo: groupConvo, profiles: [ ...groupConvo.members, { did: "did:plc:stranger", handle: "stranger.bsky.social", displayName: "Stranger", }, ], }, ), "Stranger: hi", ); });
it("should only prefix own messages in direct convos", () => { assert.deepEqual( getConvoPreviewText(messageView({ text: "hi", senderDid: alice.did }), { currentUser, convo: directConvo, profiles: directConvo.members, }), "hi", ); assert.deepEqual( getConvoPreviewText( messageView({ text: "hi", senderDid: currentUser.did }), { currentUser, convo: directConvo, profiles: directConvo.members }, ), "You: hi", ); });
it("should fall back to a generic label for embed-only messages", () => { const embedMessage = { ...messageView({ text: "", senderDid: alice.did }), embed: { $type: "app.bsky.embed.images#view" }, }; assert.deepEqual( getConvoPreviewText(embedMessage, { currentUser, convo: directConvo, profiles: directConvo.members, }), "(embedded content)", ); assert.deepEqual( getConvoPreviewText( { ...embedMessage, sender: { did: currentUser.did } }, { currentUser, convo: directConvo, profiles: directConvo.members }, ), "You: (embedded content)", ); assert.deepEqual( getConvoPreviewText(embedMessage, { currentUser, convo: groupConvo, profiles: groupConvo.members, }), "Alice: (embedded content)", ); });
it("should label quoted-post embeds distinctly", () => { const recordEmbedMessage = { ...messageView({ text: "", senderDid: alice.did }), embed: { $type: "app.bsky.embed.record#view" }, }; assert.deepEqual( getConvoPreviewText(recordEmbedMessage, { currentUser, convo: directConvo, profiles: directConvo.members, }), "(quoted post)", ); });
it("should describe reactions", () => { const reaction = { $type: "chat.bsky.convo.defs#messageAndReactionView", message: { text: "hello" }, reaction: { value: "👍", sender: { did: alice.did } }, }; assert.deepEqual( getConvoPreviewText(reaction, { currentUser, convo: groupConvo, profiles: groupConvo.members, }), 'Alice reacted 👍 to "hello"', ); });
it("should describe deleted messages", () => { assert.deepEqual( getConvoPreviewText( { $type: "chat.bsky.convo.defs#deletedMessageView" }, { currentUser, convo: directConvo, profiles: directConvo.members }, ), "Deleted message", ); });
it("should render system messages with the member name when resolvable", () => { const systemMessage = { $type: "chat.bsky.convo.defs#systemMessageView", data: { $type: "chat.bsky.convo.defs#systemMessageDataAddMember", member: { did: alice.did }, }, }; assert.deepEqual( getConvoPreviewText(systemMessage, { currentUser, convo: groupConvo, profiles: groupConvo.members, }), "Alice was added to the group", ); });
it("should render anonymous system messages for unknown members", () => { const systemMessage = { $type: "chat.bsky.convo.defs#systemMessageView", data: { $type: "chat.bsky.convo.defs#systemMessageDataMemberLeave", member: { did: "did:plc:stranger" }, }, }; assert.deepEqual( getConvoPreviewText(systemMessage, { currentUser, convo: groupConvo, profiles: groupConvo.members, }), "Someone left the group", ); });});
describe("getInteractionProfileDids", () => { it("should return an empty list for a missing interaction", () => { assert.deepEqual(getInteractionProfileDids(null), []); });
it("should extract the sender from a message", () => { const message = { $type: "chat.bsky.convo.defs#messageView", sender: { did: "did:plc:sender" }, }; assert.deepEqual(getInteractionProfileDids(message), ["did:plc:sender"]); });
it("should extract both senders from a reaction", () => { const reaction = { $type: "chat.bsky.convo.defs#messageAndReactionView", message: { sender: { did: "did:plc:author" } }, reaction: { value: "👍", sender: { did: "did:plc:reactor" } }, }; assert.deepEqual(getInteractionProfileDids(reaction), [ "did:plc:author", "did:plc:reactor", ]); });
it("should extract the member and adder from a system message", () => { const systemMessage = { $type: "chat.bsky.convo.defs#systemMessageView", data: { $type: "chat.bsky.convo.defs#systemMessageDataAddMember", member: { did: "did:plc:added" }, addedBy: { did: "did:plc:adder" }, }, }; assert.deepEqual(getInteractionProfileDids(systemMessage), [ "did:plc:added", "did:plc:adder", ]); });
it("should return an empty list for a deleted message", () => { assert.deepEqual( getInteractionProfileDids({ $type: "chat.bsky.convo.defs#deletedMessageView", }), [], ); });});
describe("groupReactions", () => { const reaction = (value, did) => ({ value, sender: { did }, createdAt: "2026-01-01T00:00:00Z", });
it("groups by emoji value, preserving first-seen order", () => { const groups = groupReactions([ reaction("❤️", "did:plc:a"), reaction("👍", "did:plc:b"), reaction("❤️", "did:plc:b"), ]); assert.deepEqual(groups.length, 2); assert.deepEqual(groups[0].value, "❤️"); assert.deepEqual(groups[0].count, 2); assert.deepEqual(groups[0].senders.length, 2); assert.deepEqual(groups[0].senders[0].did, "did:plc:a"); assert.deepEqual(groups[0].senders[1].did, "did:plc:b"); assert.deepEqual(groups[1].value, "👍"); assert.deepEqual(groups[1].count, 1); });
it("returns an empty array for empty or missing input", () => { assert.deepEqual(groupReactions([]).length, 0); assert.deepEqual(groupReactions(null).length, 0); assert.deepEqual(groupReactions(undefined).length, 0); });
it("keeps each sender entry even when the same user reacts twice with one emoji", () => { const groups = groupReactions([ reaction("❤️", "did:plc:a"), reaction("❤️", "did:plc:a"), ]); assert.deepEqual(groups.length, 1); assert.deepEqual(groups[0].count, 2); assert.deepEqual(groups[0].senders.length, 2); });});
describe("getInviteCodeFromUrl", () => { it("extracts code from absolute bsky.app URL", () => { assert.deepEqual( getInviteCodeFromUrl("https://bsky.app/chat/abcd1234"), "abcd1234", ); });
it("extracts code from relative path", () => { assert.deepEqual(getInviteCodeFromUrl("/chat/abcd1234"), "abcd1234"); });
it("ignores query and hash", () => { assert.deepEqual( getInviteCodeFromUrl("/chat/abcd1234?ref=x#y"), "abcd1234", ); });
it("rejects non-bsky hosts", () => { assert.deepEqual( getInviteCodeFromUrl("https://example.com/chat/abcd1234"), null, ); });
it("accepts impro.social hosts", () => { assert.deepEqual( getInviteCodeFromUrl("https://impro.social/chat/abcd1234"), "abcd1234", ); assert.deepEqual( getInviteCodeFromUrl("https://dev.impro.social/chat/abcd1234"), "abcd1234", ); });
it("rejects malformed codes", () => { assert.deepEqual(getInviteCodeFromUrl("/chat/short"), null); assert.deepEqual(getInviteCodeFromUrl("/chat/!!!!!!!!"), null); });
it("rejects unrelated paths", () => { assert.deepEqual(getInviteCodeFromUrl("/profile/foo"), null); assert.deepEqual(getInviteCodeFromUrl(""), null); assert.deepEqual(getInviteCodeFromUrl(null), null); });});
describe("isInviteLinkUrl", () => { it("is true for valid invite URLs", () => { assert.deepEqual(isInviteLinkUrl("https://bsky.app/chat/abcd1234"), true); assert.deepEqual(isInviteLinkUrl("/chat/abcd1234"), true); });
it("is false otherwise", () => { assert.deepEqual(isInviteLinkUrl("https://bsky.app/profile/x"), false); assert.deepEqual(isInviteLinkUrl(""), false); });});
describe("getJoinLinkCodeFromEmbed", () => { it("returns the code from a chat invite view embed", () => { assert.deepEqual( getJoinLinkCodeFromEmbed({ $type: "chat.bsky.embed.joinLink#view", joinLinkPreview: { code: "abcd1234" }, }), "abcd1234", ); });
it("returns null for a chat invite view embed without a code", () => { assert.deepEqual( getJoinLinkCodeFromEmbed({ $type: "chat.bsky.embed.joinLink#view", joinLinkPreview: { $type: "chat.bsky.group.defs#disabledJoinLinkPreviewView", }, }), null, ); });
it("returns the code from an external embed whose URI is an invite link", () => { assert.deepEqual( getJoinLinkCodeFromEmbed({ $type: "app.bsky.embed.external#view", external: { uri: "https://bsky.app/chat/abcd1234" }, }), "abcd1234", ); });
it("returns null for an external embed pointing elsewhere", () => { assert.deepEqual( getJoinLinkCodeFromEmbed({ $type: "app.bsky.embed.external#view", external: { uri: "https://example.com" }, }), null, ); });
it("returns null for unrelated embed types and falsy input", () => { assert.deepEqual( getJoinLinkCodeFromEmbed({ $type: "app.bsky.embed.images#view" }), null, ); assert.deepEqual(getJoinLinkCodeFromEmbed(null), null); assert.deepEqual(getJoinLinkCodeFromEmbed(undefined), null); });});
describe("getJoinLinkCodesFromPosts", () => { it("collects codes from joinLink and external invite embeds", () => { const posts = [ { embed: { $type: "chat.bsky.embed.joinLink#view", joinLinkPreview: { code: "aaaaaaa" }, }, }, { embed: { $type: "app.bsky.embed.external#view", external: { uri: "https://bsky.app/chat/bbbbbbb" }, }, }, ]; assert.deepEqual(getJoinLinkCodesFromPosts(posts), ["aaaaaaa", "bbbbbbb"]); });
it("skips posts without an embed or with unrelated embeds", () => { const posts = [ { embed: null }, { embed: { $type: "app.bsky.embed.images#view" } }, { embed: undefined }, undefined, ]; assert.deepEqual(getJoinLinkCodesFromPosts(posts), []); });
it("returns an empty array for null/undefined input", () => { assert.deepEqual(getJoinLinkCodesFromPosts(null), []); assert.deepEqual(getJoinLinkCodesFromPosts(undefined), []); });});
describe("getJoinLinkCodesFromMessages", () => { it("collects codes from message join link embeds", () => { const messages = [ { embed: { $type: "chat.bsky.embed.joinLink#view", joinLinkPreview: { code: "aaaaaaa" }, }, }, { embed: null }, { embed: { $type: "app.bsky.embed.external#view", external: { uri: "https://bsky.app/chat/bbbbbbb" }, }, }, ]; assert.deepEqual(getJoinLinkCodesFromMessages(messages), [ "aaaaaaa", "bbbbbbb", ]); });
it("returns an empty array for null/undefined input", () => { assert.deepEqual(getJoinLinkCodesFromMessages(null), []); assert.deepEqual(getJoinLinkCodesFromMessages(undefined), []); });});
describe("attachJoinLinkPreviewToEmbed", () => { const fresh = { $type: "chat.bsky.group.defs#joinLinkPreviewView", code: "abcd1234", name: "Updated", };
it("returns null for unrelated embeds", () => { assert.deepEqual( attachJoinLinkPreviewToEmbed( { $type: "app.bsky.embed.images#view" }, fresh, ), null, ); });
it("returns null when the cached preview is the same reference", () => { assert.deepEqual( attachJoinLinkPreviewToEmbed( { $type: "chat.bsky.embed.joinLink#view", joinLinkPreview: fresh }, fresh, ), null, ); });
it("attaches a fresh preview to a joinLink embed", () => { const updated = attachJoinLinkPreviewToEmbed( { $type: "chat.bsky.embed.joinLink#view", joinLinkPreview: { code: "abcd1234", name: "Stale" }, }, fresh, ); assert.deepEqual(updated.$type, "chat.bsky.embed.joinLink#view"); assert.deepEqual(updated.joinLinkPreview, fresh); });
it("upgrades an external invite embed into a joinLink embed", () => { const updated = attachJoinLinkPreviewToEmbed( { $type: "app.bsky.embed.external#view", external: { uri: "https://bsky.app/chat/abcd1234" }, }, fresh, ); assert.deepEqual(updated.$type, "chat.bsky.embed.joinLink#view"); assert.deepEqual(updated.joinLinkPreview, fresh); });});
function makeJoinLinkPreview(overrides = {}) { return { $type: "chat.bsky.group.defs#joinLinkPreviewView", code: "abcdefg", name: "Friends of Bsky", memberCount: 5, memberLimit: 50, joinRule: "open", requireApproval: false, owner: { did: "did:plc:owner", handle: "owner.test", viewer: {} }, viewer: {}, ...overrides, };}
describe("isAvailableJoinLinkPreview", () => { it("returns true only for the available variant", () => { assert(isAvailableJoinLinkPreview(makeJoinLinkPreview())); assert( !isAvailableJoinLinkPreview({ $type: "chat.bsky.group.defs#disabledJoinLinkPreviewView", }), ); });});
describe("getPostsFromPostThread", () => { it("should extract and deduplicate posts from post thread", () => { const mockPostThread = { post: { uri: "main-post", content: "Main post" }, parent: { post: { uri: "parent2", content: "Parent 2" }, parent: { post: { uri: "parent1", content: "Parent 1" }, }, }, replies: [ { $type: "app.bsky.feed.defs#threadViewPost", post: { uri: "reply1", content: "Reply 1" }, }, { $type: "app.bsky.feed.defs#threadViewPost", post: { uri: "reply2", content: "Reply 2" }, }, ], };
const result = getPostsFromPostThread(mockPostThread);
assert.deepEqual(result.length, 5); assert.deepEqual(result[0], { uri: "main-post", content: "Main post" }); assert.deepEqual(result[1], { uri: "parent1", content: "Parent 1" }); assert.deepEqual(result[2], { uri: "parent2", content: "Parent 2" }); assert.deepEqual(result[3], { uri: "reply1", content: "Reply 1" }); assert.deepEqual(result[4], { uri: "reply2", content: "Reply 2" }); });
it("should handle thread with no parents or replies", () => { const mockPostThread = { post: { uri: "lonely-post", content: "All alone" }, };
const result = getPostsFromPostThread(mockPostThread);
assert.deepEqual(result.length, 1); assert.deepEqual(result[0], { uri: "lonely-post", content: "All alone" }); });
it("should handle duplicate posts across thread parts", () => { const mockPostThread = { post: { uri: "main-post", content: "Main post" }, parent: { post: { uri: "parent1", content: "Parent 1" }, }, replies: [ { $type: "app.bsky.feed.defs#threadViewPost", post: { uri: "parent1", content: "Parent 1" }, }, { $type: "app.bsky.feed.defs#threadViewPost", post: { uri: "reply1", content: "Reply 1" }, }, ], };
const result = getPostsFromPostThread(mockPostThread);
assert.deepEqual(result.length, 3); assert.deepEqual(result[0], { uri: "main-post", content: "Main post" }); assert.deepEqual(result[1], { uri: "parent1", content: "Parent 1" }); assert.deepEqual(result[2], { uri: "reply1", content: "Reply 1" }); });
it("should filter out blocked replies", () => { const mockPostThread = { post: { uri: "main-post", content: "Main post" }, replies: [ { $type: "app.bsky.feed.defs#threadViewPost", post: { uri: "reply1", content: "Reply 1" }, }, { $type: "app.bsky.feed.defs#blockedPost", uri: "blocked-reply", }, { $type: "app.bsky.feed.defs#threadViewPost", post: { uri: "reply2", content: "Reply 2" }, }, ], };
const result = getPostsFromPostThread(mockPostThread);
assert.deepEqual(result.length, 3); assert.deepEqual(result[0], { uri: "main-post", content: "Main post" }); assert.deepEqual(result[1], { uri: "reply1", content: "Reply 1" }); assert.deepEqual(result[2], { uri: "reply2", content: "Reply 2" }); });});
describe("getPostsFromFeed", () => { it("should extract posts from simple feed", () => { const mockFeed = { feed: [ { post: { uri: "post1", content: "Post 1" } }, { post: { uri: "post2", content: "Post 2" } }, ], };
const result = getPostsFromFeed(mockFeed);
assert.deepEqual(result.length, 2); assert.deepEqual(result[0], { uri: "post1", content: "Post 1" }); assert.deepEqual(result[1], { uri: "post2", content: "Post 2" }); });
it("should extract posts from feed with reply context", () => { const mockFeed = { feed: [ { post: { uri: "post1", content: "Post 1" } }, { post: { uri: "post2", content: "Reply post" }, reply: { root: { $type: "app.bsky.feed.defs#postView", uri: "root1", content: "Root post", }, parent: { $type: "app.bsky.feed.defs#postView", uri: "parent1", content: "Parent post", }, }, }, ], };
const result = getPostsFromFeed(mockFeed);
assert.deepEqual(result.length, 4); assert.deepEqual(result[0].uri, "post1"); assert.deepEqual(result[1].uri, "post2"); assert.deepEqual(result[2].uri, "root1"); assert.deepEqual(result[3].uri, "parent1"); });
it("should handle feed items without reply context", () => { const mockFeed = { feed: [ { post: { uri: "post1", content: "Post 1" }, reply: undefined, }, { post: { uri: "post2", content: "Post 2" }, }, ], };
const result = getPostsFromFeed(mockFeed);
assert.deepEqual(result.length, 2); assert.deepEqual(result[0], { uri: "post1", content: "Post 1" }); assert.deepEqual(result[1], { uri: "post2", content: "Post 2" }); });
it("should handle empty feed", () => { const mockFeed = { feed: [] };
const result = getPostsFromFeed(mockFeed);
assert.deepEqual(result.length, 0); });
it("should handle duplicates in feed", () => { const mockFeed = { feed: [ { post: { uri: "post1", content: "Post 1" }, reply: { root: { $type: "app.bsky.feed.defs#postView", uri: "root1", content: "Root post", }, parent: { $type: "app.bsky.feed.defs#postView", uri: "post1", content: "Post 1", }, }, }, ], };
const result = getPostsFromFeed(mockFeed);
assert.deepEqual(result.length, 2); assert.deepEqual(result[0].uri, "post1"); assert.deepEqual(result[1].uri, "root1"); });
it("should handle mixed feed items", () => { const mockFeed = { feed: [ { post: { uri: "post1", content: "Simple post" } }, { post: { uri: "post2", content: "Reply post" }, reply: { root: { $type: "app.bsky.feed.defs#postView", uri: "root1", content: "Root", }, parent: { $type: "app.bsky.feed.defs#postView", uri: "parent1", content: "Parent", }, }, }, { post: { uri: "post3", content: "Another simple post" } }, ], };
const result = getPostsFromFeed(mockFeed);
assert.deepEqual(result.length, 5); assert.deepEqual(result[0].uri, "post1"); assert.deepEqual(result[1].uri, "post2"); assert.deepEqual(result[2].uri, "root1"); assert.deepEqual(result[3].uri, "parent1"); assert.deepEqual(result[4].uri, "post3"); });});
describe("isVideoLink", () => { it("returns true for youtube watch links", () => { assert(isVideoLink("https://www.youtube.com/watch?v=dQw4w9WgXcQ")); assert(isVideoLink("https://youtube.com/watch?v=dQw4w9WgXcQ")); assert(isVideoLink("https://m.youtube.com/watch?v=dQw4w9WgXcQ")); });
it("returns true for youtu.be links", () => { assert(isVideoLink("https://youtu.be/dQw4w9WgXcQ")); });
it("returns true for youtube shorts and live links", () => { assert(isVideoLink("https://www.youtube.com/shorts/dQw4w9WgXcQ")); assert(isVideoLink("https://www.youtube.com/live/dQw4w9WgXcQ")); });
it("returns false for youtube pages that are not videos", () => { assert(!isVideoLink("https://www.youtube.com/")); assert(!isVideoLink("https://www.youtube.com/results?search_query=cats")); assert(!isVideoLink("https://www.youtube.com/@somechannel")); });
it("returns false for non-youtube links and invalid input", () => { assert(!isVideoLink("https://example.com/watch?v=dQw4w9WgXcQ")); assert(!isVideoLink("not a url")); assert(!isVideoLink(null)); });});
describe("getImagesFromDraftPost", () => { it("reads embedGallery items", () => { const images = getImagesFromDraftPost({ embedGallery: { items: [{ localRef: { path: "image:a" } }] }, }); assert.deepEqual(images.length, 1); });
it("reads legacy embedImages", () => { const images = getImagesFromDraftPost({ embedImages: [{ localRef: { path: "image:a" }, alt: "old" }], }); assert.deepEqual(images[0].alt, "old"); });
it("skips entries without a localRef path", () => { const images = getImagesFromDraftPost({ embedGallery: { items: [{ localRef: {} }, {}] }, }); assert.deepEqual(images, []); });});
describe("getLocalRefsFromDraft", () => { it("collects image and video refs across posts, including legacy images", () => { const refs = getLocalRefsFromDraft({ posts: [ { embedGallery: { items: [{ localRef: { path: "image:a" } }] }, embedVideos: [{ localRef: { path: "video:video/mp4:v.mp4" } }], }, { embedImages: [{ localRef: { path: "image:b" } }] }, ], }); assert.deepEqual(refs, ["image:a", "video:video/mp4:v.mp4", "image:b"]); });
it("returns an empty array for drafts with no media", () => { assert.deepEqual(getLocalRefsFromDraft({ posts: [{ text: "hi" }] }), []); });});