| import { expect, test } from "bun:test"; |
| import { |
| AccountSubtype, |
| AccountType, |
| CounterpartyType, |
| TransactionCode, |
| TransactionPaymentChannelEnum, |
| TransactionTransactionTypeEnum, |
| } from "plaid"; |
| import { |
| transformAccount, |
| transformAccountBalance, |
| transformTransaction, |
| } from "./transform"; |
|
|
| test("Transform pending transaction", () => { |
| expect( |
| transformTransaction({ |
| accountType: "credit", |
| transaction: { |
| account_id: "AG7EkLW7DRSVaN8Z75jMT1DJN51QpWc9LKB7w", |
| account_owner: null, |
| amount: 5.4, |
| authorized_date: "2024-02-23", |
| authorized_datetime: null, |
| category: ["Travel", "Taxi"], |
| category_id: "22016000", |
| check_number: null, |
| counterparties: [ |
| { |
| confidence_level: "VERY_HIGH", |
| entity_id: "eyg8o776k0QmNgVpAmaQj4WgzW9Qzo6O51gdd", |
| logo_url: "https://plaid-merchant-logos.plaid.com/uber_1060.png", |
| name: "Uber", |
| type: CounterpartyType.Merchant, |
| website: "uber.com", |
| }, |
| ], |
| date: "2024-02-24", |
| datetime: null, |
| iso_currency_code: "CAD", |
| location: { |
| address: null, |
| city: null, |
| country: null, |
| lat: null, |
| lon: null, |
| postal_code: null, |
| region: null, |
| store_number: null, |
| }, |
| logo_url: "https://plaid-merchant-logos.plaid.com/uber_1060.png", |
| merchant_entity_id: "eyg8o776k0QmNgVpAmaQj4WgzW9Qzo6O51gdd", |
| merchant_name: "Uber", |
| name: "Uber 063015 SF**POOL**", |
| payment_channel: TransactionPaymentChannelEnum.Online, |
| payment_meta: { |
| by_order_of: null, |
| payee: null, |
| payer: null, |
| payment_method: null, |
| payment_processor: null, |
| ppd_id: null, |
| reason: null, |
| reference_number: null, |
| }, |
| pending: true, |
| pending_transaction_id: null, |
| personal_finance_category: { |
| confidence_level: "VERY_HIGH", |
| detailed: "TRANSPORTATION_TAXIS_AND_RIDE_SHARES", |
| primary: "TRANSPORTATION", |
| }, |
| personal_finance_category_icon_url: |
| "https://plaid-category-icons.plaid.com/PFC_TRANSPORTATION.png", |
| transaction_code: null, |
| transaction_id: "NxkDjlyk45cQoDm5PEqJuKJaw6qrj9cy89zBA", |
| transaction_type: TransactionTransactionTypeEnum.Special, |
| unofficial_currency_code: null, |
| website: "uber.com", |
| }, |
| }), |
| ).toMatchSnapshot(); |
| }); |
|
|
| test("Transform income transaction", () => { |
| expect( |
| transformTransaction({ |
| accountType: "depository", |
| transaction: { |
| account_id: "AG7EkLW7DRSVaN8Z75jMT1DJN51QpWc9LKB7w", |
| account_owner: null, |
| amount: 1500, |
| authorized_date: "2024-02-22", |
| authorized_datetime: null, |
| category: ["Travel", "Airlines and Aviation Services"], |
| category_id: "22001000", |
| check_number: null, |
| counterparties: [ |
| { |
| confidence_level: "VERY_HIGH", |
| entity_id: "NKDjqyAdQQzpyeD8qpLnX0D6yvLe2KYKYYzQ4", |
| logo_url: |
| "https://plaid-merchant-logos.plaid.com/united_airlines_1065.png", |
| name: "United Airlines", |
| type: CounterpartyType.Merchant, |
| website: "united.com", |
| }, |
| ], |
| date: "2024-02-22", |
| datetime: null, |
| iso_currency_code: "CAD", |
| location: { |
| address: null, |
| city: null, |
| country: null, |
| lat: null, |
| lon: null, |
| postal_code: null, |
| region: null, |
| store_number: null, |
| }, |
| logo_url: |
| "https://plaid-merchant-logos.plaid.com/united_airlines_1065.png", |
| merchant_entity_id: "NKDjqyAdQQzpyeD8qpLnX0D6yvLe2KYKYYzQ4", |
| merchant_name: "United Airlines", |
| name: "United Airlines", |
| payment_channel: TransactionPaymentChannelEnum.InStore, |
| payment_meta: { |
| by_order_of: null, |
| payee: null, |
| payer: null, |
| payment_method: null, |
| payment_processor: null, |
| ppd_id: null, |
| reason: null, |
| reference_number: null, |
| }, |
| pending: false, |
| pending_transaction_id: null, |
| personal_finance_category: { |
| confidence_level: "VERY_HIGH", |
| detailed: "TRAVEL_FLIGHTS", |
| primary: "TRAVEL", |
| }, |
| personal_finance_category_icon_url: |
| "https://plaid-category-icons.plaid.com/PFC_TRAVEL.png", |
| transaction_code: null, |
| transaction_id: "5QKmMdaKWgtzkvKEPmqriLZR1mV3kMF5X9EeX", |
| transaction_type: TransactionTransactionTypeEnum.Special, |
| unofficial_currency_code: null, |
| website: "united.com", |
| }, |
| }), |
| ).toMatchSnapshot(); |
| }); |
|
|
| test("Transform type transfer", () => { |
| expect( |
| transformTransaction({ |
| accountType: "credit", |
| transaction: { |
| account_id: "AG7EkLW7DRSVaN8Z75jMT1DJN51QpWc9LKB7w", |
| account_owner: null, |
| amount: 31.53, |
| authorized_date: "2024-02-23", |
| authorized_datetime: null, |
| category: ["Travel", "Taxi"], |
| category_id: "22016000", |
| check_number: null, |
| counterparties: [ |
| { |
| confidence_level: "VERY_HIGH", |
| entity_id: "eyg8o776k0QmNgVpAmaQj4WgzW9Qzo6O51gdd", |
| logo_url: "https://plaid-merchant-logos.plaid.com/uber_1060.png", |
| name: "Uber", |
| type: CounterpartyType.Merchant, |
| website: "uber.com", |
| }, |
| ], |
| date: "2024-02-24", |
| datetime: null, |
| iso_currency_code: "CAD", |
| location: { |
| address: null, |
| city: null, |
| country: null, |
| lat: null, |
| lon: null, |
| postal_code: null, |
| region: null, |
| store_number: null, |
| }, |
| logo_url: "https://plaid-merchant-logos.plaid.com/uber_1060.png", |
| merchant_entity_id: "eyg8o776k0QmNgVpAmaQj4WgzW9Qzo6O51gdd", |
| merchant_name: "Uber", |
| name: "Uber 063015 SF**POOL**", |
| payment_channel: TransactionPaymentChannelEnum.Online, |
| payment_meta: { |
| by_order_of: null, |
| payee: null, |
| payer: null, |
| payment_method: null, |
| payment_processor: null, |
| ppd_id: null, |
| reason: null, |
| reference_number: null, |
| }, |
| pending: true, |
| pending_transaction_id: null, |
| personal_finance_category: { |
| confidence_level: "VERY_HIGH", |
| detailed: "TRANSPORTATION_TAXIS_AND_RIDE_SHARES", |
| primary: "TRANSPORTATION", |
| }, |
| personal_finance_category_icon_url: |
| "https://plaid-category-icons.plaid.com/PFC_TRANSPORTATION.png", |
| transaction_code: TransactionCode.Transfer, |
| transaction_id: "NxkDjlyk45cQoDm5PEqJuKJaw6qrj9cy89zBA", |
| transaction_type: TransactionTransactionTypeEnum.Special, |
| unofficial_currency_code: null, |
| website: "uber.com", |
| }, |
| }), |
| ).toMatchSnapshot(); |
| }); |
|
|
| test("Transform accounts", () => { |
| expect( |
| transformAccount({ |
| account_id: "kKZWQnoZVqcBeN71qdyoh8mVoErgb7tL7gmBL", |
| balances: { |
| available: 56302.06, |
| current: 56302.06, |
| iso_currency_code: "CAD", |
| limit: null, |
| unofficial_currency_code: null, |
| }, |
| mask: "8888", |
| name: "Plaid Mortgage", |
| official_name: null, |
| subtype: AccountSubtype.Mortgage, |
| type: AccountType.Loan, |
| institution: { |
| id: "ins_100546", |
| name: "American Funds Retirement Solutions", |
| logo: null, |
| }, |
| }), |
| ).toMatchSnapshot(); |
| }); |
|
|
| test("Transform account balance - depository uses available", () => { |
| expect( |
| transformAccountBalance({ |
| balances: { |
| available: 2000, |
| current: 1500, |
| iso_currency_code: "USD", |
| limit: null, |
| unofficial_currency_code: null, |
| }, |
| accountType: "depository", |
| }), |
| ).toMatchSnapshot(); |
| }); |
|
|
| test("Transform account balance - credit uses current (amount owed)", () => { |
| |
| |
| |
| expect( |
| transformAccountBalance({ |
| balances: { |
| available: 4000, |
| current: 1000, |
| iso_currency_code: "USD", |
| limit: 5000, |
| unofficial_currency_code: null, |
| }, |
| accountType: "credit", |
| }), |
| ).toMatchSnapshot(); |
| }); |
|
|
| test("Transform account balance - depository falls back to current when available is null", () => { |
| |
| expect( |
| transformAccountBalance({ |
| balances: { |
| available: null, |
| current: 5000, |
| iso_currency_code: "USD", |
| limit: null, |
| unofficial_currency_code: null, |
| }, |
| accountType: "depository", |
| }), |
| ).toEqual({ |
| currency: "USD", |
| amount: 5000, |
| available_balance: null, |
| credit_limit: null, |
| }); |
| }); |
|
|
| test("Transform account balance - handles null balances gracefully", () => { |
| expect( |
| transformAccountBalance({ |
| balances: { |
| available: null, |
| current: null, |
| iso_currency_code: "USD", |
| limit: null, |
| unofficial_currency_code: null, |
| }, |
| accountType: "depository", |
| }), |
| ).toEqual({ |
| currency: "USD", |
| amount: 0, |
| available_balance: null, |
| credit_limit: null, |
| }); |
| }); |
|
|
| test("Transform account balance - credit card overpayment (negative current)", () => { |
| |
| |
| expect( |
| transformAccountBalance({ |
| balances: { |
| available: 5500, |
| current: -500, |
| iso_currency_code: "USD", |
| limit: 5000, |
| unofficial_currency_code: null, |
| }, |
| accountType: "credit", |
| }), |
| ).toEqual({ |
| currency: "USD", |
| amount: -500, |
| available_balance: 5500, |
| credit_limit: 5000, |
| }); |
| }); |
|
|
| test("Transform account balance - loan account uses current", () => { |
| |
| expect( |
| transformAccountBalance({ |
| balances: { |
| available: null, |
| current: 75000, |
| iso_currency_code: "USD", |
| limit: null, |
| unofficial_currency_code: null, |
| }, |
| accountType: "loan", |
| }), |
| ).toEqual({ |
| currency: "USD", |
| amount: 75000, |
| available_balance: null, |
| credit_limit: null, |
| }); |
| }); |
|
|
| test("Transform credit card payment - should be credit-card-payment not income", () => { |
| expect( |
| transformTransaction({ |
| accountType: "credit", |
| transaction: { |
| account_id: "AG7EkLW7DRSVaN8Z75jMT1DJN51QpWc9LKB7w", |
| account_owner: null, |
| amount: -500, |
| authorized_date: "2024-02-23", |
| authorized_datetime: null, |
| category: ["Payment", "Credit Card"], |
| category_id: "16001000", |
| check_number: null, |
| counterparties: [], |
| date: "2024-02-24", |
| datetime: null, |
| iso_currency_code: "USD", |
| location: { |
| address: null, |
| city: null, |
| country: null, |
| lat: null, |
| lon: null, |
| postal_code: null, |
| region: null, |
| store_number: null, |
| }, |
| logo_url: null, |
| merchant_entity_id: null, |
| merchant_name: null, |
| name: "Credit Card Payment", |
| payment_channel: TransactionPaymentChannelEnum.Other, |
| payment_meta: { |
| by_order_of: null, |
| payee: null, |
| payer: null, |
| payment_method: null, |
| payment_processor: null, |
| ppd_id: null, |
| reason: null, |
| reference_number: null, |
| }, |
| pending: false, |
| pending_transaction_id: null, |
| personal_finance_category: { |
| confidence_level: "VERY_HIGH", |
| detailed: "LOAN_PAYMENTS_CREDIT_CARD_PAYMENT", |
| primary: "LOAN_PAYMENTS", |
| }, |
| personal_finance_category_icon_url: undefined, |
| transaction_code: TransactionCode.BillPayment, |
| transaction_id: "payment123", |
| transaction_type: TransactionTransactionTypeEnum.Special, |
| unofficial_currency_code: null, |
| website: null, |
| }, |
| }), |
| ).toMatchSnapshot(); |
| }); |
|
|
| test("Transform credit card refund - should have no category", () => { |
| expect( |
| transformTransaction({ |
| accountType: "credit", |
| transaction: { |
| account_id: "AG7EkLW7DRSVaN8Z75jMT1DJN51QpWc9LKB7w", |
| account_owner: null, |
| amount: -50, |
| authorized_date: "2024-02-23", |
| authorized_datetime: null, |
| category: ["Shops", "Computers and Electronics"], |
| category_id: "19013000", |
| check_number: null, |
| counterparties: [ |
| { |
| confidence_level: "VERY_HIGH", |
| entity_id: "amazon123", |
| logo_url: "https://plaid-merchant-logos.plaid.com/amazon.png", |
| name: "Amazon", |
| type: CounterpartyType.Merchant, |
| website: "amazon.com", |
| }, |
| ], |
| date: "2024-02-24", |
| datetime: null, |
| iso_currency_code: "USD", |
| location: { |
| address: null, |
| city: null, |
| country: null, |
| lat: null, |
| lon: null, |
| postal_code: null, |
| region: null, |
| store_number: null, |
| }, |
| logo_url: "https://plaid-merchant-logos.plaid.com/amazon.png", |
| merchant_entity_id: "amazon123", |
| merchant_name: "Amazon", |
| name: "Amazon Refund", |
| payment_channel: TransactionPaymentChannelEnum.Online, |
| payment_meta: { |
| by_order_of: null, |
| payee: null, |
| payer: null, |
| payment_method: null, |
| payment_processor: null, |
| ppd_id: null, |
| reason: null, |
| reference_number: null, |
| }, |
| pending: false, |
| pending_transaction_id: null, |
| personal_finance_category: { |
| confidence_level: "VERY_HIGH", |
| detailed: "GENERAL_MERCHANDISE_ELECTRONICS", |
| primary: "GENERAL_MERCHANDISE", |
| }, |
| personal_finance_category_icon_url: undefined, |
| transaction_code: null, |
| transaction_id: "refund123", |
| transaction_type: TransactionTransactionTypeEnum.Special, |
| unofficial_currency_code: null, |
| website: "amazon.com", |
| }, |
| }), |
| ).toMatchSnapshot(); |
| }); |
|
|
| test("Transform account - credit card with available_balance and credit_limit", () => { |
| const result = transformAccount({ |
| account_id: "credit_123", |
| balances: { |
| available: 4000, |
| current: 1000, |
| iso_currency_code: "USD", |
| limit: 5000, |
| unofficial_currency_code: null, |
| }, |
| mask: "1234", |
| name: "My Credit Card", |
| official_name: "Chase Sapphire", |
| subtype: AccountSubtype.CreditCard, |
| type: AccountType.Credit, |
| institution: { |
| id: "ins_chase", |
| name: "Chase", |
| logo: null, |
| }, |
| }); |
|
|
| expect(result.available_balance).toBe(4000); |
| expect(result.credit_limit).toBe(5000); |
| expect(result.balance.amount).toBe(1000); |
| }); |
|
|
| test("Transform account - depository with available_balance, no credit_limit", () => { |
| const result = transformAccount({ |
| account_id: "checking_123", |
| balances: { |
| available: 5000, |
| current: 5200, |
| iso_currency_code: "USD", |
| limit: null, |
| unofficial_currency_code: null, |
| }, |
| mask: "5678", |
| name: "My Checking", |
| official_name: "Chase Checking", |
| subtype: AccountSubtype.Checking, |
| type: AccountType.Depository, |
| institution: { |
| id: "ins_chase", |
| name: "Chase", |
| logo: null, |
| }, |
| }); |
|
|
| expect(result.available_balance).toBe(5000); |
| expect(result.credit_limit).toBeNull(); |
| expect(result.balance.amount).toBe(5000); |
| }); |
|
|
| test("Transform account - handles null balances gracefully", () => { |
| const result = transformAccount({ |
| account_id: "savings_123", |
| balances: { |
| available: null, |
| current: 10000, |
| iso_currency_code: "USD", |
| limit: null, |
| unofficial_currency_code: null, |
| }, |
| mask: "9999", |
| name: "My Savings", |
| official_name: null, |
| subtype: AccountSubtype.Savings, |
| type: AccountType.Depository, |
| institution: { |
| id: "ins_boa", |
| name: "Bank of America", |
| logo: null, |
| }, |
| }); |
|
|
| expect(result.available_balance).toBeNull(); |
| expect(result.credit_limit).toBeNull(); |
| }); |
|
|