Something went wrong. Try again.
Monorepo for Tangled forked from tangled.org/core
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126import type { Did } from "@atcute/lexicons/syntax";import type { Session } from "@atcute/oauth-browser-client";import { finalizeAuthorization, getSession } from "@atcute/oauth-browser-client";import { flushSync } from "svelte";import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";import { createAuth, type Auth } from "#lib/auth.svelte.ts";
vi.mock("@atcute/oauth-browser-client", async (importOriginal) => { const mod = await importOriginal<Record<string, unknown>>(); class MockOAuthUserAgent { readonly sub: string; getSession = vi.fn(async () => this.session); signOut = vi.fn(async () => {}); constructor(readonly session: { info: { sub: string } }) { this.sub = session.info.sub; } } return { ...mod, OAuthUserAgent: MockOAuthUserAgent, configureOAuth: vi.fn(), finalizeAuthorization: vi.fn(), getSession: vi.fn(), listStoredSessions: vi.fn(() => []), deleteStoredSession: vi.fn() };});
const mockedFinalize = vi.mocked(finalizeAuthorization);const mockedGetSession = vi.mocked(getSession);
const alice = "did:plc:alice" as Did;const bob = "did:plc:bob" as Did;const liveSession = (did: Did): Session => ({ info: { sub: did } }) as unknown as Session;const response = { code: "c", state: "sid", iss: "https://pds.example" };
const watch = (read: () => unknown) => { let runs = 0; const stop = $effect.root(() => { $effect(() => { read(); runs++; }); }); flushSync(); return { get runs() { flushSync(); return runs; }, stop };};
const settle = (auth: Auth) => vi.waitFor(() => expect(auth.state.kind).toBe("authenticated"));
beforeEach(() => { vi.clearAllMocks(); localStorage.clear(); vi.stubGlobal( "fetch", vi.fn(async (input: URL) => { const did = new URL(input).searchParams.get("identifier"); return Response.json({ did, handle: `${did?.slice(8)}.example` }); }) );});
afterEach(() => { vi.unstubAllGlobals();});
describe("auth readers", () => { it("don't rerun while the same account finishes signing in", async () => { mockedFinalize.mockResolvedValue({ session: liveSession(alice), state: null }); const auth = createAuth("http://bobbin.example", { did: alice, handle: "alice.example" }); const did = watch(() => auth.currentDid); const agent = watch(() => auth.agent);
await auth.completePendingSignIn("#state=sid&code=c"); await settle(auth);
expect(did.runs).toBe(1); // once with no agent yet, once when it arrives expect(agent.runs).toBe(2); did.stop(); agent.stop(); });
it("rerun when the account changes or signs out", async () => { mockedFinalize.mockResolvedValueOnce({ session: liveSession(alice), state: null }); const auth = createAuth("http://bobbin.example", null); await auth.completeAuthorization(alice, response); await settle(auth); const did = watch(() => auth.currentDid);
mockedFinalize.mockResolvedValueOnce({ session: liveSession(bob), state: null }); await auth.completeAuthorization(bob, response); await settle(auth); expect(auth.currentDid).toBe(bob); expect(did.runs).toBe(2);
await auth.signOut(); expect(auth.currentDid).toBeNull(); expect(did.runs).toBe(3); did.stop(); });
it("don't rerun an effect that asked agentFor for an agent", async () => { mockedGetSession.mockResolvedValue(liveSession(alice)); const auth = createAuth("http://bobbin.example", null); let pending: Promise<unknown> = Promise.resolve(); const effect = watch(() => { pending = auth.agentFor(alice, { relogin: false }); }); await pending;
mockedFinalize.mockResolvedValue({ session: liveSession(bob), state: null }); await auth.completeAuthorization(bob, response); await settle(auth);
expect(effect.runs).toBe(1); effect.stop(); });});