~james/core

core/web/src/lib/api/orgProfile.test.ts -rw-r--r-- 4.3 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
108
109
110
111
112
113
import type { Did } from "@atcute/lexicons/syntax";
import type { OAuthUserAgent } from "@atcute/oauth-browser-client";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { getOrCreateDelegatedSession } from "#lib/api/actAs.ts";
import { awaitIndexedOrSaved } from "#lib/api/awaitRecord.ts";
import { createBobbinClient } from "#lib/api/client.ts";
import {
	organizationHandleAgent,
	saveOrganizationAvatar,
	saveOrganizationProfile
} from "#lib/api/orgProfile.ts";
import { putProfile, uploadProfileAvatar } from "#lib/api/profile.ts";

vi.mock("#lib/api/actAs.ts", () => ({ getOrCreateDelegatedSession: vi.fn() }));
vi.mock("#lib/api/profile.ts", () => ({
	PROFILE_COLLECTION: "org.tangled.actor.profile",
	putProfile: vi.fn(),
	uploadProfileAvatar: vi.fn()
}));
vi.mock("#lib/api/awaitRecord.ts", () => ({ awaitIndexedOrSaved: vi.fn() }));

const orgDid = "did:plc:org" as Did;
const controller = { sub: "did:plc:controller" } as unknown as OAuthUserAgent;
const orgAgent = { sub: orgDid } as unknown as OAuthUserAgent;
const bobbin = createBobbinClient({ serviceUrl: "https://bobbin.test" });
const written = { uri: `at://${orgDid}/org.tangled.actor.profile/self`, cid: "bafynew" };

beforeEach(() => {
	vi.resetAllMocks();
	vi.mocked(getOrCreateDelegatedSession).mockResolvedValue(orgAgent);
	vi.mocked(putProfile).mockResolvedValue(written as never);
});

describe("saveOrganizationProfile", () => {
	it("writes through a delegated session and keeps the organization flag", async () => {
		const result = await saveOrganizationProfile(bobbin, controller, orgDid, {
			$type: "org.tangled.actor.profile",
			description: "Updated."
		});

		expect(getOrCreateDelegatedSession).toHaveBeenCalledWith(controller, orgDid);
		expect(putProfile).toHaveBeenCalledWith(orgAgent, {
			$type: "org.tangled.actor.profile",
			description: "Updated.",
			isOrganization: true
		});
		expect(awaitIndexedOrSaved).toHaveBeenCalledWith(bobbin, written);
		expect(result).toEqual(expect.objectContaining({ isOrganization: true }));
	});
});

describe("organizationHandleAgent", () => {
	const withScope = (sub: string, scope: string) =>
		({ sub, session: { token: { scope } }, signOut: vi.fn() }) as unknown as OAuthUserAgent;
	const granted = "atproto identity:handle";

	it("uses the stored organization session when it can change the handle", async () => {
		const stored = withScope(orgDid, "atproto identity:*");
		vi.mocked(getOrCreateDelegatedSession).mockResolvedValue(stored);

		await expect(
			organizationHandleAgent(withScope("did:plc:controller", granted), orgDid)
		).resolves.toBe(stored);
		expect(stored.signOut).not.toHaveBeenCalled();
	});

	it("replaces an organization session from before the owner allowed handle changes", async () => {
		const stale = withScope(orgDid, "atproto repo:*");
		const fresh = withScope(orgDid, "atproto identity:*");
		vi.mocked(getOrCreateDelegatedSession)
			.mockResolvedValueOnce(stale)
			.mockResolvedValueOnce(fresh);
		vi.mocked(stale.signOut).mockResolvedValue();

		await expect(
			organizationHandleAgent(withScope("did:plc:controller", granted), orgDid)
		).resolves.toBe(fresh);
		expect(stale.signOut).toHaveBeenCalled();
	});

	it("keeps the organization session while the owner's own session can't change handles", async () => {
		const stale = withScope(orgDid, "atproto repo:*");
		vi.mocked(getOrCreateDelegatedSession).mockResolvedValue(stale);

		await expect(
			organizationHandleAgent(withScope("did:plc:controller", "atproto repo:*"), orgDid)
		).resolves.toBe(stale);
		expect(stale.signOut).not.toHaveBeenCalled();
	});
});

describe("saveOrganizationAvatar", () => {
	it("uploads with the organization's session, starting a record if there is none", async () => {
		const image = new Blob(["png"], { type: "image/png" });
		const avatar = {
			$type: "blob",
			ref: { $link: "bafyreidfayvfuwqa7qlnopdjiqrxzs6blmoeu4rujcjtnci5beludirz2a" },
			mimeType: "image/png",
			size: 3
		} as const;
		vi.mocked(uploadProfileAvatar).mockResolvedValue(avatar);

		const result = await saveOrganizationAvatar(bobbin, controller, orgDid, image, null);

		expect(uploadProfileAvatar).toHaveBeenCalledWith(orgAgent, image);
		expect(putProfile).toHaveBeenCalledWith(orgAgent, {
			$type: "org.tangled.actor.profile",
			isOrganization: true,
			avatar
		});
		expect(result).toEqual(expect.objectContaining({ avatar, isOrganization: true }));
	});
});