1
0
Fork 0
mirror of https://github.com/maybe-finance/maybe.git synced 2025-07-23 15:19:38 +02:00

Plaid sync domain improvements (#2267)
Some checks are pending
Publish Docker image / ci (push) Waiting to run
Publish Docker image / Build docker image (push) Blocked by required conditions

Breaks our Plaid sync process out into more manageable classes. Notably, this moves the sync process to a distinct, 2-step flow:

1. Import stage - we first make API calls and import Plaid data to "mirror" tables
2. Processing stage - read the raw data, apply business rules, build internal domain models and sync balances

This provides several benefits:

- Plaid syncs can now be "replayed" without fetching API data again
- Mirror tables provide better audit and debugging capabilities
- Eliminates the "all or nothing" sync behavior that is currently in place, which is brittle
This commit is contained in:
Zach Gollwitzer 2025-05-23 18:58:22 -04:00 committed by GitHub
parent 5c82af0e8c
commit 03a146222d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
72 changed files with 3763 additions and 706 deletions

View file

@ -0,0 +1,80 @@
require "test_helper"
class Provider::PlaidTest < ActiveSupport::TestCase
setup do
# Do not change, this is whitelisted in the Plaid Dashboard for local dev
@redirect_url = "http://localhost:3000/accounts"
# A specialization of Plaid client with sandbox-only extensions
@plaid = Provider::PlaidSandbox.new
end
test "gets link token" do
VCR.use_cassette("plaid/link_token") do
link_token = @plaid.get_link_token(
user_id: "test-user-id",
webhooks_url: "https://example.com/webhooks",
redirect_url: @redirect_url
)
assert_match /link-sandbox-.*/, link_token.link_token
end
end
test "exchanges public token" do
VCR.use_cassette("plaid/exchange_public_token") do
public_token = @plaid.create_public_token
exchange_response = @plaid.exchange_public_token(public_token)
assert_match /access-sandbox-.*/, exchange_response.access_token
end
end
test "gets item" do
VCR.use_cassette("plaid/get_item") do
access_token = get_access_token
item = @plaid.get_item(access_token).item
assert_equal "ins_109508", item.institution_id
assert_equal "First Platypus Bank", item.institution_name
end
end
test "gets item accounts" do
VCR.use_cassette("plaid/get_item_accounts") do
access_token = get_access_token
accounts_response = @plaid.get_item_accounts(access_token)
assert_equal 4, accounts_response.accounts.size
end
end
test "gets item investments" do
VCR.use_cassette("plaid/get_item_investments") do
access_token = get_access_token
investments_response = @plaid.get_item_investments(access_token)
assert_equal 3, investments_response.holdings.size
assert_equal 4, investments_response.transactions.size
end
end
test "gets item liabilities" do
VCR.use_cassette("plaid/get_item_liabilities") do
access_token = get_access_token
liabilities_response = @plaid.get_item_liabilities(access_token)
assert liabilities_response.credit.count > 0
assert liabilities_response.student.count > 0
end
end
private
def get_access_token
VCR.use_cassette("plaid/access_token") do
public_token = @plaid.create_public_token
exchange_response = @plaid.exchange_public_token(public_token)
exchange_response.access_token
end
end
end