import { TellerService } from "../src/teller/teller.service"; const createService = () => { const prisma = { account: { findMany: jest.fn(), update: jest.fn(), upsert: jest.fn(), }, transactionRaw: { upsert: jest.fn(), }, }; const service = Object.create(TellerService.prototype) as TellerService; Object.assign(service as any, { prisma, encryption: { encrypt: jest.fn((value: string) => `enc_${value}`), decrypt: jest.fn((value: string) => value.replace("enc_", "")), }, rawPayloads: { encrypt: jest.fn((payload: unknown) => ({ encrypted: true, version: 1, ciphertext: JSON.stringify(payload) })), }, logger: { warn: jest.fn(), }, planLimits: { assertCanAddAccounts: jest.fn(), }, }); return { service, prisma }; }; describe("TellerService", () => { it("imports Teller enrollment accounts with encrypted access tokens", async () => { const { service, prisma } = createService(); prisma.account.findMany.mockResolvedValue([]); jest.spyOn(service as any, "api") .mockResolvedValueOnce([ { id: "acc_teller_1", enrollment_id: "enr_1", institution: { name: "Teller Bank" }, type: "depository", subtype: "checking", currency: "USD", last_four: "1234", status: "open", links: { balances: "https://api.teller.io/accounts/acc_teller_1/balances" }, }, ]) .mockResolvedValueOnce({ ledger: "100.25", available: "95.25", }); const result = await service.exchangeEnrollment("user_1", { accessToken: "token_1", enrollment: { id: "enr_1", institution: { name: "Teller Bank" } }, }); expect(result).toEqual({ enrollmentId: "enr_1", accountCount: 1 }); expect((service as any).planLimits.assertCanAddAccounts).toHaveBeenCalledWith("user_1", 1); expect(prisma.account.upsert).toHaveBeenCalledWith(expect.objectContaining({ where: { tellerAccountId: "acc_teller_1" }, create: expect.objectContaining({ userId: "user_1", tellerAccessToken: "enc_token_1", tellerEnrollmentId: "enr_1", tellerAccountId: "acc_teller_1", institutionName: "Teller Bank", }), })); }); it("syncs Teller transactions into the raw transaction table", async () => { const { service, prisma } = createService(); prisma.account.findMany.mockResolvedValue([ { id: "acct_1", tellerAccessToken: "enc_token_1", tellerAccountId: "acc_teller_1", }, ]); prisma.account.update.mockResolvedValue({}); jest.spyOn(service as any, "api").mockResolvedValue([ { id: "txn_1", account_id: "acc_teller_1", amount: "-12.34", date: "2026-07-15", description: "Coffee", }, ]); const result = await service.syncTransactionsForUser("user_1"); expect(result).toEqual({ created: 1 }); expect(prisma.transactionRaw.upsert).toHaveBeenCalledWith(expect.objectContaining({ where: { bankTransactionId: "txn_1" }, create: expect.objectContaining({ accountId: "acct_1", source: "teller", }), })); expect(prisma.account.update).toHaveBeenCalledWith(expect.objectContaining({ where: { id: "acct_1" }, data: expect.objectContaining({ syncStatus: "idle" }), })); }); });