diff --git a/.github/workflows/test-carthage-integration.yml b/.github/workflows/test-carthage-integration.yml index f5f663f4e2..be0d0e14a0 100644 --- a/.github/workflows/test-carthage-integration.yml +++ b/.github/workflows/test-carthage-integration.yml @@ -11,7 +11,7 @@ on: jobs: carthage: - runs-on: macos-12 + runs-on: macos-12-xl steps: - uses: actions/checkout@v4 - uses: n1hility/cancel-previous-runs@v3 diff --git a/.github/workflows/test_cocoapods_integration.yml b/.github/workflows/test_cocoapods_integration.yml index 976c7795d4..9a8c707bd6 100644 --- a/.github/workflows/test_cocoapods_integration.yml +++ b/.github/workflows/test_cocoapods_integration.yml @@ -11,7 +11,7 @@ on: jobs: pods: - runs-on: macos-12 + runs-on: macos-12-xl steps: - uses: actions/checkout@v4 - uses: n1hility/cancel-previous-runs@v3 diff --git a/Adyen.xcodeproj/project.pbxproj b/Adyen.xcodeproj/project.pbxproj index 8814c9442d..a81715380a 100644 --- a/Adyen.xcodeproj/project.pbxproj +++ b/Adyen.xcodeproj/project.pbxproj @@ -148,8 +148,6 @@ 8140A3762A3327B500896403 /* AdyenComponents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F9175E55259393E800D653BE /* AdyenComponents.framework */; }; 814276622A7145F50081E896 /* AddressInputFormViewController+ViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 814276612A7145F50081E896 /* AddressInputFormViewController+ViewModel.swift */; }; 8149CCB62B0B855F007235E2 /* ThreeDS2PlusDACoreActionHandlerTests+Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8149CCB52B0B855F007235E2 /* ThreeDS2PlusDACoreActionHandlerTests+Constants.swift */; }; - 81616BE52B271CF900D341FF /* FormVerticalStackItemView+IsValid.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81616BE32B271C8D00D341FF /* FormVerticalStackItemView+IsValid.swift */; }; - 81616BE62B271CFB00D341FF /* FormVerticalStackItemView+IsValid.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81616BE32B271C8D00D341FF /* FormVerticalStackItemView+IsValid.swift */; }; 8169B9EC2A0506CC00AAC9F8 /* Adyen.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E2C0E03322097917008616F6 /* Adyen.framework */; }; 81825CB82AC59C3300F91912 /* UIView+Search.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81825CB72AC59C3300F91912 /* UIView+Search.swift */; }; 81825CB92AC59C3300F91912 /* UIView+Search.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81825CB72AC59C3300F91912 /* UIView+Search.swift */; }; @@ -224,6 +222,7 @@ 81EF2FDF2AF3AAF1001FE82F /* InstantPaymentComponentExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81EF2FDD2AF3AAF1001FE82F /* InstantPaymentComponentExample.swift */; }; 81EF2FE12AF3D75C001FE82F /* InstantPaymentComponentAdvancedFlowExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81EF2FE02AF3D75C001FE82F /* InstantPaymentComponentAdvancedFlowExample.swift */; }; 81EF2FE22AF3D75C001FE82F /* InstantPaymentComponentAdvancedFlowExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81EF2FE02AF3D75C001FE82F /* InstantPaymentComponentAdvancedFlowExample.swift */; }; + 81F177AE2B4C49B9009CAD96 /* PresenterMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81F177AD2B4C49B9009CAD96 /* PresenterMock.swift */; }; 81F1EBA42AD97095002AA93F /* ListItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = E28098BF220DBF970087928F /* ListItem.swift */; }; 81FAFB442AAF715F00828999 /* Adyen.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E2C0E03322097917008616F6 /* Adyen.framework */; }; A009837D279859DC007E68C4 /* ACHDirectDebitComponentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A009837C279859DC007E68C4 /* ACHDirectDebitComponentTests.swift */; }; @@ -1415,7 +1414,6 @@ 813EF9EF2A6551C300C65D15 /* ViewControllerPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewControllerPresenter.swift; sourceTree = ""; }; 814276612A7145F50081E896 /* AddressInputFormViewController+ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AddressInputFormViewController+ViewModel.swift"; sourceTree = ""; }; 8149CCB52B0B855F007235E2 /* ThreeDS2PlusDACoreActionHandlerTests+Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ThreeDS2PlusDACoreActionHandlerTests+Constants.swift"; sourceTree = ""; }; - 81616BE32B271C8D00D341FF /* FormVerticalStackItemView+IsValid.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FormVerticalStackItemView+IsValid.swift"; sourceTree = ""; }; 81825CB72AC59C3300F91912 /* UIView+Search.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Search.swift"; sourceTree = ""; }; 81825CBA2AC59C4000F91912 /* UIViewController+Search.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIViewController+Search.swift"; sourceTree = ""; }; 81825CC02AC59C6400F91912 /* XCTestCase+RootViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "XCTestCase+RootViewController.swift"; sourceTree = ""; }; @@ -1467,6 +1465,7 @@ 81EA6C112A44836E0071A141 /* FormAddressItemTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormAddressItemTests.swift; sourceTree = ""; }; 81EF2FDD2AF3AAF1001FE82F /* InstantPaymentComponentExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstantPaymentComponentExample.swift; sourceTree = ""; }; 81EF2FE02AF3D75C001FE82F /* InstantPaymentComponentAdvancedFlowExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstantPaymentComponentAdvancedFlowExample.swift; sourceTree = ""; }; + 81F177AD2B4C49B9009CAD96 /* PresenterMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PresenterMock.swift; sourceTree = ""; }; A009837C279859DC007E68C4 /* ACHDirectDebitComponentTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ACHDirectDebitComponentTests.swift; sourceTree = ""; }; A009837E27986B50007E68C4 /* BankDetailsEncryptorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BankDetailsEncryptorTests.swift; sourceTree = ""; }; A0113D9A2763887800AD395C /* ActionNavigationBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionNavigationBar.swift; sourceTree = ""; }; @@ -2976,7 +2975,6 @@ 813BF1102B2364E00096940E /* XCTestCase+FirstResponder.swift */, 81B505782A7BE209009B4CB3 /* UIBarButtonItem+XCTest.swift */, 819CC3332B14C53200D2EEE9 /* PaymentMethods+Equatable.swift */, - 81616BE32B271C8D00D341FF /* FormVerticalStackItemView+IsValid.swift */, ); path = Helpers; sourceTree = ""; @@ -3980,6 +3978,7 @@ F99F08592383EAC800EBB948 /* FormatterMock.swift */, F9639B4824E28DC80073F38A /* IntervalCalculatorMock.swift */, F9EDB795239663F800CFB3C9 /* PaymentComponentMock.swift */, + 81F177AD2B4C49B9009CAD96 /* PresenterMock.swift */, F96A25422371AB75007DBF0B /* PaymentComponentDelegateMock.swift */, F9EDB793239663C200CFB3C9 /* PaymentMethodMock.swift */, F9639B5124E29E340073F38A /* PresentationDelegateMock.swift */, @@ -6799,6 +6798,7 @@ E216D3C7221AF5650013CBCF /* IBANFormatterTests.swift in Sources */, F9639B5024E29D2D0073F38A /* AwaitComponentTests.swift in Sources */, F97C83F725BF0C2800D7F85C /* DokuComponentTests.swift in Sources */, + 81F177AE2B4C49B9009CAD96 /* PresenterMock.swift in Sources */, F924C072246BEEF0006DDAB8 /* CardDetailsTests.swift in Sources */, F9FE39E32679E09200F02A9B /* LoadingViewTests.swift in Sources */, F96A25472372C39F007DBF0B /* ApplePayDetailsTest.swift in Sources */, @@ -6824,7 +6824,6 @@ C9C21914276767ED0042E9BE /* BACSConfirmationViewControllerTests.swift in Sources */, E7085C1E2629FDD700D0153B /* RedirectListnerTests.swift in Sources */, E74CE3DF26727EB1008231D2 /* DropInDelegateMock.swift in Sources */, - 81616BE62B271CFB00D341FF /* FormVerticalStackItemView+IsValid.swift in Sources */, A020EC5A29ED33F90050B2FE /* CashAppPayComponentTests.swift in Sources */, F967581527D25B1600A16FB6 /* SelfRetainingAPIClientTests.swift in Sources */, E262128D22A8FE6700F2B133 /* PaymentMethodTests.swift in Sources */, @@ -7294,7 +7293,6 @@ 0022095C29A4C65E00B2BACD /* BoletoComponentUITests.swift in Sources */, F9CCA3D2296ECCFA00AD643D /* XCTestCaseExtension.swift in Sources */, F9CCA3DE296ED1F400AD643D /* XCTestCase+SnapshotTesting.swift in Sources */, - 81616BE52B271CF900D341FF /* FormVerticalStackItemView+IsValid.swift in Sources */, 81825CBC2AC59C4000F91912 /* UIViewController+Search.swift in Sources */, F9CCA3C6296ECB9900AD643D /* QRCodeActionComponentUITests.swift in Sources */, 81825CB92AC59C3300F91912 /* UIView+Search.swift in Sources */, diff --git a/Adyen/Assets/Generated/LocalizationKey.swift b/Adyen/Assets/Generated/LocalizationKey.swift index 4659a289cd..01dd6c50c7 100644 --- a/Adyen/Assets/Generated/LocalizationKey.swift +++ b/Adyen/Assets/Generated/LocalizationKey.swift @@ -185,6 +185,8 @@ public struct LocalizationKey { public static let billingAddressPlaceholder = LocalizationKey(key: "adyen.billingAddress.placeholder") /// Delivery Address public static let deliveryAddressSectionTitle = LocalizationKey(key: "adyen.deliveryAddressSection.title") + /// Your delivery address + public static let deliveryAddressPlaceholder = LocalizationKey(key: "adyen.deliveryAddress.placeholder") /// Country public static let countryFieldTitle = LocalizationKey(key: "adyen.countryField.title") /// Country @@ -407,9 +409,9 @@ public struct LocalizationKey { public static let pickerSearchEmptyTitle = LocalizationKey(key: "adyen.picker.search.empty.title") /// '%@' did not match with anything public static let pickerSearchEmptySubtitle = LocalizationKey(key: "adyen.picker.search.empty.subtitle") - /// Search your address + /// Search for your address public static let addressLookupSearchPlaceholder = LocalizationKey(key: "adyen.address.lookup.search.placeholder") - /// Can't search your address? + /// Can't search for your address? public static let addressLookupSearchEmptyTitle = LocalizationKey(key: "adyen.address.lookup.search.empty.title") /// You can always #enter your address manually# public static let addressLookupSearchEmptySubtitle = LocalizationKey(key: "adyen.address.lookup.search.empty.subtitle") @@ -434,5 +436,4 @@ public struct LocalizationKey { } } - // swiftlint:enable all diff --git a/Adyen/Assets/ar.lproj/Localizable.strings b/Adyen/Assets/ar.lproj/Localizable.strings index 2d8dd948bd..0f38184d63 100644 --- a/Adyen/Assets/ar.lproj/Localizable.strings +++ b/Adyen/Assets/ar.lproj/Localizable.strings @@ -86,6 +86,7 @@ "adyen.billingAddressSection.title" = "عنوان الفواتير"; "adyen.billingAddress.placeholder" = "عنوانك الخاص بإرسال الفواتير"; "adyen.deliveryAddressSection.title" = "عنوان التسليم"; +"adyen.deliveryAddress.placeholder" = "عنوان التسليم الخاص بك"; "adyen.countryField.title" = "البلد"; "adyen.countryField.placeholder" = "البلد"; "adyen.countryField.invalid" = "بلد غير صحيح"; @@ -142,7 +143,7 @@ "adyen.card.installments.oneTime" = "الدفع مرة واحدة"; "adyen.card.installments.title" = "الدفع على أقساط"; "adyen.card.installments.revolving" = "الدفع الدوري"; -"adyen.card.installments.monthsAndPrice" = "%@ x %@"; +"adyen.card.installments.monthsAndPrice" = "%@ × %@"; "adyen.card.installments.months" = "%@ أشهر"; "adyen.card.installments.plan" = "طريقة الدفع"; "adyen.bacs.holderNameField.title" = "اسم صاحب الحساب البنكي"; diff --git a/Adyen/Assets/cs-CZ.lproj/Localizable.strings b/Adyen/Assets/cs-CZ.lproj/Localizable.strings index b692c422f3..8742e17b77 100644 --- a/Adyen/Assets/cs-CZ.lproj/Localizable.strings +++ b/Adyen/Assets/cs-CZ.lproj/Localizable.strings @@ -86,6 +86,7 @@ "adyen.billingAddressSection.title" = "Fakturační adresa"; "adyen.billingAddress.placeholder" = "Vaše fakturační adresa"; "adyen.deliveryAddressSection.title" = "Dodací adresa"; +"adyen.deliveryAddress.placeholder" = "Vaše doručovací adresa"; "adyen.countryField.title" = "Země"; "adyen.countryField.placeholder" = "Země"; "adyen.countryField.invalid" = "Neplatná země"; @@ -197,8 +198,8 @@ "adyen.threeds2.DA.approval.remove.alert.negativeButton" = "Zrušit"; "adyen.picker.search.empty.title" = "Nebyly nalezeny žádné výsledky"; "adyen.picker.search.empty.subtitle" = "„%@“ se s ničím neshoduje"; -"adyen.address.lookup.search.placeholder" = "Vyhledat vaši adresu"; -"adyen.address.lookup.search.empty.title" = "Nedaří se vám vyhledat vaši adresu?"; +"adyen.address.lookup.search.placeholder" = "Vyhledat svou adresu"; +"adyen.address.lookup.search.empty.title" = "Nemůžete najít svou adresu?"; "adyen.address.lookup.search.empty.subtitle" = "Vždy můžete #zadat svou adresu ručně#"; "adyen.address.lookup.search.empty.title.noResults" = "Nebyly nalezeny žádné výsledky"; "adyen.address.lookup.search.empty.subtitle.noResults" = "„%@“ se s ničím neshoduje, zkuste to znovu nebo použijte #ruční zadání adresy#"; diff --git a/Adyen/Assets/da-DK.lproj/Localizable.strings b/Adyen/Assets/da-DK.lproj/Localizable.strings index 457b627eac..7fb680f7f7 100644 --- a/Adyen/Assets/da-DK.lproj/Localizable.strings +++ b/Adyen/Assets/da-DK.lproj/Localizable.strings @@ -86,6 +86,7 @@ "adyen.billingAddressSection.title" = "Faktureringsadresse"; "adyen.billingAddress.placeholder" = "Din faktureringsadresse"; "adyen.deliveryAddressSection.title" = "Leveringsadresse"; +"adyen.deliveryAddress.placeholder" = "Din leveringsadresse"; "adyen.countryField.title" = "Land"; "adyen.countryField.placeholder" = "Land"; "adyen.countryField.invalid" = "Ugyldigt land"; @@ -197,8 +198,8 @@ "adyen.threeds2.DA.approval.remove.alert.negativeButton" = "Annuller"; "adyen.picker.search.empty.title" = "Ingen resultater fundet"; "adyen.picker.search.empty.subtitle" = "Fandt ikke noget match for '%@'"; -"adyen.address.lookup.search.placeholder" = "Søg på din adresse"; -"adyen.address.lookup.search.empty.title" = "Kan du ikke søge på din adresse?"; +"adyen.address.lookup.search.placeholder" = "Søg efter din adresse"; +"adyen.address.lookup.search.empty.title" = "Kan du ikke søge efter din adresse?"; "adyen.address.lookup.search.empty.subtitle" = "Du kan altid #indtaste din adresse manuelt#"; "adyen.address.lookup.search.empty.title.noResults" = "Ingen resultater fundet"; "adyen.address.lookup.search.empty.subtitle.noResults" = "Fandt ikke noget match for '%@'. Prøv igen eller #indtast adresse manuelt#."; diff --git a/Adyen/Assets/de-DE.lproj/Localizable.strings b/Adyen/Assets/de-DE.lproj/Localizable.strings index e80233c92a..89919cf3b3 100644 --- a/Adyen/Assets/de-DE.lproj/Localizable.strings +++ b/Adyen/Assets/de-DE.lproj/Localizable.strings @@ -1,4 +1,4 @@ -"adyen.submitButton" = "Zahlen"; +"adyen.submitButton" = "Zahle"; "adyen.submitButton.formatted" = "%@ zahlen"; "adyen.cancelButton" = "Abbrechen"; "adyen.dismissButton" = "OK"; @@ -86,6 +86,7 @@ "adyen.billingAddressSection.title" = "Rechnungsadresse"; "adyen.billingAddress.placeholder" = "Ihre Rechnungsadresse"; "adyen.deliveryAddressSection.title" = "Lieferadresse"; +"adyen.deliveryAddress.placeholder" = "Ihre Lieferadresse"; "adyen.countryField.title" = "Land"; "adyen.countryField.placeholder" = "Land"; "adyen.countryField.invalid" = "Ungültiges Land"; @@ -197,8 +198,8 @@ "adyen.threeds2.DA.approval.remove.alert.negativeButton" = "Abbrechen"; "adyen.picker.search.empty.title" = "Keine Ergebnisse gefunden"; "adyen.picker.search.empty.subtitle" = "'%@' stimmte mit nichts überein"; -"adyen.address.lookup.search.placeholder" = "Suchen Sie Ihre Adresse"; -"adyen.address.lookup.search.empty.title" = "Sie können Ihre Adresse nicht suchen?"; +"adyen.address.lookup.search.placeholder" = "Suchen Sie nach Ihrer Adresse"; +"adyen.address.lookup.search.empty.title" = "Sie können nicht nach Ihrer Adresse suchen?"; "adyen.address.lookup.search.empty.subtitle" = "Sie können Ihre Adresse jederzeit manuell #eingeben#"; "adyen.address.lookup.search.empty.title.noResults" = "Keine Ergebnisse gefunden"; "adyen.address.lookup.search.empty.subtitle.noResults" = "'%@' stimmt nicht mit irgendetwas überein, versuchen Sie es erneut oder verwenden Sie #manual address entry#"; diff --git a/Adyen/Assets/el-GR.lproj/Localizable.strings b/Adyen/Assets/el-GR.lproj/Localizable.strings index 67ade7e80b..10a80df0fa 100644 --- a/Adyen/Assets/el-GR.lproj/Localizable.strings +++ b/Adyen/Assets/el-GR.lproj/Localizable.strings @@ -86,6 +86,7 @@ "adyen.billingAddressSection.title" = "Διεύθυνση τιμολόγησης"; "adyen.billingAddress.placeholder" = "Η διεύθυνση τιμολόγησής σας"; "adyen.deliveryAddressSection.title" = "Διεύθυνση παράδοσης"; +"adyen.deliveryAddress.placeholder" = "Η διεύθυνση παράδοσής σας"; "adyen.countryField.title" = "Χώρα"; "adyen.countryField.placeholder" = "Χώρα"; "adyen.countryField.invalid" = "Μη έγκυρη χώρα"; @@ -198,7 +199,7 @@ "adyen.picker.search.empty.title" = "Δεν βρέθηκαν αποτελέσματα"; "adyen.picker.search.empty.subtitle" = "Ο όρος '%@' δεν ταιριάζει με τίποτα"; "adyen.address.lookup.search.placeholder" = "Αναζητήστε τη διεύθυνσή σας"; -"adyen.address.lookup.search.empty.title" = "Δεν μπορείτε να κάνετε αναζήτηση της διεύθυνσής σας;"; +"adyen.address.lookup.search.empty.title" = "Δεν μπορείτε να αναζητήσετε τη διεύθυνσή σας;"; "adyen.address.lookup.search.empty.subtitle" = "Μπορείτε πάντα να #εισαγάγετε τη διεύθυνσή σας μη αυτόματα#"; "adyen.address.lookup.search.empty.title.noResults" = "Δεν βρέθηκαν αποτελέσματα"; "adyen.address.lookup.search.empty.subtitle.noResults" = "Το '%@' δεν ταιριάζει με τίποτα. Προσπαθήστε ξανά ή χρησιμοποιήστε #μη αυτόματη εισαγωγή διεύθυνσης#"; diff --git a/Adyen/Assets/en-US.lproj/Localizable.strings b/Adyen/Assets/en-US.lproj/Localizable.strings index daa898c14c..52f97f7ff7 100644 --- a/Adyen/Assets/en-US.lproj/Localizable.strings +++ b/Adyen/Assets/en-US.lproj/Localizable.strings @@ -86,6 +86,7 @@ "adyen.billingAddressSection.title" = "Billing address"; "adyen.billingAddress.placeholder" = "Your billing address"; "adyen.deliveryAddressSection.title" = "Delivery Address"; +"adyen.deliveryAddress.placeholder" = "Your delivery address"; "adyen.countryField.title" = "Country"; "adyen.countryField.placeholder" = "Country"; "adyen.countryField.invalid" = "Invalid country"; @@ -197,8 +198,8 @@ "adyen.threeds2.DA.approval.remove.alert.negativeButton" = "Cancel"; "adyen.picker.search.empty.title" = "No results found"; "adyen.picker.search.empty.subtitle" = "'%@' did not match with anything"; -"adyen.address.lookup.search.placeholder" = "Search your address"; -"adyen.address.lookup.search.empty.title" = "Can't search your address?"; +"adyen.address.lookup.search.placeholder" = "Search for your address"; +"adyen.address.lookup.search.empty.title" = "Can't search for your address?"; "adyen.address.lookup.search.empty.subtitle" = "You can always #enter your address manually#"; "adyen.address.lookup.search.empty.title.noResults" = "No results found"; "adyen.address.lookup.search.empty.subtitle.noResults" = "'%@' did not match with anything, try again or use #manual address entry#"; diff --git a/Adyen/Assets/es-ES.lproj/Localizable.strings b/Adyen/Assets/es-ES.lproj/Localizable.strings index 0584679129..c7b1c8d346 100644 --- a/Adyen/Assets/es-ES.lproj/Localizable.strings +++ b/Adyen/Assets/es-ES.lproj/Localizable.strings @@ -86,6 +86,7 @@ "adyen.billingAddressSection.title" = "Dirección de facturación"; "adyen.billingAddress.placeholder" = "Su dirección de facturación"; "adyen.deliveryAddressSection.title" = "Dirección de envío"; +"adyen.deliveryAddress.placeholder" = "Su dirección de entrega"; "adyen.countryField.title" = "País"; "adyen.countryField.placeholder" = "País"; "adyen.countryField.invalid" = "País no válido"; diff --git a/Adyen/Assets/fi.lproj/Localizable.strings b/Adyen/Assets/fi.lproj/Localizable.strings index 25730e8f78..c225607b8f 100644 --- a/Adyen/Assets/fi.lproj/Localizable.strings +++ b/Adyen/Assets/fi.lproj/Localizable.strings @@ -86,6 +86,7 @@ "adyen.billingAddressSection.title" = "Laskutusosoite"; "adyen.billingAddress.placeholder" = "Laskutusosoitteesi"; "adyen.deliveryAddressSection.title" = "Toimitusosoite"; +"adyen.deliveryAddress.placeholder" = "Toimitusosoitteesi"; "adyen.countryField.title" = "Maa"; "adyen.countryField.placeholder" = "Maa"; "adyen.countryField.invalid" = "Virheellinen maa"; diff --git a/Adyen/Assets/fr-FR.lproj/Localizable.strings b/Adyen/Assets/fr-FR.lproj/Localizable.strings index c232946d2b..5dcdcd3393 100644 --- a/Adyen/Assets/fr-FR.lproj/Localizable.strings +++ b/Adyen/Assets/fr-FR.lproj/Localizable.strings @@ -86,6 +86,7 @@ "adyen.billingAddressSection.title" = "Adresse de facturation"; "adyen.billingAddress.placeholder" = "Votre adresse de facturation"; "adyen.deliveryAddressSection.title" = "Adresse de livraison"; +"adyen.deliveryAddress.placeholder" = "Votre adresse de livraison"; "adyen.countryField.title" = "Pays"; "adyen.countryField.placeholder" = "Pays"; "adyen.countryField.invalid" = "Pays non valide"; @@ -197,7 +198,7 @@ "adyen.threeds2.DA.approval.remove.alert.negativeButton" = "Annuler"; "adyen.picker.search.empty.title" = "Aucun résultat trouvé"; "adyen.picker.search.empty.subtitle" = "Aucune correspondance pour '%@'"; -"adyen.address.lookup.search.placeholder" = "Rechercher votre adresse"; +"adyen.address.lookup.search.placeholder" = "Recherchez votre adresse"; "adyen.address.lookup.search.empty.title" = "Vous ne pouvez pas rechercher votre adresse ?"; "adyen.address.lookup.search.empty.subtitle" = "Vous pouvez toujours #saisir votre adresse manuellement#"; "adyen.address.lookup.search.empty.title.noResults" = "Aucun résultat trouvé"; diff --git a/Adyen/Assets/hr-HR.lproj/Localizable.strings b/Adyen/Assets/hr-HR.lproj/Localizable.strings index e018dae378..3a744045ff 100644 --- a/Adyen/Assets/hr-HR.lproj/Localizable.strings +++ b/Adyen/Assets/hr-HR.lproj/Localizable.strings @@ -86,6 +86,7 @@ "adyen.billingAddressSection.title" = "Adresa za račun"; "adyen.billingAddress.placeholder" = "Vaša adresa za plaćanje"; "adyen.deliveryAddressSection.title" = "Adresa za dostavu"; +"adyen.deliveryAddress.placeholder" = "Vaša adresa za dostavu"; "adyen.countryField.title" = "Zemlja"; "adyen.countryField.placeholder" = "Zemlja"; "adyen.countryField.invalid" = "Nevažeća zemlja"; @@ -197,8 +198,8 @@ "adyen.threeds2.DA.approval.remove.alert.negativeButton" = "Otkaži"; "adyen.picker.search.empty.title" = "Nisu pronađeni rezultati"; "adyen.picker.search.empty.subtitle" = "'%@' ne podudara se s ničime"; -"adyen.address.lookup.search.placeholder" = "Pretraživanje vaše adrese"; -"adyen.address.lookup.search.empty.title" = "Ne možete pretražiti svoju adresu?"; +"adyen.address.lookup.search.placeholder" = "Potraži svoju adresu"; +"adyen.address.lookup.search.empty.title" = "Ne možeš potražiti svoju adresu?"; "adyen.address.lookup.search.empty.subtitle" = "Uvijek možete #ručno unijeti svoju adresu#"; "adyen.address.lookup.search.empty.title.noResults" = "Nisu pronađeni rezultati"; "adyen.address.lookup.search.empty.subtitle.noResults" = "'%@' nije se podudarao s ničime, pokušajte ponovno ili upotrijebite #ručni unos adrese#"; diff --git a/Adyen/Assets/hu-HU.lproj/Localizable.strings b/Adyen/Assets/hu-HU.lproj/Localizable.strings index 65b9398c2f..47be90af66 100644 --- a/Adyen/Assets/hu-HU.lproj/Localizable.strings +++ b/Adyen/Assets/hu-HU.lproj/Localizable.strings @@ -86,6 +86,7 @@ "adyen.billingAddressSection.title" = "Számlázási cím"; "adyen.billingAddress.placeholder" = "Az Ön számlázási címe"; "adyen.deliveryAddressSection.title" = "Szállítási cím"; +"adyen.deliveryAddress.placeholder" = "Az Ön szállítási címe"; "adyen.countryField.title" = "Ország"; "adyen.countryField.placeholder" = "Ország"; "adyen.countryField.invalid" = "Érvénytelen ország"; diff --git a/Adyen/Assets/it-IT.lproj/Localizable.strings b/Adyen/Assets/it-IT.lproj/Localizable.strings index 823b4dfd5d..3799842fba 100644 --- a/Adyen/Assets/it-IT.lproj/Localizable.strings +++ b/Adyen/Assets/it-IT.lproj/Localizable.strings @@ -86,6 +86,7 @@ "adyen.billingAddressSection.title" = "Indirizzo di fatturazione"; "adyen.billingAddress.placeholder" = "Il tuo indirizzo di fatturazione"; "adyen.deliveryAddressSection.title" = "Indirizzo di consegna"; +"adyen.deliveryAddress.placeholder" = "Il tuo indirizzo di consegna"; "adyen.countryField.title" = "Paese"; "adyen.countryField.placeholder" = "Paese"; "adyen.countryField.invalid" = "Paese non valido"; diff --git a/Adyen/Assets/ja-JP.lproj/Localizable.strings b/Adyen/Assets/ja-JP.lproj/Localizable.strings index b3b3c28d6e..862aeca3b2 100644 --- a/Adyen/Assets/ja-JP.lproj/Localizable.strings +++ b/Adyen/Assets/ja-JP.lproj/Localizable.strings @@ -69,7 +69,7 @@ "adyen.voucher.collectionInstitutionNumber" = "収納機関番号"; "adyen.voucher.merchantName" = "業者"; "adyen.voucher.expirationDate" = "有効期限"; -"adyen.voucher.paymentReferenceLabel" = "支払いの参照"; +"adyen.voucher.paymentReferenceLabel" = "確認番号"; "adyen.voucher.shopperName" = "購入者氏名"; "adyen.button.copy" = "コピー"; "adyen.voucher.introduction" = "お買い上げありがとうございます。以下の情報を使用して、お支払いを完了してください。"; @@ -86,6 +86,7 @@ "adyen.billingAddressSection.title" = "ご請求住所"; "adyen.billingAddress.placeholder" = "ご請求先住所"; "adyen.deliveryAddressSection.title" = "配送先住所"; +"adyen.deliveryAddress.placeholder" = "配送先住所"; "adyen.countryField.title" = "国"; "adyen.countryField.placeholder" = "国"; "adyen.countryField.invalid" = "国名が正しくありません"; diff --git a/Adyen/Assets/ko.lproj/Localizable.strings b/Adyen/Assets/ko.lproj/Localizable.strings index 99002a5606..4031f77a5c 100644 --- a/Adyen/Assets/ko.lproj/Localizable.strings +++ b/Adyen/Assets/ko.lproj/Localizable.strings @@ -86,6 +86,7 @@ "adyen.billingAddressSection.title" = "청구지 주소"; "adyen.billingAddress.placeholder" = "청구 주소"; "adyen.deliveryAddressSection.title" = "배송 주소"; +"adyen.deliveryAddress.placeholder" = "배송 주소"; "adyen.countryField.title" = "국가"; "adyen.countryField.placeholder" = "국가"; "adyen.countryField.invalid" = "잘못된 국가"; diff --git a/Adyen/Assets/nb-NO.lproj/Localizable.strings b/Adyen/Assets/nb-NO.lproj/Localizable.strings index 57d487182c..27160f7977 100644 --- a/Adyen/Assets/nb-NO.lproj/Localizable.strings +++ b/Adyen/Assets/nb-NO.lproj/Localizable.strings @@ -86,6 +86,7 @@ "adyen.billingAddressSection.title" = "Faktureringsadresse"; "adyen.billingAddress.placeholder" = "Faktureringsadressen din"; "adyen.deliveryAddressSection.title" = "Leveringsadresse"; +"adyen.deliveryAddress.placeholder" = "Leveringsadressen din"; "adyen.countryField.title" = "Land"; "adyen.countryField.placeholder" = "Land"; "adyen.countryField.invalid" = "Ugyldig land"; @@ -197,8 +198,8 @@ "adyen.threeds2.DA.approval.remove.alert.negativeButton" = "Avbryt"; "adyen.picker.search.empty.title" = "Fant ingen resultater"; "adyen.picker.search.empty.subtitle" = "Fikk ingen treff på «%@»"; -"adyen.address.lookup.search.placeholder" = "Søk på adressen din"; -"adyen.address.lookup.search.empty.title" = "Kan du ikke søke på adressen din?"; +"adyen.address.lookup.search.placeholder" = "Søk etter adressen din"; +"adyen.address.lookup.search.empty.title" = "Kan du ikke søke etter adressen din?"; "adyen.address.lookup.search.empty.subtitle" = "Du kan alltids #skrive inn adressen din manuelt#"; "adyen.address.lookup.search.empty.title.noResults" = "Fant ingen resultater"; "adyen.address.lookup.search.empty.subtitle.noResults" = "Fikk ingen treff på «%@». Prøv igjen eller #skriv inn adressen manuelt#"; diff --git a/Adyen/Assets/nl-NL.lproj/Localizable.strings b/Adyen/Assets/nl-NL.lproj/Localizable.strings index 2c57b3a3d9..5742cf168c 100644 --- a/Adyen/Assets/nl-NL.lproj/Localizable.strings +++ b/Adyen/Assets/nl-NL.lproj/Localizable.strings @@ -86,6 +86,7 @@ "adyen.billingAddressSection.title" = "Factuuradres"; "adyen.billingAddress.placeholder" = "Uw factuuradres"; "adyen.deliveryAddressSection.title" = "Bezorgadres"; +"adyen.deliveryAddress.placeholder" = "Uw bezorgadres"; "adyen.countryField.title" = "Land"; "adyen.countryField.placeholder" = "Land"; "adyen.countryField.invalid" = "Ongeldig land"; @@ -197,8 +198,8 @@ "adyen.threeds2.DA.approval.remove.alert.negativeButton" = "Annuleer"; "adyen.picker.search.empty.title" = "Geen resultaten gevonden"; "adyen.picker.search.empty.subtitle" = "Geen resultaten gevonden voor '%@'"; -"adyen.address.lookup.search.placeholder" = "Zoek uw adres"; -"adyen.address.lookup.search.empty.title" = "Werd uw adres niet gevonden?"; +"adyen.address.lookup.search.placeholder" = "Zoeken naar uw adres"; +"adyen.address.lookup.search.empty.title" = "Kunt u niet zoeken naar uw adres?"; "adyen.address.lookup.search.empty.subtitle" = "U kunt #uw adres handmatig invoeren#"; "adyen.address.lookup.search.empty.title.noResults" = "Geen resultaten gevonden"; "adyen.address.lookup.search.empty.subtitle.noResults" = "Geen resulaten gevonden voor '%@', probeer het opnieuw of gebruik #adres handmatig invoeren#"; diff --git a/Adyen/Assets/pl-PL.lproj/Localizable.strings b/Adyen/Assets/pl-PL.lproj/Localizable.strings index 4e0baadec9..9a22de0b47 100644 --- a/Adyen/Assets/pl-PL.lproj/Localizable.strings +++ b/Adyen/Assets/pl-PL.lproj/Localizable.strings @@ -86,6 +86,7 @@ "adyen.billingAddressSection.title" = "Adres rozliczeniowy"; "adyen.billingAddress.placeholder" = "Twój adres rozliczeniowy"; "adyen.deliveryAddressSection.title" = "Adres dostawy"; +"adyen.deliveryAddress.placeholder" = "Adres dostawy"; "adyen.countryField.title" = "Kraj"; "adyen.countryField.placeholder" = "Kraj"; "adyen.countryField.invalid" = "Nieprawidłowy kraj"; @@ -197,7 +198,7 @@ "adyen.threeds2.DA.approval.remove.alert.negativeButton" = "Anuluj"; "adyen.picker.search.empty.title" = "Nie znaleziono żadnych wyników"; "adyen.picker.search.empty.subtitle" = "Nie znaleziono żadnych dopasowań dla '%@'"; -"adyen.address.lookup.search.placeholder" = "Znajdź swój adres"; +"adyen.address.lookup.search.placeholder" = "Wyszukaj swój adres"; "adyen.address.lookup.search.empty.title" = "Nie możesz znaleźć swojego adresu?"; "adyen.address.lookup.search.empty.subtitle" = "Zawsze możesz #wprowadzić swój adres ręcznie#"; "adyen.address.lookup.search.empty.title.noResults" = "Nie znaleziono żadnych wyników"; diff --git a/Adyen/Assets/pt-BR.lproj/Localizable.strings b/Adyen/Assets/pt-BR.lproj/Localizable.strings index dc80dcf2c6..1aa3edefdc 100644 --- a/Adyen/Assets/pt-BR.lproj/Localizable.strings +++ b/Adyen/Assets/pt-BR.lproj/Localizable.strings @@ -86,6 +86,7 @@ "adyen.billingAddressSection.title" = "Endereço de cobrança"; "adyen.billingAddress.placeholder" = "Endereço de cobrança"; "adyen.deliveryAddressSection.title" = "Endereço de entrega"; +"adyen.deliveryAddress.placeholder" = "Seu endereço de entrega"; "adyen.countryField.title" = "País"; "adyen.countryField.placeholder" = "País"; "adyen.countryField.invalid" = "País inválido"; @@ -197,8 +198,8 @@ "adyen.threeds2.DA.approval.remove.alert.negativeButton" = "Cancelar"; "adyen.picker.search.empty.title" = "Nenhum resultado encontrado"; "adyen.picker.search.empty.subtitle" = "A pesquisa de '%@' não obteve resultados"; -"adyen.address.lookup.search.placeholder" = "Pesquise seu endereço"; -"adyen.address.lookup.search.empty.title" = "Não consegue pesquisar seu endereço?"; +"adyen.address.lookup.search.placeholder" = "Procure seu endereço"; +"adyen.address.lookup.search.empty.title" = "Não consegue encontrar seu endereço?"; "adyen.address.lookup.search.empty.subtitle" = "Você pode #inserir seu endereço manualmente#"; "adyen.address.lookup.search.empty.title.noResults" = "Nenhum resultado encontrado"; "adyen.address.lookup.search.empty.subtitle.noResults" = "A pesquisa de '%@' não obteve resultados. Tente novamente ou use #inserir endereço manualmente#"; diff --git a/Adyen/Assets/pt-PT.lproj/Localizable.strings b/Adyen/Assets/pt-PT.lproj/Localizable.strings index 5bd683ebe3..67c29fffef 100644 --- a/Adyen/Assets/pt-PT.lproj/Localizable.strings +++ b/Adyen/Assets/pt-PT.lproj/Localizable.strings @@ -86,6 +86,7 @@ "adyen.billingAddressSection.title" = "Morada de cobrança"; "adyen.billingAddress.placeholder" = "O seu endereço de faturação"; "adyen.deliveryAddressSection.title" = "Morada de entrega"; +"adyen.deliveryAddress.placeholder" = "A sua morada de entrega"; "adyen.countryField.title" = "País"; "adyen.countryField.placeholder" = "País"; "adyen.countryField.invalid" = "País inválido"; diff --git a/Adyen/Assets/ro-RO.lproj/Localizable.strings b/Adyen/Assets/ro-RO.lproj/Localizable.strings index 13d51ed5eb..837d667bae 100644 --- a/Adyen/Assets/ro-RO.lproj/Localizable.strings +++ b/Adyen/Assets/ro-RO.lproj/Localizable.strings @@ -86,6 +86,7 @@ "adyen.billingAddressSection.title" = "Adresa de facturare"; "adyen.billingAddress.placeholder" = "Adresa dvs. de facturare"; "adyen.deliveryAddressSection.title" = "Adresă de livrare"; +"adyen.deliveryAddress.placeholder" = "Adresa dvs. de livrare"; "adyen.countryField.title" = "Țară"; "adyen.countryField.placeholder" = "Țară"; "adyen.countryField.invalid" = "Țară incorectă"; diff --git a/Adyen/Assets/ru-RU.lproj/Localizable.strings b/Adyen/Assets/ru-RU.lproj/Localizable.strings index f721ada383..861acfe377 100644 --- a/Adyen/Assets/ru-RU.lproj/Localizable.strings +++ b/Adyen/Assets/ru-RU.lproj/Localizable.strings @@ -86,6 +86,7 @@ "adyen.billingAddressSection.title" = "Платежный адрес"; "adyen.billingAddress.placeholder" = "Ваш платежный адрес"; "adyen.deliveryAddressSection.title" = "Адрес доставки"; +"adyen.deliveryAddress.placeholder" = "Ваш адрес доставки"; "adyen.countryField.title" = "Страна"; "adyen.countryField.placeholder" = "Страна"; "adyen.countryField.invalid" = "Неправильная страна"; @@ -197,8 +198,8 @@ "adyen.threeds2.DA.approval.remove.alert.negativeButton" = "Отменить"; "adyen.picker.search.empty.title" = "Результаты не найдены"; "adyen.picker.search.empty.subtitle" = "Не найдено соответствий «%@»"; -"adyen.address.lookup.search.placeholder" = "Поиск по адресу"; -"adyen.address.lookup.search.empty.title" = "Не можете найти адрес?"; +"adyen.address.lookup.search.placeholder" = "Найдите свой адрес"; +"adyen.address.lookup.search.empty.title" = "Не удается найти адрес?"; "adyen.address.lookup.search.empty.subtitle" = "Можно #ввести адрес вручную#"; "adyen.address.lookup.search.empty.title.noResults" = "Результаты не найдены"; "adyen.address.lookup.search.empty.subtitle.noResults" = "Не найдено соответствий «%@». Повторите попытку или используйте #ручной ввод адреса#"; diff --git a/Adyen/Assets/sk-SK.lproj/Localizable.strings b/Adyen/Assets/sk-SK.lproj/Localizable.strings index 48eaa8d1fd..e88892075c 100644 --- a/Adyen/Assets/sk-SK.lproj/Localizable.strings +++ b/Adyen/Assets/sk-SK.lproj/Localizable.strings @@ -86,6 +86,7 @@ "adyen.billingAddressSection.title" = "Fakturačná adresa"; "adyen.billingAddress.placeholder" = "Vaša fakturačná adresa"; "adyen.deliveryAddressSection.title" = "Dodacia adresa"; +"adyen.deliveryAddress.placeholder" = "Vaša dodacia adresa"; "adyen.countryField.title" = "Krajina"; "adyen.countryField.placeholder" = "Krajina"; "adyen.countryField.invalid" = "Neplatná krajina"; diff --git a/Adyen/Assets/sl-SI.lproj/Localizable.strings b/Adyen/Assets/sl-SI.lproj/Localizable.strings index 9315d6948d..da060ced8e 100644 --- a/Adyen/Assets/sl-SI.lproj/Localizable.strings +++ b/Adyen/Assets/sl-SI.lproj/Localizable.strings @@ -86,6 +86,7 @@ "adyen.billingAddressSection.title" = "Naslov za račun"; "adyen.billingAddress.placeholder" = "Vaš naslov za račun"; "adyen.deliveryAddressSection.title" = "Naslov za dostavo"; +"adyen.deliveryAddress.placeholder" = "Vaš naslov za dostavo"; "adyen.countryField.title" = "Država"; "adyen.countryField.placeholder" = "Država"; "adyen.countryField.invalid" = "Neveljavna država"; @@ -198,7 +199,7 @@ "adyen.picker.search.empty.title" = "Nobenega rezultata ni bilo mogoče najti"; "adyen.picker.search.empty.subtitle" = "»%@« se ni ujemalo z ničemer"; "adyen.address.lookup.search.placeholder" = "Poiščite svoj naslov"; -"adyen.address.lookup.search.empty.title" = "Ne morete iskati svojega naslova?"; +"adyen.address.lookup.search.empty.title" = "Ne morete poiskati svojega naslova?"; "adyen.address.lookup.search.empty.subtitle" = "Vedno lahko #ročno vnesete svoj naslov#"; "adyen.address.lookup.search.empty.title.noResults" = "Nobenega rezultata ni bilo mogoče najti"; "adyen.address.lookup.search.empty.subtitle.noResults" = "»%@« se ni ujemalo z ničemer, poskusite znova ali uporabite #ročni vnos naslova#"; diff --git a/Adyen/Assets/sv-SE.lproj/Localizable.strings b/Adyen/Assets/sv-SE.lproj/Localizable.strings index 37b62a2d70..2861413e65 100644 --- a/Adyen/Assets/sv-SE.lproj/Localizable.strings +++ b/Adyen/Assets/sv-SE.lproj/Localizable.strings @@ -86,6 +86,7 @@ "adyen.billingAddressSection.title" = "Faktureringsadress"; "adyen.billingAddress.placeholder" = "Din faktureringsadress"; "adyen.deliveryAddressSection.title" = "Leveransadress"; +"adyen.deliveryAddress.placeholder" = "Din leveransadress"; "adyen.countryField.title" = "Land"; "adyen.countryField.placeholder" = "Land"; "adyen.countryField.invalid" = "Ogiltigt land"; @@ -197,7 +198,7 @@ "adyen.threeds2.DA.approval.remove.alert.negativeButton" = "Avbryt"; "adyen.picker.search.empty.title" = "Inga resultat hittades"; "adyen.picker.search.empty.subtitle" = "Det finns inga matchningar för ”%@”"; -"adyen.address.lookup.search.placeholder" = "Sök upp din adress"; +"adyen.address.lookup.search.placeholder" = "Sök efter din adress"; "adyen.address.lookup.search.empty.title" = "Kan du inte söka efter din adress?"; "adyen.address.lookup.search.empty.subtitle" = "Du kan alltid #ange din adress manuellt#"; "adyen.address.lookup.search.empty.title.noResults" = "Inga resultat hittades"; diff --git a/Adyen/Assets/zh-CN.lproj/Localizable.strings b/Adyen/Assets/zh-CN.lproj/Localizable.strings index dfcd609da6..6db71021f0 100644 --- a/Adyen/Assets/zh-CN.lproj/Localizable.strings +++ b/Adyen/Assets/zh-CN.lproj/Localizable.strings @@ -83,6 +83,7 @@ "adyen.billingAddressSection.title" = "账单地址"; "adyen.billingAddress.placeholder" = "您的账单地址"; "adyen.deliveryAddressSection.title" = "寄送地址"; +"adyen.deliveryAddress.placeholder" = "您的送货地址"; "adyen.countryField.title" = "国家/地区"; "adyen.countryField.placeholder" = "国家/地区"; "adyen.countryField.invalid" = "无效国家/地区"; diff --git a/Adyen/Assets/zh-TW.lproj/Localizable.strings b/Adyen/Assets/zh-TW.lproj/Localizable.strings index a01afdbd53..2b4ebb84f5 100644 --- a/Adyen/Assets/zh-TW.lproj/Localizable.strings +++ b/Adyen/Assets/zh-TW.lproj/Localizable.strings @@ -82,6 +82,7 @@ "adyen.billingAddressSection.title" = "帳單地址"; "adyen.billingAddress.placeholder" = "您的帳單地址"; "adyen.deliveryAddressSection.title" = "派送地址"; +"adyen.deliveryAddress.placeholder" = "您的派送地址"; "adyen.countryField.title" = "國家/地區"; "adyen.countryField.placeholder" = "國家/地區"; "adyen.countryField.invalid" = "國家/地區無效"; diff --git a/Adyen/Core/Components/AbstractPersonalInformationComponent/AbstractPersonalInformationComponent.swift b/Adyen/Core/Components/AbstractPersonalInformationComponent/AbstractPersonalInformationComponent.swift index 4941f5bc3c..749d022c22 100644 --- a/Adyen/Core/Components/AbstractPersonalInformationComponent/AbstractPersonalInformationComponent.swift +++ b/Adyen/Core/Components/AbstractPersonalInformationComponent/AbstractPersonalInformationComponent.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2023 Adyen N.V. +// Copyright (c) 2024 Adyen N.V. // // This file is open source and available under the MIT license. See the LICENSE file for more info. // @@ -76,8 +76,10 @@ open class AbstractPersonalInformationComponent: PaymentComponent, PresentableCo formViewController.append(FormSpacerItem(numberOfSpaces: 2)) } - private func add(_ field: PersonalInformation, - into formViewController: FormViewController) { + private func add( + _ field: PersonalInformation, + into formViewController: FormViewController + ) { switch field { case .email: emailItemInjector?.inject(into: formViewController) @@ -146,13 +148,14 @@ open class AbstractPersonalInformationComponent: PaymentComponent, PresentableCo return AddressFormItemInjector(value: configuration.shopperInformation?.billingAddress, initialCountry: initialCountry, identifier: identifier, - style: configuration.style.addressStyle, + style: configuration.style, presenter: self, - addressViewModelBuilder: addressViewModelBuilder()) + addressViewModelBuilder: addressViewModelBuilder(), + addressType: .billing) }() @_spi(AdyenInternal) - public var addressItem: FormAddressItem? { addressItemInjector?.item } + public var addressItem: FormAddressPickerItem? { addressItemInjector?.item } internal lazy var deliveryAddressItemInjector: AddressFormItemInjector? = { guard fields.contains(.deliveryAddress) else { return nil } @@ -161,13 +164,14 @@ open class AbstractPersonalInformationComponent: PaymentComponent, PresentableCo return AddressFormItemInjector(value: configuration.shopperInformation?.deliveryAddress, initialCountry: initialCountry, identifier: identifier, - style: configuration.style.addressStyle, + style: configuration.style, presenter: self, - addressViewModelBuilder: addressViewModelBuilder()) + addressViewModelBuilder: addressViewModelBuilder(), + addressType: .delivery) }() @_spi(AdyenInternal) - public var deliveryAddressItem: FormAddressItem? { deliveryAddressItemInjector?.item } + public var deliveryAddressItem: FormAddressPickerItem? { deliveryAddressItemInjector?.item } internal lazy var phoneItemInjector: PhoneFormItemInjector? = { guard fields.contains(.phone) else { return nil } diff --git a/Adyen/Core/Components/AbstractPersonalInformationComponent/AddressFormItemInjector.swift b/Adyen/Core/Components/AbstractPersonalInformationComponent/AddressFormItemInjector.swift index 81b63927d2..ca2ddf46c1 100644 --- a/Adyen/Core/Components/AbstractPersonalInformationComponent/AddressFormItemInjector.swift +++ b/Adyen/Core/Components/AbstractPersonalInformationComponent/AddressFormItemInjector.swift @@ -1,10 +1,10 @@ // -// Copyright (c) 2023 Adyen N.V. +// Copyright (c) 2024 Adyen N.V. // // This file is open source and available under the MIT license. See the LICENSE file for more info. // -import Foundation +import UIKit internal final class AddressFormItemInjector: FormItemInjector, Localizable { @@ -16,37 +16,45 @@ internal final class AddressFormItemInjector: FormItemInjector, Localizable { internal var identifier: String - internal let style: AddressStyle + internal let style: FormComponentStyle internal let addressViewModelBuilder: AddressViewModelBuilder private weak var presenter: ViewControllerPresenter? + + private let addressType: FormAddressPickerItem.AddressType - internal lazy var item: FormAddressItem = { - let addressItem = FormAddressItem(initialCountry: initialCountry, - configuration: .init( - style: style, - localizationParameters: localizationParameters - ), - identifier: identifier, - presenter: presenter, - addressViewModelBuilder: addressViewModelBuilder) - value.map { addressItem.value = $0 } - return addressItem + internal lazy var item: FormAddressPickerItem = { + .init( + for: addressType, + initialCountry: initialCountry, + supportedCountryCodes: nil, + prefillAddress: value, + style: style, + localizationParameters: localizationParameters, + identifier: identifier, + addressViewModelBuilder: addressViewModelBuilder, + presenter: self, + lookupProvider: nil + ) }() - internal init(value: PostalAddress?, - initialCountry: String, - identifier: String, - style: AddressStyle, - presenter: ViewControllerPresenter?, - addressViewModelBuilder: AddressViewModelBuilder) { + internal init( + value: PostalAddress?, + initialCountry: String, + identifier: String, + style: FormComponentStyle, + presenter: ViewControllerPresenter?, + addressViewModelBuilder: AddressViewModelBuilder, + addressType: FormAddressPickerItem.AddressType + ) { self.value = value self.initialCountry = initialCountry self.identifier = identifier self.style = style self.presenter = presenter self.addressViewModelBuilder = addressViewModelBuilder + self.addressType = addressType } internal func inject(into formViewController: FormViewController) { @@ -54,3 +62,14 @@ internal final class AddressFormItemInjector: FormItemInjector, Localizable { } } + +extension AddressFormItemInjector: ViewControllerPresenter { + + internal func presentViewController(_ viewController: UIViewController, animated: Bool) { + presenter?.presentViewController(viewController, animated: animated) + } + + internal func dismissViewController(animated: Bool) { + presenter?.dismissViewController(animated: animated) + } +} diff --git a/Adyen/Core/Core Protocols/ViewControllerPresenter.swift b/Adyen/Core/Core Protocols/ViewControllerPresenter.swift index 0133baa5b7..568cf20819 100644 --- a/Adyen/Core/Core Protocols/ViewControllerPresenter.swift +++ b/Adyen/Core/Core Protocols/ViewControllerPresenter.swift @@ -24,3 +24,25 @@ extension UIViewController: ViewControllerPresenter { self.dismiss(animated: animated) } } + +/// Wrapper class that holds onto a weak reference of ``ViewControllerPresenter``. +/// It conforms to ``ViewControllerPresenter`` itself and forwards all ``ViewControllerPresenter`` calls to the reference. +/// +/// To be used in places where a non optional presenter is required (e.g. to instantiate a different object) +@_spi(AdyenInternal) +public class WeakReferenceViewControllerPresenter: ViewControllerPresenter { + + private weak var presenter: ViewControllerPresenter? + + public init(_ presenter: ViewControllerPresenter) { + self.presenter = presenter + } + + public func presentViewController(_ viewController: UIViewController, animated: Bool) { + presenter?.presentViewController(viewController, animated: animated) + } + + public func dismissViewController(animated: Bool) { + presenter?.dismissViewController(animated: animated) + } +} diff --git a/Adyen/UI/Form/Items/Address/Picker/FormAddressPickerItem.swift b/Adyen/UI/Form/Items/Address/Picker/FormAddressPickerItem.swift index 95ed982303..6ca33b95a6 100644 --- a/Adyen/UI/Form/Items/Address/Picker/FormAddressPickerItem.swift +++ b/Adyen/UI/Form/Items/Address/Picker/FormAddressPickerItem.swift @@ -1,18 +1,27 @@ // -// Copyright (c) 2023 Adyen N.V. +// Copyright (c) 2024 Adyen N.V. // // This file is open source and available under the MIT license. See the LICENSE file for more info. // -import Foundation +import UIKit /// An address form item that allows picking an address on a separate screen. @_spi(AdyenInternal) -public final class FormAddressPickerItem: FormSelectableValueItem { +public final class FormAddressPickerItem: FormSelectableValueItem, Hidable { + + public var isHidden: AdyenObservable = AdyenObservable(false) + + public enum AddressType { + case billing + case delivery + } private var initialCountry: String private var context: AddressViewModelBuilderContext private let localizationParameters: LocalizationParameters? + private let addressViewModelBuilder: AddressViewModelBuilder + private weak var presenter: ViewControllerPresenter? /// The view model to validate the address with @_spi(AdyenInternal) @@ -20,8 +29,6 @@ public final class FormAddressPickerItem: FormSelectableValueItem Void + ) { + let securedViewController = SecuredViewController( + child: addressPickerViewController( + for: addressType, + with: prefillAddress, + initialCountry: initialCountry, + supportedCountryCodes: supportedCountryCodes, + lookupProvider: lookupProvider, + style: style, + completionHandler: { [weak presenter] address in + completion(address) + presenter?.dismissViewController(animated: true) + } + ), + style: style + ) + + presenter.presentViewController(securedViewController, animated: true) + } + + private func addressPickerViewController( + for addressType: FormAddressPickerItem.AddressType, + with prefillAddress: PostalAddress?, + initialCountry: String, + supportedCountryCodes: [String]?, + lookupProvider: AddressLookupProvider?, + style: FormComponentStyle, + completionHandler: @escaping (PostalAddress?) -> Void + ) -> UIViewController { + + guard let lookupProvider else { + + let viewModel = AddressInputFormViewController.ViewModel( + for: addressType, + style: style, + localizationParameters: localizationParameters, + initialCountry: initialCountry, + prefillAddress: prefillAddress, + supportedCountryCodes: supportedCountryCodes, + addressViewModelBuilder: addressViewModelBuilder, + handleShowSearch: nil, + completionHandler: completionHandler + ) + + return UINavigationController( + rootViewController: AddressInputFormViewController(viewModel: viewModel) + ) + } + + let viewModel = AddressLookupViewController.ViewModel( + for: addressType, + style: .init(form: style), + localizationParameters: localizationParameters, + supportedCountryCodes: supportedCountryCodes, + initialCountry: initialCountry, + prefillAddress: prefillAddress, + lookupProvider: lookupProvider, + completionHandler: completionHandler + ) + + return AddressLookupViewController(viewModel: viewModel) + } +} + +// MARK: - AddressType + +public extension FormAddressPickerItem.AddressType { + + func placeholder(with localizationParameters: LocalizationParameters?) -> String { + switch self { + case .billing: return localizedString(.billingAddressPlaceholder, localizationParameters) + case .delivery: return localizedString(.deliveryAddressPlaceholder, localizationParameters) + } + } + + func title(with localizationParameters: LocalizationParameters?) -> String { + switch self { + case .billing: return localizedString(.billingAddressSectionTitle, localizationParameters) + case .delivery: return localizedString(.deliveryAddressSectionTitle, localizationParameters) + } + } +} diff --git a/Adyen/UI/View Controllers/AddressLookup/AddressLookupStyle.swift b/Adyen/UI/View Controllers/AddressLookup/AddressLookupStyle.swift index 20ceceb962..6a58134c9e 100644 --- a/Adyen/UI/View Controllers/AddressLookup/AddressLookupStyle.swift +++ b/Adyen/UI/View Controllers/AddressLookup/AddressLookupStyle.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2023 Adyen N.V. +// Copyright (c) 2024 Adyen N.V. // // This file is open source and available under the MIT license. See the LICENSE file for more info. // @@ -13,5 +13,15 @@ public struct AddressLookupStyle: ViewStyle { public var search: AddressLookupSearchStyle = .init() public var form: FormComponentStyle = .init() - public init() {} + /// Initializes the address lookup style. + /// + /// - Parameter search: The address lookup search style + /// - Parameter form: The form style + public init( + search: AddressLookupSearchStyle = .init(), + form: FormComponentStyle = .init() + ) { + self.search = search + self.form = form + } } diff --git a/Adyen/UI/View Controllers/AddressLookup/AddressLookupViewController+ViewModel.swift b/Adyen/UI/View Controllers/AddressLookup/AddressLookupViewController+ViewModel.swift index 80b33f28fe..0054ae031f 100644 --- a/Adyen/UI/View Controllers/AddressLookup/AddressLookupViewController+ViewModel.swift +++ b/Adyen/UI/View Controllers/AddressLookup/AddressLookupViewController+ViewModel.swift @@ -25,6 +25,8 @@ public extension AddressLookupViewController { internal let lookupProvider: AddressLookupProvider private let completionHandler: (PostalAddress?) -> Void + internal let addressType: FormAddressPickerItem.AddressType + @AdyenObservable(nil) internal private(set) var prefillAddress: PostalAddress? @@ -51,6 +53,7 @@ public extension AddressLookupViewController { /// - completionHandler: A closure that takes an optional address. /// It's the presenters responsibility to dismiss the viewController. public init( + for addressType: FormAddressPickerItem.AddressType, style: AddressLookupStyle = .init(), localizationParameters: LocalizationParameters?, supportedCountryCodes: [String]?, @@ -59,6 +62,7 @@ public extension AddressLookupViewController { lookupProvider: AddressLookupProvider, completionHandler: @escaping (PostalAddress?) -> Void ) { + self.addressType = addressType self.style = style self.localizationParameters = localizationParameters self.supportedCountryCodes = supportedCountryCodes diff --git a/Adyen/UI/View Controllers/AddressLookup/AddressLookupViewController.swift b/Adyen/UI/View Controllers/AddressLookup/AddressLookupViewController.swift index d03ff3f51a..e45bb1753d 100644 --- a/Adyen/UI/View Controllers/AddressLookup/AddressLookupViewController.swift +++ b/Adyen/UI/View Controllers/AddressLookup/AddressLookupViewController.swift @@ -86,6 +86,7 @@ extension AddressLookupViewController.ViewModel { ) -> AddressInputFormViewController.ViewModel { .init( + for: addressType, style: style.form, localizationParameters: localizationParameters, initialCountry: initialCountry, diff --git a/Adyen/UI/View Controllers/AddressLookup/Form/AddressInputFormViewController+ViewModel.swift b/Adyen/UI/View Controllers/AddressLookup/Form/AddressInputFormViewController+ViewModel.swift index 23bf440e20..7b831d4a6e 100644 --- a/Adyen/UI/View Controllers/AddressLookup/Form/AddressInputFormViewController+ViewModel.swift +++ b/Adyen/UI/View Controllers/AddressLookup/Form/AddressInputFormViewController+ViewModel.swift @@ -20,6 +20,11 @@ extension AddressInputFormViewController { internal let addressViewModelBuilder: AddressViewModelBuilder internal let localizationParameters: LocalizationParameters? + internal var title: String { + addressType.title(with: localizationParameters) + } + + private let addressType: FormAddressPickerItem.AddressType private let showSearchHandler: ShowSearchHandler? private let completionHandler: (PostalAddress?) -> Void @@ -36,15 +41,17 @@ extension AddressInputFormViewController { /// - completionHandler: A closure that takes an optional address. /// It's the presenters responsibility to dismiss the viewController. public init( + for addressType: FormAddressPickerItem.AddressType, style: FormComponentStyle, localizationParameters: LocalizationParameters?, initialCountry: String, prefillAddress: PostalAddress?, supportedCountryCodes: [String]?, addressViewModelBuilder: AddressViewModelBuilder = DefaultAddressViewModelBuilder(), - handleShowSearch: ShowSearchHandler?, + handleShowSearch: ShowSearchHandler? = nil, completionHandler: @escaping (PostalAddress?) -> Void ) { + self.addressType = addressType self.style = style self.initialCountry = initialCountry self.prefillAddress = prefillAddress diff --git a/Adyen/UI/View Controllers/AddressLookup/Form/AddressInputFormViewController.swift b/Adyen/UI/View Controllers/AddressLookup/Form/AddressInputFormViewController.swift index 31125ddcb9..11f0c7d783 100644 --- a/Adyen/UI/View Controllers/AddressLookup/Form/AddressInputFormViewController.swift +++ b/Adyen/UI/View Controllers/AddressLookup/Form/AddressInputFormViewController.swift @@ -20,7 +20,7 @@ public class AddressInputFormViewController: FormViewController { localizationParameters: viewModel.localizationParameters ) - title = localizedString(.billingAddressSectionTitle, viewModel.localizationParameters) + title = viewModel.title if #available(iOS 13.0, *) { isModalInPresentation = true @@ -30,7 +30,7 @@ public class AddressInputFormViewController: FormViewController { append(searchButtonItem) } - append(billingAddressItem) + append(addressItem) setupNavigationItems() } @@ -41,10 +41,10 @@ public class AddressInputFormViewController: FormViewController { // The done button should only be enabled once at least one field is filled in. // Either by prefilling or manually entering. // The country field is excluded as it is always prefilled. - var itemWithoutCountry = billingAddressItem.value + var itemWithoutCountry = addressItem.value itemWithoutCountry.country = nil navigationItem.rightBarButtonItem?.isEnabled = !itemWithoutCountry.isEmpty - observe(billingAddressItem.publisher, eventHandler: { [weak self] _ in + observe(addressItem.publisher, eventHandler: { [weak self] _ in self?.navigationItem.rightBarButtonItem?.isEnabled = true }) } @@ -61,14 +61,14 @@ public class AddressInputFormViewController: FormViewController { identifier: identifier ) { [weak self] in guard let self else { return } - self.viewModel.handleShowSearch(currentInput: self.billingAddressItem.value) + self.viewModel.handleShowSearch(currentInput: self.addressItem.value) } }() - internal lazy var billingAddressItem: FormAddressItem = { + internal lazy var addressItem: FormAddressItem = { let identifier = ViewIdentifierBuilder.build( scopeInstance: Self.self, - postfix: "billingAddress" + postfix: "address" ) let item = FormAddressItem( @@ -109,7 +109,7 @@ private extension AddressInputFormViewController { @objc func submitTapped() { guard validate() else { return } - viewModel.handleSubmit(validAddress: billingAddressItem.value) + viewModel.handleSubmit(validAddress: addressItem.value) } @objc diff --git a/Adyen/UI/View Controllers/AddressLookup/Search/AddressLookupSearchViewController+Style.swift b/Adyen/UI/View Controllers/AddressLookup/Search/AddressLookupSearchViewController+Style.swift index 90cef3c303..bd1f38a338 100644 --- a/Adyen/UI/View Controllers/AddressLookup/Search/AddressLookupSearchViewController+Style.swift +++ b/Adyen/UI/View Controllers/AddressLookup/Search/AddressLookupSearchViewController+Style.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2023 Adyen N.V. +// Copyright (c) 2024 Adyen N.V. // // This file is open source and available under the MIT license. See the LICENSE file for more info. // @@ -18,4 +18,6 @@ public struct AddressLookupSearchStyle: ViewStyle { }() public var emptyView: EmptyStateViewStyle = .init() + + public init() {} } diff --git a/AdyenCard/Components/Card/CardComponent.swift b/AdyenCard/Components/Card/CardComponent.swift index 2378197d99..290c17d74a 100644 --- a/AdyenCard/Components/Card/CardComponent.swift +++ b/AdyenCard/Components/Card/CardComponent.swift @@ -211,51 +211,6 @@ extension CardComponent: CardViewControllerDelegate { self.cardComponentDelegate?.didChangeCardBrand(binInfo.brands ?? [], component: self) } } - - internal func didSelectAddressPicker(lookupProvider: AddressLookupProvider?) { - - let securedViewController = SecuredViewController( - child: addressPickerViewController(with: lookupProvider), - style: configuration.style - ) - - viewController.present(securedViewController, animated: true) - } - - private func addressPickerViewController( - with lookupProvider: AddressLookupProvider? - ) -> UIViewController { - - let prefillAddress = cardViewController.items.billingAddressPickerItem.value - let initialCountry = initialCountryCode - let completionHandler: (PostalAddress?) -> Void = { [weak self] address in - guard let self else { return } - address.map { self.cardViewController.items.billingAddressPickerItem.value = $0 } - self.viewController.dismiss(animated: true) - } - - guard let lookupProvider else { - - let viewModel = configuration.addressInputFormViewModel( - with: initialCountry, - prefillAddress: prefillAddress, - completionHandler: completionHandler - ) - - let addressInputForm = AddressInputFormViewController(viewModel: viewModel) - - return UINavigationController(rootViewController: addressInputForm) - } - - let viewModel = configuration.addressLookupViewModel( - with: initialCountry, - prefillAddress: prefillAddress, - lookupProvider: lookupProvider, - completionHandler: completionHandler - ) - - return AddressLookupViewController(viewModel: viewModel) - } } @_spi(AdyenInternal) @@ -290,6 +245,7 @@ private extension CardComponent.Configuration { ) -> AddressLookupViewController.ViewModel { .init( + for: .billing, localizationParameters: localizationParameters, supportedCountryCodes: billingAddress.countryCodes, initialCountry: initialCountry, @@ -306,6 +262,7 @@ private extension CardComponent.Configuration { ) -> AddressInputFormViewController.ViewModel { .init( + for: .billing, style: style, localizationParameters: localizationParameters, initialCountry: initialCountry, diff --git a/AdyenCard/Components/Card/CardViewController.swift b/AdyenCard/Components/Card/CardViewController.swift index cb0759a8d7..75f8cb4969 100644 --- a/AdyenCard/Components/Card/CardViewController.swift +++ b/AdyenCard/Components/Card/CardViewController.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2023 Adyen N.V. +// Copyright (c) 2024 Adyen N.V. // // This file is open source and available under the MIT license. See the LICENSE file for more info. // @@ -46,7 +46,9 @@ internal class CardViewController: FormViewController { scope: scope, initialCountryCode: initialCountryCode, localizationParameters: localizationParameters, - addressViewModelBuilder: DefaultAddressViewModelBuilder() + addressViewModelBuilder: DefaultAddressViewModelBuilder(), + presenter: self, + addressMode: configuration.billingAddress.mode ) }() @@ -133,9 +135,13 @@ internal class CardViewController: FormViewController { switch configuration.billingAddress.mode { case .lookup, .full: - guard let lookupBillingAddress = items.billingAddressPickerItem.value else { return nil } + guard + let billingAddressItem = items.billingAddressPickerItem, + let lookupBillingAddress = billingAddressItem.value + else { return nil } + address = lookupBillingAddress - requiredFields = items.billingAddressPickerItem.addressViewModel.requiredFields + requiredFields = billingAddressItem.addressViewModel.requiredFields case .postalCode: address = PostalAddress(postalCode: items.postalCodeItem.value) @@ -208,7 +214,7 @@ extension CardViewController { let isOptional = configuration.billingAddress.isOptional(for: brands.map(\.type)) switch configuration.billingAddress.mode { case .lookup, .full: - items.billingAddressPickerItem.updateOptionalStatus(isOptional: isOptional) + items.billingAddressPickerItem?.updateOptionalStatus(isOptional: isOptional) case .postalCode: items.postalCodeItem.updateOptionalStatus(isOptional: isOptional) case .none: @@ -276,7 +282,7 @@ extension CardViewController { append(FormSpacerItem()) } - if let billingAddressItem = billingAddressItem(for: configuration.billingAddress.mode) { + if let billingAddressItem { append(billingAddressItem) } @@ -285,22 +291,14 @@ extension CardViewController { append(FormSpacerItem(numberOfSpaces: 2)) } - private func billingAddressItem(for billingAddressMode: CardComponent.AddressFormType) -> FormItem? { - switch billingAddressMode { + private var billingAddressItem: FormItem? { + + switch configuration.billingAddress.mode { case let .lookup(provider): - let item = items.billingAddressPickerItem - item.selectionHandler = { [weak cardDelegate, weak provider] in - guard let provider else { return } - cardDelegate?.didSelectAddressPicker(lookupProvider: provider) - } - return item + return items.billingAddressPickerItem case .full: - let item = items.billingAddressPickerItem - item.selectionHandler = { [weak cardDelegate] in - cardDelegate?.didSelectAddressPicker(lookupProvider: nil) - } - return item + return items.billingAddressPickerItem case .postalCode: return items.postalCodeItem @@ -314,7 +312,7 @@ extension CardViewController { guard let shopperInformation else { return } shopperInformation.billingAddress.map { billingAddress in - items.billingAddressPickerItem.value = billingAddress + items.billingAddressPickerItem?.value = billingAddress billingAddress.postalCode.map { items.postalCodeItem.value = $0 } } shopperInformation.card.map { items.holderNameItem.value = $0.holderName } @@ -366,8 +364,6 @@ extension CardViewController { internal protocol CardViewControllerDelegate: AnyObject { - func didSelectAddressPicker(lookupProvider: AddressLookupProvider?) - func didSelectSubmitButton() func didChange(bin: String) diff --git a/AdyenCard/Components/Card/CardViewControllerItemsProvider.swift b/AdyenCard/Components/Card/CardViewControllerItemsProvider.swift index ad695f01d6..6d23f925e6 100644 --- a/AdyenCard/Components/Card/CardViewControllerItemsProvider.swift +++ b/AdyenCard/Components/Card/CardViewControllerItemsProvider.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2023 Adyen N.V. +// Copyright (c) 2024 Adyen N.V. // // This file is open source and available under the MIT license. See the LICENSE file for more info. // @@ -28,16 +28,24 @@ extension CardViewController { private let initialCountry: String private let addressViewModelBuilder: AddressViewModelBuilder - - internal init(formStyle: FormComponentStyle, - payment: Payment?, - configuration: CardComponent.Configuration, - shopperInformation: PrefilledShopperInformation?, - cardLogos: [FormCardLogosItem.CardTypeLogo], - scope: String, - initialCountryCode: String, - localizationParameters: LocalizationParameters?, - addressViewModelBuilder: AddressViewModelBuilder) { + + private let presenter: WeakReferenceViewControllerPresenter + + private let addressMode: CardComponent.AddressFormType + + internal init( + formStyle: FormComponentStyle, + payment: Payment?, + configuration: CardComponent.Configuration, + shopperInformation: PrefilledShopperInformation?, + cardLogos: [FormCardLogosItem.CardTypeLogo], + scope: String, + initialCountryCode: String, + localizationParameters: LocalizationParameters?, + addressViewModelBuilder: AddressViewModelBuilder, + presenter: ViewControllerPresenter, + addressMode: CardComponent.AddressFormType + ) { self.formStyle = formStyle self.amount = payment?.amount self.configuration = configuration @@ -47,22 +55,38 @@ extension CardViewController { self.initialCountry = initialCountryCode self.localizationParameters = localizationParameters self.addressViewModelBuilder = addressViewModelBuilder + self.presenter = .init(presenter) + self.addressMode = addressMode } - internal lazy var billingAddressPickerItem: FormAddressPickerItem = { + internal lazy var billingAddressPickerItem: FormAddressPickerItem? = { + switch addressMode { + case let .lookup(provider): + return billingAddressPickerItem(with: provider) + case .full: + return billingAddressPickerItem(with: nil) + case .postalCode, .none: + return nil + } + }() + + private func billingAddressPickerItem(with lookupProvider: AddressLookupProvider?) -> FormAddressPickerItem { let identifier = ViewIdentifierBuilder.build(scopeInstance: scope, postfix: "billingAddress") let prefillAddress = shopperInformation?.billingAddress - let item = FormAddressPickerItem( + return FormAddressPickerItem( + for: .billing, initialCountry: initialCountry, + supportedCountryCodes: configuration.billingAddress.countryCodes, prefillAddress: prefillAddress, - style: formStyle.addressStyle, + style: formStyle, localizationParameters: localizationParameters, identifier: identifier, - addressViewModelBuilder: addressViewModelBuilder + addressViewModelBuilder: addressViewModelBuilder, + presenter: presenter, + lookupProvider: lookupProvider ) - return item - }() + } internal lazy var postalCodeItem: FormPostalCodeItem = { let zipCodeItem = FormPostalCodeItem(style: formStyle.textField, localizationParameters: localizationParameters) diff --git a/AdyenComponents/ACH Direct Debit/ACHDirectDebitComponent.swift b/AdyenComponents/ACH Direct Debit/ACHDirectDebitComponent.swift index 2ae274f025..3e42659743 100644 --- a/AdyenComponents/ACH Direct Debit/ACHDirectDebitComponent.swift +++ b/AdyenComponents/ACH Direct Debit/ACHDirectDebitComponent.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2023 Adyen N.V. +// Copyright (c) 2024 Adyen N.V. // // This file is open source and available under the MIT license. See the LICENSE file for more info. // @@ -209,27 +209,30 @@ public final class ACHDirectDebitComponent: PaymentComponent, return storeDetailsItem }() - internal lazy var billingAddressItem: FormAddressItem = { + internal lazy var billingAddressItem: FormAddressPickerItem = { let identifier = ViewIdentifierBuilder.build(scopeInstance: self, postfix: ViewIdentifier.billingAddressItem) var initialCountry = defaultCountryCode - if let prefillCountryCode = configuration.shopperInformation?.billingAddress?.country, - configuration.billingAddressCountryCodes.contains(prefillCountryCode) { + + if + let prefillCountryCode = configuration.shopperInformation?.billingAddress?.country, + configuration.billingAddressCountryCodes.contains(prefillCountryCode) { initialCountry = prefillCountryCode } - let item = FormAddressItem(initialCountry: initialCountry, - configuration: .init( - style: configuration.style.addressStyle, - localizationParameters: configuration.localizationParameters, - supportedCountryCodes: configuration.billingAddressCountryCodes - ), - identifier: identifier, - presenter: self, - addressViewModelBuilder: DefaultAddressViewModelBuilder()) - configuration.shopperInformation?.billingAddress.map { item.value = $0 } - item.style.backgroundColor = UIColor.Adyen.lightGray - return item + + let prefillAddress = configuration.shopperInformation?.billingAddress + + return FormAddressPickerItem( + for: .billing, + initialCountry: initialCountry, + supportedCountryCodes: configuration.billingAddressCountryCodes, + prefillAddress: prefillAddress, + style: configuration.style, + localizationParameters: configuration.localizationParameters, + identifier: identifier, + presenter: self + ) }() internal lazy var payButton: FormButtonItem = { diff --git a/AdyenComponents/Affirm/AffirmComponent.swift b/AdyenComponents/Affirm/AffirmComponent.swift index c77f116e87..5bb0b0d2e4 100644 --- a/AdyenComponents/Affirm/AffirmComponent.swift +++ b/AdyenComponents/Affirm/AffirmComponent.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2022 Adyen N.V. +// Copyright (c) 2024 Adyen N.V. // // This file is open source and available under the MIT license. See the LICENSE file for more info. // @@ -39,16 +39,16 @@ public final class AffirmComponent: AbstractPersonalInformationComponent { deliveryAddressToggleItem = FormToggleItem(style: configuration.style.toggle) let fields: [PersonalInformation] = [ - .custom(CustomFormItemInjector(item: FormSpacerItem(numberOfSpaces: 2))), - .custom(CustomFormItemInjector(item: personalDetailsHeaderItem.addingDefaultMargins())), .firstName, .lastName, .email, .phone, + .custom(CustomFormItemInjector(item: FormSpacerItem(numberOfSpaces: 2))), .address, + .custom(CustomFormItemInjector(item: FormSpacerItem(numberOfSpaces: 1))), .custom(CustomFormItemInjector(item: deliveryAddressToggleItem)), .deliveryAddress, - .custom(CustomFormItemInjector(item: FormSpacerItem(numberOfSpaces: 1))) + .custom(CustomFormItemInjector(item: FormSpacerItem(numberOfSpaces: 2))) ] super.init(paymentMethod: paymentMethod, @@ -98,23 +98,26 @@ public final class AffirmComponent: AbstractPersonalInformationComponent { @_spi(AdyenInternal) override public func createPaymentDetails() throws -> PaymentMethodDetails { + guard let firstName = firstNameItem?.value, let lastName = lastNameItem?.value, let emailAddress = emailItem?.value, let telephoneNumber = phoneItem?.phoneNumber, let billingAddress = addressItem?.value, - let deliveryAddress = deliveryAddressItem?.value else { + let deliveryAddress = deliveryAddressToggleItem.value ? deliveryAddressItem?.value : billingAddress else { throw UnknownError(errorDescription: "There seems to be an error in the BasicPersonalInfoFormComponent configuration.") } let shopperName = ShopperName(firstName: firstName, lastName: lastName) - let affirmDetails = AffirmDetails(paymentMethod: paymentMethod, - shopperName: shopperName, - telephoneNumber: telephoneNumber, - emailAddress: emailAddress, - billingAddress: billingAddress, - deliveryAddress: deliveryAddressToggleItem.value ? deliveryAddress : billingAddress) - return affirmDetails + + return AffirmDetails( + paymentMethod: paymentMethod, + shopperName: shopperName, + telephoneNumber: telephoneNumber, + emailAddress: emailAddress, + billingAddress: billingAddress, + deliveryAddress: deliveryAddress + ) } @_spi(AdyenInternal) diff --git a/AdyenComponents/Atome/AtomeComponent.swift b/AdyenComponents/Atome/AtomeComponent.swift index f23efc3a90..0c42d0e43b 100644 --- a/AdyenComponents/Atome/AtomeComponent.swift +++ b/AdyenComponents/Atome/AtomeComponent.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2022 Adyen N.V. +// Copyright (c) 2024 Adyen N.V. // // This file is open source and available under the MIT license. See the LICENSE file for more info. // @@ -34,11 +34,10 @@ public final class AtomeComponent: AbstractPersonalInformationComponent { personalDetailsHeaderItem = FormLabelItem(text: "", style: configuration.style.sectionHeader) let fields: [PersonalInformation] = [ - .custom(CustomFormItemInjector(item: FormSpacerItem(numberOfSpaces: 2))), - .custom(CustomFormItemInjector(item: personalDetailsHeaderItem.addingDefaultMargins())), .firstName, .lastName, .phone, + .custom(CustomFormItemInjector(item: FormSpacerItem(numberOfSpaces: 2))), .address, .custom(CustomFormItemInjector(item: FormSpacerItem(numberOfSpaces: 1))) ] diff --git a/AdyenComponents/Boleto/BoletoComponent.swift b/AdyenComponents/Boleto/BoletoComponent.swift index 0377cb351e..e746e6feeb 100644 --- a/AdyenComponents/Boleto/BoletoComponent.swift +++ b/AdyenComponents/Boleto/BoletoComponent.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2023 Adyen N.V. +// Copyright (c) 2024 Adyen N.V. // // This file is open source and available under the MIT license. See the LICENSE file for more info. // @@ -67,17 +67,6 @@ public final class BoletoComponent: PaymentComponent, return sendCopyToEmailItem }() - private func headerFormItem(key: LocalizationKey) -> FormContainerItem { - FormLabelItem( - text: localizedString(key, configuration.localizationParameters), - style: configuration.style.sectionHeader, - identifier: ViewIdentifierBuilder.build( - scopeInstance: self, - postfix: localizedString(key, configuration.localizationParameters) - ) - ).addingDefaultMargins() - } - private lazy var formComponent: FormComponent = { let configuration = AbstractPersonalInformationComponent.Configuration(style: configuration.style, shopperInformation: configuration.shopperInformation, @@ -109,15 +98,15 @@ public final class BoletoComponent: PaymentComponent, /// Constructs the fields for the form based on the configuration private var formFields: [PersonalInformation] { var fields: [PersonalInformation] = [ - .custom(CustomFormItemInjector(item: headerFormItem(key: .boletoPersonalDetails))), .firstName, .lastName, .custom(CustomFormItemInjector(item: socialSecurityNumberItem)), - .address + .custom(CustomFormItemInjector(item: FormSpacerItem(numberOfSpaces: 2))), + .address, + .custom(CustomFormItemInjector(item: FormSpacerItem(numberOfSpaces: 1))) ] if configuration.showEmailAddress { - fields.append(.custom(CustomFormItemInjector(item: FormSpacerItem(numberOfSpaces: 1)))) fields.append(.custom(CustomFormItemInjector(item: sendCopyByEmailItem))) fields.append(.email) fields.append(.custom(CustomFormItemInjector(item: FormSpacerItem(numberOfSpaces: 1)))) diff --git a/Demo/Common/Configuration/AnalyticsSettingsView.swift b/Demo/Common/Configuration/AnalyticsSettingsView.swift index a9a18dc218..f4d2070ef3 100644 --- a/Demo/Common/Configuration/AnalyticsSettingsView.swift +++ b/Demo/Common/Configuration/AnalyticsSettingsView.swift @@ -22,5 +22,6 @@ internal struct AnalyticsSettingsView: View { .navigationBarTitle("") .navigationBarHidden(true) } + .navigationViewStyle(.stack) } } diff --git a/Demo/Common/Configuration/ApplePaySettingsView.swift b/Demo/Common/Configuration/ApplePaySettingsView.swift index 74179f4768..6021a2dcea 100644 --- a/Demo/Common/Configuration/ApplePaySettingsView.swift +++ b/Demo/Common/Configuration/ApplePaySettingsView.swift @@ -30,5 +30,6 @@ internal struct ApplePaySettingsView: View { .navigationBarTitle("") .navigationBarHidden(true) } + .navigationViewStyle(.stack) } } diff --git a/Demo/Common/Configuration/CardComponentSettingsView.swift b/Demo/Common/Configuration/CardComponentSettingsView.swift index 7882b3bd71..466fc4ef40 100644 --- a/Demo/Common/Configuration/CardComponentSettingsView.swift +++ b/Demo/Common/Configuration/CardComponentSettingsView.swift @@ -70,6 +70,7 @@ internal struct CardSettingsView: View { .navigationBarTitle("") .navigationBarHidden(true) } + .navigationViewStyle(.stack) } } diff --git a/Demo/Common/Configuration/DropInSettingsView.swift b/Demo/Common/Configuration/DropInSettingsView.swift index 79112d5ebc..935be4eaab 100644 --- a/Demo/Common/Configuration/DropInSettingsView.swift +++ b/Demo/Common/Configuration/DropInSettingsView.swift @@ -37,5 +37,6 @@ internal struct DropInSettingsView: View { .navigationBarTitle("") .navigationBarHidden(true) } + .navigationViewStyle(.stack) } } diff --git a/Demo/SwiftUI/ComponentsView.swift b/Demo/SwiftUI/ComponentsView.swift index c3affcfcc5..6a6b057acd 100644 --- a/Demo/SwiftUI/ComponentsView.swift +++ b/Demo/SwiftUI/ComponentsView.swift @@ -39,6 +39,7 @@ internal struct ComponentsView: View { loadingIndicator } } + .navigationViewStyle(.stack) .ignoresSafeArea() .present(viewController: $viewModel.viewControllerToPresent) .onAppear { diff --git a/Tests/Adyen Tests/Mocks/PresentationDelegateMock.swift b/Tests/Adyen Tests/Mocks/PresentationDelegateMock.swift index e8f9a9efa9..4252349dd5 100644 --- a/Tests/Adyen Tests/Mocks/PresentationDelegateMock.swift +++ b/Tests/Adyen Tests/Mocks/PresentationDelegateMock.swift @@ -3,6 +3,7 @@ @_spi(AdyenInternal) import Adyen @testable import AdyenDropIn import Foundation +import XCTest final class PresentationDelegateMock: NavigationDelegate { @@ -20,12 +21,17 @@ final class PresentationDelegateMock: NavigationDelegate { } var presentComponentReceivedComponent: PresentableComponent? - var doPresent: ((_ component: PresentableComponent) -> Void)? + var doPresent: ((_ component: PresentableComponent) throws -> Void)? func present(component: PresentableComponent) { presentComponentCallsCount += 1 presentComponentReceivedComponent = component - doPresent?(component) + + do { + try doPresent?(component) + } catch { + XCTFail(error.localizedDescription) + } } } diff --git a/Tests/Adyen Tests/Mocks/PresenterMock.swift b/Tests/Adyen Tests/Mocks/PresenterMock.swift new file mode 100644 index 0000000000..145b4cbf99 --- /dev/null +++ b/Tests/Adyen Tests/Mocks/PresenterMock.swift @@ -0,0 +1,30 @@ +// +// Copyright (c) 2024 Adyen N.V. +// +// This file is open source and available under the MIT license. See the LICENSE file for more info. +// + +@_spi(AdyenInternal) import Adyen +import UIKit + +class PresenterMock: ViewControllerPresenter { + + var present: (UIViewController, Bool) -> Void + var dismiss: (Bool) -> Void + + init( + present: @escaping (UIViewController, Bool) -> Void, + dismiss: @escaping (Bool) -> Void + ) { + self.present = present + self.dismiss = dismiss + } + + func presentViewController(_ viewController: UIViewController, animated: Bool) { + present(viewController, animated) + } + + func dismissViewController(animated: Bool) { + dismiss(animated) + } +} diff --git a/Tests/Adyen Tests/UI/Form/FormItems/Address/FormAddressPickerItemTests.swift b/Tests/Adyen Tests/UI/Form/FormItems/Address/FormAddressPickerItemTests.swift index 994f82a422..d9f7aec63c 100644 --- a/Tests/Adyen Tests/UI/Form/FormItems/Address/FormAddressPickerItemTests.swift +++ b/Tests/Adyen Tests/UI/Form/FormItems/Address/FormAddressPickerItemTests.swift @@ -12,10 +12,12 @@ class FormAddressPickerItemTests: XCTestCase { func testEmptyPrefillAddress() { let addressLookupItem = FormAddressPickerItem( + for: .billing, initialCountry: "NL", + supportedCountryCodes: nil, prefillAddress: nil, style: .init(), - addressViewModelBuilder: DefaultAddressViewModelBuilder() + presenter: PresenterMock(present: { _, _ in }, dismiss: { _ in }) ) XCTAssertNil(addressLookupItem.value) @@ -29,10 +31,12 @@ class FormAddressPickerItemTests: XCTestCase { func testPrefillAddress() { let addressLookupItem = FormAddressPickerItem( + for: .billing, initialCountry: "NL", + supportedCountryCodes: nil, prefillAddress: PostalAddressMocks.singaporePostalAddress, style: .init(), - addressViewModelBuilder: DefaultAddressViewModelBuilder() + presenter: PresenterMock(present: { _, _ in }, dismiss: { _ in }) ) XCTAssertEqual(addressLookupItem.value, PostalAddressMocks.singaporePostalAddress) @@ -42,10 +46,12 @@ class FormAddressPickerItemTests: XCTestCase { func testValidationFailureMessage() { let addressLookupItem = FormAddressPickerItem( + for: .billing, initialCountry: "NL", + supportedCountryCodes: nil, prefillAddress: nil, style: .init(), - addressViewModelBuilder: DefaultAddressViewModelBuilder() + presenter: PresenterMock(present: { _, _ in }, dismiss: { _ in }) ) XCTAssertEqual(addressLookupItem.validationFailureMessage, "Address required") @@ -55,10 +61,12 @@ class FormAddressPickerItemTests: XCTestCase { func testFormattedValue() { let addressLookupItem = FormAddressPickerItem( + for: .billing, initialCountry: "NL", + supportedCountryCodes: nil, prefillAddress: nil, style: .init(), - addressViewModelBuilder: DefaultAddressViewModelBuilder() + presenter: PresenterMock(present: { _, _ in }, dismiss: { _ in }) ) XCTAssertNil(addressLookupItem.formattedValue) diff --git a/Tests/Adyen Tests/UI/Form/FormItems/Picker/FormPickerItemTests.swift b/Tests/Adyen Tests/UI/Form/FormItems/Picker/FormPickerItemTests.swift index 04b397f222..97015ca731 100644 --- a/Tests/Adyen Tests/UI/Form/FormItems/Picker/FormPickerItemTests.swift +++ b/Tests/Adyen Tests/UI/Form/FormItems/Picker/FormPickerItemTests.swift @@ -9,28 +9,6 @@ import XCTest class FormPickerItemTests: XCTestCase { - class MockPresenter: ViewControllerPresenter { - - var present: (UIViewController, Bool) -> Void - var dismiss: (Bool) -> Void - - init( - present: @escaping (UIViewController, Bool) -> Void, - dismiss: @escaping (Bool) -> Void - ) { - self.present = present - self.dismiss = dismiss - } - - func presentViewController(_ viewController: UIViewController, animated: Bool) { - present(viewController, animated) - } - - func dismissViewController(animated: Bool) { - dismiss(animated) - } - } - func testPresentation() throws { let presentViewControllerExpectation = expectation(description: "presenter.presentViewController was called") @@ -38,7 +16,7 @@ class FormPickerItemTests: XCTestCase { var presentedViewController: FormPickerSearchViewController? - let mockPresenter = MockPresenter { viewController, animated in + let mockPresenter = PresenterMock { viewController, animated in presentedViewController = viewController as? FormPickerSearchViewController presentViewControllerExpectation.fulfill() } dismiss: { animated in diff --git a/Tests/Adyen Tests/UI/View Controllers/AddressInputFormViewControllerTests.swift b/Tests/Adyen Tests/UI/View Controllers/AddressInputFormViewControllerTests.swift index 542f4907ec..cf94c4dc46 100644 --- a/Tests/Adyen Tests/UI/View Controllers/AddressInputFormViewControllerTests.swift +++ b/Tests/Adyen Tests/UI/View Controllers/AddressInputFormViewControllerTests.swift @@ -25,15 +25,15 @@ class AddressInputFormViewControllerTests: XCTestCase { let view: UIView = viewController.view - let houseNumberItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.billingAddress.houseNumberOrName")) - let countryItemView: FormPickerItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.billingAddress.country")) - let addressItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.billingAddress.street")) - let apartmentSuiteItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.billingAddress.apartment")) - let cityItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.billingAddress.city")) - let provinceOrTerritoryItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.billingAddress.stateOrProvince")) - let postalCodeItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.billingAddress.postalCode")) + let houseNumberItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.address.houseNumberOrName")) + let countryItemView: FormPickerItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.address.country")) + let addressItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.address.street")) + let apartmentSuiteItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.address.apartment")) + let cityItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.address.city")) + let provinceOrTerritoryItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.address.stateOrProvince")) + let postalCodeItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.address.postalCode")) - XCTAssertNil(view.findView(by: "AddressInputFormViewController.billingAddressItem.title")) + XCTAssertNil(view.findView(by: "AddressInputFormViewController.addressItem.title")) XCTAssertEqual(countryItemView.titleLabel.text, "Country") XCTAssertEqual(countryItemView.item.value!.title, "Netherlands") @@ -78,13 +78,13 @@ class AddressInputFormViewControllerTests: XCTestCase { // When let view: UIView = viewController.view - let houseNumberItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.billingAddress.houseNumberOrName")) - let countryItemView: FormPickerItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.billingAddress.country")) - let addressItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.billingAddress.street")) - let apartmentSuiteItemView = view.findView(with: "AddressInputFormViewController.billingAddress.apartment") as? FormTextInputItemView - let cityItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.billingAddress.city")) - let provinceOrTerritoryItemView: FormPickerItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.billingAddress.stateOrProvince")) - let postalCodeItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.billingAddress.postalCode")) + let houseNumberItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.address.houseNumberOrName")) + let countryItemView: FormPickerItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.address.country")) + let addressItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.address.street")) + let apartmentSuiteItemView = view.findView(with: "AddressInputFormViewController.address.apartment") as? FormTextInputItemView + let cityItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.address.city")) + let provinceOrTerritoryItemView: FormPickerItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.address.stateOrProvince")) + let postalCodeItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.address.postalCode")) let searchItemView = view.findView(with: "AddressInputFormViewController.searchBar") as? FormSearchButtonItemView // Then @@ -128,13 +128,13 @@ class AddressInputFormViewControllerTests: XCTestCase { let view: UIView = viewController.view - let houseNumberItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.billingAddress.houseNumberOrName")) - let countryItemView: FormPickerItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.billingAddress.country")) - let addressItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.billingAddress.street")) - let apartmentSuiteItemView = view.findView(with: "AddressInputFormViewController.billingAddress.apartment") as? FormTextInputItemView - let cityItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.billingAddress.city")) - let provinceOrTerritoryItemView = view.findView(with: "AddressInputFormViewController.billingAddress.stateOrProvince") as? FormPickerItemView - let postalCodeItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.billingAddress.postalCode")) + let houseNumberItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.address.houseNumberOrName")) + let countryItemView: FormPickerItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.address.country")) + let addressItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.address.street")) + let apartmentSuiteItemView = view.findView(with: "AddressInputFormViewController.address.apartment") as? FormTextInputItemView + let cityItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.address.city")) + let provinceOrTerritoryItemView = view.findView(with: "AddressInputFormViewController.address.stateOrProvince") as? FormPickerItemView + let postalCodeItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.address.postalCode")) XCTAssertNil(apartmentSuiteItemView) XCTAssertEqual(countryItemView.titleLabel.text, "Country") @@ -161,13 +161,13 @@ class AddressInputFormViewControllerTests: XCTestCase { let view: UIView = viewController.view - var houseNumberItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.billingAddress.houseNumberOrName")) - var countryItemView: FormPickerItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.billingAddress.country")) - var addressItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.billingAddress.street")) - var apartmentSuiteItemView: FormTextInputItemView! = view.findView(with: "AddressInputFormViewController.billingAddress.apartment") - var cityItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.billingAddress.city")) - var provinceOrTerritoryItemView: FormPickerItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.billingAddress.stateOrProvince")) - var postalCodeItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.billingAddress.postalCode")) + var houseNumberItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.address.houseNumberOrName")) + var countryItemView: FormPickerItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.address.country")) + var addressItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.address.street")) + var apartmentSuiteItemView: FormTextInputItemView! = view.findView(with: "AddressInputFormViewController.address.apartment") + var cityItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.address.city")) + var provinceOrTerritoryItemView: FormPickerItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.address.stateOrProvince")) + var postalCodeItemView: FormTextInputItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.address.postalCode")) XCTAssertNil(apartmentSuiteItemView) @@ -182,13 +182,13 @@ class AddressInputFormViewControllerTests: XCTestCase { countryItemView.item.value = countryItemView.item.selectableValues.first { $0.identifier == "BR" }! - houseNumberItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.billingAddress.houseNumberOrName")) - countryItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.billingAddress.country")) - addressItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.billingAddress.street")) - apartmentSuiteItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.billingAddress.apartment")) - cityItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.billingAddress.city")) - provinceOrTerritoryItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.billingAddress.stateOrProvince")) - postalCodeItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.billingAddress.postalCode")) + houseNumberItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.address.houseNumberOrName")) + countryItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.address.country")) + addressItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.address.street")) + apartmentSuiteItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.address.apartment")) + cityItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.address.city")) + provinceOrTerritoryItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.address.stateOrProvince")) + postalCodeItemView = try XCTUnwrap(view.findView(with: "AddressInputFormViewController.address.postalCode")) XCTAssertEqual(countryItemView.titleLabel.text, "Country") XCTAssertEqual(countryItemView.item.value!.title, "Brazil") @@ -243,7 +243,7 @@ class AddressInputFormViewControllerTests: XCTestCase { ) } - func testDoneButtonStatePrefillCountryAddingStreet() { + func testDoneButtonStatePrefillCountryAddingStreet() throws { let viewController = AddressInputFormViewController( viewModel: self.viewModel( @@ -262,8 +262,8 @@ class AddressInputFormViewControllerTests: XCTestCase { // Adding street name value - let countryItemView: FormPickerItemView? = viewController.view.findView(with: "AddressInputFormViewController.billingAddress.country") - countryItemView?.item.value = .init(identifier: "DE", title: "DE", subtitle: nil) + let countryItemView: FormPickerItemView = try XCTUnwrap(viewController.view.findView(with: "AddressInputFormViewController.address.country")) + countryItemView.item.value = .init(identifier: "DE", title: "DE", subtitle: nil) XCTAssertEqual( viewController.navigationItem.rightBarButtonItem?.isEnabled, @@ -303,7 +303,7 @@ class AddressInputFormViewControllerTests: XCTestCase { setupRootViewController(UIViewController()) XCTAssertEqual( - viewController.billingAddressItem.value.street, + viewController.addressItem.value.street, "" ) } @@ -318,6 +318,7 @@ private extension AddressInputFormViewControllerTests { ) -> AddressInputFormViewController.ViewModel { .init( + for: .billing, style: .init(), localizationParameters: nil, initialCountry: initialCountry, diff --git a/Tests/Adyen Tests/UI/View Controllers/AddressLookupViewControllerTests.swift b/Tests/Adyen Tests/UI/View Controllers/AddressLookupViewControllerTests.swift index 482c2ac189..776c8dbe20 100644 --- a/Tests/Adyen Tests/UI/View Controllers/AddressLookupViewControllerTests.swift +++ b/Tests/Adyen Tests/UI/View Controllers/AddressLookupViewControllerTests.swift @@ -25,6 +25,7 @@ class AddressLookupViewControllerTests: XCTestCase { } let viewModel = AddressLookupViewController.ViewModel( + for: .billing, style: .init(), localizationParameters: nil, supportedCountryCodes: nil, @@ -63,6 +64,7 @@ class AddressLookupViewControllerTests: XCTestCase { let emptyCompletionExpectation = expectation(description: "Completion handler called with nil object") let viewModel = AddressLookupViewController.ViewModel( + for: .billing, style: .init(), localizationParameters: nil, supportedCountryCodes: nil, @@ -90,6 +92,7 @@ class AddressLookupViewControllerTests: XCTestCase { let mockLookupProvider = MockAddressLookupProvider { _ in [] } let viewModel = AddressLookupViewController.ViewModel( + for: .billing, style: .init(), localizationParameters: nil, supportedCountryCodes: nil, @@ -128,6 +131,7 @@ class AddressLookupViewControllerTests: XCTestCase { // Given let viewModel = AddressLookupViewController.ViewModel( + for: .billing, style: .init(), localizationParameters: nil, supportedCountryCodes: nil, @@ -151,6 +155,7 @@ class AddressLookupViewControllerTests: XCTestCase { let prefillAddress = PostalAddressMocks.all.first! let viewModel = AddressLookupViewController.ViewModel( + for: .billing, style: .init(), localizationParameters: nil, supportedCountryCodes: nil, @@ -187,6 +192,7 @@ class AddressLookupViewControllerTests: XCTestCase { } let viewModel = AddressLookupViewController.ViewModel( + for: .billing, style: .init(), localizationParameters: nil, supportedCountryCodes: nil, diff --git a/Tests/Card Tests/CardComponentTests.swift b/Tests/Card Tests/CardComponentTests.swift index 7f0f2cadda..c3e74cfd5b 100644 --- a/Tests/Card Tests/CardComponentTests.swift +++ b/Tests/Card Tests/CardComponentTests.swift @@ -1667,8 +1667,8 @@ class CardComponentTests: XCTestCase { XCTAssertTrue(presentedViewController.viewControllers.first is AddressInputFormViewController) let inputForm = try XCTUnwrap(presentedViewController.viewControllers.first as? AddressInputFormViewController) - XCTAssertEqual(inputForm.billingAddressItem.configuration.supportedCountryCodes, ["UK"]) - XCTAssertEqual(inputForm.billingAddressItem.countryPickerItem.value?.identifier, "UK") + XCTAssertEqual(inputForm.addressItem.configuration.supportedCountryCodes, ["UK"]) + XCTAssertEqual(inputForm.addressItem.countryPickerItem.value?.identifier, "UK") } func testAddressWithSupportedCountriesWithMatchingPrefill() throws { @@ -1703,8 +1703,8 @@ class CardComponentTests: XCTestCase { XCTAssertTrue(presentedViewController.viewControllers.first is AddressInputFormViewController) let inputForm = try XCTUnwrap(presentedViewController.viewControllers.first as? AddressInputFormViewController) - XCTAssertEqual(inputForm.billingAddressItem.configuration.supportedCountryCodes, ["US", "JP"]) - XCTAssertEqual(inputForm.billingAddressItem.value, expectedBillingAddress) + XCTAssertEqual(inputForm.addressItem.configuration.supportedCountryCodes, ["US", "JP"]) + XCTAssertEqual(inputForm.addressItem.value, expectedBillingAddress) } func testAddressWithSupportedCountriesWithNonMatchingPrefill() throws { @@ -1734,8 +1734,8 @@ class CardComponentTests: XCTestCase { let inputForm = try XCTUnwrap(presentedViewController.viewControllers.first as? AddressInputFormViewController) - XCTAssertEqual(inputForm.billingAddressItem.configuration.supportedCountryCodes, ["UK"]) - XCTAssertEqual(inputForm.billingAddressItem.countryPickerItem.value?.identifier, "UK") + XCTAssertEqual(inputForm.addressItem.configuration.supportedCountryCodes, ["UK"]) + XCTAssertEqual(inputForm.addressItem.countryPickerItem.value?.identifier, "UK") } func testOptionalInvalidFullAddressWithCertainSchemes() throws { diff --git a/Tests/Components Tests/ACH Direct Debit/ACHDirectDebitComponentTests.swift b/Tests/Components Tests/ACH Direct Debit/ACHDirectDebitComponentTests.swift index e4ea859312..250da9446f 100644 --- a/Tests/Components Tests/ACH Direct Debit/ACHDirectDebitComponentTests.swift +++ b/Tests/Components Tests/ACH Direct Debit/ACHDirectDebitComponentTests.swift @@ -62,8 +62,7 @@ class ACHDirectDebitComponentTests: XCTestCase { XCTAssertEqual(sut.bankRoutingNumberItem.placeholder, localizedString(.achAccountLocationFieldTitle, sut.configuration.localizationParameters)) XCTAssertEqual(sut.bankRoutingNumberItem.validationFailureMessage, localizedString(.achAccountLocationFieldInvalid, sut.configuration.localizationParameters)) - XCTAssertEqual(sut.billingAddressItem.headerItem.text, localizedString(.billingAddressSectionTitle, sut.configuration.localizationParameters)) - XCTAssertEqual(sut.billingAddressItem.configuration.supportedCountryCodes, ["US", "UK"]) + XCTAssertEqual(sut.billingAddressItem.title, localizedString(.billingAddressSectionTitle, sut.configuration.localizationParameters)) XCTAssertEqual(sut.payButton.title, localizedSubmitButtonTitle(with: sut.payment?.amount, style: .immediate, @@ -121,7 +120,6 @@ class ACHDirectDebitComponentTests: XCTestCase { let payButtonItemViewButtonTitle: UILabel? = sut.viewController.view.findView(with: "AdyenComponents.ACHDirectDebitComponent.payButtonItem.button.titleLabel") XCTAssertNotNil(sut.viewController.view.findView(by: "AdyenComponents.ACHDirectDebitComponent.billingAddressItem")) - XCTAssertNotNil(sut.viewController.view.findView(by: "AdyenComponents.ACHDirectDebitComponent.billingAddressItem.title")) /// holder name XCTAssertEqual(nameItemView?.backgroundColor, .red) @@ -173,13 +171,11 @@ class ACHDirectDebitComponentTests: XCTestCase { setupRootViewController(sut.viewController) - wait(for: .milliseconds(300)) - // Then let view: UIView = sut.viewController.view - let billingAddressView: FormVerticalStackItemView = view.findView(by: "AdyenComponents.ACHDirectDebitComponent.billingAddressItem")! - let expectedBillingAddress = shopperInformation.billingAddress! + let billingAddressView: FormAddressPickerItemView = try XCTUnwrap(view.findView(by: "AdyenComponents.ACHDirectDebitComponent.billingAddressItem")) + let expectedBillingAddress = shopperInformation.billingAddress let billingAddress = billingAddressView.item.value XCTAssertEqual(expectedBillingAddress, billingAddress) } @@ -251,7 +247,7 @@ class ACHDirectDebitComponentTests: XCTestCase { let paymentMethod = ACHDirectDebitPaymentMethod(type: .achDirectDebit, name: "Test name") let sut = ACHDirectDebitComponent(paymentMethod: paymentMethod, context: context, - configuration: .init(showsBillingAddress: false), + configuration: .init(shopperInformation: shopperInformation, showsBillingAddress: false), publicKeyProvider: PublicKeyProviderMock()) setupRootViewController(sut.viewController) diff --git a/Tests/Components Tests/Affirm/AffirmComponentTests.swift b/Tests/Components Tests/Affirm/AffirmComponentTests.swift index cdda3ba0a7..2a81b5b1a7 100644 --- a/Tests/Components Tests/Affirm/AffirmComponentTests.swift +++ b/Tests/Components Tests/Affirm/AffirmComponentTests.swift @@ -10,24 +10,28 @@ import XCTest class AffirmComponentTests: XCTestCase { - private var paymentMethod: PaymentMethod! - private var context: AdyenContext! - private var style: FormComponentStyle! + private var paymentMethod: PaymentMethod { + AffirmPaymentMethod(type: .affirm, name: "Affirm") + } + + private var context: AdyenContext { + Dummy.context(with: nil) + } + + private var style: FormComponentStyle { + FormComponentStyle() + } + private var sut: AffirmComponent! override func setUpWithError() throws { try super.setUpWithError() - paymentMethod = AffirmPaymentMethod(type: .affirm, name: "Affirm") - context = Dummy.context(with: nil) - style = FormComponentStyle() sut = AffirmComponent(paymentMethod: paymentMethod, context: context, configuration: AffirmComponent.Configuration(style: style)) } override func tearDownWithError() throws { - paymentMethod = nil - style = nil sut = nil try super.tearDownWithError() } @@ -147,15 +151,15 @@ class AffirmComponentTests: XCTestCase { let emailView: FormTextInputItemView = try XCTUnwrap(view.findView(by: AffirmViewIdentifier.email)) populate(textItemView: emailView, with: "katrina@mail.com") - let billingAddressView: FormVerticalStackItemView = try XCTUnwrap(view.findView(by: AffirmViewIdentifier.billingAddress)) - fill(addressView: billingAddressView, with: expectedBillingAddress) + let billingAddressView: FormAddressPickerItemView = try XCTUnwrap(view.findView(by: AffirmViewIdentifier.billingAddress)) + billingAddressView.item.value = expectedBillingAddress let deliveryAddressToggleView: FormToggleItemView! = try XCTUnwrap(view.findView(by: AffirmViewIdentifier.deliveryAddressToggle)) deliveryAddressToggleView.switchControl.isOn = true deliveryAddressToggleView.switchControl.sendActions(for: .valueChanged) - let deliveryAddressView: FormVerticalStackItemView = try XCTUnwrap(view.findView(by: AffirmViewIdentifier.deliveryAddress)) - fill(addressView: deliveryAddressView, with: expectedDeliveryAddress) + let deliveryAddressView: FormAddressPickerItemView = try XCTUnwrap(view.findView(by: AffirmViewIdentifier.deliveryAddress)) + deliveryAddressView.item.value = expectedDeliveryAddress wait(until: firstNameView, at: \.isValid, is: true) wait(until: lastNameView, at: \.isValid, is: true) @@ -211,7 +215,7 @@ class AffirmComponentTests: XCTestCase { let email = emailView.item.value XCTAssertEqual(expectedEmail, email) - let billingAddressView: FormVerticalStackItemView = try XCTUnwrap(view.findView(by: AffirmViewIdentifier.billingAddress)) + let billingAddressView: FormAddressPickerItemView = try XCTUnwrap(view.findView(by: AffirmViewIdentifier.billingAddress)) let expectedBillingAddress = try XCTUnwrap(shopperInformation.billingAddress) let billingAddress = billingAddressView.item.value XCTAssertEqual(expectedBillingAddress, billingAddress) @@ -219,7 +223,7 @@ class AffirmComponentTests: XCTestCase { let deliveryAddressToggleView: FormToggleItemView! = try XCTUnwrap(view.findView(by: AffirmViewIdentifier.deliveryAddressToggle)) XCTAssertTrue(deliveryAddressToggleView.item.value) - let deliveryAddressView: FormVerticalStackItemView = try XCTUnwrap(view.findView(by: AffirmViewIdentifier.deliveryAddress)) + let deliveryAddressView: FormAddressPickerItemView = try XCTUnwrap(view.findView(by: AffirmViewIdentifier.deliveryAddress)) let expectedDeliveryAddress = try XCTUnwrap(shopperInformation.deliveryAddress) let deliveryAddress = deliveryAddressView.item.value XCTAssertEqual(expectedDeliveryAddress, deliveryAddress) @@ -259,7 +263,7 @@ class AffirmComponentTests: XCTestCase { let email = emailView.item.value XCTAssertEqual(expectedEmail, email) - let billingAddressView: FormVerticalStackItemView = try XCTUnwrap(view.findView(by: AffirmViewIdentifier.billingAddress)) + let billingAddressView: FormAddressPickerItemView = try XCTUnwrap(view.findView(by: AffirmViewIdentifier.billingAddress)) let expectedBillingAddress = try XCTUnwrap(shopperInformation.billingAddress) let billingAddress = billingAddressView.item.value XCTAssertEqual(expectedBillingAddress, billingAddress) @@ -267,18 +271,14 @@ class AffirmComponentTests: XCTestCase { let deliveryAddressToggleView: FormToggleItemView! = try XCTUnwrap(view.findView(by: AffirmViewIdentifier.deliveryAddressToggle)) XCTAssertFalse(deliveryAddressToggleView.item.value) - let deliveryAddressView: FormVerticalStackItemView = try XCTUnwrap(view.findView(by: AffirmViewIdentifier.deliveryAddress)) - let expectedDeliveryAddress = PostalAddressMocks.emptyUSPostalAddress - let deliveryAddress = deliveryAddressView.item.value - XCTAssertEqual(expectedDeliveryAddress, deliveryAddress) + let deliveryAddressView: FormAddressPickerItemView = try XCTUnwrap(view.findView(by: AffirmViewIdentifier.deliveryAddress)) + XCTAssertNil(deliveryAddressView.item.value) } func testAffirm_givenNoShopperInformation_shouldNotPrefill() throws { // Given setupRootViewController(sut.viewController) - wait(for: .seconds(1)) - // Then let view: UIView = sut.viewController.view @@ -298,18 +298,14 @@ class AffirmComponentTests: XCTestCase { let email = emailView.item.value XCTAssertTrue(email.isEmpty) - let billingAddressView: FormVerticalStackItemView = try XCTUnwrap(view.findView(by: AffirmViewIdentifier.billingAddress)) - let expectedBillingAddress = PostalAddressMocks.emptyUSPostalAddress - let billingAddress = billingAddressView.item.value - XCTAssertEqual(expectedBillingAddress, billingAddress) + let billingAddressView: FormAddressPickerItemView = try XCTUnwrap(view.findView(by: AffirmViewIdentifier.billingAddress)) + XCTAssertNil(billingAddressView.item.value) - let deliveryAddressToggleView: FormToggleItemView! = try XCTUnwrap(view.findView(by: AffirmViewIdentifier.deliveryAddressToggle)) + let deliveryAddressToggleView: FormToggleItemView = try XCTUnwrap(view.findView(by: AffirmViewIdentifier.deliveryAddressToggle)) XCTAssertFalse(deliveryAddressToggleView.item.value) - let deliveryAddressView: FormVerticalStackItemView = try XCTUnwrap(view.findView(by: AffirmViewIdentifier.deliveryAddress)) - let expectedDeliveryAddress = PostalAddressMocks.emptyUSPostalAddress - let deliveryAddress = deliveryAddressView.item.value - XCTAssertEqual(expectedDeliveryAddress, deliveryAddress) + let deliveryAddressView: FormAddressPickerItemView = try XCTUnwrap(view.findView(by: AffirmViewIdentifier.deliveryAddress)) + XCTAssertNil(deliveryAddressView.item.value) } func testViewWillAppear_shouldSendTelemetryEvent() throws { diff --git a/Tests/Components Tests/Boleto/BoletoComponentTests.swift b/Tests/Components Tests/Boleto/BoletoComponentTests.swift index 3b70a852d4..2df054b199 100644 --- a/Tests/Components Tests/Boleto/BoletoComponentTests.swift +++ b/Tests/Components Tests/Boleto/BoletoComponentTests.swift @@ -30,45 +30,21 @@ class BoletoComponentTests: XCTestCase { setupRootViewController(viewController) - let firstNameField: UITextField? = viewController.view.findView(by: "firstNameItem.textField") as? UITextField - let lastNameField: UITextField? = viewController.view.findView(by: "lastNameItem.textField") as? UITextField - let socialSecurityNumberField: UITextField? = viewController.view.findView(by: "socialSecurityNumberItem.textField") as? UITextField - let emailField: UITextField? = viewController.view.findView(by: "emailItem.textField") as? UITextField - - let streetField = viewController.view.findView(by: "addressItem.street.textField") as? UITextField - let houseNumberField = viewController.view.findView(by: "addressItem.houseNumberOrName.textField") as? UITextField - let cityField = viewController.view.findView(by: "addressItem.city.textField") as? UITextField - let postalCodeField = viewController.view.findView(by: "addressItem.postalCode.textField") as? UITextField - - XCTAssertNotNil(viewController.view.findView(by: "addressItem.title")) - - XCTAssertNotNil(firstNameField) - XCTAssertEqual(firstNameField?.text, prefilledInformation.shopperName?.firstName) - - XCTAssertNotNil(lastNameField) - XCTAssertEqual(lastNameField?.text, prefilledInformation.shopperName?.lastName) - - XCTAssertNotNil(socialSecurityNumberField) + let firstNameField: UITextField = try XCTUnwrap(viewController.view.findView(by: "firstNameItem.textField")) + let lastNameField: UITextField = try XCTUnwrap(viewController.view.findView(by: "lastNameItem.textField")) + let socialSecurityNumberField: UITextField = try XCTUnwrap(viewController.view.findView(by: "socialSecurityNumberItem.textField")) + let emailField: UITextField = try XCTUnwrap(viewController.view.findView(by: "emailItem.textField")) + let addressField: FormAddressPickerItemView = try XCTUnwrap(viewController.view.findView(by: "addressItem")) + + XCTAssertEqual(firstNameField.text, prefilledInformation.shopperName?.firstName) + XCTAssertEqual(lastNameField.text, prefilledInformation.shopperName?.lastName) let formattedSocialSecurityNumber = brazilSocialSecurityNumberFormatter.formattedValue(for: prefilledInformation.socialSecurityNumber!) - XCTAssertEqual(socialSecurityNumberField?.text, formattedSocialSecurityNumber) - - XCTAssertNotNil(emailField) - XCTAssertEqual(emailField?.text, prefilledInformation.emailAddress) - - XCTAssertNotNil(streetField) - XCTAssertEqual(streetField?.text, Dummy.dummyAddress.street) - - XCTAssertNotNil(houseNumberField) - XCTAssertEqual(houseNumberField?.text, Dummy.dummyAddress.houseNumberOrName) - - XCTAssertNotNil(cityField) - XCTAssertEqual(cityField?.text, Dummy.dummyAddress.city) - - XCTAssertNotNil(postalCodeField) - XCTAssertEqual(postalCodeField?.text, Dummy.dummyAddress.postalCode) + XCTAssertEqual(socialSecurityNumberField.text, formattedSocialSecurityNumber) + XCTAssertEqual(emailField.text, prefilledInformation.emailAddress) + XCTAssertEqual(addressField.item.value, Dummy.dummyAddress) } - func testNoPrefilledInformation() { + func testNoPrefilledInformation() throws { let context = Dummy.context(with: AnalyticsProviderMock()) @@ -87,34 +63,8 @@ class BoletoComponentTests: XCTestCase { let socialSecurityNumberField: UITextField? = viewController.view.findView(by: "socialSecurityNumberItem.textField") as? UITextField let emailField: UITextField? = viewController.view.findView(by: "emailItem.textField") as? UITextField - let streetField = viewController.view.findView(by: "addressItem.street.textField") as? UITextField - let houseNumberField = viewController.view.findView(by: "addressItem.houseNumberOrName.textField") as? UITextField - let cityField = viewController.view.findView(by: "addressItem.city.textField") as? UITextField - let postalCodeField = viewController.view.findView(by: "addressItem.postalCode.textField") as? UITextField - - XCTAssertNotNil(firstNameField) - XCTAssertNil(firstNameField?.text?.adyen.nilIfEmpty) - - XCTAssertNotNil(lastNameField) - XCTAssertNil(lastNameField?.text?.adyen.nilIfEmpty) - - XCTAssertNotNil(socialSecurityNumberField) - XCTAssertNil(socialSecurityNumberField?.text?.adyen.nilIfEmpty) - - XCTAssertNotNil(emailField) - XCTAssertNil(emailField?.text?.adyen.nilIfEmpty) - - XCTAssertNotNil(streetField) - XCTAssertTrue(streetField?.text?.isEmpty ?? true) - - XCTAssertNotNil(houseNumberField) - XCTAssertTrue(houseNumberField?.text?.isEmpty ?? true) - - XCTAssertNotNil(cityField) - XCTAssertTrue(cityField?.text?.isEmpty ?? true) - - XCTAssertNotNil(postalCodeField) - XCTAssertTrue(postalCodeField?.text?.isEmpty ?? true) + let addressField: FormAddressPickerItemView = try XCTUnwrap(viewController.view.findView(by: "addressItem")) + XCTAssertNil(addressField.item.value) } func testNoEmailSection() { diff --git a/Tests/Helpers/FormVerticalStackItemView+IsValid.swift b/Tests/Helpers/FormVerticalStackItemView+IsValid.swift deleted file mode 100644 index 5642441c8c..0000000000 --- a/Tests/Helpers/FormVerticalStackItemView+IsValid.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// Copyright (c) 2023 Adyen N.V. -// -// This file is open source and available under the MIT license. See the LICENSE file for more info. -// - -@_spi(AdyenInternal) import Adyen - -extension FormVerticalStackItemView { - - /// Returns true if all validatable items are valid - var isValid: Bool { - return flatSubitemViews.compactMap { $0 as? AnyFormValidatableValueItemView }.allSatisfy(\.isValid) - } -} diff --git a/Tests/Helpers/XCTestCase+FirstResponder.swift b/Tests/Helpers/XCTestCase+FirstResponder.swift index ee9ecaae5a..0626404f0c 100644 --- a/Tests/Helpers/XCTestCase+FirstResponder.swift +++ b/Tests/Helpers/XCTestCase+FirstResponder.swift @@ -10,8 +10,8 @@ import XCTest extension XCTestCase { /// invokes endEditing on the view and waits until none of the subviews is first responder anymore func endEditing(for view: UIView) { - guard view.firstResponder != nil else { return } - view.endEditing(true) + guard let responder = view.firstResponder else { return } + responder.endEditing(true) wait(until: view, at: \.firstResponder, is: nil) } } diff --git a/Tests/Helpers/XCTestCase+RootViewController.swift b/Tests/Helpers/XCTestCase+RootViewController.swift index 09c584384b..294d2ea86e 100644 --- a/Tests/Helpers/XCTestCase+RootViewController.swift +++ b/Tests/Helpers/XCTestCase+RootViewController.swift @@ -65,8 +65,10 @@ extension DispatchTimeInterval { extension XCTestCase { enum TestAnimationSpeed: Float { + /// Default system animation speed case system = 1 - case fast = 100 + /// 10x speed + case fast = 10 } /// Executes a block with a specified animation speed diff --git a/UITests/Components/Affirm/AffirmComponentUITests.swift b/UITests/Components/Affirm/AffirmComponentUITests.swift index 35cb1efe26..efa3347459 100644 --- a/UITests/Components/Affirm/AffirmComponentUITests.swift +++ b/UITests/Components/Affirm/AffirmComponentUITests.swift @@ -80,8 +80,8 @@ class AffirmComponentUITests: XCTestCase { let phoneNumberView: FormPhoneNumberItemView = try XCTUnwrap(view.findView(by: AffirmViewIdentifier.phone)) let emailView: FormTextInputItemView = try XCTUnwrap(view.findView(by: AffirmViewIdentifier.email)) - let billingAddressView: FormVerticalStackItemView = try XCTUnwrap(view.findView(by: AffirmViewIdentifier.billingAddress)) - let deliveryAddressView: FormVerticalStackItemView = try XCTUnwrap(view.findView(by: AffirmViewIdentifier.deliveryAddress)) + let billingAddressView: FormAddressPickerItemView = try XCTUnwrap(view.findView(by: AffirmViewIdentifier.billingAddress)) + let deliveryAddressView: FormAddressPickerItemView = try XCTUnwrap(view.findView(by: AffirmViewIdentifier.deliveryAddress)) wait(until: firstNameView, at: \.isValid, is: true) wait(until: lastNameView, at: \.isValid, is: true) @@ -91,8 +91,6 @@ class AffirmComponentUITests: XCTestCase { wait(until: billingAddressView, at: \.isValid, is: true) wait(until: deliveryAddressView, at: \.isValid, is: true) - XCTAssertNotNil(view.findView(by: "AdyenComponents.AffirmComponent.addressItem.title")) - let submitButton: UIControl = try XCTUnwrap(view.findView(by: AffirmViewIdentifier.payButton)) submitButton.sendActions(for: .touchUpInside) @@ -138,7 +136,7 @@ class AffirmComponentUITests: XCTestCase { XCTAssertEqual(expectedDeliveryAddress, deliveryAddress) let view = try XCTUnwrap(prefillSut.viewController.view) - let billingAddressView: FormVerticalStackItemView = try XCTUnwrap(view.findView(by: "addressItem")) + let billingAddressView: FormAddressPickerItemView = try XCTUnwrap(view.findView(by: "addressItem")) wait(until: billingAddressView, at: \.isValid, is: true) endEditing(for: prefillSut.viewController.view) @@ -180,12 +178,11 @@ class AffirmComponentUITests: XCTestCase { XCTAssertFalse(prefillSut.deliveryAddressToggleItem.value) - let expectedDeliveryAddress = PostalAddressMocks.emptyUSPostalAddress - let deliveryAddress = try XCTUnwrap(prefillSut.deliveryAddressItem?.value) - XCTAssertEqual(expectedDeliveryAddress, deliveryAddress) + let deliveryAddress = try XCTUnwrap(prefillSut.deliveryAddressItem) + XCTAssertNil(deliveryAddress.value) let view = try XCTUnwrap(prefillSut.viewController.view) - let billingAddressView: FormVerticalStackItemView = try XCTUnwrap(view.findView(by: "addressItem")) + let billingAddressView: FormAddressPickerItemView = try XCTUnwrap(view.findView(by: "addressItem")) wait(until: billingAddressView, at: \.isValid, is: true) endEditing(for: prefillSut.viewController.view) @@ -215,15 +212,13 @@ class AffirmComponentUITests: XCTestCase { let email = try XCTUnwrap(sut.emailItem?.value) XCTAssertTrue(email.isEmpty) - let expectedBillingAddress = PostalAddressMocks.emptyUSPostalAddress - let billingAddress = try XCTUnwrap(sut.addressItem?.value) - XCTAssertEqual(expectedBillingAddress, billingAddress) + let billingAddress = try XCTUnwrap(sut.addressItem) + XCTAssertNil(billingAddress.value) XCTAssertFalse(sut.deliveryAddressToggleItem.value) - let expectedDeliveryAddress = PostalAddressMocks.emptyUSPostalAddress - let deliveryAddress = try XCTUnwrap(sut.deliveryAddressItem?.value) - XCTAssertEqual(expectedDeliveryAddress, deliveryAddress) + let deliveryAddress = try XCTUnwrap(sut.deliveryAddressItem) + XCTAssertNil(deliveryAddress.value) endEditing(for: sut.viewController.view) diff --git a/UITests/Components/Affirm/__Snapshots__/AffirmComponentUITests/testAffirmPrefilling_givenDeliveryAddressIsNotSet-iPhone12.shopper-info-prefilled-address-not-set.png b/UITests/Components/Affirm/__Snapshots__/AffirmComponentUITests/testAffirmPrefilling_givenDeliveryAddressIsNotSet-iPhone12.shopper-info-prefilled-address-not-set.png index 2b5518256c..cc70c444c2 100644 Binary files a/UITests/Components/Affirm/__Snapshots__/AffirmComponentUITests/testAffirmPrefilling_givenDeliveryAddressIsNotSet-iPhone12.shopper-info-prefilled-address-not-set.png and b/UITests/Components/Affirm/__Snapshots__/AffirmComponentUITests/testAffirmPrefilling_givenDeliveryAddressIsNotSet-iPhone12.shopper-info-prefilled-address-not-set.png differ diff --git a/UITests/Components/Affirm/__Snapshots__/AffirmComponentUITests/testAffirmPrefilling_givenDeliveryAddressIsNotSet-iPhone12.shopper-info-prefilled.png b/UITests/Components/Affirm/__Snapshots__/AffirmComponentUITests/testAffirmPrefilling_givenDeliveryAddressIsNotSet-iPhone12.shopper-info-prefilled.png index 6d9eae8a37..cc70c444c2 100644 Binary files a/UITests/Components/Affirm/__Snapshots__/AffirmComponentUITests/testAffirmPrefilling_givenDeliveryAddressIsNotSet-iPhone12.shopper-info-prefilled.png and b/UITests/Components/Affirm/__Snapshots__/AffirmComponentUITests/testAffirmPrefilling_givenDeliveryAddressIsNotSet-iPhone12.shopper-info-prefilled.png differ diff --git a/UITests/Components/Affirm/__Snapshots__/AffirmComponentUITests/testAffirmPrefilling_givenDeliveryAddressIsSet-iPhone12.shopper-info-prefilled-address-set.png b/UITests/Components/Affirm/__Snapshots__/AffirmComponentUITests/testAffirmPrefilling_givenDeliveryAddressIsSet-iPhone12.shopper-info-prefilled-address-set.png index 618541b14c..fae4f55874 100644 Binary files a/UITests/Components/Affirm/__Snapshots__/AffirmComponentUITests/testAffirmPrefilling_givenDeliveryAddressIsSet-iPhone12.shopper-info-prefilled-address-set.png and b/UITests/Components/Affirm/__Snapshots__/AffirmComponentUITests/testAffirmPrefilling_givenDeliveryAddressIsSet-iPhone12.shopper-info-prefilled-address-set.png differ diff --git a/UITests/Components/Affirm/__Snapshots__/AffirmComponentUITests/testAffirmPrefilling_givenDeliveryAddressIsSet-iPhone12.shopper-info-prefilled.png b/UITests/Components/Affirm/__Snapshots__/AffirmComponentUITests/testAffirmPrefilling_givenDeliveryAddressIsSet-iPhone12.shopper-info-prefilled.png index 60a4be3393..fae4f55874 100644 Binary files a/UITests/Components/Affirm/__Snapshots__/AffirmComponentUITests/testAffirmPrefilling_givenDeliveryAddressIsSet-iPhone12.shopper-info-prefilled.png and b/UITests/Components/Affirm/__Snapshots__/AffirmComponentUITests/testAffirmPrefilling_givenDeliveryAddressIsSet-iPhone12.shopper-info-prefilled.png differ diff --git a/UITests/Components/Affirm/__Snapshots__/AffirmComponentUITests/testAffirm_givenNoShopperInformation_shouldNotPrefill-iPhone12.shopper-info-not-filled.png b/UITests/Components/Affirm/__Snapshots__/AffirmComponentUITests/testAffirm_givenNoShopperInformation_shouldNotPrefill-iPhone12.shopper-info-not-filled.png index 61e5972624..ad2c49b5c5 100644 Binary files a/UITests/Components/Affirm/__Snapshots__/AffirmComponentUITests/testAffirm_givenNoShopperInformation_shouldNotPrefill-iPhone12.shopper-info-not-filled.png and b/UITests/Components/Affirm/__Snapshots__/AffirmComponentUITests/testAffirm_givenNoShopperInformation_shouldNotPrefill-iPhone12.shopper-info-not-filled.png differ diff --git a/UITests/Components/Affirm/__Snapshots__/AffirmComponentUITests/testSubmitForm_shouldCallDelegateWithProperParameters-iPhone12.shopper-info-prefilled.png b/UITests/Components/Affirm/__Snapshots__/AffirmComponentUITests/testSubmitForm_shouldCallDelegateWithProperParameters-iPhone12.shopper-info-prefilled.png index 406ee96a1c..8a5c1010ec 100644 Binary files a/UITests/Components/Affirm/__Snapshots__/AffirmComponentUITests/testSubmitForm_shouldCallDelegateWithProperParameters-iPhone12.shopper-info-prefilled.png and b/UITests/Components/Affirm/__Snapshots__/AffirmComponentUITests/testSubmitForm_shouldCallDelegateWithProperParameters-iPhone12.shopper-info-prefilled.png differ diff --git a/UITests/Components/Atome/AtomeComponentUITests.swift b/UITests/Components/Atome/AtomeComponentUITests.swift index bad905fcd7..4b82c42b0e 100644 --- a/UITests/Components/Atome/AtomeComponentUITests.swift +++ b/UITests/Components/Atome/AtomeComponentUITests.swift @@ -58,7 +58,7 @@ class AtomeComponentUITests: XCTestCase { context: context, configuration: config) - XCTAssertNotNil(sut.viewController.view.findView(by: "AdyenComponents.AtomeComponent.addressItem.title")) + XCTAssertNotNil(sut.viewController.view.findView(by: "AdyenComponents.AtomeComponent.addressItem")) assertViewControllerImage(matching: sut.viewController, named: "UI_configuration") } @@ -105,7 +105,7 @@ class AtomeComponentUITests: XCTestCase { let lastNameView: FormTextInputItemView = try XCTUnwrap(view.findView(by: AtomeViewIdentifier.lastName)) let phoneNumberView: FormPhoneNumberItemView = try XCTUnwrap(view.findView(by: AtomeViewIdentifier.phone)) - let billingAddressView: FormVerticalStackItemView = try XCTUnwrap(view.findView(by: AtomeViewIdentifier.billingAddress)) + let billingAddressView: FormAddressPickerItemView = try XCTUnwrap(view.findView(by: AtomeViewIdentifier.billingAddress)) wait(until: firstNameView, at: \.isValid, is: true) wait(until: lastNameView, at: \.isValid, is: true) diff --git a/UITests/Components/Atome/__Snapshots__/AtomeComponentUITests/testAllRequiredTextField_shouldExist-iPhone12.all_required_fields_exist.png b/UITests/Components/Atome/__Snapshots__/AtomeComponentUITests/testAllRequiredTextField_shouldExist-iPhone12.all_required_fields_exist.png index b27cd39f1e..5b4d56938c 100644 Binary files a/UITests/Components/Atome/__Snapshots__/AtomeComponentUITests/testAllRequiredTextField_shouldExist-iPhone12.all_required_fields_exist.png and b/UITests/Components/Atome/__Snapshots__/AtomeComponentUITests/testAllRequiredTextField_shouldExist-iPhone12.all_required_fields_exist.png differ diff --git a/UITests/Components/Atome/__Snapshots__/AtomeComponentUITests/testAtome_givenNoShopperInformation_shouldNotPrefill-iPhone12.empty_form.png b/UITests/Components/Atome/__Snapshots__/AtomeComponentUITests/testAtome_givenNoShopperInformation_shouldNotPrefill-iPhone12.empty_form.png index aae996daef..512081a2a1 100644 Binary files a/UITests/Components/Atome/__Snapshots__/AtomeComponentUITests/testAtome_givenNoShopperInformation_shouldNotPrefill-iPhone12.empty_form.png and b/UITests/Components/Atome/__Snapshots__/AtomeComponentUITests/testAtome_givenNoShopperInformation_shouldNotPrefill-iPhone12.empty_form.png differ diff --git a/UITests/Components/Atome/__Snapshots__/AtomeComponentUITests/testSubmitForm_shouldCallDelegateWithProperParameters-iPhone12.prefilled_shopper_info.png b/UITests/Components/Atome/__Snapshots__/AtomeComponentUITests/testSubmitForm_shouldCallDelegateWithProperParameters-iPhone12.prefilled_shopper_info.png index b27cd39f1e..5b4d56938c 100644 Binary files a/UITests/Components/Atome/__Snapshots__/AtomeComponentUITests/testSubmitForm_shouldCallDelegateWithProperParameters-iPhone12.prefilled_shopper_info.png and b/UITests/Components/Atome/__Snapshots__/AtomeComponentUITests/testSubmitForm_shouldCallDelegateWithProperParameters-iPhone12.prefilled_shopper_info.png differ diff --git a/UITests/Components/Atome/__Snapshots__/AtomeComponentUITests/testUIConfiguration-iPhone12.UI_configuration.png b/UITests/Components/Atome/__Snapshots__/AtomeComponentUITests/testUIConfiguration-iPhone12.UI_configuration.png index 6034b1dc07..b51e0110d4 100644 Binary files a/UITests/Components/Atome/__Snapshots__/AtomeComponentUITests/testUIConfiguration-iPhone12.UI_configuration.png and b/UITests/Components/Atome/__Snapshots__/AtomeComponentUITests/testUIConfiguration-iPhone12.UI_configuration.png differ diff --git a/UITests/Components/BLIK/BLIKComponentUITests.swift b/UITests/Components/BLIK/BLIKComponentUITests.swift index e3ada89b04..5bf5ded371 100644 --- a/UITests/Components/BLIK/BLIKComponentUITests.swift +++ b/UITests/Components/BLIK/BLIKComponentUITests.swift @@ -11,27 +11,12 @@ import XCTest final class BLIKComponentUITests: XCTestCase { - private var paymentMethod: BLIKPaymentMethod! - private var context: AdyenContext! - private var style: FormComponentStyle! - - override func setUpWithError() throws { - paymentMethod = BLIKPaymentMethod(type: .blik, name: "test_name") - let payment = Payment(amount: Amount(value: 2, currencyCode: "PLN"), countryCode: "PL") - context = AdyenContext(apiContext: Dummy.apiContext, payment: payment) - style = FormComponentStyle() - UIApplication.shared.adyen.mainKeyWindow?.layer.speed = 1 - try super.setUpWithError() - } - - override func tearDownWithError() throws { - paymentMethod = nil - context = nil - style = nil - } + private let payment = Payment(amount: Amount(value: 2, currencyCode: "PLN"), countryCode: "PL") + private var paymentMethod: BLIKPaymentMethod { BLIKPaymentMethod(type: .blik, name: "test_name") } + private var context: AdyenContext { AdyenContext(apiContext: Dummy.apiContext, payment: payment) } func testUIConfiguration() { - style = FormComponentStyle() + var style = FormComponentStyle() style.hintLabel.backgroundColor = .brown style.hintLabel.font = .systemFont(ofSize: 10) @@ -66,7 +51,7 @@ final class BLIKComponentUITests: XCTestCase { } func testSubmitForm() throws { - let config = BLIKComponent.Configuration(style: style) + let config = BLIKComponent.Configuration(style: .init()) let sut = BLIKComponent(paymentMethod: paymentMethod, context: context, configuration: config) let delegate = PaymentComponentDelegateMock() @@ -103,25 +88,25 @@ final class BLIKComponentUITests: XCTestCase { } func testSubmitButtonLoading() throws { - let config = BLIKComponent.Configuration(style: style) + let config = BLIKComponent.Configuration(style: .init()) let sut = BLIKComponent(paymentMethod: paymentMethod, context: context, configuration: config) setupRootViewController(sut.viewController) - // Disabling animation to assure the spinner is always in the same state when taking the snapshot - UIApplication.shared.adyen.mainKeyWindow?.layer.speed = 0 + let submitButton: SubmitButton = try XCTUnwrap(sut.viewController.view.findView(with: "AdyenComponents.BLIKComponent.payButtonItem.button")) + + endEditing(for: sut.viewController.view) - let submitButton: SubmitButton! = sut.viewController.view.findView(with: "AdyenComponents.BLIKComponent.payButtonItem.button") - try withoutAnimation { // start loading submitButton.showsActivityIndicator = true wait(until: submitButton, at: \.showsActivityIndicator, is: true) assertViewControllerImage(matching: sut.viewController, named: "initial_state") - + // stop loading sut.stopLoading() submitButton.showsActivityIndicator = false + wait(until: submitButton, at: \.showsActivityIndicator, is: false) assertViewControllerImage(matching: sut.viewController, named: "stopped_loading") } diff --git a/UITests/Components/Boleto/BoletoComponentUITests.swift b/UITests/Components/Boleto/BoletoComponentUITests.swift index dc7dd8e7bd..6d814c60e7 100644 --- a/UITests/Components/Boleto/BoletoComponentUITests.swift +++ b/UITests/Components/Boleto/BoletoComponentUITests.swift @@ -74,9 +74,14 @@ final class BoletoComponentUITests: XCTestCase { background: .magenta ) - let sut = BoletoComponent(paymentMethod: paymentMethod, - context: context, - configuration: Dummy.getConfiguration(showEmailAddress: true)) + let sut = BoletoComponent( + paymentMethod: paymentMethod, + context: context, + configuration: Dummy.getConfiguration( + style: style, + showEmailAddress: true + ) + ) verifyViewControllerImage(matching: sut.viewController, named: "UI_configuration") } @@ -99,7 +104,7 @@ final class BoletoComponentUITests: XCTestCase { let submitButton: SubmitButton = try XCTUnwrap(view.findView(by: "payButtonItem.button")) let firstNameView: FormTextInputItemView = try XCTUnwrap(view.findView(by: "firstNameItem")) let lastNameView: FormTextInputItemView = try XCTUnwrap(view.findView(by: "lastNameItem")) - let billingAddressView: FormVerticalStackItemView = try XCTUnwrap(view.findView(by: "addressItem")) + let billingAddressView: FormAddressPickerItemView = try XCTUnwrap(view.findView(by: "addressItem")) mockDelegate.onDidSubmit = { paymentData, paymentComponent in let boletoDetails = paymentData.paymentMethod as? BoletoDetails diff --git a/UITests/Components/Boleto/__Snapshots__/BoletoComponentUITests/testPaymentDataNoName-iPhone12.boleto_flow_no_name.png b/UITests/Components/Boleto/__Snapshots__/BoletoComponentUITests/testPaymentDataNoName-iPhone12.boleto_flow_no_name.png index 76ed7fc94c..ccd35eddec 100644 Binary files a/UITests/Components/Boleto/__Snapshots__/BoletoComponentUITests/testPaymentDataNoName-iPhone12.boleto_flow_no_name.png and b/UITests/Components/Boleto/__Snapshots__/BoletoComponentUITests/testPaymentDataNoName-iPhone12.boleto_flow_no_name.png differ diff --git a/UITests/Components/Boleto/__Snapshots__/BoletoComponentUITests/testPaymentDataProvided-iPhone12.boleto_flow.png b/UITests/Components/Boleto/__Snapshots__/BoletoComponentUITests/testPaymentDataProvided-iPhone12.boleto_flow.png index 34d9a165bb..6abb5e3efb 100644 Binary files a/UITests/Components/Boleto/__Snapshots__/BoletoComponentUITests/testPaymentDataProvided-iPhone12.boleto_flow.png and b/UITests/Components/Boleto/__Snapshots__/BoletoComponentUITests/testPaymentDataProvided-iPhone12.boleto_flow.png differ diff --git a/UITests/Components/Boleto/__Snapshots__/BoletoComponentUITests/testPaymentDataProvidedNoEmail-iPhone12.boleto_flow.png b/UITests/Components/Boleto/__Snapshots__/BoletoComponentUITests/testPaymentDataProvidedNoEmail-iPhone12.boleto_flow.png deleted file mode 100644 index 500807b71c..0000000000 Binary files a/UITests/Components/Boleto/__Snapshots__/BoletoComponentUITests/testPaymentDataProvidedNoEmail-iPhone12.boleto_flow.png and /dev/null differ diff --git a/UITests/Components/Boleto/__Snapshots__/BoletoComponentUITests/testUIConfiguration-iPhone12.UI_configuration.png b/UITests/Components/Boleto/__Snapshots__/BoletoComponentUITests/testUIConfiguration-iPhone12.UI_configuration.png index 932985057c..10e651826b 100644 Binary files a/UITests/Components/Boleto/__Snapshots__/BoletoComponentUITests/testUIConfiguration-iPhone12.UI_configuration.png and b/UITests/Components/Boleto/__Snapshots__/BoletoComponentUITests/testUIConfiguration-iPhone12.UI_configuration.png differ diff --git a/UITests/Components/Doku/DokuComponentUITests.swift b/UITests/Components/Doku/DokuComponentUITests.swift index c4f9a2ff21..52f2c26412 100644 --- a/UITests/Components/Doku/DokuComponentUITests.swift +++ b/UITests/Components/Doku/DokuComponentUITests.swift @@ -89,14 +89,13 @@ final class DokuComponentUITests: XCTestCase { XCTAssertEqual(data.firstName, "Mohamed") XCTAssertEqual(data.lastName, "Smith") XCTAssertEqual(data.emailAddress, "mohamed.smith@domain.com") - + sut.stopLoadingIfNeeded() delegateExpectation.fulfill() XCTAssertEqual(sut.viewController.view.isUserInteractionEnabled, true) XCTAssertEqual(sut.button.showsActivityIndicator, false) - self.wait(for: .aMoment) - self.assertViewControllerImage(matching: sut.viewController, named: "doku_flow") + self.verifyViewControllerImage(matching: sut.viewController, named: "doku_flow") delegateExpectation.fulfill() } diff --git a/UITests/Components/MBWay/MBWayComponentUITests.swift b/UITests/Components/MBWay/MBWayComponentUITests.swift index 5c1f095907..1808b3c0be 100644 --- a/UITests/Components/MBWay/MBWayComponentUITests.swift +++ b/UITests/Components/MBWay/MBWayComponentUITests.swift @@ -84,7 +84,7 @@ final class MBWayComponentUITests: XCTestCase { XCTAssertEqual(sut.viewController.view.isUserInteractionEnabled, true) XCTAssertEqual(sut.button.showsActivityIndicator, false) - self.assertViewControllerImage(matching: sut.viewController, named: "mbway_flow") + self.verifyViewControllerImage(matching: sut.viewController, named: "mbway_flow") delegateExpectation.fulfill() } diff --git a/UITests/Components/Online Banking/OnlineBankingComponentUITests.swift b/UITests/Components/Online Banking/OnlineBankingComponentUITests.swift index 9b4087e1ae..9801239128 100644 --- a/UITests/Components/Online Banking/OnlineBankingComponentUITests.swift +++ b/UITests/Components/Online Banking/OnlineBankingComponentUITests.swift @@ -84,8 +84,7 @@ class OnlineBankingComponentUITests: XCTestCase { XCTAssertEqual(details.issuer, "jp") sut.stopLoadingIfNeeded() - self.wait(for: .aMoment) - self.assertViewControllerImage(matching: sut.viewController, named: "online_banking_flow") + self.verifyViewControllerImage(matching: sut.viewController, named: "online_banking_flow") didContinueExpectation.fulfill() } diff --git a/UITests/Components/QRCode/QRCodeActionComponentUITests.swift b/UITests/Components/QRCode/QRCodeActionComponentUITests.swift index f1a7a5cfcb..235a499574 100644 --- a/UITests/Components/QRCode/QRCodeActionComponentUITests.swift +++ b/UITests/Components/QRCode/QRCodeActionComponentUITests.swift @@ -11,18 +11,6 @@ import XCTest class QRCodeActionComponentUITests: XCTestCase { - var context: AdyenContext! - - override func setUpWithError() throws { - try super.setUpWithError() - context = Dummy.context - } - - override func tearDownWithError() throws { - context = nil - try super.tearDownWithError() - } - func testUIConfigurationForPromptPay() { lazy var method = InstantPaymentMethod(type: .other("promptpay"), name: "promptpay") let action = QRCodeAction(paymentMethodType: .promptPay, qrCodeData: "DummyData", paymentData: "DummyData") @@ -61,20 +49,21 @@ class QRCodeActionComponentUITests: XCTestCase { style.backgroundColor = UIColor.Adyen.componentSeparator - let sut = QRCodeActionComponent(context: context) + let sut = QRCodeActionComponent(context: Dummy.context) sut.configuration.style = style let presentationDelegate = PresentationDelegateMock() sut.presentationDelegate = presentationDelegate presentationDelegate.doPresent = { component in - let qrCodeViewController = component.viewController as? QRCodeViewController - XCTAssertNotNil(qrCodeViewController) + let qrCodeViewController = try XCTUnwrap(component.viewController as? QRCodeViewController) + + self.setupRootViewController(qrCodeViewController) - self.setupRootViewController(component.viewController) - self.wait { qrCodeViewController?.qrCodeView.expirationLabel.text?.starts(with: "This QR code is valid for") == true } - self.wait { qrCodeViewController?.qrCodeView.logo.image != nil } + let qrCodeView = qrCodeViewController.qrCodeView + self.wait { qrCodeView.expirationLabel.text?.starts(with: "This QR code is valid for") == true } + self.wait { qrCodeView.logo.image != nil } - self.assertViewControllerImage(matching: component.viewController, named: "promptPay") + self.assertViewControllerImage(matching: qrCodeViewController, named: "promptPay") dummyExpectation.fulfill() } @@ -122,20 +111,21 @@ class QRCodeActionComponentUITests: XCTestCase { style.backgroundColor = UIColor.Adyen.componentSeparator - let sut = QRCodeActionComponent(context: context) + let sut = QRCodeActionComponent(context: Dummy.context) sut.configuration.style = style let presentationDelegate = PresentationDelegateMock() sut.presentationDelegate = presentationDelegate presentationDelegate.doPresent = { component in - let qrCodeViewController = component.viewController as? QRCodeViewController - XCTAssertNotNil(qrCodeViewController) + let qrCodeViewController = try XCTUnwrap(component.viewController as? QRCodeViewController) - self.setupRootViewController(component.viewController) - self.wait { qrCodeViewController?.qrCodeView.expirationLabel.text?.starts(with: "You have") == true } - self.wait { qrCodeViewController?.qrCodeView.logo.image != nil } + self.setupRootViewController(qrCodeViewController) - self.assertViewControllerImage(matching: component.viewController, named: "pix") + let qrCodeView = qrCodeViewController.qrCodeView + self.wait { qrCodeView.expirationLabel.text?.starts(with: "You have") == true } + self.wait { qrCodeView.logo.image != nil } + + self.verifyViewControllerImage(matching: qrCodeViewController, named: "pix") dummyExpectation.fulfill() } @@ -183,20 +173,21 @@ class QRCodeActionComponentUITests: XCTestCase { style.backgroundColor = UIColor.Adyen.componentSeparator - let sut = QRCodeActionComponent(context: context) + let sut = QRCodeActionComponent(context: Dummy.context) sut.configuration.style = style let presentationDelegate = PresentationDelegateMock() sut.presentationDelegate = presentationDelegate presentationDelegate.doPresent = { component in - let qrCodeViewController = component.viewController as? QRCodeViewController - XCTAssertNotNil(qrCodeViewController) - - self.setupRootViewController(component.viewController) - self.wait { qrCodeViewController?.qrCodeView.expirationLabel.text?.starts(with: "You have") == true } - self.wait { qrCodeViewController?.qrCodeView.logo.image != nil } + let qrCodeViewController = try XCTUnwrap(component.viewController as? QRCodeViewController) - self.assertViewControllerImage(matching: component.viewController, named: "upi") + self.setupRootViewController(qrCodeViewController) + + let qrCodeView = qrCodeViewController.qrCodeView + self.wait { qrCodeView.expirationLabel.text?.starts(with: "You have") == true } + self.wait { qrCodeView.logo.image != nil } + + self.verifyViewControllerImage(matching: qrCodeViewController, named: "upi") dummyExpectation.fulfill() } @@ -245,24 +236,34 @@ class QRCodeActionComponentUITests: XCTestCase { style.backgroundColor = UIColor.Adyen.componentSeparator - let sut = QRCodeActionComponent(context: context) + let sut = QRCodeActionComponent(context: Dummy.context) sut.configuration.style = style let presentationDelegate = PresentationDelegateMock() sut.presentationDelegate = presentationDelegate presentationDelegate.doPresent = { component in - let qrCodeViewController = component.viewController as? QRCodeViewController - XCTAssertNotNil(qrCodeViewController) - let pollingComponentToolBar = CancellingToolBar(title: qrCodeViewController!.title, style: NavigationStyle()) - let wrapperVC = WrapperViewController( - child: ModalViewController(rootViewController: qrCodeViewController!, navBarType: .custom(pollingComponentToolBar))) - - // wait until the expiration label is rendered - XCTAssertNotNil(wrapperVC) + let qrCodeViewController = try XCTUnwrap(component.viewController as? QRCodeViewController) + + let pollingComponentToolBar = CancellingToolBar( + title: qrCodeViewController.title, + style: NavigationStyle() + ) + + let wrapper = WrapperViewController( + child: ModalViewController( + rootViewController: qrCodeViewController, + navBarType: .custom(pollingComponentToolBar) + ) + ) + + self.setupRootViewController(wrapper) + + let qrCodeView = qrCodeViewController.qrCodeView + self.wait { qrCodeView.expirationLabel.text?.starts(with: "You have") == true } + self.wait { qrCodeView.logo.image != nil } - self.wait { qrCodeViewController?.qrCodeView.expirationLabel.text?.starts(with: "You have") == true } - self.assertViewControllerImage(matching: component.viewController, named: "upi_cancel_button") + self.verifyViewControllerImage(matching: wrapper, named: "upi_cancel_button") dummyExpectation.fulfill() } diff --git a/UITests/Components/QRCode/__Snapshots__/QRCodeActionComponentUITests/testQRCodeCancelButtonOnUPI-iPhone12.upi_cancel_button.png b/UITests/Components/QRCode/__Snapshots__/QRCodeActionComponentUITests/testQRCodeCancelButtonOnUPI-iPhone12.upi_cancel_button.png index ad4f4daceb..007a091a88 100644 Binary files a/UITests/Components/QRCode/__Snapshots__/QRCodeActionComponentUITests/testQRCodeCancelButtonOnUPI-iPhone12.upi_cancel_button.png and b/UITests/Components/QRCode/__Snapshots__/QRCodeActionComponentUITests/testQRCodeCancelButtonOnUPI-iPhone12.upi_cancel_button.png differ diff --git a/UITests/Components/UPIComponent/UPIComponentUITests.swift b/UITests/Components/UPIComponent/UPIComponentUITests.swift index 7c14a42af3..7fc18b759b 100644 --- a/UITests/Components/UPIComponent/UPIComponentUITests.swift +++ b/UITests/Components/UPIComponent/UPIComponentUITests.swift @@ -115,14 +115,6 @@ class UPIComponentUITests: XCTestCase { assertViewControllerImage(matching: sut.viewController, named: "all_required_fields_exist") } - func testUPIComponentDetailsExists() { - // Given - let upiComponentDetails = UPIComponentDetails(type: "vpa", virtualPaymentAddress: "testvpa@icici") - - // Assert - XCTAssertNotNil(upiComponentDetails) - } - func testUPIComponentDetailsForUPICollectFlow() { // Given let config = UPIComponent.Configuration(style: style) diff --git a/UITests/Helpers/XCTestCase+SnapshotTesting.swift b/UITests/Helpers/XCTestCase+SnapshotTesting.swift index 41d707aeb5..080d83b7e5 100644 --- a/UITests/Helpers/XCTestCase+SnapshotTesting.swift +++ b/UITests/Helpers/XCTestCase+SnapshotTesting.swift @@ -12,40 +12,24 @@ import XCTest extension XCTestCase { - func assertViewHeirarchy(matching viewController: @autoclosure () throws -> UIViewController, - named name: String, - devices: [ViewImageConfig] = [.iPhone12], - file: StaticString = #file, - testName: String = #function, - line: UInt = #line) { - - for device in devices { - try SnapshotTesting.assertSnapshot(matching: viewController(), - as: .recursiveDescription(on: device), - named: name, - record: false, - file: file, - testName: "\(testName)-\(device.description)", - line: line) - } - } + static var shouldRecordSnapshots: Bool = false func assertViewControllerImage(matching viewController: @autoclosure () throws -> UIViewController, named name: String, - devices: [ViewImageConfig] = [.iPhone12], + device: ViewImageConfig = .iPhone12, file: StaticString = #file, - testName: String = #function, + caller: String = #function, line: UInt = #line) { - for device in devices { - try SnapshotTesting.assertSnapshot(matching: viewController(), - as: .image(on: device, perceptualPrecision: 0.98), - named: name, - record: false, - file: file, - testName: "\(testName)-\(device.description)", - line: line) - } + try SnapshotTesting.assertSnapshot( + matching: viewController(), + as: device.snapshotConfiguration, + named: name, + record: XCTestCase.shouldRecordSnapshots, + file: file, + testName: device.testName(for: caller), + line: line + ) } /// Verifies whether or not the snapshot of the view controller matches the previously recorded snapshot @@ -56,18 +40,33 @@ extension XCTestCase { timeout: TimeInterval = 120, device: ViewImageConfig = .iPhone12, file: StaticString = #file, - testName: String = #function, + caller: String = #function, line: UInt = #line) { + if XCTestCase.shouldRecordSnapshots { + // We're recording so we assert immediately + // to not wait until it finally throws an error on the code below + try assertViewControllerImage( + matching: viewController(), + named: name, + device: device, + file: file, + caller: caller, + line: line + ) + + return + } + wait( until: { let failure = try! verifySnapshot( of: viewController(), - as: .image(on: device, perceptualPrecision: 0.98), + as: device.snapshotConfiguration, named: name, record: false, file: file, - testName: "\(testName)-\(device.description)", + testName: device.testName(for: caller), line: line ) return failure == nil @@ -79,6 +78,17 @@ extension XCTestCase { } } +extension ViewImageConfig { + + func testName(for callingFunction: String) -> String { + "\(callingFunction)-\(description)" + } + + var snapshotConfiguration: Snapshotting { + .image(on: self, perceptualPrecision: 0.98) + } +} + extension ViewImageConfig: CustomStringConvertible { public var description: String { switch self {