The Appview for the kipclip.com atproto bookmarking service
at main 160 lines 4.2 kB view raw
1/** 2 * Tests for PLC directory resolution. 3 * Uses mock fetcher to avoid network calls. 4 */ 5 6import "./test-setup.ts"; 7 8import { assertEquals } from "@std/assert"; 9import { resolveDidWithFetcher } from "../lib/plc-resolver.ts"; 10import { createMockFetcher, createPlcResponse } from "./test-helpers.ts"; 11 12Deno.test("resolveDid - resolves valid DID to PDS URL and handle", async () => { 13 const mockFetcher = createMockFetcher( 14 new Map([ 15 [ 16 "plc.directory/did:plc:test123", 17 createPlcResponse({ 18 did: "did:plc:test123", 19 pdsUrl: "https://bsky.social", 20 handle: "alice.bsky.social", 21 }), 22 ], 23 ]), 24 ); 25 26 const result = await resolveDidWithFetcher("did:plc:test123", mockFetcher); 27 28 assertEquals(result?.did, "did:plc:test123"); 29 assertEquals(result?.pdsUrl, "https://bsky.social"); 30 assertEquals(result?.handle, "alice.bsky.social"); 31}); 32 33Deno.test("resolveDid - returns null for 404 DID", async () => { 34 const mockFetcher = createMockFetcher( 35 new Map([ 36 [ 37 "plc.directory", 38 new Response("Not Found", { status: 404 }), 39 ], 40 ]), 41 ); 42 43 const result = await resolveDidWithFetcher( 44 "did:plc:nonexistent", 45 mockFetcher, 46 ); 47 48 assertEquals(result, null); 49}); 50 51Deno.test("resolveDid - returns null for non-DID input", async () => { 52 const mockFetcher = createMockFetcher(new Map()); 53 54 const result = await resolveDidWithFetcher("not-a-did", mockFetcher); 55 56 assertEquals(result, null); 57}); 58 59Deno.test("resolveDid - returns null for DID without PDS service", async () => { 60 const mockFetcher = createMockFetcher( 61 new Map([ 62 [ 63 "plc.directory/did:plc:nopds", 64 new Response( 65 JSON.stringify({ 66 id: "did:plc:nopds", 67 alsoKnownAs: ["at://test.handle"], 68 service: [], // No services 69 }), 70 { 71 status: 200, 72 headers: { "Content-Type": "application/json" }, 73 }, 74 ), 75 ], 76 ]), 77 ); 78 79 const result = await resolveDidWithFetcher("did:plc:nopds", mockFetcher); 80 81 assertEquals(result, null); 82}); 83 84Deno.test("resolveDid - extracts handle from alsoKnownAs", async () => { 85 const mockFetcher = createMockFetcher( 86 new Map([ 87 [ 88 "plc.directory/did:plc:test", 89 new Response( 90 JSON.stringify({ 91 id: "did:plc:test", 92 alsoKnownAs: ["at://custom.handle.example"], 93 service: [ 94 { 95 id: "#atproto_pds", 96 type: "AtprotoPersonalDataServer", 97 serviceEndpoint: "https://pds.example.com", 98 }, 99 ], 100 }), 101 { 102 status: 200, 103 headers: { "Content-Type": "application/json" }, 104 }, 105 ), 106 ], 107 ]), 108 ); 109 110 const result = await resolveDidWithFetcher("did:plc:test", mockFetcher); 111 112 assertEquals(result?.handle, "custom.handle.example"); 113}); 114 115Deno.test("resolveDid - uses DID as handle fallback", async () => { 116 const mockFetcher = createMockFetcher( 117 new Map([ 118 [ 119 "plc.directory/did:plc:nohandle", 120 new Response( 121 JSON.stringify({ 122 id: "did:plc:nohandle", 123 alsoKnownAs: [], // No alsoKnownAs 124 service: [ 125 { 126 id: "#atproto_pds", 127 type: "AtprotoPersonalDataServer", 128 serviceEndpoint: "https://pds.example.com", 129 }, 130 ], 131 }), 132 { 133 status: 200, 134 headers: { "Content-Type": "application/json" }, 135 }, 136 ), 137 ], 138 ]), 139 ); 140 141 const result = await resolveDidWithFetcher("did:plc:nohandle", mockFetcher); 142 143 assertEquals(result?.handle, "did:plc:nohandle"); 144}); 145 146Deno.test("resolveDid - handles network error gracefully", async () => { 147 const mockFetcher = createMockFetcher( 148 new Map([ 149 [ 150 "plc.directory", 151 new Response("Internal Server Error", { status: 500 }), 152 ], 153 ]), 154 ); 155 156 const result = await resolveDidWithFetcher("did:plc:error", mockFetcher); 157 158 // Should return null on error (after logging) 159 assertEquals(result, null); 160});