~james/core

core/web/src/lib/api/profile.test.ts -rw-r--r-- 3.6 KiB
452f17b7 — james chore(import): snapshot james.dad.town/core at f70c71c7696a 15 hours ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import type { OAuthUserAgent } from "@atcute/oauth-browser-client";
import { describe, expect, it, vi } from "vitest";
import { createBobbinClient } from "#lib/api/client.ts";
import { FOLLOW_VIEWER, STAR_VIEWER } from "#lib/api/descriptors.ts";
import { TYPE_VIEWER } from "#lib/api/enrich.ts";
import { ensureProfile, getTrendingWithViewerState, hasProfile } from "#lib/api/profile.ts";
import type { Fetch } from "#lib/fetch.ts";

it("gets viewer-neutral trending data with relationship state in the enrichment sidecar", async () => {
	const fetchMock = vi.fn<Fetch>().mockResolvedValue(
		new Response(JSON.stringify({ output: { people: [], repos: [] }, data: {} }), {
			status: 200,
			headers: { "content-type": "application/json" }
		})
	);
	const ctx = createBobbinClient({ serviceUrl: "https://bobbin.test", fetch: fetchMock });

	await getTrendingWithViewerState(ctx, "did:plc:viewer");

	const [url, request] = fetchMock.mock.calls[0];
	expect(String(url)).toBe("https://bobbin.test/xrpc/org.tangled.query.enrichResponse");
	expect(JSON.parse(String(request?.body))).toEqual({
		xrpc: "org.tangled.actor.getTrending",
		viewer: "did:plc:viewer",
		enrich: [
			{
				source: FOLLOW_VIEWER.source,
				type: TYPE_VIEWER,
				targets: ["people[].did"]
			},
			{
				source: STAR_VIEWER.source,
				type: TYPE_VIEWER,
				targets: ["repos[].did"]
			}
		]
	});
});

describe("profile existence", () => {
	const pds = "https://pds.example";
	const cid = "bafyreidfayvfuwqa7qlnopdjiqrxzs6blmoeu4rujcjtnci5beludirz2a";
	const agent = (handle: ReturnType<typeof vi.fn>) =>
		({
			sub: "did:plc:org",
			session: { info: { aud: pds } },
			handle
		}) as unknown as OAuthUserAgent;
	const found = () =>
		Response.json({
			uri: "at://did:plc:org/org.tangled.actor.profile/self",
			cid,
			value: { $type: "org.tangled.actor.profile" }
		});
	const missing = () =>
		Response.json(
			{ error: "RecordNotFound", message: "Could not locate record" },
			{ status: 400 }
		);

	it("reads the record from the account's own pds", async () => {
		const handle = vi.fn(async () => found());

		expect(await hasProfile(agent(handle))).toBe(true);
		const [path] = handle.mock.calls[0] as unknown as [string];
		const url = new URL(path, pds);
		expect(url.pathname).toBe("/xrpc/com.atproto.repo.getRecord");
		expect(url.searchParams.get("repo")).toBe("did:plc:org");
		expect(url.searchParams.get("collection")).toBe("org.tangled.actor.profile");
		expect(url.searchParams.get("rkey")).toBe("self");
	});

	it("treats a missing record as no profile, and anything else as an error", async () => {
		expect(await hasProfile(agent(vi.fn(async () => missing())))).toBe(false);
		await expect(
			hasProfile(
				agent(
					vi.fn(async () =>
						Response.json({ error: "UpstreamFailure", message: "" }, { status: 502 })
					)
				)
			)
		).rejects.toThrow();
	});

	it("writes the record only when it is missing", async () => {
		const record = {
			$type: "org.tangled.actor.profile",
			isOrganization: true
		} as const;
		const written = vi
			.fn()
			.mockResolvedValueOnce(missing())
			.mockResolvedValueOnce(
				Response.json({ uri: "at://did:plc:org/org.tangled.actor.profile/self", cid })
			);
		await ensureProfile(agent(written), record);
		expect(written).toHaveBeenCalledTimes(2);
		const [path, init] = written.mock.calls[1] as unknown as [string, RequestInit];
		expect(new URL(path, pds).pathname).toBe("/xrpc/com.atproto.repo.putRecord");
		expect(JSON.parse(String(init.body))).toMatchObject({ rkey: "self", record });

		const untouched = vi.fn(async () => found());
		await ensureProfile(agent(untouched), record);
		expect(untouched).toHaveBeenCalledTimes(1);
	});
});