Skip to content

Commit 86fb191

Browse files
authored
chore Adding tests (#1470)
## Added tests - Drop-in reloading (partial payment) - Partial payment encoding/decoding
2 parents 4bbce20 + 09cd403 commit 86fb191

File tree

11 files changed

+269
-28
lines changed

11 files changed

+269
-28
lines changed

Adyen.xcodeproj/project.pbxproj

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@
156156
81825CC52AC59C6C00F91912 /* XCTestCase+Wait.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81825CC32AC59C6C00F91912 /* XCTestCase+Wait.swift */; };
157157
81896E852A4DB5F300C532CA /* SearchViewControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81896E842A4DB5F300C532CA /* SearchViewControllerTests.swift */; };
158158
8191838E2A53062F008EB61A /* FormAddressItem+Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8191838D2A53062F008EB61A /* FormAddressItem+Configuration.swift */; };
159+
819CC3342B14C53200D2EEE9 /* PaymentMethods+Equatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 819CC3332B14C53200D2EEE9 /* PaymentMethods+Equatable.swift */; };
159160
81A2E3BE2A5C453200CF5F9C /* LinkTextViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81A2E3BD2A5C453200CF5F9C /* LinkTextViewTests.swift */; };
160161
81A48DBB2A5709F600242341 /* DemoAddressLookupProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81A48DBA2A5709F600242341 /* DemoAddressLookupProvider.swift */; };
161162
81A48DBC2A5709F600242341 /* DemoAddressLookupProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81A48DBA2A5709F600242341 /* DemoAddressLookupProvider.swift */; };
@@ -1368,6 +1369,7 @@
13681369
81825CC32AC59C6C00F91912 /* XCTestCase+Wait.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "XCTestCase+Wait.swift"; sourceTree = "<group>"; };
13691370
81896E842A4DB5F300C532CA /* SearchViewControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchViewControllerTests.swift; sourceTree = "<group>"; };
13701371
8191838D2A53062F008EB61A /* FormAddressItem+Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FormAddressItem+Configuration.swift"; sourceTree = "<group>"; };
1372+
819CC3332B14C53200D2EEE9 /* PaymentMethods+Equatable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PaymentMethods+Equatable.swift"; sourceTree = "<group>"; };
13711373
81A2E3BD2A5C453200CF5F9C /* LinkTextViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinkTextViewTests.swift; sourceTree = "<group>"; };
13721374
81A2E3BF2A5C453F00CF5F9C /* LinkTextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinkTextView.swift; sourceTree = "<group>"; };
13731375
81A48DBA2A5709F600242341 /* DemoAddressLookupProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemoAddressLookupProvider.swift; sourceTree = "<group>"; };
@@ -2910,6 +2912,7 @@
29102912
A04E60D227E0E6280051C72C /* XCTestCase+Result.swift */,
29112913
00EACBC5288013990082B360 /* XCTestCase+Coder.swift */,
29122914
81B505782A7BE209009B4CB3 /* UIBarButtonItem+XCTest.swift */,
2915+
819CC3332B14C53200D2EEE9 /* PaymentMethods+Equatable.swift */,
29132916
);
29142917
path = Helpers;
29152918
sourceTree = "<group>";
@@ -3767,8 +3770,8 @@
37673770
F9EDB79023965FFC00CFB3C9 /* Payment Method List */,
37683771
E759E1F425CB373F00B1F8DC /* DropInTests.swift */,
37693772
F9EDB79D2397AEF400CFB3C9 /* ComponentManagerTests.swift */,
3770-
E7D189AF25D31936006AD3B7 /* DropInActionTests.swift */,
37713773
E74CE3DE26727EB1008231D2 /* DropInDelegateMock.swift */,
3774+
E7D189AF25D31936006AD3B7 /* DropInActionTests.swift */,
37723775
E767F4DB25A603A50077029E /* ModalToolbarTests.swift */,
37733776
E7620EAC23C3466B00A492C3 /* ModalViewControllerTests.swift */,
37743777
E7D5311B2447065B000046B4 /* PreselectedPaymentComponentTests.swift */,
@@ -6604,6 +6607,7 @@
66046607
81BBB34B2A692F6500AF1F9E /* FormPickerSearchViewControllerTests.swift in Sources */,
66056608
8109FF4E2AD6D8A9000748C8 /* MockAddressLookupProvider.swift in Sources */,
66066609
E72521EE25517EB100533E35 /* BLIKComponentTests.swift in Sources */,
6610+
819CC3342B14C53200D2EEE9 /* PaymentMethods+Equatable.swift in Sources */,
66076611
E2B317A22265BC9400C1BB30 /* LengthValidatorTests.swift in Sources */,
66086612
F9B019442611E965001F23FC /* EContextATMShareableVoucherViewProviderTests.swift in Sources */,
66096613
E9E3DAB2221D79C800697074 /* CardNumberFormatterTests.swift in Sources */,

AdyenDropIn/DropInComponent.swift

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,27 @@ public final class DropInComponent: NSObject,
6060
self.configuration = configuration
6161
self.context = context
6262
self.paymentMethods = paymentMethods
63+
64+
let scheduler = SimpleScheduler(maximumCount: 3)
65+
self.apiClient = APIClient(apiContext: context.apiContext)
66+
.retryAPIClient(with: scheduler)
67+
.retryOnErrorAPIClient()
68+
69+
super.init()
70+
}
71+
72+
/// For testing only
73+
internal init(paymentMethods: PaymentMethods,
74+
context: AdyenContext,
75+
configuration: Configuration = .init(),
76+
title: String? = nil,
77+
apiClient: APIClientProtocol) {
78+
self.title = title ?? Bundle.main.displayName
79+
self.configuration = configuration
80+
self.context = context
81+
self.paymentMethods = paymentMethods
82+
self.apiClient = apiClient
83+
6384
super.init()
6485
}
6586

@@ -92,12 +113,7 @@ public final class DropInComponent: NSObject,
92113

93114
// MARK: - Handling Partial Payments
94115

95-
private lazy var apiClient: APIClientProtocol = {
96-
let scheduler = SimpleScheduler(maximumCount: 3)
97-
return APIClient(apiContext: context.apiContext)
98-
.retryAPIClient(with: scheduler)
99-
.retryOnErrorAPIClient()
100-
}()
116+
private let apiClient: APIClientProtocol
101117

102118
internal func reloadComponentManager() {
103119
componentManager = createComponentManager(componentManager.order)

Demo/Common/Utils/APIClientMock.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,12 @@ internal final class APIClientMock: APIClientProtocol {
2323
self.onExecute?(request)
2424
switch nextResult {
2525
case let .success(response):
26-
guard let response = response as? R.ResponseType else { return }
26+
guard let response = response as? R.ResponseType else {
27+
fatalError("""
28+
The provided Response "\(response.self)" does not match \
29+
the ResponseType of the Request "\(R.ResponseType.self)"
30+
""")
31+
}
2732
completionHandler(.success(response))
2833
case let .failure(error):
2934
completionHandler(.failure(error))

Scripts/test-carthage-integration.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,10 @@ cp "../Tests/Card Tests/3DS2 Component/ThreeDSResultExtension.swift" Tests/Three
134134
cp "../Tests/Helpers/XCTestCase+RootViewController.swift" Tests/XCTestCase+RootViewController.swift
135135
cp "../Tests/Helpers/XCTestCase+Wait.swift" Tests/XCTestCase+Wait.swift
136136
cp "../Tests/Helpers/UIViewController+Search.swift" Tests/UIViewController+Search.swift
137+
cp "../Tests/Helpers/PaymentMethods+Equatable.swift" Tests/PaymentMethods+Equatable.swift
137138
cp "../Tests/Adyen Tests/Analytics/AnalyticsProviderMock.swift" Tests/AnalyticsProviderMock.swift
138139
cp "../Tests/DummyData/Dummy.swift" Tests/Dummy.swift
140+
cp "../Demo/Common/Utils/APIClientMock.swift" Tests/APIClientMock.swift
139141
cp -a "../Demo/Common" Source/
140142
cp -a "../Demo/UIKit" Source/
141143
cp "../Demo/Configuration.swift" Source/Configuration.swift

Tests/Adyen Tests/Mocks/PaymentComponentDelegateMock.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@
77
@_spi(AdyenInternal) @testable import Adyen
88

99
final class PaymentComponentDelegateMock: PaymentComponentDelegate {
10+
11+
init(
12+
onDidSubmit: ((PaymentComponentData, PaymentComponent) -> Void)? = nil,
13+
onDidFail: ((Error, PaymentComponent) -> Void)? = nil
14+
) {
15+
self.onDidSubmit = onDidSubmit
16+
self.onDidFail = onDidFail
17+
}
18+
1019
var onDidSubmit: ((PaymentComponentData, PaymentComponent) -> Void)?
1120
func didSubmit(_ data: PaymentComponentData, from component: PaymentComponent) {
1221
onDidSubmit?(data, component)

Tests/Card Tests/CardComponentTests.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1052,6 +1052,17 @@ class CardComponentTests: XCTestCase {
10521052
XCTAssertTrue(expDateItem.isValid())
10531053
}
10541054

1055+
func testInstallmentEncoding() throws {
1056+
1057+
let installments = Installments(totalMonths: 12, plan: .regular)
1058+
1059+
let installmentsData = try JSONEncoder().encode(installments)
1060+
let decodedInstallments = try XCTUnwrap(JSONSerialization.jsonObject(with: installmentsData) as? [String: Any])
1061+
1062+
XCTAssertEqual(decodedInstallments["value"] as? Int, installments.totalMonths)
1063+
XCTAssertEqual(decodedInstallments["plan"] as? String, installments.plan.rawValue)
1064+
}
1065+
10551066
func testInstallmentsWithDefaultAndCardBasedOptions() {
10561067
let cardBasedInstallmentOptions: [CardType: InstallmentOptions] = [.visa:
10571068
InstallmentOptions(maxInstallmentMonth: 8, includesRevolving: true)]

Tests/Components Tests/Gift Card/GiftCardComponentTests.swift

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -615,8 +615,53 @@ class GiftCardComponentTests: XCTestCase {
615615
XCTAssertNotNil(expiryDateItemView, "expiry date should still be shown when security code item is hidden")
616616
XCTAssertNil(securityCodeItemView)
617617
}
618+
619+
func testPartialConfirmationPaymentMethod() {
620+
621+
let giftCard = GiftCardPaymentMethod(type: .giftcard, name: "Giftcard", brand: "giftcard")
622+
623+
let paymentMethod = PartialConfirmationPaymentMethod(
624+
paymentMethod: giftCard,
625+
lastFour: "1234",
626+
remainingAmount: .init(value: 1000, currencyCode: "USD")
627+
)
628+
629+
XCTAssertEqual(paymentMethod.type, giftCard.type)
630+
631+
let displayInformation = paymentMethod.defaultDisplayInformation(using: nil)
632+
633+
XCTAssertEqual(displayInformation.title, "•••• 1234")
634+
XCTAssertEqual(displayInformation.logoName, giftCard.brand)
635+
XCTAssertEqual(displayInformation.accessibilityLabel, "Giftcard, Last 4 digits: 1, 2, 3, 4, Remaining balance will be $10.00")
636+
}
637+
638+
func testPartialPaymentOrder() throws {
639+
640+
let order = PartialPaymentOrder(
641+
pspReference: "psp-reference",
642+
orderData: "order-data",
643+
reference: "reference",
644+
amount: .init(value: 1000, currencyCode: "USD"),
645+
remainingAmount: .init(value: 500, currencyCode: "USD"),
646+
expiresAt: Date()
647+
)
648+
649+
let encodedOrder = try JSONEncoder().encode(order)
650+
let decodedOrder = try JSONDecoder().decode(PartialPaymentOrder.self, from: encodedOrder)
651+
652+
XCTAssertEqual(order.pspReference, decodedOrder.pspReference)
653+
XCTAssertEqual(order.orderData, decodedOrder.orderData)
654+
XCTAssertEqual(order.reference, decodedOrder.reference)
655+
XCTAssertEqual(order.amount, decodedOrder.amount)
656+
XCTAssertEqual(order.remainingAmount, decodedOrder.remainingAmount)
657+
XCTAssertNil(decodedOrder.expiresAt)
658+
XCTAssertEqual(order.compactOrder, decodedOrder.compactOrder)
659+
}
660+
}
618661

619-
private func populate(cardNumber: String, pin: String) {
662+
private extension GiftCardComponentTests {
663+
664+
func populate(cardNumber: String, pin: String) {
620665
populate(textItemView: numberItemView!, with: cardNumber)
621666
populate(textItemView: securityCodeItemView!, with: pin)
622667
}

Tests/DropIn Tests/DropInDelegateMock.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,22 @@
1111
import AdyenDropIn
1212

1313
class DropInDelegateMock: DropInComponentDelegate {
14+
15+
internal init(
16+
didSubmitHandler: ((PaymentComponentData, AnyDropInComponent) -> Void)? = nil,
17+
didProvideHandler: ((ActionComponentData, AnyDropInComponent) -> Void)? = nil,
18+
didCompleteHandler: ((AnyDropInComponent) -> Void)? = nil,
19+
didFailHandler: ((Error, AnyDropInComponent) -> Void)? = nil,
20+
didOpenExternalApplicationHandler: ((AnyDropInComponent) -> Void)? = nil,
21+
didCancelHandler: ((PaymentComponent, AnyDropInComponent) -> Void)? = nil
22+
) {
23+
self.didSubmitHandler = didSubmitHandler
24+
self.didProvideHandler = didProvideHandler
25+
self.didCompleteHandler = didCompleteHandler
26+
self.didFailHandler = didFailHandler
27+
self.didOpenExternalApplicationHandler = didOpenExternalApplicationHandler
28+
self.didCancelHandler = didCancelHandler
29+
}
1430

1531
var didSubmitHandler: ((PaymentComponentData, AnyDropInComponent) -> Void)?
1632
var didProvideHandler: ((ActionComponentData, AnyDropInComponent) -> Void)?

Tests/DropIn Tests/DropInTests.swift

Lines changed: 127 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
@_spi(AdyenInternal) @testable import Adyen
88
@_spi(AdyenInternal) @testable import AdyenActions
9-
import AdyenDropIn
9+
@testable import AdyenDropIn
1010
import SafariServices
1111
import XCTest
1212

@@ -130,6 +130,42 @@ class DropInTests: XCTestCase {
130130
}
131131
}
132132

133+
func testDropInStyle() throws {
134+
var style = DropInComponent.Style(tintColor: .brown)
135+
136+
XCTAssertEqual(style.formComponent.textField.tintColor, .brown)
137+
XCTAssertEqual(style.navigation.tintColor, .brown)
138+
139+
// MARK: Update separatorColor
140+
141+
style.separatorColor = .yellow
142+
143+
XCTAssertEqual(style.formComponent.separatorColor, .yellow)
144+
XCTAssertEqual(style.navigation.separatorColor, .yellow)
145+
146+
style.separatorColor = .green
147+
148+
/*
149+
In its current implementation calling `separatorColor` with multiple times with different colors
150+
won't have any effect. This might be unexpected but this tests confirms the current implementation detail.
151+
*/
152+
XCTAssertEqual(style.formComponent.separatorColor, .yellow)
153+
XCTAssertEqual(style.navigation.separatorColor, .yellow)
154+
155+
/*
156+
To be able to restore the initial behavior
157+
the `formComponent.separatorColor` and/or `navigation.separatorColor`
158+
have to be nilled out
159+
*/
160+
style.formComponent.separatorColor = nil
161+
style.navigation.separatorColor = nil
162+
163+
style.separatorColor = .green
164+
165+
XCTAssertEqual(style.formComponent.separatorColor, .green)
166+
XCTAssertEqual(style.navigation.separatorColor, .green)
167+
}
168+
133169
func testOpenDropInAsList() throws {
134170
let config = DropInComponent.Configuration()
135171

@@ -307,6 +343,96 @@ class DropInTests: XCTestCase {
307343

308344
wait(for: [waitExpectation], timeout: 30)
309345
}
346+
347+
func testReload() throws {
348+
349+
let config = DropInComponent.Configuration()
350+
351+
let paymentMethods = try JSONDecoder().decode(
352+
PaymentMethods.self,
353+
from: XCTUnwrap(DropInTests.paymentMethods.data(using: .utf8))
354+
)
355+
356+
let updatedPaymentMethods = try JSONDecoder().decode(
357+
PaymentMethods.self,
358+
from: XCTUnwrap(DropInTests.paymentMethodsWithSingleInstant.data(using: .utf8))
359+
)
360+
361+
let expectation = expectation(description: "Api Client Called")
362+
363+
let apiClient = APIClientMock()
364+
apiClient.mockedResults = [
365+
.success(OrderStatusResponse(
366+
remainingAmount: .init(value: 100, currencyCode: "EUR"),
367+
paymentMethods: nil
368+
))
369+
]
370+
apiClient.onExecute = {
371+
XCTAssertTrue($0 is OrderStatusRequest)
372+
expectation.fulfill()
373+
}
374+
375+
let sut = DropInComponent(
376+
paymentMethods: paymentMethods,
377+
context: Dummy.context,
378+
configuration: config,
379+
apiClient: apiClient
380+
)
381+
382+
try sut.reload(with: .init(pspReference: "", orderData: ""), updatedPaymentMethods)
383+
384+
wait(for: [expectation], timeout: 10)
385+
386+
XCTAssertEqual(sut.paymentMethods, updatedPaymentMethods)
387+
}
388+
389+
func testReloadFailure() throws {
390+
391+
let config = DropInComponent.Configuration()
392+
393+
let paymentMethods = try JSONDecoder().decode(
394+
PaymentMethods.self,
395+
from: XCTUnwrap(DropInTests.paymentMethods.data(using: .utf8))
396+
)
397+
398+
let updatedPaymentMethods = try JSONDecoder().decode(
399+
PaymentMethods.self,
400+
from: XCTUnwrap(DropInTests.paymentMethodsWithSingleInstant.data(using: .utf8))
401+
)
402+
403+
let apiClientExpectation = expectation(description: "Api Client Called")
404+
let failExpectation = expectation(description: "Delegate didFail Called")
405+
406+
let apiClient = APIClientMock()
407+
apiClient.mockedResults = [
408+
// Returning a random error so the reload fails
409+
.failure(APIError(status: nil, errorCode: "", errorMessage: "", type: .internal))
410+
]
411+
apiClient.onExecute = {
412+
XCTAssertTrue($0 is OrderStatusRequest)
413+
apiClientExpectation.fulfill()
414+
}
415+
416+
let sut = DropInComponent(
417+
paymentMethods: paymentMethods,
418+
context: Dummy.context,
419+
configuration: config,
420+
apiClient: apiClient
421+
)
422+
423+
let delegateMock = DropInDelegateMock(
424+
didFailHandler: { _, _ in
425+
failExpectation.fulfill()
426+
})
427+
428+
sut.delegate = delegateMock
429+
430+
try sut.reload(with: .init(pspReference: "", orderData: ""), updatedPaymentMethods)
431+
432+
wait(for: [apiClientExpectation, failExpectation], timeout: 10)
433+
434+
XCTAssertEqual(sut.paymentMethods, paymentMethods) // Should still be the old paymentMethods
435+
}
310436
}
311437

312438
extension UIViewController {
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//
2+
// Copyright (c) 2023 Adyen N.V.
3+
//
4+
// This file is open source and available under the MIT license. See the LICENSE file for more info.
5+
//
6+
7+
import Adyen
8+
9+
extension PaymentMethods: Equatable {
10+
public static func == (lhs: PaymentMethods, rhs: PaymentMethods) -> Bool {
11+
guard lhs.regular.count == rhs.regular.count else { return false }
12+
guard lhs.stored.count == rhs.stored.count else { return false }
13+
for (paymentMethod1, paymentMethod2) in zip(lhs.regular, rhs.regular) {
14+
if paymentMethod1 != paymentMethod2 {
15+
return false
16+
}
17+
}
18+
for (paymentMethod1, paymentMethod2) in zip(lhs.stored, rhs.stored) {
19+
if paymentMethod1 != paymentMethod2 {
20+
return false
21+
}
22+
}
23+
return true
24+
}
25+
}

0 commit comments

Comments
 (0)