ledgerone_backend/test/teller.service.spec.ts

109 lines
3.2 KiB
TypeScript

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_", "")),
},
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" }),
}));
});
});