Skip to content

Commit

Permalink
[Link] Add signup and sign-in flow UI tests (#1006)
Browse files Browse the repository at this point in the history
* Add signup flow UI tests

* Refactor virtual keyboard text entry

* Add signin test

* Add comment
  • Loading branch information
ramont-stripe authored Apr 14, 2022
1 parent fffab3f commit e60f3c3
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,8 @@ class PaymentSheetUITest: XCTestCase {

extension PaymentSheetUITest {

// MARK: Inline signup

/// Tests the Link inline signup flow.
func testLinkInlineSignup() throws {
loadPlayground(app, settings: [
Expand All @@ -335,9 +337,7 @@ extension PaymentSheetUITest {

// XCUIApplication cannot synthesize typing events to the phone field.
// So we need to punch-in each digit via the keyboard.
"3105551234".forEach { digit in
app.keys[String(digit)].tap()
}
app.typeTextWithKeyboard("3105551234")

// Pay!
app.buttons["Pay $50.99"].tap()
Expand Down Expand Up @@ -376,11 +376,112 @@ extension PaymentSheetUITest {
let codeField = app.descendants(matching: .any)["Code field"]
XCTAssert(codeField.waitForExistence(timeout: 10))
codeField.tap()
app.typeTextWithKeyboard("000000")

let successText = app.alerts.staticTexts["Success!"]
XCTAssertTrue(successText.waitForExistence(timeout: 10))

let okButton = app.alerts.buttons["OK"]
okButton.tap()
}

// MARK: Modal

func testLinkSignup() throws {
loadPlayground(app, settings: [
"customer_mode": "new",
"automatic_payment_methods": "off",
"link": "on"
])

app.buttons["Checkout (Complete)"].tap()

let payWithLinkButton = app.buttons["Pay with Link"]
XCTAssertTrue(payWithLinkButton.waitForExistence(timeout: 10))
payWithLinkButton.tap()

let modal = app.otherElements["Stripe.Link.PayWithLinkViewController"]
XCTAssertTrue(modal.waitForExistence(timeout: 10))

let emailField = modal.textFields["Email"]
XCTAssertTrue(emailField.waitForExistence(timeout: 10))
emailField.tap()
emailField.typeText("mobile-payments-sdk-ci+\(UUID())@stripe.com")

let phoneField = modal.otherElements["Mobile number"]
XCTAssert(phoneField.waitForExistence(timeout: 10))
phoneField.tap()
app.typeTextWithKeyboard("3105551234")

// Terms and privacy policy
for linkText in ["Terms", "Privacy Policy"] {
modal.links[linkText].tap()
let closeTermsButton = app.otherElements["TopBrowserBar"].buttons["Close"]
XCTAssert(closeTermsButton.waitForExistence(timeout: 10))
closeTermsButton.tap()
}

modal.buttons["Join Link"].tap()

// Because we are presenting view controllers with `modalPresentationStyle = .overFullScreen`,
// there are currently 2 card forms on screen. Specifying a container helps the `fillCardData()`
// method operate on the correct card form.
try fillCardData(app, container: modal)

// Pay!
let payButton = modal.buttons["Pay $50.99"]
expectation(for: NSPredicate(format: "enabled == true"), evaluatedWith: payButton, handler: nil)
waitForExpectations(timeout: 10, handler: nil)
payButton.tap()

let successText = app.alerts.staticTexts["Success!"]
XCTAssertTrue(successText.waitForExistence(timeout: 10))

let okButton = app.alerts.buttons["OK"]
okButton.tap()
}

func testLinkSignIn() throws {
loadPlayground(app, settings: [
"customer_mode": "new",
"automatic_payment_methods": "off",
"link": "on"
])

app.buttons["Checkout (Complete)"].tap()

let payWithLinkButton = app.buttons["Pay with Link"]
XCTAssertTrue(payWithLinkButton.waitForExistence(timeout: 10))
payWithLinkButton.tap()

let modal = app.otherElements["Stripe.Link.PayWithLinkViewController"]
XCTAssertTrue(modal.waitForExistence(timeout: 10))

let emailField = modal.textFields["Email"]
XCTAssertTrue(emailField.waitForExistence(timeout: 10))
emailField.tap()
emailField.typeText("[email protected]")

// Wait for OTP screen and enter the code
let codeField = app.descendants(matching: .any)["Code field"]
XCTAssert(codeField.waitForExistence(timeout: 10))
codeField.tap()
app.typeTextWithKeyboard("000000")

"000000".forEach { digit in
app.keys[String(digit)].tap()
let paymentMethodPicker = app.otherElements["Stripe.Link.PaymentMethodPicker"]
if paymentMethodPicker.waitForExistence(timeout: 10) {
paymentMethodPicker.tap()
paymentMethodPicker.buttons["Add new payment method"].tap()
}

try fillCardData(app, container: modal)

// Pay!
let payButton = modal.buttons["Pay $50.99"]
expectation(for: NSPredicate(format: "enabled == true"), evaluatedWith: payButton, handler: nil)
waitForExpectations(timeout: 10, handler: nil)
payButton.tap()

let successText = app.alerts.staticTexts["Success!"]
XCTAssertTrue(successText.waitForExistence(timeout: 10))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,21 @@ extension XCUIElement {
}
}

// MARK: - XCUIApplication

extension XCUIApplication {
/// Types a text using the software keyboard.
///
/// This method is significantly slower than `XCUIElement.typeText()` but it works with custom controls.
///
/// - Parameter text: Text to type.
func typeTextWithKeyboard(_ text: String) {
for key in text {
self.keys[String(key)].tap()
}
}
}

// https://gist.github.com/jlnquere/d2cd529874ca73624eeb7159e3633d0f
func scroll(collectionView: XCUIElement, toFindCellWithId identifier:String) -> XCUIElement? {
guard collectionView.elementType == .collectionView else {
Expand Down Expand Up @@ -66,8 +81,10 @@ func scroll(collectionView: XCUIElement, toFindCellWithId identifier:String) ->


extension XCTestCase {
func fillCardData(_ app: XCUIApplication) throws {
let numberField = app.textFields["Card number"]
func fillCardData(_ app: XCUIApplication, container: XCUIElement? = nil) throws {
let context = container ?? app

let numberField = context.textFields["Card number"]
numberField.forceTapWhenHittableInTestCase(self)
app.typeText("4242424242424242")
app.typeText("1228") // Expiry
Expand Down
1 change: 1 addition & 0 deletions Stripe/LinkPaymentMethodPicker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ final class LinkPaymentMethodPicker: UIView {

private func setup() {
clipsToBounds = true
accessibilityIdentifier = "Stripe.Link.PaymentMethodPicker"

layer.cornerRadius = 16
layer.borderWidth = 1
Expand Down
1 change: 1 addition & 0 deletions Stripe/PayWithLinkViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ final class PayWithLinkViewController: UINavigationController {

override func viewDidLoad() {
super.viewDidLoad()
view.accessibilityIdentifier = "Stripe.Link.PayWithLinkViewController"
navigationBar.applyLinkTheme()
view.tintColor = .linkBrand
updateUI()
Expand Down

0 comments on commit e60f3c3

Please sign in to comment.