Something went wrong. Try again.
Monorepo for Tangled tangled.org
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148import { ClientResponseError } from "@atcute/client";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 { provisionDelegate } from "#lib/api/delegation.ts";import { createOrg, createOrgAccount, ORG_PROFILE_MARKER } from "#lib/api/orgCreate.ts";import { ensureProfile } from "#lib/api/profile.ts";
vi.mock("#lib/api/delegation.ts", () => ({ provisionDelegate: vi.fn() }));vi.mock("#lib/api/actAs.ts", () => ({ getOrCreateDelegatedSession: vi.fn() }));vi.mock("#lib/api/profile.ts", () => ({ PROFILE_COLLECTION: "org.tangled.actor.profile", ensureProfile: vi.fn()}));
const service = { serviceUrl: "https://gate.example", handleDomain: "orgs.example" };const controllerDid = "did:plc:controller" as Did;const controller = { sub: controllerDid } as OAuthUserAgent;const orgAgent = {} as OAuthUserAgent;const orgDid = "did:plc:org" as Did;const orgLabel = "acme";const fullHandle = `${orgLabel}.orgs.example`;
beforeEach(() => { vi.resetAllMocks(); vi.mocked(provisionDelegate).mockResolvedValue({ did: orgDid, handle: fullHandle, controllerDid }); vi.mocked(getOrCreateDelegatedSession).mockResolvedValue(orgAgent);});
describe("createOrgAccount", () => { it("provisions through the sidecar", async () => { const org = await createOrgAccount(controller, " ACME ", service);
expect(provisionDelegate).toHaveBeenCalledWith(controller, fullHandle, service); expect(org).toEqual({ did: orgDid, handle: fullHandle }); });
it("rejects a name that is not a valid subdomain label", async () => { await expect(createOrgAccount(controller, "-bad", service)).rejects.toThrow(/name/); expect(provisionDelegate).not.toHaveBeenCalled(); });
it("refuses to guess a handle domain the deployment does not set", async () => { await expect( createOrgAccount(controller, orgLabel, { serviceUrl: "https://gate.example" }) ).rejects.toThrow("Organization creation isn't set up on this server."); expect(provisionDelegate).not.toHaveBeenCalled(); });
it("rejects a name carrying its own domain", async () => { await expect(createOrgAccount(controller, "acme.owner.example", service)).rejects.toThrow( /name/ ); expect(provisionDelegate).not.toHaveBeenCalled(); });});
describe("createOrg", () => { it("creates the account, then writes the profile marker as the organization", async () => { const org = await createOrg(controller, orgLabel, service);
expect(provisionDelegate).toHaveBeenCalledWith(controller, fullHandle, service); expect(getOrCreateDelegatedSession).toHaveBeenCalledWith(controller, orgDid); expect(ensureProfile).toHaveBeenCalledWith(orgAgent, ORG_PROFILE_MARKER); expect(ORG_PROFILE_MARKER).toEqual({ $type: "org.tangled.actor.profile", isOrganization: true }); expect(org).toEqual({ did: orgDid, handle: fullHandle, warnings: [] }); });
it("retries the organization session once before giving up", async () => { vi.mocked(getOrCreateDelegatedSession) .mockRejectedValueOnce(new Error("grant unavailable")) .mockResolvedValueOnce(orgAgent);
const org = await createOrg(controller, orgLabel, service);
expect(getOrCreateDelegatedSession).toHaveBeenCalledTimes(2); expect(ensureProfile).toHaveBeenCalledWith(orgAgent, ORG_PROFILE_MARKER); expect(org.warnings).toEqual([]); });
it("keeps the account and names the failed session step in the warning", async () => { const cause = new Error("grant unavailable"); vi.mocked(getOrCreateDelegatedSession).mockRejectedValue(cause); const log = vi.spyOn(console, "error").mockImplementation(() => {});
const org = await createOrg(controller, orgLabel, service);
expect(getOrCreateDelegatedSession).toHaveBeenCalledTimes(2); expect(org).toEqual({ did: orgDid, handle: fullHandle, warnings: ["Unable to sign in to the organization account (grant unavailable)."] }); expect(ensureProfile).not.toHaveBeenCalled(); expect(log).toHaveBeenCalledWith( expect.stringContaining("organization session"), orgDid, cause ); });
it("names the profile write when that is what failed, without redoing the session", async () => { const cause = new Error("scope missing."); vi.mocked(ensureProfile).mockRejectedValue(cause); const log = vi.spyOn(console, "error").mockImplementation(() => {});
const org = await createOrg(controller, orgLabel, service);
expect(getOrCreateDelegatedSession).toHaveBeenCalledTimes(1); expect(org.warnings).toEqual([ "Unable to save the organization's profile (scope missing)." ]); expect(log).toHaveBeenCalledWith(expect.stringContaining("profile write"), orgDid, cause); });
it("shows a PDS error's description rather than its code", async () => { vi.mocked(ensureProfile).mockRejectedValue( new ClientResponseError({ status: 500, data: { error: "InternalServerError", message: "Repo is not ready yet" } }) ); vi.spyOn(console, "error").mockImplementation(() => {});
const org = await createOrg(controller, orgLabel, service);
expect(org.warnings).toEqual([ "Unable to save the organization's profile (Repo is not ready yet)." ]); });
it("retries with the existing account without consuming another quota slot", async () => { await createOrg(controller, orgLabel, service, { did: orgDid, handle: fullHandle });
expect(provisionDelegate).not.toHaveBeenCalled(); expect(getOrCreateDelegatedSession).toHaveBeenCalledWith(controller, orgDid); expect(ensureProfile).toHaveBeenCalledWith(orgAgent, ORG_PROFILE_MARKER); });});