import { describe, expect, test } from "bun:test"; import { reconcileDiscordUser, type DiscordIdentity, type DiscordUserOperations, } from "@/lib/auth/discord-user-core"; type MemoryUser = { id: string; discordId: string; name: string; image: string | null; email: string | null; }; function createMemoryStore() { const users = new Map(); const userIdByDiscord = new Map(); const accounts = new Map }>(); let nextUserId = 1; const operations: DiscordUserOperations = { async findLinkedUserId(discordId) { return accounts.get(discordId)?.userId ?? null; }, async upsertUser(identity) { let userId = userIdByDiscord.get(identity.discordId); if (!userId) { userId = `user-${nextUserId++}`; userIdByDiscord.set(identity.discordId, userId); users.set(userId, { id: userId, discordId: identity.discordId, name: identity.displayName, image: identity.avatarUrl, email: identity.email ?? null, }); } return userId; }, async insertAccount(userId, discordId, account) { if (!accounts.has(discordId)) { accounts.set(discordId, { userId, fields: { type: account?.type ?? "oauth" }, }); } }, async updateUser(userId, identity) { const user = users.get(userId); if (!user) return null; const updated = { ...user, discordId: identity.discordId, name: identity.displayName, image: identity.avatarUrl, ...(identity.email !== undefined ? { email: identity.email } : {}), }; users.set(userId, updated); return updated; }, async updateAccount(discordId, update) { const account = accounts.get(discordId); if (account) account.fields = { ...account.fields, ...update }; }, }; return { users, accounts, operations }; } const botIdentity: DiscordIdentity = { discordId: "123456789012345678", displayName: "Bot-created user", avatarUrl: "https://cdn.discordapp.com/avatar.png", }; describe("Discord account reconciliation", () => { test("creates one user and one account for a new bot sender", async () => { const store = createMemoryStore(); const user = await reconcileDiscordUser(botIdentity, store.operations); expect(user.id).toBe("user-1"); expect(store.users.size).toBe(1); expect(store.accounts.size).toBe(1); expect(store.accounts.get(botIdentity.discordId)?.userId).toBe(user.id); }); test("concurrent first uploads resolve to the same database winner", async () => { const store = createMemoryStore(); const [first, second] = await Promise.all([ reconcileDiscordUser(botIdentity, store.operations), reconcileDiscordUser(botIdentity, store.operations), ]); expect(first.id).toBe(second.id); expect(store.users.size).toBe(1); expect(store.accounts.size).toBe(1); }); test("OAuth reuses a bot-created user and bot refreshes preserve email", async () => { const store = createMemoryStore(); const botUser = await reconcileDiscordUser(botIdentity, store.operations); const oauthUser = await reconcileDiscordUser( { ...botIdentity, displayName: "OAuth name", email: "member@example.com", account: { type: "oauth", access_token: "access-token", refresh_token: "refresh-token", }, }, store.operations, ); const refreshedByBot = await reconcileDiscordUser( { ...botIdentity, displayName: "Latest Discord name" }, store.operations, ); expect(oauthUser.id).toBe(botUser.id); expect(refreshedByBot.id).toBe(botUser.id); expect(refreshedByBot.email).toBe("member@example.com"); expect(store.users.size).toBe(1); expect(store.accounts.size).toBe(1); expect(store.accounts.get(botIdentity.discordId)?.fields).toMatchObject({ access_token: "access-token", refresh_token: "refresh-token", }); }); });