Files
sure/test/controllers/akahu_items_controller_test.rb
Brad 1b8b21760b feat(provider): Akahu integration (#1921)
* First pass of Akahu

* fix up sync all

* conflicts

* fix db migration issue? - fix auto selection of akahu account type

* Address Akahu PR feedback

* Complete provider metadata

* Fix PR 1921 CI tests

* PR feedback

* PR feedback

* post merge

---------

Co-authored-by: failing <failing@users.noreply.github.com>
Co-authored-by: Juan José Mata <jjmata@jjmata.com>
Co-authored-by: sure-admin <sure-admin@splashblot.com>
2026-06-02 21:44:57 +02:00

291 lines
9.1 KiB
Ruby

require "test_helper"
class AkahuItemsControllerTest < ActionDispatch::IntegrationTest
setup do
ensure_tailwind_build
sign_in users(:family_admin)
SyncJob.stubs(:perform_later)
@family = families(:dylan_family)
@akahu_item = AkahuItem.create!(
family: @family,
name: "Main Akahu",
app_token: "akahu-app-credential",
user_token: "akahu-user-credential"
)
@akahu_account = @akahu_item.akahu_accounts.create!(
name: "Akahu Checking",
account_id: "acc_123",
currency: "NZD"
)
@account = accounts(:depository)
end
test "setup_accounts preselects mapped account type for each account" do
AkahuItemsController.any_instance.stubs(:fetch_akahu_accounts_from_api).returns(nil)
@akahu_account.update!(account_type: "SAVINGS")
get setup_accounts_akahu_item_url(@akahu_item)
assert_response :success
selected_option = css_select("select[name='account_types[#{@akahu_account.id}]'] option[selected='selected']").first
assert_equal "Depository", selected_option["value"]
@akahu_account.update!(account_type: "FOREIGN")
get setup_accounts_akahu_item_url(@akahu_item)
assert_response :success
selected_option = css_select("select[name='account_types[#{@akahu_account.id}]'] option[selected='selected']").first
assert_equal "skip", selected_option["value"]
end
test "complete_account_setup uses Akahu account type suggestion subtype for investment accounts" do
@akahu_account.update!(account_type: "KIWISAVER")
assert_difference "Account.count", 1 do
assert_difference "AccountProvider.count", 1 do
post complete_account_setup_akahu_item_url(@akahu_item), params: {
account_types: { @akahu_account.id.to_s => "Investment" }
}
end
end
assert_redirected_to accounts_path
@akahu_account.reload
created_account = @akahu_account.current_account
assert_not_nil created_account
assert_equal "Investment", created_account.accountable_type
assert_equal "retirement", created_account.accountable.subtype
end
test "select accounts rejects unsafe return paths" do
AkahuItemsController.any_instance.stubs(:fetch_akahu_accounts_from_api).returns(nil)
unsafe_return_paths.each do |return_to|
get select_accounts_akahu_items_url, params: {
akahu_item_id: @akahu_item.id,
accountable_type: "Depository",
return_to: return_to
}
assert_response :success
assert_select %(input[name="return_to"]) do |fields|
assert fields.first["value"].blank?
end
end
end
test "select existing account rejects unsafe return paths" do
AkahuItemsController.any_instance.stubs(:fetch_akahu_accounts_from_api).returns(nil)
unsafe_return_paths.each do |return_to|
get select_existing_account_akahu_items_url, params: {
account_id: @account.id,
akahu_item_id: @akahu_item.id,
return_to: return_to
}
assert_response :success
assert_select %(input[name="return_to"]) do |fields|
assert fields.first["value"].blank?
end
end
end
test "select existing account preserves safe local return path" do
return_to = "/accounts?tab=manual"
AkahuItemsController.any_instance.stubs(:fetch_akahu_accounts_from_api).returns(nil)
get select_existing_account_akahu_items_url, params: {
account_id: @account.id,
akahu_item_id: @akahu_item.id,
return_to: return_to
}
assert_response :success
assert_select %(input[name="return_to"][value="#{return_to}"])
end
test "link accounts rejects unsafe return path on no selection redirect" do
post link_accounts_akahu_items_url, params: {
akahu_item_id: @akahu_item.id,
accountable_type: "Depository",
return_to: "https://evil.example/accounts"
}
assert_redirected_to select_accounts_akahu_items_path(
akahu_item_id: @akahu_item.id,
accountable_type: "Depository",
return_to: nil
)
end
test "link accounts rejects unsafe return path after linking" do
@akahu_account.update!(current_balance: 10)
assert_difference "AccountProvider.count", 1 do
post link_accounts_akahu_items_url, params: {
akahu_item_id: @akahu_item.id,
account_ids: [ @akahu_account.id ],
accountable_type: "Depository",
return_to: "https://evil.example/accounts"
}
end
assert_redirected_to accounts_path
end
test "link existing account rejects unsafe return paths" do
unsafe_return_paths.each_with_index do |return_to, index|
account = @family.accounts.create!(
name: "Manual Checking #{index}",
balance: 0,
currency: "NZD",
accountable: Depository.new
)
akahu_account = @akahu_item.akahu_accounts.create!(
name: "Akahu Checking #{index}",
account_id: "acc_unsafe_#{index}",
currency: "NZD"
)
assert_difference "AccountProvider.count", 1 do
post link_existing_account_akahu_items_url, params: {
account_id: account.id,
akahu_item_id: @akahu_item.id,
akahu_account_id: akahu_account.id,
return_to: return_to
}
end
assert_redirected_to accounts_path
end
end
test "preload accounts uses requested Akahu connection" do
second_item = AkahuItem.create!(
family: @family,
name: "Secondary Akahu",
app_token: "akahu-app-credential-2",
user_token: "akahu-user-credential-2"
)
AkahuItemsController.any_instance
.expects(:fetch_akahu_accounts_from_api)
.with(second_item)
.returns(nil)
get preload_accounts_akahu_items_url, params: { akahu_item_id: second_item.id }, as: :json
assert_response :success
assert_equal false, JSON.parse(response.body)["has_accounts"]
end
test "select accounts uses requested Akahu connection" do
second_item = AkahuItem.create!(
family: @family,
name: "Secondary Akahu",
app_token: "akahu-app-credential-2",
user_token: "akahu-user-credential-2"
)
second_item.akahu_accounts.create!(
name: "Secondary Checking",
account_id: "acc_secondary",
currency: "NZD"
)
AkahuItemsController.any_instance.stubs(:fetch_akahu_accounts_from_api).returns(nil)
get select_accounts_akahu_items_url, params: { akahu_item_id: second_item.id, accountable_type: "Depository" }
assert_response :success
assert_includes response.body, "Secondary Checking"
refute_includes response.body, "Akahu Checking"
end
test "link accounts uses requested Akahu connection" do
second_item = AkahuItem.create!(
family: @family,
name: "Secondary Akahu",
app_token: "akahu-app-credential-2",
user_token: "akahu-user-credential-2"
)
second_account = second_item.akahu_accounts.create!(
name: "Secondary Checking",
account_id: "acc_secondary",
currency: "NZD",
current_balance: 42
)
assert_difference "Account.count", 1 do
assert_difference "AccountProvider.count", 1 do
post link_accounts_akahu_items_url, params: {
akahu_item_id: second_item.id,
account_ids: [ second_account.id ],
accountable_type: "Depository"
}
end
end
assert_redirected_to accounts_path
assert_equal second_account.id, AccountProvider.order(:created_at).last.provider_id
assert_nil @akahu_account.reload.current_account
end
test "select existing account uses requested Akahu connection" do
second_item = AkahuItem.create!(
family: @family,
name: "Secondary Akahu",
app_token: "akahu-app-credential-2",
user_token: "akahu-user-credential-2"
)
second_item.akahu_accounts.create!(
name: "Secondary Checking",
account_id: "acc_secondary",
currency: "NZD"
)
AkahuItemsController.any_instance.stubs(:fetch_akahu_accounts_from_api).returns(nil)
get select_existing_account_akahu_items_url, params: {
account_id: @account.id,
akahu_item_id: second_item.id
}
assert_response :success
assert_includes response.body, "Secondary Checking"
refute_includes response.body, "Akahu Checking"
end
test "complete account setup hides raw creation errors from users" do
raw_message = "raw provider failure with akahu-user-credential"
AkahuItemsController.any_instance
.stubs(:create_account_from_akahu)
.raises(ActiveRecord::RecordNotSaved.new(raw_message))
post complete_account_setup_akahu_item_url(@akahu_item), params: {
account_types: { @akahu_account.id.to_s => "Depository" }
}
assert_redirected_to accounts_path
assert_equal I18n.t("akahu_items.complete_account_setup.creation_failed"), flash[:alert]
refute_includes flash[:alert], raw_message
end
private
def unsafe_return_paths
[
"https://evil.example/accounts",
"http://evil.example/accounts",
"//evil.example/accounts",
"\\evil.example/accounts",
"/\\evil.example/accounts",
"/%2fevil.example/accounts",
"/%2Fevil.example/accounts",
"/%5cevil.example/accounts",
"/%5Cevil.example/accounts",
"/\naccounts",
"/ accounts",
" "
]
end
end