diff --git a/AdyenComponents/PayTo/PayToComponent.swift b/AdyenComponents/PayTo/PayToComponent.swift index 12a198e841..9b382c9b89 100644 --- a/AdyenComponents/PayTo/PayToComponent.swift +++ b/AdyenComponents/PayTo/PayToComponent.swift @@ -75,7 +75,7 @@ public final class PayToComponent: PaymentComponent, private lazy var bsbDynamicItems: [FormItem] = [ bsbInstructionTitleItem, accountNumberInputItem, - bankStateBranchInputItem + bsbInputItem ] private var payToPhoneCodes: [PhoneExtension] { @@ -100,12 +100,12 @@ public final class PayToComponent: PaymentComponent, /// The payment flow selection title label item. internal lazy var flowSelectionTitleItem: FormLabelItem = { - itemsProvider.flowSelectionTitleItem + itemsProvider.createFlowSelectionTitleItem() }() /// The segment control item to choose the payTo flow. internal lazy var flowSelectionItem: FormSegmentedControlItem = { - let item = itemsProvider.flowSelectionItem + let item = itemsProvider.createFlowSelectionItem() item.selectionHandler = { [weak self] in self?.didChangeSegment($0) } @@ -113,57 +113,57 @@ public final class PayToComponent: PaymentComponent, }() internal lazy var phoneNumberItem: FormPhoneNumberItem = { - itemsProvider.phoneNumberItem + itemsProvider.createPhoneNumberItem() }() /// The account holder firstname text input item. internal lazy var firstNameInputItem: FormTextInputItem = { - itemsProvider.firstNameInputItem + itemsProvider.createFirstNameInputItem() }() /// The account holder lastname text input item. internal lazy var lastNameInputItem: FormTextInputItem = { - itemsProvider.lastNameInputItem + itemsProvider.createLastNameInputItem() }() /// The identifier picker item. internal lazy var identifierPickerItem: FormStringPickerItem = { - itemsProvider.identifierPickerItem + itemsProvider.createIdentifierPickerItem() }() /// The account holder email text input item. internal lazy var emailInputItem: FormTextInputItem = { - itemsProvider.emailInputItem + itemsProvider.createEmailInputItem() }() /// The account holder abn text input item. internal lazy var abnInputItem: FormTextInputItem = { - itemsProvider.abnInputItem + itemsProvider.createAbnInputItem() }() /// The account holder organization ID text input item. internal lazy var organizationIdInputItem: FormTextInputItem = { - itemsProvider.organizationIdInputItem + itemsProvider.createOrganizationIdInputItem() }() /// The payment instructions label item. internal lazy var bsbInstructionTitleItem: FormContainerItem = { - itemsProvider.bsbInstructionTitleItem + itemsProvider.createBsbInstructionTitleItem() }() /// The bank account number text input item. internal lazy var accountNumberInputItem: FormTextInputItem = { - itemsProvider.accountNumberInputItem + itemsProvider.createAccountNumberInputItem() }() /// The bank state branch input item. - internal lazy var bankStateBranchInputItem: FormTextInputItem = { - itemsProvider.bsbInputItem + internal lazy var bsbInputItem: FormTextInputItem = { + itemsProvider.createBsbInputItem() }() /// The continue button item. internal lazy var continueButtonItem: FormButtonItem = { - let item = itemsProvider.continueButtonItem + let item = itemsProvider.createContinueButtonItem() item.buttonSelectionHandler = { [weak self] in self?.didSelectContinueButton() } @@ -273,7 +273,7 @@ private extension PayToComponent { formViewController.append(bsbInstructionTitleItem) formViewController.append(FormSpacerItem(numberOfSpaces: 2)) formViewController.append(accountNumberInputItem) - formViewController.append(bankStateBranchInputItem) + formViewController.append(bsbInputItem) bsbDynamicItems.forEach { $0.isHidden.wrappedValue = true } } @@ -333,13 +333,5 @@ private extension PayToComponent { bsbDynamicItems.forEach { $0.isHidden.wrappedValue = true } identifierPickerItem.isHidden.wrappedValue = false - - let items: [PayToPayIdentifier: FormItem] = [ - .phone: phoneNumberItem, - .email: emailInputItem, - .abn: abnInputItem, - .organizationId: organizationIdInputItem - ] - items[.abn]?.isHidden.wrappedValue = true } } diff --git a/AdyenComponents/PayTo/PayToItemsProvider.swift b/AdyenComponents/PayTo/PayToItemsProvider.swift index 1e33c14ecd..5e6eb26e48 100644 --- a/AdyenComponents/PayTo/PayToItemsProvider.swift +++ b/AdyenComponents/PayTo/PayToItemsProvider.swift @@ -9,20 +9,20 @@ import UIKit internal protocol PayToItemsProviding { - var flowSelectionTitleItem: FormLabelItem { get } - var flowSelectionItem: FormSegmentedControlItem { get } - var phoneNumberItem: FormPhoneNumberItem { get } - var firstNameInputItem: FormTextInputItem { get } - var lastNameInputItem: FormTextInputItem { get } - var identifierPickerItem: FormStringPickerItem { get } - var emailInputItem: FormTextInputItem { get } - var abnInputItem: FormTextInputItem { get } - var organizationIdInputItem: FormTextInputItem { get } - var bsbInstructionTitleItem: FormContainerItem { get } - var accountNumberInputItem: FormTextInputItem { get } - var bsbInputItem: FormTextInputItem { get } + func createFlowSelectionTitleItem() -> FormLabelItem + func createFlowSelectionItem() -> FormSegmentedControlItem + func createPhoneNumberItem() -> FormPhoneNumberItem + func createFirstNameInputItem() -> FormTextInputItem + func createLastNameInputItem() -> FormTextInputItem + func createIdentifierPickerItem() -> FormStringPickerItem + func createEmailInputItem() -> FormTextInputItem + func createAbnInputItem() -> FormTextInputItem + func createOrganizationIdInputItem() -> FormTextInputItem + func createBsbInstructionTitleItem() -> FormContainerItem + func createAccountNumberInputItem() -> FormTextInputItem + func createBsbInputItem() -> FormTextInputItem - var continueButtonItem: FormButtonItem { get } + func createContinueButtonItem() -> FormButtonItem } internal class PayToItemsProvider: PayToItemsProviding { @@ -44,11 +44,15 @@ internal class PayToItemsProvider: PayToItemsProviding { } private enum ValidationRegex { - static let phone = #"^\+[0-9]{1,3}-[1-9]{1,1}[0-9]{1,29}$"# + static let phone = #"^[1-9]{1,1}[0-9]{1,29}$"# static let abn = #"^((\d{9})|(\d{11}))$"# static let organizationId = #"^[!-@\[-~][ -@\[-~]{0,254}[!-@\[-~]$"# - static let bsb = #"^\d{6}"# - static let accountNumber = #"^\[ -~]{1,28}$"# + static let bsb = #"^\d{6}$"# + static let accountNumber = #"^[ -~]{1,28}$"# + } + + private enum Constants { + static let bsbDigitLength = 6 } private var payToPhoneCodes: [PhoneExtension] { @@ -56,8 +60,25 @@ internal class PayToItemsProvider: PayToItemsProviding { return PhoneExtensionsRepository.get(with: query) } + private let style: FormComponentStyle + private let localizationParameters: LocalizationParameters? + private let scope: String + private let presenter: WeakReferenceViewControllerPresenter + + internal init( + style: FormComponentStyle, + localizationParameters: LocalizationParameters?, + scope: String, + presenter: WeakReferenceViewControllerPresenter + ) { + self.style = style + self.localizationParameters = localizationParameters + self.scope = scope + self.presenter = presenter + } + /// The payment flow selection title label item. - internal lazy var flowSelectionTitleItem: FormLabelItem = { + internal func createFlowSelectionTitleItem() -> FormLabelItem { // TODO: Add translation let item = FormLabelItem( text: localizedString(LocalizationKey(key: "How would you like to use Payto?"), localizationParameters), @@ -68,10 +89,10 @@ internal class PayToItemsProvider: PayToItemsProviding { postfix: ViewIdentifier.flowSelectionTitleItem ) return item - }() + } /// The segment control item to choose the payTo flow. - internal lazy var flowSelectionItem: FormSegmentedControlItem = { + internal func createFlowSelectionItem() -> FormSegmentedControlItem { // TODO: Add translation let item = FormSegmentedControlItem( items: ["PayID", "BSB"], @@ -82,9 +103,9 @@ internal class PayToItemsProvider: PayToItemsProviding { ) ) return item - }() + } - internal lazy var phoneNumberItem: FormPhoneNumberItem = { + internal func createPhoneNumberItem() -> FormPhoneNumberItem { let item = FormPhoneNumberItem( phoneNumber: nil, selectableValues: payToPhoneCodes, @@ -96,40 +117,43 @@ internal class PayToItemsProvider: PayToItemsProviding { scopeInstance: scope, postfix: ViewIdentifier.phoneNumberItem ) + item.validator = RegularExpressionValidator(regularExpression: ValidationRegex.phone) // TODO: Add translation item.title = localizedString(LocalizationKey(key: "Phone"), localizationParameters) item.placeholder = localizedString(LocalizationKey(key: "Mobile number"), localizationParameters) return item - }() + } /// The account holder firstname text input item. - internal lazy var firstNameInputItem: FormTextInputItem = { + internal func createFirstNameInputItem() -> FormTextInputItem { let item = FormTextInputItem(style: style.textField) // TODO: Add translation item.title = localizedString(LocalizationKey(key: "Account holder first name"), localizationParameters) item.placeholder = localizedString(LocalizationKey(key: "Account holder first name"), localizationParameters) + item.validator = LengthValidator(minimumLength: 1) item.identifier = ViewIdentifierBuilder.build( scopeInstance: scope, postfix: ViewIdentifier.firstNameInputItem ) return item - }() + } /// The account holder lastname text input item. - internal lazy var lastNameInputItem: FormTextInputItem = { + internal func createLastNameInputItem() -> FormTextInputItem { let item = FormTextInputItem(style: style.textField) // TODO: Add translation item.title = localizedString(LocalizationKey(key: "Account holder last name"), localizationParameters) item.placeholder = localizedString(LocalizationKey(key: "Account holder last name"), localizationParameters) + item.validator = LengthValidator(minimumLength: 1) item.identifier = ViewIdentifierBuilder.build( scopeInstance: scope, postfix: ViewIdentifier.lastNameInputItem ) return item - }() + } /// The identifier picker item. - internal lazy var identifierPickerItem: FormStringPickerItem = { + internal func createIdentifierPickerItem() -> FormStringPickerItem { let selectableValues = PayToPayIdentifier.allCases.map { identifier in FormStringPickerElement( identifier: identifier.rawValue, @@ -152,49 +176,57 @@ internal class PayToItemsProvider: PayToItemsProviding { ) return item - }() + } /// The account holder email text input item. - internal lazy var emailInputItem: FormTextInputItem = { + internal func createEmailInputItem() -> FormTextInputItem { let item = FormTextInputItem(style: style.textField) // TODO: Add translation item.title = localizedString(.emailItemTitle, localizationParameters) item.placeholder = localizedString(.emailItemPlaceHolder, localizationParameters) + item.validator = EmailValidator() item.identifier = ViewIdentifierBuilder.build( scopeInstance: scope, postfix: ViewIdentifier.emailInputItem ) return item - }() + } /// The account holder abn text input item. - internal lazy var abnInputItem: FormTextInputItem = { + internal func createAbnInputItem() -> FormTextInputItem { let item = FormTextInputItem(style: style.textField) // TODO: Add translation item.title = localizedString(LocalizationKey(key: "ABN"), localizationParameters) item.placeholder = localizedString(LocalizationKey(key: "Australian Business Number"), localizationParameters) + item.formatter = NumericFormatter() + item.validator = RegularExpressionValidator(regularExpression: ValidationRegex.abn) + item.keyboardType = .numberPad item.identifier = ViewIdentifierBuilder.build( scopeInstance: scope, postfix: ViewIdentifier.abnInputItem ) return item - }() + } /// The account holder organization ID text input item. - internal lazy var organizationIdInputItem: FormTextInputItem = { + internal func createOrganizationIdInputItem() -> FormTextInputItem { let item = FormTextInputItem(style: style.textField) // TODO: Add translation item.title = localizedString(LocalizationKey(key: "Organization ID"), localizationParameters) item.placeholder = localizedString(LocalizationKey(key: "Organization ID number"), localizationParameters) + item.validator = RegularExpressionValidator( + regularExpression: ValidationRegex.organizationId, + minimumLength: 2 + ) item.identifier = ViewIdentifierBuilder.build( scopeInstance: scope, postfix: ViewIdentifier.organizationIDInputItem ) return item - }() + } /// The payment instructions label item. - internal lazy var bsbInstructionTitleItem: FormContainerItem = { + internal func createBsbInstructionTitleItem() -> FormContainerItem { // TODO: Add translation let item = FormLabelItem( text: localizedString( @@ -208,36 +240,43 @@ internal class PayToItemsProvider: PayToItemsProviding { postfix: ViewIdentifier.paymentInstructionTitleItem ) return item.padding() - }() + } /// The bank account number text input item. - internal lazy var accountNumberInputItem: FormTextInputItem = { + internal func createAccountNumberInputItem() -> FormTextInputItem { let item = FormTextInputItem(style: style.textField) // TODO: Add translation item.title = localizedString(.bacsBankAccountNumberFieldTitle, localizationParameters) item.placeholder = localizedString(.bacsBankAccountNumberFieldTitle, localizationParameters) + item.validator = RegularExpressionValidator(regularExpression: ValidationRegex.accountNumber) item.identifier = ViewIdentifierBuilder.build( scopeInstance: scope, postfix: ViewIdentifier.accountNumberInputItem ) return item - }() + } /// The bank state branch input item. - internal lazy var bsbInputItem: FormTextInputItem = { + internal func createBsbInputItem() -> FormTextInputItem { let item = FormTextInputItem(style: style.textField) // TODO: Add translation item.title = localizedString(LocalizationKey(key: "Bank state branch"), localizationParameters) item.placeholder = localizedString(LocalizationKey(key: "Bank State Branch"), localizationParameters) + item.validator = RegularExpressionValidator( + regularExpression: ValidationRegex.bsb, + minimumLength: Constants.bsbDigitLength, + maximumLength: Constants.bsbDigitLength + ) + item.formatter = NumericFormatter() item.identifier = ViewIdentifierBuilder.build( scopeInstance: scope, postfix: ViewIdentifier.bankStateBranchInputItem ) return item - }() + } /// The continue button item. - internal lazy var continueButtonItem: FormButtonItem = { + internal func createContinueButtonItem() -> FormButtonItem { let item = FormButtonItem(style: style.mainButtonItem) item.identifier = ViewIdentifierBuilder.build( scopeInstance: scope, @@ -245,23 +284,6 @@ internal class PayToItemsProvider: PayToItemsProviding { ) item.title = localizedString(.continueTitle, localizationParameters) return item - }() - - private let style: FormComponentStyle - private let localizationParameters: LocalizationParameters? - private let scope: String - private let presenter: WeakReferenceViewControllerPresenter - - internal init( - style: FormComponentStyle, - localizationParameters: LocalizationParameters?, - scope: String, - presenter: WeakReferenceViewControllerPresenter - ) { - self.style = style - self.localizationParameters = localizationParameters - self.scope = scope - self.presenter = presenter } } diff --git a/Tests/IntegrationTests/Components Tests/PayTo/PayToComponentTests.swift b/Tests/IntegrationTests/Components Tests/PayTo/PayToComponentTests.swift index 4a24c6e6ce..4bcfa166ab 100644 --- a/Tests/IntegrationTests/Components Tests/PayTo/PayToComponentTests.swift +++ b/Tests/IntegrationTests/Components Tests/PayTo/PayToComponentTests.swift @@ -9,6 +9,16 @@ import XCTest class PayToComponentTests: XCTestCase { + + var sut: PayToComponent! + + override func setUpWithError() throws { + try super.setUpWithError() + sut = try PayToComponent( + paymentMethod: AdyenCoder.decode(payto), + context: Dummy.context + ) + } func test_init() throws { let sut = try PayToComponent( @@ -20,21 +30,11 @@ class PayToComponentTests: XCTestCase { } func test_paymentMethodType_isPayto() throws { - let sut = try PayToComponent( - paymentMethod: AdyenCoder.decode(payto), - context: Dummy.context - ) - XCTAssertEqual(sut.paymentMethod.type, .payto) } func test_flowSelection_titleLabel_exists() throws { // Given - let sut = try PayToComponent( - paymentMethod: AdyenCoder.decode(payto), - context: Dummy.context - ) - sut.viewController.loadViewIfNeeded() // Check by accessibility identifier @@ -46,11 +46,6 @@ class PayToComponentTests: XCTestCase { func test_flowSelectionItem_exists() throws { // Given - let sut = try PayToComponent( - paymentMethod: AdyenCoder.decode(payto), - context: Dummy.context - ) - sut.viewController.loadViewIfNeeded() // Check by accessibility identifier @@ -61,13 +56,26 @@ class PayToComponentTests: XCTestCase { XCTAssertNotNil(flowSelectionItem, "Flow selection item should exist") } - func test_phoneNumberItem_exists() throws { + func test_phoneNumberItem() throws { + // invalid + sut.phoneNumberItem.value = "" + XCTAssertFalse(sut.phoneNumberItem.isValid()) + sut.phoneNumberItem.value = "01231" + XCTAssertFalse(sut.phoneNumberItem.isValid()) + sut.phoneNumberItem.value = "05" + XCTAssertFalse(sut.phoneNumberItem.isValid()) + sut.phoneNumberItem.value = "9" + XCTAssertFalse(sut.phoneNumberItem.isValid()) + + // valid + sut.phoneNumberItem.value = "10" + XCTAssertTrue(sut.phoneNumberItem.isValid()) + sut.phoneNumberItem.value = "99" + XCTAssertTrue(sut.phoneNumberItem.isValid()) + sut.phoneNumberItem.value = "41124123" + XCTAssertTrue(sut.phoneNumberItem.isValid()) + // Given - let sut = try PayToComponent( - paymentMethod: AdyenCoder.decode(payto), - context: Dummy.context - ) - sut.viewController.loadViewIfNeeded() // Check by accessibility identifier @@ -77,29 +85,8 @@ class PayToComponentTests: XCTestCase { XCTAssertNotNil(phoneNumberItem, "Phone number item should exist") } - func test_continueButton_exists() throws { - // Given - let sut = try PayToComponent( - paymentMethod: AdyenCoder.decode(payto), - context: Dummy.context - ) - - sut.viewController.loadViewIfNeeded() - - // Check by accessibility identifier - let continueButton: FormButtonItemView = try XCTUnwrap(sut.viewController.view.findView(with: "AdyenComponents.PayToComponent.continueButton")) - - // Then - XCTAssertNotNil(continueButton, "ContinueButton should exist") - } - func test_identifierPicker_exists() throws { // Given - let sut = try PayToComponent( - paymentMethod: AdyenCoder.decode(payto), - context: Dummy.context - ) - sut.viewController.loadViewIfNeeded() // Check by accessibility identifier @@ -109,13 +96,13 @@ class PayToComponentTests: XCTestCase { XCTAssertNotNil(identifierPickerItem, "identifier picker should exist") } - func test_firstname_textfield_exists() throws { + func test_firstname_textfield() throws { + sut.firstNameInputItem.value = "" + XCTAssertFalse(sut.firstNameInputItem.isValid()) + sut.firstNameInputItem.value = "test" + XCTAssertTrue(sut.firstNameInputItem.isValid()) + // Given - let sut = try PayToComponent( - paymentMethod: AdyenCoder.decode(payto), - context: Dummy.context - ) - sut.viewController.loadViewIfNeeded() // Check by accessibility identifier @@ -125,13 +112,13 @@ class PayToComponentTests: XCTestCase { XCTAssertNotNil(firstNameInputItem, "first name input field should exist") } - func test_lastname_textfield_exists() throws { + func test_lastname_textfield() throws { + sut.lastNameInputItem.value = "" + XCTAssertFalse(sut.lastNameInputItem.isValid()) + sut.lastNameInputItem.value = "test" + XCTAssertTrue(sut.lastNameInputItem.isValid()) + // Given - let sut = try PayToComponent( - paymentMethod: AdyenCoder.decode(payto), - context: Dummy.context - ) - sut.viewController.loadViewIfNeeded() // Check by accessibility identifier @@ -141,13 +128,25 @@ class PayToComponentTests: XCTestCase { XCTAssertNotNil(lastNameInputItem, "last name input field should exist") } - func test_email_textfield_exists() throws { + func test_email_textfield() throws { + + // invalid + sut.emailInputItem.value = "" + XCTAssertFalse(sut.emailInputItem.isValid()) + sut.emailInputItem.value = "test" + XCTAssertFalse(sut.emailInputItem.isValid()) + sut.emailInputItem.value = "test@" + XCTAssertFalse(sut.emailInputItem.isValid()) + sut.emailInputItem.value = "aa@aa.com" + + // valid + XCTAssertTrue(sut.emailInputItem.isValid()) + sut.emailInputItem.value = "user@example.com" + XCTAssertTrue(sut.emailInputItem.isValid()) + sut.emailInputItem.value = "test-test@example.co.uk" + XCTAssertTrue(sut.emailInputItem.isValid()) + // Given - let sut = try PayToComponent( - paymentMethod: AdyenCoder.decode(payto), - context: Dummy.context - ) - sut.viewController.loadViewIfNeeded() // Check by accessibility identifier @@ -157,13 +156,27 @@ class PayToComponentTests: XCTestCase { XCTAssertNotNil(emailInputItem, "email input field should exist") } - func test_abn_textfield_exists() throws { + func test_abn_textfield() throws { + + // only 9 or 11 integers are valid + + // invalid + sut.abnInputItem.value = "" + XCTAssertFalse(sut.abnInputItem.isValid()) + sut.abnInputItem.value = "12345678" + XCTAssertFalse(sut.abnInputItem.isValid()) + sut.abnInputItem.value = "1234567890" + XCTAssertFalse(sut.abnInputItem.isValid()) + sut.abnInputItem.value = "123asd123" + XCTAssertFalse(sut.abnInputItem.isValid()) + sut.abnInputItem.value = "123456789" + + // valid + XCTAssertTrue(sut.abnInputItem.isValid()) + sut.abnInputItem.value = "12345678900" + XCTAssertTrue(sut.abnInputItem.isValid()) + // Given - let sut = try PayToComponent( - paymentMethod: AdyenCoder.decode(payto), - context: Dummy.context - ) - sut.viewController.loadViewIfNeeded() // Check by accessibility identifier @@ -173,13 +186,34 @@ class PayToComponentTests: XCTestCase { XCTAssertNotNil(abnInputItem, "abn input field should exist") } - func test_organizationID_textfield_exists() throws { + func test_organizationID_textfield() throws { + // invalid + sut.organizationIdInputItem.value = "" + XCTAssertFalse(sut.organizationIdInputItem.isValid()) + sut.organizationIdInputItem.value = " Hello" + XCTAssertFalse(sut.organizationIdInputItem.isValid()) + sut.organizationIdInputItem.value = "Hello world " + XCTAssertFalse(sut.organizationIdInputItem.isValid()) + sut.organizationIdInputItem.value = "A valid sentence?" + XCTAssertFalse(sut.organizationIdInputItem.isValid()) + sut.organizationIdInputItem.value = "!" + XCTAssertFalse(sut.organizationIdInputItem.isValid()) + + // valid + sut.organizationIdInputItem.value = "123123" + XCTAssertTrue(sut.organizationIdInputItem.isValid()) + sut.organizationIdInputItem.value = "*hello123.world*" + XCTAssertTrue(sut.organizationIdInputItem.isValid()) + sut.organizationIdInputItem.value = "34ff34?" + XCTAssertTrue(sut.organizationIdInputItem.isValid()) + sut.organizationIdInputItem.value = ".valid." + XCTAssertTrue(sut.organizationIdInputItem.isValid()) + sut.organizationIdInputItem.value = "+abc+" + XCTAssertTrue(sut.organizationIdInputItem.isValid()) + sut.organizationIdInputItem.value = "{ }" + XCTAssertTrue(sut.organizationIdInputItem.isValid()) + // Given - let sut = try PayToComponent( - paymentMethod: AdyenCoder.decode(payto), - context: Dummy.context - ) - sut.viewController.loadViewIfNeeded() // Check by accessibility identifier @@ -189,13 +223,26 @@ class PayToComponentTests: XCTestCase { XCTAssertNotNil(organizationIDInputItem, "organizationID input field should exist") } - func test_accountNumber_textfield_exists() throws { + func test_accountNumber_textfield() throws { + // invalid + sut.accountNumberInputItem.value = "" + XCTAssertFalse(sut.accountNumberInputItem.isValid()) + sut.accountNumberInputItem.value = "This string is too long for the limit of 28 characters." + XCTAssertFalse(sut.accountNumberInputItem.isValid()) + sut.accountNumberInputItem.value = "\nNew line" + XCTAssertFalse(sut.accountNumberInputItem.isValid()) + + // valid + sut.accountNumberInputItem.value = "Hello!" + XCTAssertTrue(sut.accountNumberInputItem.isValid()) + sut.accountNumberInputItem.value = " 123 " + XCTAssertTrue(sut.accountNumberInputItem.isValid()) + sut.accountNumberInputItem.value = "password123!@#" + XCTAssertTrue(sut.accountNumberInputItem.isValid()) + sut.accountNumberInputItem.value = " this_is valid -~ " + XCTAssertTrue(sut.accountNumberInputItem.isValid()) + // Given - let sut = try PayToComponent( - paymentMethod: AdyenCoder.decode(payto), - context: Dummy.context - ) - sut.viewController.loadViewIfNeeded() // Check by accessibility identifier @@ -205,13 +252,31 @@ class PayToComponentTests: XCTestCase { XCTAssertNotNil(accountNumberInputItem, "Bank account number input field should exist") } - func test_bank_state_number_textfield_exists() throws { + func test_bank_state_number_textfield() throws { + + // invalid + sut.bsbInputItem.value = "" + XCTAssertFalse(sut.bsbInputItem.isValid()) + sut.bsbInputItem.value = "12345" + XCTAssertFalse(sut.bsbInputItem.isValid()) + sut.bsbInputItem.value = "12345667" + XCTAssertFalse(sut.bsbInputItem.isValid()) + sut.bsbInputItem.value = "abcabc" + XCTAssertFalse(sut.bsbInputItem.isValid()) + sut.bsbInputItem.value = " 12345" + XCTAssertFalse(sut.bsbInputItem.isValid()) + sut.bsbInputItem.value = "12345 " + XCTAssertFalse(sut.bsbInputItem.isValid()) + + // valid + sut.bsbInputItem.value = "123456" + XCTAssertTrue(sut.bsbInputItem.isValid()) + sut.bsbInputItem.value = "666666" + XCTAssertTrue(sut.bsbInputItem.isValid()) + sut.bsbInputItem.value = "000000" + XCTAssertTrue(sut.bsbInputItem.isValid()) + // Given - let sut = try PayToComponent( - paymentMethod: AdyenCoder.decode(payto), - context: Dummy.context - ) - sut.viewController.loadViewIfNeeded() // Check by accessibility identifier @@ -223,11 +288,6 @@ class PayToComponentTests: XCTestCase { func test_payment_instruction_titleLabel_exists() throws { // Given - let sut = try PayToComponent( - paymentMethod: AdyenCoder.decode(payto), - context: Dummy.context - ) - sut.viewController.loadViewIfNeeded() // Check by accessibility identifier @@ -236,5 +296,16 @@ class PayToComponentTests: XCTestCase { // Then XCTAssertNotNil(paymentInstructionTitleLabelItem, "Payment instruction title label should exist") } + + func test_continueButton_exists() throws { + // Given + sut.viewController.loadViewIfNeeded() + + // Check by accessibility identifier + let continueButton: FormButtonItemView = try XCTUnwrap(sut.viewController.view.findView(with: "AdyenComponents.PayToComponent.continueButton")) + + // Then + XCTAssertNotNil(continueButton, "ContinueButton should exist") + } }