This repository has no description
1import { describe, expect, it, vi } from "vitest";
2import { createBobbinClient } from "$lib/api/client";
3import {
4 fetchPeoplePage,
5 fetchPinned,
6 fetchReposPage,
7 fetchStarredPage,
8 fetchVouchesPage
9} from "./pages";
10
11const enriched = () => Response.json({ output: { items: [], hits: [] }, data: {} });
12
13const requestBody = (fetchMock: ReturnType<typeof vi.fn>, index = 0) => {
14 const init = fetchMock.mock.calls[index][1] as RequestInit;
15 return JSON.parse(String(init.body)) as {
16 xrpc: string;
17 enrich: { source: string; type: string; targets?: string[] }[];
18 };
19};
20
21describe("fetchStarredPage", () => {
22 it("only requests minidocs for string URI subjects", async () => {
23 const fetchMock = vi.fn<typeof globalThis.fetch>().mockResolvedValue(
24 Response.json({
25 output: { items: [] },
26 data: {}
27 })
28 );
29 const ctx = createBobbinClient({ serviceUrl: "https://bobbin.test", fetch: fetchMock });
30
31 await fetchStarredPage(ctx, { did: "did:plc:alice" });
32
33 const body = requestBody(fetchMock);
34 expect(body.enrich[0].targets).toEqual(["items[].value.subject.uri"]);
35 });
36
37 it("targets repo stats and owner minidocs independently", async () => {
38 const fetchMock = vi
39 .fn<typeof globalThis.fetch>()
40 .mockResolvedValueOnce(
41 Response.json({
42 output: {
43 items: [
44 {
45 uri: "at://did:plc:alice/sh.tangled.feed.star/one",
46 value: { subject: { did: "did:plc:repo" }, createdAt: "2026-08-01T00:00:00Z" }
47 }
48 ]
49 },
50 data: {}
51 })
52 )
53 .mockResolvedValueOnce(Response.json({ output: { items: [] }, data: {} }));
54 const ctx = createBobbinClient({ serviceUrl: "https://bobbin.test", fetch: fetchMock });
55
56 await fetchStarredPage(ctx, { did: "did:plc:alice" });
57
58 const body = requestBody(fetchMock, 1);
59 expect(body.enrich).toEqual([
60 {
61 source: "sh.tangled.feed.star:subject",
62 type: "sh.tangled.query.enrichResponse#count",
63 targets: ["items[].value.repoDid"]
64 },
65 {
66 source: "sh.tangled.repo:.repo",
67 type: "com.bad-example.identity.miniDoc",
68 targets: ["items[].uri"]
69 }
70 ]);
71 });
72
73 it.each([
74 [undefined, "items[].value.repoDid"],
75 ["needle", "hits[].value.repoDid"]
76 ])("targets repo stats for list/search results", async (q, expectedTarget) => {
77 const fetchMock = vi.fn<typeof globalThis.fetch>().mockResolvedValue(enriched());
78 const ctx = createBobbinClient({ serviceUrl: "https://bobbin.test", fetch: fetchMock });
79
80 await fetchReposPage(ctx, {
81 did: "did:plc:alice",
82 handle: "alice.test",
83 viewerDid: "did:plc:viewer",
84 q
85 });
86
87 const body = requestBody(fetchMock);
88 expect(body.enrich).toHaveLength(2);
89 expect(body.enrich.every((descriptor) => descriptor.targets?.[0] === expectedTarget)).toBe(
90 true
91 );
92 });
93
94 it.each([
95 ["followers" as const, "items[].uri"],
96 ["following" as const, "items[].value.subject"]
97 ])("targets %s identities and stats", async (direction, expectedTarget) => {
98 const fetchMock = vi.fn<typeof globalThis.fetch>().mockResolvedValue(enriched());
99 const ctx = createBobbinClient({ serviceUrl: "https://bobbin.test", fetch: fetchMock });
100
101 await fetchPeoplePage(ctx, {
102 did: "did:plc:alice",
103 viewerDid: "did:plc:viewer",
104 direction
105 });
106
107 const body = requestBody(fetchMock);
108 expect(body.enrich).toHaveLength(4);
109 expect(body.enrich.every((descriptor) => descriptor.targets?.[0] === expectedTarget)).toBe(
110 true
111 );
112 });
113
114 it("targets incoming vouch authors", async () => {
115 const fetchMock = vi.fn<typeof globalThis.fetch>().mockResolvedValue(enriched());
116 const ctx = createBobbinClient({ serviceUrl: "https://bobbin.test", fetch: fetchMock });
117
118 await fetchVouchesPage(ctx, {
119 did: "did:plc:alice",
120 cursors: { outgoing: null }
121 });
122
123 expect(requestBody(fetchMock).enrich[0].targets).toEqual(["items[].uri"]);
124 });
125
126 it("targets repo dids for both pinned repo queries", async () => {
127 const fetchMock = vi.fn<typeof globalThis.fetch>().mockImplementation(async () => enriched());
128 const ctx = createBobbinClient({ serviceUrl: "https://bobbin.test", fetch: fetchMock });
129
130 await fetchPinned(ctx, {
131 keys: ["did:plc:repo", "at://did:plc:alice/sh.tangled.repo/example"],
132 handle: "alice.test",
133 viewerDid: "did:plc:viewer"
134 });
135
136 const bodies = fetchMock.mock.calls.map((_, index) => requestBody(fetchMock, index));
137 expect(bodies.map((body) => body.xrpc).sort()).toEqual([
138 "sh.tangled.repo.getRepos",
139 "sh.tangled.repo.getReposByRepoDids"
140 ]);
141 expect(
142 bodies.every((body) =>
143 body.enrich.every((descriptor) => descriptor.targets?.[0] === "items[].value.repoDid")
144 )
145 ).toBe(true);
146 });
147});