352 lines
14 KiB
Swift
352 lines
14 KiB
Swift
//
|
|
// STPPaymentOptionsViewControllerTest.swift
|
|
// StripeiOS Tests
|
|
//
|
|
// Created by Brian Dorfman on 10/10/17.
|
|
// Copyright © 2017 Stripe, Inc. All rights reserved.
|
|
//
|
|
|
|
import OCMock
|
|
|
|
@testable@_spi(STP) import Stripe
|
|
@testable@_spi(STP) import StripeCore
|
|
@testable@_spi(STP) import StripePayments
|
|
@testable@_spi(STP) import StripePaymentSheet
|
|
@testable@_spi(STP) import StripePaymentsUI
|
|
|
|
class STPPaymentOptionsViewControllerTest: XCTestCase {
|
|
class MockSTPPaymentOptionsViewControllerDelegate: NSObject,
|
|
STPPaymentOptionsViewControllerDelegate
|
|
{
|
|
var didFail = false
|
|
func paymentOptionsViewController(
|
|
_ paymentOptionsViewController: STPPaymentOptionsViewController,
|
|
didFailToLoadWithError error: Error
|
|
) {
|
|
didFail = true
|
|
}
|
|
|
|
var didFinish = false
|
|
func paymentOptionsViewControllerDidFinish(
|
|
_ paymentOptionsViewController: STPPaymentOptionsViewController
|
|
) {
|
|
didFinish = true
|
|
}
|
|
|
|
var didCancel = false
|
|
func paymentOptionsViewControllerDidCancel(
|
|
_ paymentOptionsViewController: STPPaymentOptionsViewController
|
|
) {
|
|
didCancel = true
|
|
}
|
|
|
|
var didSelect = false
|
|
func paymentOptionsViewController(
|
|
_ paymentOptionsViewController: STPPaymentOptionsViewController,
|
|
didSelect paymentOption: STPPaymentOption
|
|
) {
|
|
didSelect = true
|
|
}
|
|
}
|
|
|
|
func buildViewController(
|
|
with customer: STPCustomer,
|
|
paymentMethods: [STPPaymentMethod],
|
|
configuration config: STPPaymentConfiguration,
|
|
delegate: STPPaymentOptionsViewControllerDelegate
|
|
) -> STPPaymentOptionsViewController {
|
|
let mockCustomerContext = Testing_StaticCustomerContext(
|
|
customer: customer,
|
|
paymentMethods: paymentMethods
|
|
)
|
|
return buildViewController(
|
|
with: mockCustomerContext,
|
|
configuration: config,
|
|
delegate: delegate
|
|
)
|
|
}
|
|
|
|
func buildViewController(
|
|
with customerContext: STPCustomerContext,
|
|
configuration config: STPPaymentConfiguration,
|
|
delegate: STPPaymentOptionsViewControllerDelegate
|
|
) -> STPPaymentOptionsViewController {
|
|
let theme = STPTheme.defaultTheme
|
|
let vc = STPPaymentOptionsViewController(
|
|
configuration: config,
|
|
theme: theme,
|
|
customerContext: customerContext,
|
|
delegate: delegate
|
|
)
|
|
let didLoadExpectation = expectation(description: "VC did load")
|
|
vc.loadingPromise?.onSuccess({ (_) in
|
|
didLoadExpectation.fulfill()
|
|
})
|
|
|
|
wait(for: [didLoadExpectation], timeout: 2)
|
|
|
|
return vc
|
|
}
|
|
|
|
/// When the customer has no sources, and card is the sole available payment
|
|
/// method, STPAddCardViewController should be shown.
|
|
func testInitWithNoSourcesAndConfigWithUseSourcesOffAndCardAvailable() {
|
|
let customer = STPFixtures.customerWithNoSources()
|
|
let config = STPFixtures.paymentConfiguration()
|
|
config.applePayEnabled = false
|
|
let delegate = MockSTPPaymentOptionsViewControllerDelegate()
|
|
let sut = buildViewController(
|
|
with: customer,
|
|
paymentMethods: [],
|
|
configuration: config,
|
|
delegate: delegate
|
|
)
|
|
XCTAssertTrue((sut.internalViewController is STPAddCardViewController))
|
|
}
|
|
|
|
/// When the customer has a single card token source and the available payment methods
|
|
/// are card and apple pay, STPPaymentOptionsInternalVC should be shown.
|
|
func testInitWithSingleCardTokenSourceAndCardAvailable() {
|
|
let customer = STPFixtures.customerWithSingleCardTokenSource()
|
|
let paymentMethods = [STPFixtures.paymentMethod()]
|
|
let config = STPFixtures.paymentConfiguration()
|
|
let delegate = MockSTPPaymentOptionsViewControllerDelegate()
|
|
let sut = buildViewController(
|
|
with: customer,
|
|
paymentMethods: paymentMethods.compactMap { $0 },
|
|
configuration: config,
|
|
delegate: delegate
|
|
)
|
|
XCTAssertTrue((sut.internalViewController is STPPaymentOptionsInternalViewController))
|
|
}
|
|
|
|
/// When the customer has a single card source source and the available payment methods
|
|
/// are card only, STPPaymentOptionsInternalVC should be shown.
|
|
func testInitWithSingleCardSourceSourceAndCardAvailable() {
|
|
let customer = STPFixtures.customerWithSingleCardSourceSource()
|
|
let paymentMethods = [STPFixtures.paymentMethod()]
|
|
let config = STPFixtures.paymentConfiguration()
|
|
config.applePayEnabled = false
|
|
let delegate = MockSTPPaymentOptionsViewControllerDelegate()
|
|
let sut = buildViewController(
|
|
with: customer,
|
|
paymentMethods: paymentMethods.compactMap { $0 },
|
|
configuration: config,
|
|
delegate: delegate
|
|
)
|
|
XCTAssertTrue((sut.internalViewController is STPPaymentOptionsInternalViewController))
|
|
}
|
|
|
|
/// Tapping cancel in an internal AddCard view controller should result in a call to
|
|
/// didCancel:
|
|
func testAddCardCancelForwardsToDelegate() {
|
|
let customer = STPFixtures.customerWithNoSources()
|
|
let config = STPFixtures.paymentConfiguration()
|
|
let delegate = MockSTPPaymentOptionsViewControllerDelegate()
|
|
let sut = buildViewController(
|
|
with: customer,
|
|
paymentMethods: [],
|
|
configuration: config,
|
|
delegate: delegate
|
|
)
|
|
XCTAssertTrue((sut.internalViewController is STPAddCardViewController))
|
|
let cancelButton = sut.internalViewController?.navigationItem.leftBarButtonItem
|
|
cancelButton?.target?.perform(cancelButton?.action, with: cancelButton)
|
|
|
|
XCTAssertTrue(delegate.didCancel)
|
|
}
|
|
|
|
/// Tapping cancel in an internal PaymentOptionsInternal view controller should
|
|
/// result in a call to didCancel:
|
|
func testInternalCancelForwardsToDelegate() {
|
|
let customer = STPFixtures.customerWithSingleCardTokenSource()
|
|
let paymentMethods = [STPFixtures.paymentMethod()]
|
|
let config = STPFixtures.paymentConfiguration()
|
|
let delegate = MockSTPPaymentOptionsViewControllerDelegate()
|
|
let sut = buildViewController(
|
|
with: customer,
|
|
paymentMethods: paymentMethods.compactMap { $0 },
|
|
configuration: config,
|
|
delegate: delegate
|
|
)
|
|
XCTAssertTrue((sut.internalViewController is STPPaymentOptionsInternalViewController))
|
|
let cancelButton = sut.internalViewController?.navigationItem.leftBarButtonItem
|
|
_ = cancelButton?.target?.perform(cancelButton?.action, with: cancelButton)
|
|
|
|
XCTAssertTrue(delegate.didCancel)
|
|
}
|
|
|
|
/// When an AddCard view controller creates a card payment method, it should be attached to the
|
|
/// customer and the correct delegate methods should be called.
|
|
func testAddCardAttachesToCustomerAndFinishes() {
|
|
let config = STPFixtures.paymentConfiguration()
|
|
let customer = STPFixtures.customerWithNoSources()
|
|
let mockCustomerContext = Testing_StaticCustomerContext(
|
|
customer: customer,
|
|
paymentMethods: []
|
|
)
|
|
let delegate = MockSTPPaymentOptionsViewControllerDelegate()
|
|
let sut = buildViewController(
|
|
with: mockCustomerContext,
|
|
configuration: config,
|
|
delegate: delegate
|
|
)
|
|
XCTAssertNotNil(sut.view)
|
|
XCTAssertTrue((sut.internalViewController is STPAddCardViewController))
|
|
|
|
let internalVC = sut.internalViewController as? STPAddCardViewController
|
|
let exp = expectation(description: "completion")
|
|
let expectedPaymentMethod = STPFixtures.paymentMethod()
|
|
internalVC?.delegate?.addCardViewController(
|
|
internalVC!,
|
|
didCreatePaymentMethod: expectedPaymentMethod
|
|
) { error in
|
|
XCTAssertNil(error)
|
|
exp.fulfill()
|
|
}
|
|
|
|
let _: ((Any?) -> Bool)? = { obj in
|
|
let paymentMethod = obj as? STPPaymentMethod
|
|
return paymentMethod?.stripeId == expectedPaymentMethod.stripeId
|
|
}
|
|
XCTAssertTrue(mockCustomerContext.didAttach)
|
|
XCTAssertTrue(delegate.didSelect)
|
|
XCTAssertTrue(delegate.didFinish)
|
|
waitForExpectations(timeout: 2, handler: nil)
|
|
}
|
|
|
|
// Tests for race condition where the promise for fetching payment methods
|
|
// finishes in the context of intializing the sut, and `addCardViewControllerFooterView`
|
|
// is set directly after init, while internalViewController is `STPAddCardViewController`
|
|
func testSetAfterInit_addCardViewControllerFooterView_STPAddCardViewController() {
|
|
let customer = STPFixtures.customerWithNoSources()
|
|
let config = STPFixtures.paymentConfiguration()
|
|
config.applePayEnabled = false
|
|
let delegate = MockSTPPaymentOptionsViewControllerDelegate()
|
|
let sut = buildViewController(
|
|
with: customer,
|
|
paymentMethods: [],
|
|
configuration: config,
|
|
delegate: delegate
|
|
)
|
|
sut.addCardViewControllerFooterView = UIView()
|
|
guard let payMethodsInternal = sut.internalViewController as? STPAddCardViewController else {
|
|
XCTFail()
|
|
return
|
|
}
|
|
XCTAssertNotNil(payMethodsInternal.customFooterView)
|
|
}
|
|
|
|
// Tests for race condition where the promise for fetching payment methods
|
|
// finishes in the context of intializing the sut, and the `paymentOptionsViewControllerFooterView`
|
|
// is set directly after init, while internalViewController is `STPPaymentOptionsInternalViewController`
|
|
func testSetAfterInit_paymentOptionsViewControllerFooterView_STPPaymentOptionsInternalViewController() {
|
|
let customer = STPFixtures.customerWithSingleCardTokenSource()
|
|
let paymentMethods = [STPFixtures.paymentMethod()]
|
|
let config = STPFixtures.paymentConfiguration()
|
|
let delegate = MockSTPPaymentOptionsViewControllerDelegate()
|
|
let sut = buildViewController(
|
|
with: customer,
|
|
paymentMethods: paymentMethods.compactMap { $0 },
|
|
configuration: config,
|
|
delegate: delegate
|
|
)
|
|
sut.paymentOptionsViewControllerFooterView = UIView()
|
|
guard let payMethodsInternal = sut.internalViewController as? STPPaymentOptionsInternalViewController else {
|
|
XCTFail()
|
|
return
|
|
}
|
|
#if compiler(>=5.7)
|
|
XCTAssertNotNil(payMethodsInternal.customFooterView)
|
|
#endif
|
|
}
|
|
|
|
// Tests for race condition where the promise for fetching payment methods
|
|
// finishes in the context of init the sut, and the `addCardViewControllerFooterView`
|
|
// is set directly after init, while internalViewController is `STPPaymentOptionsInternalViewController`
|
|
func testSetAfterInit_addCardViewControllerFooterView_STPPaymentOptionsInternalViewController() {
|
|
let customer = STPFixtures.customerWithSingleCardTokenSource()
|
|
let paymentMethods = [STPFixtures.paymentMethod()]
|
|
let config = STPFixtures.paymentConfiguration()
|
|
let delegate = MockSTPPaymentOptionsViewControllerDelegate()
|
|
let sut = buildViewController(
|
|
with: customer,
|
|
paymentMethods: paymentMethods.compactMap { $0 },
|
|
configuration: config,
|
|
delegate: delegate
|
|
)
|
|
sut.addCardViewControllerFooterView = UIView()
|
|
guard let payMethodsInternal = sut.internalViewController as? STPPaymentOptionsInternalViewController else {
|
|
XCTFail()
|
|
return
|
|
}
|
|
#if compiler(>=5.7)
|
|
XCTAssertNotNil(payMethodsInternal.addCardViewControllerCustomFooterView)
|
|
#endif
|
|
}
|
|
|
|
// Tests for race condition where the promise for fetching payment methods
|
|
// finishes in the context of init the sut, and the `prefilledInformation`
|
|
// is set directly after init, while internalViewController is `STPPaymentOptionsInternalViewController`
|
|
func testSetAfterInit_prefilledInformation_STPPaymentOptionsInternalViewController() {
|
|
let customer = STPFixtures.customerWithSingleCardTokenSource()
|
|
let paymentMethods = [STPFixtures.paymentMethod()]
|
|
let config = STPFixtures.paymentConfiguration()
|
|
let delegate = MockSTPPaymentOptionsViewControllerDelegate()
|
|
let sut = buildViewController(
|
|
with: customer,
|
|
paymentMethods: paymentMethods.compactMap { $0 },
|
|
configuration: config,
|
|
delegate: delegate
|
|
)
|
|
let userInformation = STPUserInformation()
|
|
let address = STPAddress()
|
|
address.name = "John Doe"
|
|
address.line1 = "123 Main"
|
|
address.city = "Seattle"
|
|
address.state = "Washington"
|
|
address.postalCode = "98104"
|
|
address.phone = "2065551234"
|
|
userInformation.billingAddress = address
|
|
sut.prefilledInformation = userInformation
|
|
guard let payMethodsInternal = sut.internalViewController as? STPPaymentOptionsInternalViewController else {
|
|
XCTFail()
|
|
return
|
|
}
|
|
#if compiler(>=5.7)
|
|
XCTAssertNotNil(payMethodsInternal.prefilledInformation)
|
|
#endif
|
|
}
|
|
|
|
// Tests for race condition where the promise for fetching payment methods
|
|
// finishes in the context of init the sut, and the `prefilledInformation`
|
|
// is set directly after init, while internalViewController is `STPAddCardViewController`
|
|
func testSetAfterInit_prefilledInformation_STPAddCardViewController() {
|
|
let customer = STPFixtures.customerWithNoSources()
|
|
let config = STPFixtures.paymentConfiguration()
|
|
config.applePayEnabled = false
|
|
let delegate = MockSTPPaymentOptionsViewControllerDelegate()
|
|
let sut = buildViewController(
|
|
with: customer,
|
|
paymentMethods: [],
|
|
configuration: config,
|
|
delegate: delegate
|
|
)
|
|
let userInformation = STPUserInformation()
|
|
let address = STPAddress()
|
|
address.name = "John Doe"
|
|
address.line1 = "123 Main"
|
|
address.city = "Seattle"
|
|
address.state = "Washington"
|
|
address.postalCode = "98104"
|
|
address.phone = "2065551234"
|
|
userInformation.billingAddress = address
|
|
sut.prefilledInformation = userInformation
|
|
guard let payMethodsInternal = sut.internalViewController as? STPAddCardViewController else {
|
|
XCTFail()
|
|
return
|
|
}
|
|
XCTAssertNotNil(payMethodsInternal.prefilledInformation)
|
|
}
|
|
}
|