mirror of
https://github.com/we-promise/sure.git
synced 2026-04-07 14:31:25 +00:00
* Feat(CoinStats): Scaffold implementation, not yet functional * Feat(CoinStats): Implement crypto wallet balance and transactions * Feat(CoinStats): Add tests, Minor improvements * Feat(CoinStats): Utilize bulk fetch API endpoints * Feat(CoinStats): Migrate strings to i8n * Feat(CoinStats): Fix error handling in wallet link modal * Feat(CoinStats): Implement hourly provider sync job * Feat(CoinStats): Generate docstrings * Fix(CoinStats): Validate API Key on provider update * Fix(Providers): Safely handle race condition in merchance creation * Fix(CoinStats): Don't catch system signals in account processor * Fix(CoinStats): Preload before iterating accounts * Fix(CoinStats): Add no opener / referrer to API dashboard link * Fix(CoinStats): Use strict matching for symbols * Fix(CoinStats): Remove dead code in transactions importer * Fix(CoinStats): Avoid transaction fallback ID collisions * Fix(CoinStats): Improve Blockchains fetch error handling * Fix(CoinStats): Enforce NOT NULL constraint for API Key schema * Fix(CoinStats): Migrate sync status strings to i8n * Fix(CoinStats): Use class name rather than hardcoded string * Fix(CoinStats): Use account currency rather than hardcoded USD * Fix(CoinStats): Migrate from standalone to Provider class * Fix(CoinStats): Fix test failures due to string changes
232 lines
6.7 KiB
Ruby
232 lines
6.7 KiB
Ruby
require "test_helper"
|
|
|
|
class CoinstatsItemTest < ActiveSupport::TestCase
|
|
setup do
|
|
@family = families(:dylan_family)
|
|
@coinstats_item = CoinstatsItem.create!(
|
|
family: @family,
|
|
name: "Test CoinStats Connection",
|
|
api_key: "test_api_key_123"
|
|
)
|
|
end
|
|
|
|
test "belongs to family" do
|
|
assert_equal @family, @coinstats_item.family
|
|
end
|
|
|
|
test "has many coinstats_accounts" do
|
|
account = @coinstats_item.coinstats_accounts.create!(
|
|
name: "Test Wallet",
|
|
currency: "USD",
|
|
current_balance: 1000.00
|
|
)
|
|
|
|
assert_includes @coinstats_item.coinstats_accounts, account
|
|
end
|
|
|
|
test "has good status by default" do
|
|
assert_equal "good", @coinstats_item.status
|
|
end
|
|
|
|
test "can be marked for deletion" do
|
|
refute @coinstats_item.scheduled_for_deletion?
|
|
|
|
@coinstats_item.destroy_later
|
|
|
|
assert @coinstats_item.scheduled_for_deletion?
|
|
end
|
|
|
|
test "is syncable" do
|
|
assert_respond_to @coinstats_item, :sync_later
|
|
assert_respond_to @coinstats_item, :syncing?
|
|
end
|
|
|
|
test "requires name to be present" do
|
|
coinstats_item = CoinstatsItem.new(family: @family, api_key: "key")
|
|
coinstats_item.name = nil
|
|
|
|
assert_not coinstats_item.valid?
|
|
assert_includes coinstats_item.errors[:name], "can't be blank"
|
|
end
|
|
|
|
test "requires api_key to be present" do
|
|
coinstats_item = CoinstatsItem.new(family: @family, name: "Test")
|
|
coinstats_item.api_key = nil
|
|
|
|
assert_not coinstats_item.valid?
|
|
assert_includes coinstats_item.errors[:api_key], "can't be blank"
|
|
end
|
|
|
|
test "requires api_key to be present on update" do
|
|
@coinstats_item.api_key = ""
|
|
|
|
assert_not @coinstats_item.valid?
|
|
assert_includes @coinstats_item.errors[:api_key], "can't be blank"
|
|
end
|
|
|
|
test "scopes work correctly" do
|
|
# Create one for deletion
|
|
item_for_deletion = CoinstatsItem.create!(
|
|
family: @family,
|
|
name: "Delete Me",
|
|
api_key: "delete_key",
|
|
scheduled_for_deletion: true
|
|
)
|
|
|
|
active_items = CoinstatsItem.active
|
|
ordered_items = CoinstatsItem.ordered
|
|
|
|
assert_includes active_items, @coinstats_item
|
|
refute_includes active_items, item_for_deletion
|
|
|
|
assert_equal [ @coinstats_item, item_for_deletion ].sort_by(&:created_at).reverse,
|
|
ordered_items.to_a
|
|
end
|
|
|
|
test "needs_update scope returns items requiring update" do
|
|
@coinstats_item.update!(status: :requires_update)
|
|
|
|
good_item = CoinstatsItem.create!(
|
|
family: @family,
|
|
name: "Good Item",
|
|
api_key: "good_key"
|
|
)
|
|
|
|
needs_update_items = CoinstatsItem.needs_update
|
|
|
|
assert_includes needs_update_items, @coinstats_item
|
|
refute_includes needs_update_items, good_item
|
|
end
|
|
|
|
test "institution display name returns name when present" do
|
|
assert_equal "Test CoinStats Connection", @coinstats_item.institution_display_name
|
|
end
|
|
|
|
test "institution display name falls back to CoinStats" do
|
|
# Bypass validation by using update_column
|
|
@coinstats_item.update_column(:name, "")
|
|
assert_equal "CoinStats", @coinstats_item.institution_display_name
|
|
end
|
|
|
|
test "credentials_configured? returns true when api_key present" do
|
|
assert @coinstats_item.credentials_configured?
|
|
end
|
|
|
|
test "credentials_configured? returns false when api_key blank" do
|
|
@coinstats_item.api_key = nil
|
|
refute @coinstats_item.credentials_configured?
|
|
end
|
|
|
|
test "upserts coinstats snapshot" do
|
|
snapshot_data = {
|
|
total_balance: 5000.0,
|
|
wallets: [ { address: "0x123", blockchain: "ethereum" } ]
|
|
}
|
|
|
|
@coinstats_item.upsert_coinstats_snapshot!(snapshot_data)
|
|
@coinstats_item.reload
|
|
|
|
# Verify key data is stored correctly (keys may be string or symbol)
|
|
assert_equal 5000.0, @coinstats_item.raw_payload["total_balance"]
|
|
assert_equal 1, @coinstats_item.raw_payload["wallets"].count
|
|
assert_equal "0x123", @coinstats_item.raw_payload["wallets"].first["address"]
|
|
end
|
|
|
|
test "has_completed_initial_setup? returns false when no accounts" do
|
|
refute @coinstats_item.has_completed_initial_setup?
|
|
end
|
|
|
|
test "has_completed_initial_setup? returns true when accounts exist" do
|
|
crypto = Crypto.create!
|
|
account = @family.accounts.create!(
|
|
accountable: crypto,
|
|
name: "Test Crypto",
|
|
balance: 1000,
|
|
currency: "USD"
|
|
)
|
|
coinstats_account = @coinstats_item.coinstats_accounts.create!(
|
|
name: "Test Wallet",
|
|
currency: "USD"
|
|
)
|
|
AccountProvider.create!(account: account, provider: coinstats_account)
|
|
|
|
assert @coinstats_item.has_completed_initial_setup?
|
|
end
|
|
|
|
test "linked_accounts_count returns count of accounts with provider links" do
|
|
# Initially no linked accounts
|
|
assert_equal 0, @coinstats_item.linked_accounts_count
|
|
|
|
# Create a linked account
|
|
crypto = Crypto.create!
|
|
account = @family.accounts.create!(
|
|
accountable: crypto,
|
|
name: "Test Crypto",
|
|
balance: 1000,
|
|
currency: "USD"
|
|
)
|
|
coinstats_account = @coinstats_item.coinstats_accounts.create!(
|
|
name: "Test Wallet",
|
|
currency: "USD"
|
|
)
|
|
AccountProvider.create!(account: account, provider: coinstats_account)
|
|
|
|
assert_equal 1, @coinstats_item.linked_accounts_count
|
|
end
|
|
|
|
test "unlinked_accounts_count returns count of accounts without provider links" do
|
|
# Create an unlinked account
|
|
@coinstats_item.coinstats_accounts.create!(
|
|
name: "Unlinked Wallet",
|
|
currency: "USD"
|
|
)
|
|
|
|
assert_equal 1, @coinstats_item.unlinked_accounts_count
|
|
end
|
|
|
|
test "sync_status_summary shows no accounts message" do
|
|
assert_equal "No crypto wallets found", @coinstats_item.sync_status_summary
|
|
end
|
|
|
|
test "sync_status_summary shows all synced message" do
|
|
crypto = Crypto.create!
|
|
account = @family.accounts.create!(
|
|
accountable: crypto,
|
|
name: "Test Crypto",
|
|
balance: 1000,
|
|
currency: "USD"
|
|
)
|
|
coinstats_account = @coinstats_item.coinstats_accounts.create!(
|
|
name: "Test Wallet",
|
|
currency: "USD"
|
|
)
|
|
AccountProvider.create!(account: account, provider: coinstats_account)
|
|
|
|
assert_equal "1 crypto wallet synced", @coinstats_item.sync_status_summary
|
|
end
|
|
|
|
test "sync_status_summary shows mixed status message" do
|
|
# Create a linked account
|
|
crypto = Crypto.create!
|
|
account = @family.accounts.create!(
|
|
accountable: crypto,
|
|
name: "Test Crypto",
|
|
balance: 1000,
|
|
currency: "USD"
|
|
)
|
|
coinstats_account = @coinstats_item.coinstats_accounts.create!(
|
|
name: "Linked Wallet",
|
|
currency: "USD"
|
|
)
|
|
AccountProvider.create!(account: account, provider: coinstats_account)
|
|
|
|
# Create an unlinked account
|
|
@coinstats_item.coinstats_accounts.create!(
|
|
name: "Unlinked Wallet",
|
|
currency: "USD"
|
|
)
|
|
|
|
assert_equal "1 crypto wallets synced, 1 need setup", @coinstats_item.sync_status_summary
|
|
end
|
|
end
|