Open onmyway133 opened 7 years ago
Hey @onmyway133, this was very useful even in testing Facebook Login on React Native apps! By the way, I found a way to find the password field instead of having to rely on its coordinates. The key is using XCUIApplication().secureTextFields
instead of looking for generic textFields
.
As of writing, the code below works:
let predicate = NSPredicate(format: "placeholderValue == %@", "Facebook Password")
let passwordTextField = app.secureTextFields.element(matching: predicate)
Hope this helps improve things on your end. Cheers! 🎉
@jaunesarmiento Hi, thanks. Glad that you find it useful
Was not able to interact with permission alert (not discussed in this guide, maybe it was added after), so finished up with XCUIApplication().launchArguments
to skip login process:
token from Graph API explorer and user id (GET me?fields=id)
let app = XCUIApplication()
app.launchArguments += [
"-FACEBOOK_TOKEN", facebookUserToken,
"-FACEBOOK_USER", facebookUserId
]
app.launch()
and modified login method from the app:
NSString *testUserToken = [[NSUserDefaults standardUserDefaults] stringForKey:@"FACEBOOK_TOKEN"];
NSString *testUserId = [[NSUserDefaults standardUserDefaults] stringForKey:@"FACEBOOK_USER"];
if (testUserToken && testUserId) {
FBSDKAccessToken *token = [[FBSDKAccessToken alloc] initWithTokenString:testUserToken
permissions:permissions
declinedPermissions:@[]
appID:appId //https://developers.facebook.com/apps/{id}
userID:testUserId
expirationDate:nil refreshDate:nil];
[FBSDKAccessToken setCurrentAccessToken:token];
}
Two things:
This won’t work if you are testing in other locales normally because the text will change. It’s an unfortunate thing but often it involves using an ‘xpath’ of sorts depending on how you are testing.
I would suggest making an extension for the XCUIElement class and make the wait function part of that instead. This would complement the other state functions in that class well.
@BJap Hi, thanks for the suggestion, I will link to yours in the article
For sure. As a followup, sources below are included.
There are nice state functions in XCUIElement and a nifty new one added in Xcode 9
https://developer.apple.com/documentation/xctest/xcuielement/2879412-waitforexistence
The comprehensive list of element state query functions is here:
https://developer.apple.com/documentation/xctest/xcuielement
Good article 👍
Today I'm trying to run some UITest on my app, which uses Facebook login. And here are some of my notes on it.
Challenges
Safari controller
, we we deal mostly withweb view
for now. Starting from iOS 9+, Facebook decided to usesafari
instead ofnative facebook app
to avoid app switching. You can read the detail here Building the Best Facebook Login Experience for People on iOS 9accessibilityIdentifier
oraccessibilityLabel
Create a Facebook test user
Luckily, you don't have to create your own Facebook user to test. Facebook supports test users that you can manage permissions and friends, very handy
When creating the test user, you have the option to select language. That will be the displayed language in Safari web view. I choose
Norwegian
🇳🇴 for nowClick the login button and show Facebook login
Here we use the default
FBSDKLoginButton
And then tap it
Check login status
When going to safari Facebook form, user may have already logged in or not. So we need to handle these 2 cases. When user has logged in, Facebook will say something like "you have already logged in" or the
OK
button.The advice here is to put breakpoint and
po app.staticTexts
,po app.buttons
to see which UI elements are at a certain point.You can check for the static text, or simply just the
OK
buttonWait and refresh
But Facebook form is a webview, so its content is a bit dynamic. And UITest seems to cache content for fast query, so before checking
staticTexts
, we need towait
andrefresh the cache
This is the
wait
functionWait for element to appear
But a more solid approach would be to wait for element to appear. For Facebook login form, they should display a
Facebook
label after loading. So we should wait for this elementAnd call this before you do any further inspection on elements in Facebook login form
If user is logged in
After login, my app shows the main controller with a map view inside. So a basic test would be to check the existence of that map
Handle interruption
You know that when showing the map with location,
Core Location
will ask for permission. So we need to handle that interruption as well. You need to ensure to call it early before the alert happensThere is another problem, this
monitor
won't be called. So the workaround is to callapp.tap()
again when the alert will happen. In my case, I callapp.tap()
when mymap
has been shown for 1,2 seconds, just to make sureapp.tap()
is called after alert is shownFor a more detailed guide, please read https://github.com/onmyway133/blog/issues/48
If user is not logged in
In this case, we need to fill in email and password. You can take a look at the
The full source code
section below. When things don't work orpo
does not show you the elements you needed, it's probably because of caching or you need to wait until dynamic content finishes rendering.You need to wait for element to appear
Tap on the text field
You may get
Neither element nor any descendant has keyboard focus
, here are the workaroundSimulator -> Hardware -> Keyboard -> Connect Hardware Keyboard
is not checkedwait
a bit after tapClear all the text
The idea is to move the caret to the end of the textField, then apply each
delete key
for each character, then type the next textChange language
For my case, I want to test in Norwegian, so we need to find the
Norwegian
option and tap on that. It is identified asstatic text
byUI Test
The email text field
Luckily, email text field is detected by
UI Test
astext field
element, so we can query for that. This uses predicateThe password text field
UI Test
can't seem to identify the password text field, so we need to search for it bycoordinate
This is the document for
func coordinate(withNormalizedOffset normalizedOffset: CGVector) -> XCUICoordinate
Then type the password
We should not use
app.passwordCoordinate.referencedElement
because it will point to email text field ❗️ 😢Run that test again
Go to
Xcode -> Product -> Perform Actions -> Test Again
to run the previous test againThe full source code
Read more
I found these guides to cover many aspects of UITests, worth taking a look