6

I would like to write a UI test in Xcode covering a login with FBDSKLoginKit.

However, Facebook iOS SDK uses SFSafariViewController presented to the user in order to authenticate her and unfortunately, there's no way how to interact with SFSafariViewController in UI tests in Xcode 7.

Any ideas how to test the facebook login without interacting with SFSafariViewController?

Community
  • 1
  • 1
Tom Kraina
  • 3,569
  • 1
  • 38
  • 58

2 Answers2

4

Swift 3 Xcode 8 solution

 func testFacebookLogin() {
    let app = XCUIApplication()

    // set up an expectation predicate to test whether elements exist
    let exists = NSPredicate(format: "exists == true")

    // as soon as your sign in button shows up, press it
    let facebookSignInButton = app.buttons["Login With Facebook"]
    expectation(for: exists, evaluatedWith: facebookSignInButton, handler: nil)
    facebookSignInButton.tap()

    // wait for the "Confirm" title at the top of facebook's sign in screen
    let confirmTitle = app.staticTexts["Confirm"]
    expectation(for: exists, evaluatedWith: confirmTitle, handler: nil)

    // create a reference to the button through the webView and press it
    let webView = app.descendants(matching: .webView)
    webView.buttons["OK"].tap()

    // wait for your app to return and test for expected behavior here
    self.waitForExpectations(timeout: 10, handler: nil)        
}

Extension:

extension XCUIElement {
    func forceTap() {
        if self.isHittable {
            self.tap()
        } else {
            let coordinate: XCUICoordinate = self.coordinate(withNormalizedOffset: .zero)
            coordinate.tap()
        }
    }
}

Tested and verified to work great!

Zaporozhchenko Oleksandr
  • 4,660
  • 3
  • 26
  • 48
thexande
  • 1,645
  • 16
  • 23
  • For me it didn't work until I added `self.waitForExpectations(timeout: 10.0)` after each expectation line. It's not enough to create an expectation, you have to wait for it... – Matej Vargovčík Mar 25 '17 at 13:08
  • You are correct. I have added the required line to my code example. Just tested as well, all is working as expected. – thexande Mar 25 '17 at 17:15
2

Swift 3 Xcode 8 update

func testFacebookLogin() {
  let app = XCUIApplication()

  // set up an expectation predicate to test whether elements exist
  let exists = NSPredicate(format: "exists == true")

  // as soon as your sign in button shows up, press it
  let facebookSignInButton = app.buttons["Login With Facebook"]
  expectation(for: exists, evaluatedWith: facebookSignInButton, handler: nil)
  facebookSignInButton.tap()

  // wait for the "Confirm" title at the top of facebook's sign in screen
  let confirmTitle = app.staticTexts["Confirm"]
  expectation(for: exists, evaluatedWith: confirmTitle, handler: nil)

  // create a reference to the button through the webView and press it
  let webView = app.descendants(matching: .webView)
  webView.buttons["OK"].tap()

  // wait for your app to return and test for expected behavior here
  self.waitForExpectations(timeout: 10, handler: nil)        
}

Extension:

extension XCUIElement {
  func forceTap() {
      if self.isHittable {
          self.tap()
      } else {
          let coordinate: XCUICoordinate = self.coordinate(withNormalizedOffset: .zero)
          coordinate.tap()
      }
  }

Swift 2

func testFacebookLogin() 
{
    let app = XCUIApplication()

    // set up an expectation predicate to test whether elements exist
    let exists = NSPredicate(format: "exists == true")

    // as soon as your sign in button shows up, press it
    let facebookSignInButton = app.buttons["Sign in with Facebook"]
    expectationForPredicate(exists, evaluatedWithObject: facebookSignInButton, handler: nil)
    facebookSignInButton.tap()

    // wait for the "Confirm" title at the top of facebook's sign in screen
    let confirmTitle = app.staticTexts["Confirm"]
    expectationForPredicate(exists, evaluatedWithObject: confirmTitle, handler: nil)

    // create a reference to the button through the webView and press it
    var webView = app.descendantsMatchingType(.WebView)
    webView.buttons["OK"].tap()

    // wait for your app to return and test for expected behavior here
}

In my case, I also had to deal with the Assertion Failure: UI Testing Failure - Unable to find hit point for Button error via the forceTap() extension:

extension XCUIElement {
    func forceTap() {
        if self.hittable {
            self.tap()
        } else {
            let coordinate: XCUICoordinate = self.coordinateWithNormalizedOffset(CGVectorMake(0.0, 0.0))
            coordinate.tap()
        }
    }
}

as per this awesome blog post here

lonesomewhistle
  • 796
  • 1
  • 9
  • 20