Skip to content

Commit

Permalink
Update StripeConnect's FinancialConnections integration to work with …
Browse files Browse the repository at this point in the history
…public key override. (#4379)

## Summary
- Ensures the financial connection integration uses the public key
override.
- Updates implementation to make it more testable.
  • Loading branch information
nschris-stripe authored Dec 21, 2024
1 parent 672dc10 commit e6546d7
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 14 deletions.
4 changes: 4 additions & 0 deletions StripeConnect/StripeConnect.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
41814EEF2C6BEF2C0014EB5E /* FetchInitParamsMessageHandlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41814EEE2C6BEF2C0014EB5E /* FetchInitParamsMessageHandlerTests.swift */; };
41814EF12C6BF94B0014EB5E /* OnExitMessageHandlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41814EF02C6BF94B0014EB5E /* OnExitMessageHandlerTests.swift */; };
41814EF32C6BFA4B0014EB5E /* OnLoaderStartMessageHandlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41814EF22C6BFA4B0014EB5E /* OnLoaderStartMessageHandlerTests.swift */; };
418570562D13CA3700DE3FBE /* FinancialConnectionsPresenterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 418570552D13CA3400DE3FBE /* FinancialConnectionsPresenterTests.swift */; };
4186664A2C66AC66003DB62E /* OnSetterFunctionCalledMessageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 418666492C66AC66003DB62E /* OnSetterFunctionCalledMessageHandler.swift */; };
4186664C2C66AC8C003DB62E /* OnLoaderStartMessageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4186664B2C66AC8C003DB62E /* OnLoaderStartMessageHandler.swift */; };
4186664E2C66ACB3003DB62E /* OnLoadErrorMessageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4186664D2C66ACB3003DB62E /* OnLoadErrorMessageHandler.swift */; };
Expand Down Expand Up @@ -214,6 +215,7 @@
41814EEE2C6BEF2C0014EB5E /* FetchInitParamsMessageHandlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchInitParamsMessageHandlerTests.swift; sourceTree = "<group>"; };
41814EF02C6BF94B0014EB5E /* OnExitMessageHandlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnExitMessageHandlerTests.swift; sourceTree = "<group>"; };
41814EF22C6BFA4B0014EB5E /* OnLoaderStartMessageHandlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnLoaderStartMessageHandlerTests.swift; sourceTree = "<group>"; };
418570552D13CA3400DE3FBE /* FinancialConnectionsPresenterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FinancialConnectionsPresenterTests.swift; sourceTree = "<group>"; };
418666492C66AC66003DB62E /* OnSetterFunctionCalledMessageHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnSetterFunctionCalledMessageHandler.swift; sourceTree = "<group>"; };
4186664B2C66AC8C003DB62E /* OnLoaderStartMessageHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnLoaderStartMessageHandler.swift; sourceTree = "<group>"; };
4186664D2C66ACB3003DB62E /* OnLoadErrorMessageHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnLoadErrorMessageHandler.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -495,6 +497,7 @@
41814EE62C6BC8690014EB5E /* Internal */ = {
isa = PBXGroup;
children = (
418570552D13CA3400DE3FBE /* FinancialConnectionsPresenterTests.swift */,
E6660DBA2CDDC5BC002A7631 /* Analytics */,
E640C9D12CBF4790009D0C6E /* AuthenticatedWebView */,
E6660DBF2CDE7D48002A7631 /* Extensions */,
Expand Down Expand Up @@ -966,6 +969,7 @@
41814EF12C6BF94B0014EB5E /* OnExitMessageHandlerTests.swift in Sources */,
4161C2732C9D0A8A005BD67C /* AccountOnboardingViewControllerTests.swift in Sources */,
E6F485FE2C9E36B2000D914F /* PaymentDetailsViewControllerTests.swift in Sources */,
418570562D13CA3700DE3FBE /* FinancialConnectionsPresenterTests.swift in Sources */,
E6660CFB2CC2F438002A7631 /* SetCollectMobileFinancialConnectionsResultTests.swift in Sources */,
416E9E782C753B7900A0B917 /* ConnectComponentWebViewControllerTests.swift in Sources */,
410D0FD42C6D051B009B0E26 /* OpenAuthenticatedWebViewMessageHandlerTests.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,42 @@ import UIKit

/// Wraps `FinancialConnectionsSheet` for easy dependency injection in tests
class FinancialConnectionsPresenter {

@MainActor
func presentForToken(
apiClient: STPAPIClient,
@available(iOS 15, *)
func makeSheet(
componentManager: EmbeddedComponentManager,
clientSecret: String,
connectedAccountId: String,
from presentingViewController: UIViewController
) async -> FinancialConnectionsSheet.TokenResult {
let financialConnectionsSheet = FinancialConnectionsSheet(
financialConnectionsSessionClientSecret: clientSecret
)
) -> FinancialConnectionsSheet {
let financialConnectionsSheet: FinancialConnectionsSheet = .init(financialConnectionsSessionClientSecret: clientSecret)
// FC needs the connected account ID to be configured on the API Client
// Make a copy before modifying so we don't unexpectedly modify the shared API client
financialConnectionsSheet.apiClient = apiClient.makeCopy()
financialConnectionsSheet.apiClient = componentManager.apiClient.makeCopy()

// FC expects a public key and not a UK. If there is a public key override we should use that.
if let publicKeyOverride = componentManager.publicKeyOverride {
financialConnectionsSheet.apiClient.publishableKey = publicKeyOverride
}

financialConnectionsSheet.apiClient.stripeAccount = connectedAccountId

return financialConnectionsSheet
}

@MainActor
@available(iOS 15, *)
func presentForToken(
componentManager: EmbeddedComponentManager,
clientSecret: String,
connectedAccountId: String,
from presentingViewController: UIViewController
) async -> FinancialConnectionsSheet.TokenResult {
let financialConnectionsSheet = makeSheet(componentManager: componentManager,
clientSecret: clientSecret,
connectedAccountId: connectedAccountId,
from: presentingViewController)
return await withCheckedContinuation { continuation in
financialConnectionsSheet.presentForToken(from: presentingViewController) { result in
continuation.resume(returning: result)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ private extension ConnectComponentWebViewController {
func openFinancialConnections(_ args: OpenFinancialConnectionsMessageHandler.Payload) {
Task { @MainActor in
let result = await financialConnectionsPresenter.presentForToken(
apiClient: componentManager.apiClient,
componentManager: componentManager,
clientSecret: args.clientSecret,
connectedAccountId: args.connectedAccountId,
from: self
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//
// FinancialConnectionsPresenterTests.swift
// StripeConnect
//
// Created by Chris Mays on 12/18/24.
//
@_spi(PrivateBetaConnect) @_spi(DashboardOnly) @testable import StripeConnect
@testable import StripeFinancialConnections

import UIKit
import XCTest

class FinancialConnectionsPresenterTests: XCTestCase {

@MainActor
func testStandardPresent() {
let presenter = FinancialConnectionsPresenter()

let clientSecret = "client_secret"
let connectedAccountId = "account_1234"
let publishableKey = "pk_12"

let componentManager = EmbeddedComponentManager(apiClient: .init(publishableKey: publishableKey),
appearance: .default,
fonts: [],
fetchClientSecret: {return nil})

let sheet = presenter.makeSheet(componentManager: componentManager, clientSecret: clientSecret, connectedAccountId: connectedAccountId, from: .init())

XCTAssertEqual(sheet.apiClient.publishableKey, publishableKey)
XCTAssertEqual(sheet.apiClient.stripeAccount, connectedAccountId)
}

@MainActor
func testPresentWithPublicKeyOverride() {
let clientSecret = "client_secret"
let connectedAccountId = "account_1234"
let ukKey = "uk_123"
let publishableKey = "pk_12"

let presenter = FinancialConnectionsPresenter()
let componentManager = EmbeddedComponentManager(apiClient: .init(publishableKey: ukKey),
appearance: .default,
publicKeyOverride: publishableKey,
baseURLOverride: nil)

let sheet = presenter.makeSheet(componentManager: componentManager, clientSecret: clientSecret, connectedAccountId: connectedAccountId, from: .init())


XCTAssertEqual(sheet.apiClient.publishableKey, publishableKey)
XCTAssertEqual(sheet.apiClient.stripeAccount, connectedAccountId)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -463,8 +463,9 @@ class ConnectComponentWebViewControllerTests: XCTestCase {
let componentManager = componentManagerAssertingOnFetch()
let session = try FinancialConnectionsSessionMock.default.make()

let financialConnectionsPresenter = MockFinancialConnectionsPresenter { apiClient, secret, connectedAccountId, vc in
XCTAssert(apiClient === componentManager.apiClient)
let financialConnectionsPresenter = MockFinancialConnectionsPresenter { compManager, secret, connectedAccountId, vc in
XCTAssert(compManager.apiClient == componentManager.apiClient)
XCTAssert(compManager.publicKeyOverride == componentManager.publicKeyOverride)
XCTAssertEqual(secret, "client_secret_123")
XCTAssertEqual(connectedAccountId, "acct_1234")
XCTAssert(vc is ConnectComponentWebViewController)
Expand Down Expand Up @@ -588,14 +589,14 @@ private class MockAuthenticatedWebViewManager: AuthenticatedWebViewManager {

private class MockFinancialConnectionsPresenter: FinancialConnectionsPresenter {
var overridePresentForToken: (
_ apiClient: STPAPIClient,
_ componentManager: EmbeddedComponentManager,
_ clientSecret: String,
_ connectedAccountId: String,
_ presentingViewController: UIViewController
) async -> FinancialConnectionsSheet.TokenResult

init(overridePresentForToken: @escaping (
_ apiClient: STPAPIClient,
_ componentManager: EmbeddedComponentManager,
_ clientSecret: String,
_ connectedAccountId: String,
_ presentingViewController: UIViewController
Expand All @@ -604,11 +605,11 @@ private class MockFinancialConnectionsPresenter: FinancialConnectionsPresenter {
}

override func presentForToken(
apiClient: STPAPIClient,
componentManager: EmbeddedComponentManager,
clientSecret: String,
connectedAccountId: String,
from presentingViewController: UIViewController
) async -> FinancialConnectionsSheet.TokenResult {
await overridePresentForToken(apiClient, clientSecret, connectedAccountId, presentingViewController)
await overridePresentForToken(componentManager, clientSecret, connectedAccountId, presentingViewController)
}
}

0 comments on commit e6546d7

Please sign in to comment.