diff --git a/Example/Auth/ApiTests/AccountInfoTests.m b/Example/Auth/ApiTests/AccountInfoTests.m new file mode 100644 index 00000000000..227b1c2423e --- /dev/null +++ b/Example/Auth/ApiTests/AccountInfoTests.m @@ -0,0 +1,67 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FIRAuthApiTestsBase.h" + +/** The testing email address for testCreateAccountWithEmailAndPassword. */ +static NSString *const kOldUserEmail = @"olduseremail@iosapitests.com"; + +/** The testing email address for testUpdatingUsersEmail. */ +static NSString *const kNewUserEmail = @"newuseremail@iosapitests.com"; + +@interface AccountInfoTests : FIRAuthApiTestsBase + +@end + +@implementation AccountInfoTests + +- (void)testUpdatingUsersEmail { + SKIP_IF_ON_MOBILE_HARNESS + FIRAuth *auth = [FIRAuth auth]; + if (!auth) { + XCTFail(@"Could not obtain auth object."); + } + + __block NSError *apiError; + XCTestExpectation *expectation = + [self expectationWithDescription:@"Created account with email and password."]; + [auth createUserWithEmail:kOldUserEmail + password:@"password" + completion:^(FIRAuthDataResult *user, NSError *error) { + apiError = error; + [expectation fulfill]; + }]; + [self waitForExpectationsWithTimeout:kExpectationsTimeout handler:nil]; + expectation = [self expectationWithDescription:@"Created account with email and password."]; + XCTAssertEqualObjects(auth.currentUser.email, kOldUserEmail); + XCTAssertNil(apiError); + + [auth.currentUser updateEmail:kNewUserEmail + completion:^(NSError *_Nullable error) { + apiError = error; + [expectation fulfill]; + }]; + [self waitForExpectationsWithTimeout:kExpectationsTimeout handler:nil]; + XCTAssertNil(apiError); + XCTAssertEqualObjects(auth.currentUser.email, kNewUserEmail); + + // Clean up the created Firebase user for future runs. + [self deleteCurrentUser]; +} + +@end diff --git a/Example/Auth/ApiTests/AnonymousAuthTests.m b/Example/Auth/ApiTests/AnonymousAuthTests.m new file mode 100644 index 00000000000..90be13f0410 --- /dev/null +++ b/Example/Auth/ApiTests/AnonymousAuthTests.m @@ -0,0 +1,34 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FIRAuthApiTestsBase.h" + +@interface AnonymousAuthTests : FIRAuthApiTestsBase + +@end + +@implementation AnonymousAuthTests + +- (void)testSignInAnonymously { + [self signInAnonymously]; + XCTAssertTrue([FIRAuth auth].currentUser.anonymous); + + [self deleteCurrentUser]; +} + +@end diff --git a/Example/Auth/ApiTests/Auth_ApiTests-Bridging-Header.h b/Example/Auth/ApiTests/Auth_ApiTests-Bridging-Header.h new file mode 100644 index 00000000000..ab4a71c9709 --- /dev/null +++ b/Example/Auth/ApiTests/Auth_ApiTests-Bridging-Header.h @@ -0,0 +1,17 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FIRAuthApiTestsBase.h" diff --git a/Example/Auth/ApiTests/CustomAuthTests.m b/Example/Auth/ApiTests/CustomAuthTests.m new file mode 100644 index 00000000000..362d962d4ae --- /dev/null +++ b/Example/Auth/ApiTests/CustomAuthTests.m @@ -0,0 +1,191 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FIRAuthApiTestsBase.h" + +/** The user name string for Custom Auth testing account. */ +static NSString *const kCustomAuthTestingAccountUserID = KCUSTOM_AUTH_USER_ID; + +/** The url for obtaining a valid custom token string used to test Custom Auth. */ +static NSString *const kCustomTokenUrl = KCUSTOM_AUTH_TOKEN_URL; + +/** The url for obtaining an expired but valid custom token string used to test Custom Auth failure. + */ +static NSString *const kExpiredCustomTokenUrl = KCUSTOM_AUTH_TOKEN_EXPIRED_URL; + +/** The invalid custom token string for testing Custom Auth. */ +static NSString *const kInvalidCustomToken = @"invalid token."; + +/** Error message for invalid custom token sign in. */ +NSString *kInvalidTokenErrorMessage = + @"Invalid assertion format. 3 dot separated segments required."; + +@interface CustomAuthTests : FIRAuthApiTestsBase + +@end + +@implementation CustomAuthTests + +- (void)testSignInWithValidCustomAuthToken { + FIRAuth *auth = [FIRAuth auth]; + if (!auth) { + XCTFail(@"Could not obtain auth object."); + } + + NSError *error; + NSString *customToken = [NSString stringWithContentsOfURL:[NSURL URLWithString:kCustomTokenUrl] + encoding:NSUTF8StringEncoding + error:&error]; + if (!customToken) { + XCTFail(@"There was an error retrieving the custom token: %@", error); + } + NSLog(@"The valid token is: %@", customToken); + + XCTestExpectation *expectation = + [self expectationWithDescription:@"CustomAuthToken sign-in finished."]; + + [auth signInWithCustomToken:customToken + completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) { + if (error) { + NSLog(@"Valid token sign in error: %@", error); + } + [expectation fulfill]; + }]; + [self waitForExpectationsWithTimeout:kExpectationsTimeout + handler:^(NSError *error) { + if (error != nil) { + XCTFail(@"Failed to wait for expectations " + @"in CustomAuthToken sign in. Error: %@", + error.localizedDescription); + } + }]; + + XCTAssertEqualObjects(auth.currentUser.uid, kCustomAuthTestingAccountUserID); +} + +- (void)testSignInWithValidCustomAuthExpiredToken { + FIRAuth *auth = [FIRAuth auth]; + if (!auth) { + XCTFail(@"Could not obtain auth object."); + } + + NSError *error; + NSString *customToken = + [NSString stringWithContentsOfURL:[NSURL URLWithString:kExpiredCustomTokenUrl] + encoding:NSUTF8StringEncoding + error:&error]; + if (!customToken) { + XCTFail(@"There was an error retrieving the custom token: %@", error); + } + XCTestExpectation *expectation = + [self expectationWithDescription:@"CustomAuthToken sign-in finished."]; + + __block NSError *apiError; + [auth signInWithCustomToken:customToken + completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) { + if (error) { + apiError = error; + } + [expectation fulfill]; + }]; + [self waitForExpectationsWithTimeout:kExpectationsTimeout + handler:^(NSError *error) { + if (error != nil) { + XCTFail(@"Failed to wait for expectations " + @"in CustomAuthToken sign in. Error: %@", + error.localizedDescription); + } + }]; + + XCTAssertNil(auth.currentUser); + XCTAssertEqual(apiError.code, FIRAuthErrorCodeInvalidCustomToken); +} + +- (void)testSignInWithInvalidCustomAuthToken { + FIRAuth *auth = [FIRAuth auth]; + if (!auth) { + XCTFail(@"Could not obtain auth object."); + } + XCTestExpectation *expectation = + [self expectationWithDescription:@"Invalid CustomAuthToken sign-in finished."]; + + [auth signInWithCustomToken:kInvalidCustomToken + completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) { + XCTAssertEqualObjects(error.localizedDescription, kInvalidTokenErrorMessage); + [expectation fulfill]; + }]; + [self waitForExpectationsWithTimeout:kExpectationsTimeout + handler:^(NSError *error) { + if (error != nil) { + XCTFail(@"Failed to wait for expectations " + @"in CustomAuthToken sign in. Error: %@", + error.localizedDescription); + } + }]; +} + +- (void)testInMemoryUserAfterSignOut { + FIRAuth *auth = [FIRAuth auth]; + if (!auth) { + XCTFail(@"Could not obtain auth object."); + } + NSError *error; + NSString *customToken = [NSString stringWithContentsOfURL:[NSURL URLWithString:kCustomTokenUrl] + encoding:NSUTF8StringEncoding + error:&error]; + if (!customToken) { + XCTFail(@"There was an error retrieving the custom token: %@", error); + } + XCTestExpectation *expectation = + [self expectationWithDescription:@"CustomAuthToken sign-in finished."]; + __block NSError *rpcError; + [auth signInWithCustomToken:customToken + completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) { + if (error) { + rpcError = error; + } + [expectation fulfill]; + }]; + [self waitForExpectationsWithTimeout:kExpectationsTimeout + handler:^(NSError *error) { + if (error != nil) { + XCTFail(@"Failed to wait for expectations " + @"in CustomAuthToken sign in. Error: %@", + error.localizedDescription); + } + }]; + XCTAssertEqualObjects(auth.currentUser.uid, kCustomAuthTestingAccountUserID); + XCTAssertNil(rpcError); + FIRUser *inMemoryUser = auth.currentUser; + XCTestExpectation *expectation1 = [self expectationWithDescription:@"Profile data change."]; + [auth signOut:NULL]; + rpcError = nil; + NSString *newEmailAddress = [self fakeRandomEmail]; + XCTAssertNotEqualObjects(newEmailAddress, inMemoryUser.email); + [inMemoryUser updateEmail:newEmailAddress + completion:^(NSError *_Nullable error) { + rpcError = error; + [expectation1 fulfill]; + }]; + [self waitForExpectationsWithTimeout:kExpectationsTimeout handler:nil]; + XCTAssertEqualObjects(inMemoryUser.email, newEmailAddress); + XCTAssertNil(rpcError); + XCTAssertNil(auth.currentUser); +} + +@end diff --git a/Example/Auth/ApiTests/EmailPasswordAuthTests.m b/Example/Auth/ApiTests/EmailPasswordAuthTests.m new file mode 100644 index 00000000000..f6dade914ed --- /dev/null +++ b/Example/Auth/ApiTests/EmailPasswordAuthTests.m @@ -0,0 +1,93 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FIRAuthApiTestsBase.h" + +/** The testing email address for testCreateAccountWithEmailAndPassword. */ +static NSString *const kNewEmailToCreateUser = @"new_user@iosapitests.com"; + +/** The testing email address for testSignInExistingUserWithEmailAndPassword. */ +static NSString *const kExistingEmailToSignIn = @"existing_user@iosapitests.com"; + +/** The testing password for testSignInExistingUserWithEmailAndPassword. */ +static NSString *const kExistingPasswordToSignIn = @"password"; + +@interface EmailPasswordAuthTests : FIRAuthApiTestsBase + +@end + +@implementation EmailPasswordAuthTests + +- (void)testCreateAccountWithEmailAndPassword { + SKIP_IF_ON_MOBILE_HARNESS + FIRAuth *auth = [FIRAuth auth]; + if (!auth) { + XCTFail(@"Could not obtain auth object."); + } + XCTestExpectation *expectation = + [self expectationWithDescription:@"Created account with email and password."]; + [auth createUserWithEmail:kNewEmailToCreateUser + password:@"password" + completion:^(FIRAuthDataResult *result, NSError *error) { + if (error) { + NSLog(@"createUserWithEmail has error: %@", error); + } + [expectation fulfill]; + }]; + [self waitForExpectationsWithTimeout:kExpectationsTimeout + handler:^(NSError *error) { + if (error != nil) { + XCTFail(@"Failed to wait for expectations " + @"in creating account. Error: %@", + error.localizedDescription); + } + }]; + + XCTAssertEqualObjects(auth.currentUser.email, kNewEmailToCreateUser); + + [self deleteCurrentUser]; +} + +- (void)testSignInExistingUserWithEmailAndPassword { + FIRAuth *auth = [FIRAuth auth]; + if (!auth) { + XCTFail(@"Could not obtain auth object."); + } + XCTestExpectation *expectation = + [self expectationWithDescription:@"Signed in existing account with email and password."]; + [auth signInWithEmail:kExistingEmailToSignIn + password:kExistingPasswordToSignIn + completion:^(FIRAuthDataResult *user, NSError *error) { + if (error) { + NSLog(@"Signing in existing account has error: %@", error); + } + [expectation fulfill]; + }]; + [self waitForExpectationsWithTimeout:kExpectationsTimeout + handler:^(NSError *error) { + if (error != nil) { + XCTFail(@"Failed to wait for expectations " + @"in signing in existing account. Error: %@", + error.localizedDescription); + } + }]; + + XCTAssertEqualObjects(auth.currentUser.email, kExistingEmailToSignIn); +} + +@end diff --git a/Example/Auth/ApiTests/FIRAuthApiTestsBase.h b/Example/Auth/ApiTests/FIRAuthApiTestsBase.h new file mode 100644 index 00000000000..57b06d5d85c --- /dev/null +++ b/Example/Auth/ApiTests/FIRAuthApiTestsBase.h @@ -0,0 +1,60 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import +#import "AuthCredentials.h" +#import "FirebaseAuth.h" + +#ifdef NO_NETWORK +#import "ITUIOSTestUtil.h" +#endif + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +#ifdef NO_NETWORK +#define SKIP_IF_ON_MOBILE_HARNESS \ + if ([ITUIOSTestUtil isOnMobileHarness]) { \ + NSLog(@"Skipping '%@' on mobile harness", NSStringFromSelector(_cmd)); \ + return; \ + } +#else +#define SKIP_IF_ON_MOBILE_HARNESS +#endif + +static NSTimeInterval const kExpectationsTimeout = 10; + +@interface FIRAuthApiTestsBase : XCTestCase + +/** Sign in anonymously. */ +- (void)signInAnonymously; + +/** Sign out current account. */ +- (void)signOut; + +/** Clean up the created user for tests' future runs. */ +- (void)deleteCurrentUser; + +/** Generate fake random email address */ +- (NSString *)fakeRandomEmail; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Example/Auth/ApiTests/FIRAuthApiTestsBase.m b/Example/Auth/ApiTests/FIRAuthApiTestsBase.m new file mode 100644 index 00000000000..d67bb2d4720 --- /dev/null +++ b/Example/Auth/ApiTests/FIRAuthApiTestsBase.m @@ -0,0 +1,100 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FIRAuthApiTestsBase.h" + +@implementation FIRAuthApiTestsBase + +- (void)setUp { + [super setUp]; + + [self signOut]; +} + +- (void)tearDown { + [super tearDown]; +} + +- (void)signInAnonymously { + FIRAuth *auth = [FIRAuth auth]; + if (!auth) { + XCTFail(@"Could not obtain auth object."); + } + + XCTestExpectation *expectation = + [self expectationWithDescription:@"Anonymousy sign-in finished."]; + [auth signInAnonymouslyWithCompletion:^(FIRAuthDataResult *result, NSError *error) { + if (error) { + NSLog(@"Anonymousy sign in error: %@", error); + } + [expectation fulfill]; + }]; + [self waitForExpectationsWithTimeout:kExpectationsTimeout + handler:^(NSError *error) { + if (error != nil) { + XCTFail(@"Failed to wait for expectations " + @"in anonymousy sign in. Error: %@", + error.localizedDescription); + } + }]; +} + +- (void)signOut { + NSError *signOutError; + BOOL status = [[FIRAuth auth] signOut:&signOutError]; + + // Just log the error because we don't want to fail the test if signing out + // fails. + if (!status) { + NSLog(@"Error signing out: %@", signOutError); + } +} + +- (void)deleteCurrentUser { + FIRAuth *auth = [FIRAuth auth]; + if (!auth) { + NSLog(@"Could not obtain auth object."); + } + + XCTestExpectation *expectation = + [self expectationWithDescription:@"Delete current user finished."]; + [auth.currentUser deleteWithCompletion:^(NSError *_Nullable error) { + if (error) { + XCTFail(@"Failed to delete user. Error: %@.", error); + } + [expectation fulfill]; + }]; + [self waitForExpectationsWithTimeout:kExpectationsTimeout + handler:^(NSError *error) { + if (error != nil) { + XCTFail(@"Failed to wait for expectations " + @"in deleting user. Error: %@", + error.localizedDescription); + } + }]; +} + +- (NSString *)fakeRandomEmail { + NSMutableString *fakeEmail = [[NSMutableString alloc] init]; + for (int i = 0; i < 10; i++) { + [fakeEmail + appendString:[NSString stringWithFormat:@"%c", 'a' + arc4random_uniform('z' - 'a' + 1)]]; + } + [fakeEmail appendString:@"@gmail.com"]; + return fakeEmail; +} + +@end diff --git a/Example/Auth/ApiTests/FacebookAuthTests.m b/Example/Auth/ApiTests/FacebookAuthTests.m new file mode 100644 index 00000000000..cb74fe71461 --- /dev/null +++ b/Example/Auth/ApiTests/FacebookAuthTests.m @@ -0,0 +1,204 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FIRAuthApiTestsBase.h" + +/** Facebook app access token that will be used for Facebook Graph API, which is different from + * account access token. + */ +static NSString *const kFacebookAppAccessToken = KFACEBOOK_APP_ACCESS_TOKEN; + +/** Facebook app ID that will be used for Facebook Graph API. */ +static NSString *const kFacebookAppID = KFACEBOOK_APP_ID; + +static NSString *const kFacebookGraphApiAuthority = @"graph.facebook.com"; + +static NSString *const kFacebookTestAccountName = KFACEBOOK_USER_NAME; + +@interface FacebookAuthTests : FIRAuthApiTestsBase + +@end + +@implementation FacebookAuthTests + +- (void)testSignInWithFaceboook { + FIRAuth *auth = [FIRAuth auth]; + if (!auth) { + XCTFail(@"Could not obtain auth object."); + } + + NSDictionary *userInfoDict = [self createFacebookTestingAccount]; + NSString *facebookAccessToken = userInfoDict[@"access_token"]; + NSLog(@"Facebook testing account access token is: %@", facebookAccessToken); + NSString *facebookAccountId = userInfoDict[@"id"]; + NSLog(@"Facebook testing account id is: %@", facebookAccountId); + + FIRAuthCredential *credential = + [FIRFacebookAuthProvider credentialWithAccessToken:facebookAccessToken]; + + XCTestExpectation *expectation = [self expectationWithDescription:@"Facebook sign-in finished."]; + + [auth signInWithCredential:credential + completion:^(FIRUser *user, NSError *error) { + if (error) { + NSLog(@"Facebook sign in error: %@", error); + } + [expectation fulfill]; + }]; + + [self waitForExpectationsWithTimeout:kExpectationsTimeout + handler:^(NSError *error) { + if (error != nil) { + XCTFail(@"Failed to wait for expectations " + @"in Facebook sign in. Error: %@", + error.localizedDescription); + } + }]; + XCTAssertEqualObjects(auth.currentUser.displayName, kFacebookTestAccountName); + + // Clean up the created Firebase/Facebook user for future runs. + [self deleteCurrentUser]; + [self deleteFacebookTestingAccountbyId:facebookAccountId]; +} + +- (void)testLinkAnonymousAccountToFacebookAccount { + FIRAuth *auth = [FIRAuth auth]; + if (!auth) { + XCTFail(@"Could not obtain auth object."); + } + [self signInAnonymously]; + + NSDictionary *userInfoDict = [self createFacebookTestingAccount]; + NSString *facebookAccessToken = userInfoDict[@"access_token"]; + NSLog(@"Facebook testing account access token is: %@", facebookAccessToken); + NSString *facebookAccountId = userInfoDict[@"id"]; + NSLog(@"Facebook testing account id is: %@", facebookAccountId); + + FIRAuthCredential *credential = + [FIRFacebookAuthProvider credentialWithAccessToken:facebookAccessToken]; + + XCTestExpectation *expectation = [self expectationWithDescription:@"Facebook linking finished."]; + [auth.currentUser linkWithCredential:credential + completion:^(FIRUser *user, NSError *error) { + if (error) { + NSLog(@"Link to Facebok error: %@", error); + } + [expectation fulfill]; + }]; + + [self waitForExpectationsWithTimeout:kExpectationsTimeout + handler:^(NSError *error) { + if (error != nil) { + XCTFail(@"Failed to wait for expectations " + @"in linking to Facebook. Error: %@", + error.localizedDescription); + } + }]; + NSArray> *providerData = auth.currentUser.providerData; + XCTAssertEqual([providerData count], 1); + XCTAssertEqualObjects([providerData[0] providerID], @"facebook.com"); + + // Clean up the created Firebase/Facebook user for future runs. + [self deleteCurrentUser]; + [self deleteFacebookTestingAccountbyId:facebookAccountId]; +} + +/** Creates a Facebook testing account using Facebook Graph API and return a dictionary that + * constains "id", "access_token", "login_url", "email" and "password" of the created account. + */ +- (NSDictionary *)createFacebookTestingAccount { + // Build the URL. + NSString *urltoCreateTestUser = + [NSString stringWithFormat:@"https://%@/%@/accounts/test-users", kFacebookGraphApiAuthority, + kFacebookAppID]; + // Build the POST request. + NSString *bodyString = + [NSString stringWithFormat:@"installed=true&name=%@&permissions=read_stream&access_token=%@", + kFacebookTestAccountName, kFacebookAppAccessToken]; + NSData *postData = [bodyString dataUsingEncoding:NSUTF8StringEncoding]; + GTMSessionFetcherService *service = [[GTMSessionFetcherService alloc] init]; + GTMSessionFetcher *fetcher = [service fetcherWithURLString:urltoCreateTestUser]; + fetcher.bodyData = postData; + [fetcher setRequestValue:@"text/plain" forHTTPHeaderField:@"Content-Type"]; + + XCTestExpectation *expectation = + [self expectationWithDescription:@"Creating Facebook account finished."]; + __block NSData *data = nil; + [fetcher beginFetchWithCompletionHandler:^(NSData *receivedData, NSError *error) { + if (error) { + NSLog(@"Creating Facebook account finished with error: %@", error); + return; + } + data = receivedData; + [expectation fulfill]; + }]; + [self waitForExpectationsWithTimeout:kExpectationsTimeout + handler:^(NSError *error) { + if (error != nil) { + XCTFail(@"Failed to wait for expectations " + @"in creating Facebook account. Error: %@", + error.localizedDescription); + } + }]; + NSString *userInfo = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + NSLog(@"The info of created Facebook testing account is: %@", userInfo); + // Parses the access token from the JSON data. + NSDictionary *userInfoDict = [NSJSONSerialization JSONObjectWithData:data + options:kNilOptions + error:nil]; + return userInfoDict; +} + +/** Delete a Facebook testing account by account Id using Facebook Graph API. */ +- (void)deleteFacebookTestingAccountbyId:(NSString *)accountId { + // Build the URL. + NSString *urltoDeleteTestUser = + [NSString stringWithFormat:@"https://%@/%@", kFacebookGraphApiAuthority, accountId]; + + // Build the POST request. + NSString *bodyString = + [NSString stringWithFormat:@"method=delete&access_token=%@", kFacebookAppAccessToken]; + NSData *postData = [bodyString dataUsingEncoding:NSUTF8StringEncoding]; + GTMSessionFetcherService *service = [[GTMSessionFetcherService alloc] init]; + GTMSessionFetcher *fetcher = [service fetcherWithURLString:urltoDeleteTestUser]; + fetcher.bodyData = postData; + [fetcher setRequestValue:@"text/plain" forHTTPHeaderField:@"Content-Type"]; + + XCTestExpectation *expectation = + [self expectationWithDescription:@"Deleting Facebook account finished."]; + [fetcher beginFetchWithCompletionHandler:^(NSData *receivedData, NSError *error) { + NSString *deleteResult = [[NSString alloc] initWithData:receivedData + encoding:NSUTF8StringEncoding]; + NSLog(@"The result of deleting Facebook account is: %@", deleteResult); + if (error) { + NSLog(@"Deleting Facebook account finished with error: %@", error); + } + [expectation fulfill]; + }]; + + [self waitForExpectationsWithTimeout:kExpectationsTimeout + handler:^(NSError *error) { + if (error != nil) { + XCTFail(@"Failed to wait for expectations " + @"in deleting Facebook account. Error: %@", + error.localizedDescription); + } + }]; +} + +@end diff --git a/Example/Auth/ApiTests/FirebaseAuthApiTests.m b/Example/Auth/ApiTests/FirebaseAuthApiTests.m deleted file mode 100644 index 91275b6c419..00000000000 --- a/Example/Auth/ApiTests/FirebaseAuthApiTests.m +++ /dev/null @@ -1,674 +0,0 @@ -/* - * Copyright 2017 Google - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#import -#import - -#import -#import "FirebaseAuth.h" -#import "AuthCredentials.h" - -#ifdef NO_NETWORK -#import "ITUIOSTestUtil.h" -#endif - -#import -#import - -/** The user name string for Custom Auth testing account. */ -static NSString *const kCustomAuthTestingAccountUserID = KCUSTOM_AUTH_USER_ID; - -/** The url for obtaining a valid custom token string used to test Custom Auth. */ -static NSString *const kCustomTokenUrl = KCUSTOM_AUTH_TOKEN_URL; - -/** The url for obtaining an expired but valid custom token string used to test Custom Auth failure. - */ -static NSString *const kExpiredCustomTokenUrl = KCUSTOM_AUTH_TOKEN_EXPIRED_URL; - -/** Facebook app access token that will be used for Facebook Graph API, which is different from - * account access token. - */ -static NSString *const kFacebookAppAccessToken = KFACEBOOK_APP_ACCESS_TOKEN; - -/** Facebook app ID that will be used for Facebook Graph API. */ -static NSString *const kFacebookAppID = KFACEBOOK_APP_ID; - -static NSString *const kFacebookGraphApiAuthority = @"graph.facebook.com"; - -static NSString *const kFacebookTestAccountName = KFACEBOOK_USER_NAME; - -static NSString *const kGoogleTestAccountName = KGOOGLE_USER_NAME; - -/** The invalid custom token string for testing Custom Auth. */ -static NSString *const kInvalidCustomToken = @"invalid token."; - -/** The testing email address for testCreateAccountWithEmailAndPassword. */ -static NSString *const kTestingEmailToCreateUser = @"abc@xyz.com"; - -/** The testing email address for testSignInExistingUserWithEmailAndPassword. */ -static NSString *const kExistingTestingEmailToSignIn = @"456@abc.com"; - -/** The testing email address for testUpdatingUsersEmail. */ -static NSString *const kNewTestingEmail = @"updatedEmail@abc.com"; - -/** The testing password for testSignInExistingUserWithModifiedEmailAndPassword. */ -static NSString *const kNewTestingPasswordToSignIn = @"password_new"; - -/** Error message for invalid custom token sign in. */ -NSString *kInvalidTokenErrorMessage = - @"Invalid assertion format. 3 dot separated segments required."; - -NSString *kGoogleCliendId = KGOOGLE_CLIENT_ID; - -/** Refresh token of Google test account to exchange for access token. Refresh token never expires - * unless user revokes it. If this refresh token expires, tests in record mode will fail and this - * token needs to be updated. - */ -NSString *kGoogleTestAccountRefreshToken = KGOOGLE_TEST_ACCOUNT_REFRESH_TOKEN; - -static NSTimeInterval const kExpectationsTimeout = 10; - -#ifdef NO_NETWORK -#define SKIP_IF_ON_MOBILE_HARNESS \ - if ([ITUIOSTestUtil isOnMobileHarness]) { \ - NSLog(@"Skipping '%@' on mobile harness", NSStringFromSelector(_cmd)); \ - return; \ - } -#else -#define SKIP_IF_ON_MOBILE_HARNESS -#endif - -@interface ApiTests : XCTestCase - -@end - -@implementation ApiTests - -/** To reset the app so that each test sees the app in a clean state. */ -- (void)setUp { - [super setUp]; - [self signOut]; -} - -#pragma mark - Tests - -/** - * This test runs in replay mode by default. To run in a different mode follow the instructions - * below. - * - * Blaze: --test_arg=\'--networkReplayMode=(replay|record|disabled|observe)\' - * - * Xcode: - * Update the following flag in the xcscheme. - * --networkReplayMode=(replay|record|disabled|observe) - */ -- (void)testCreateAccountWithEmailAndPassword { - SKIP_IF_ON_MOBILE_HARNESS - FIRAuth *auth = [FIRAuth auth]; - if (!auth) { - XCTFail(@"Could not obtain auth object."); - } - XCTestExpectation *expectation = - [self expectationWithDescription:@"Created account with email and password."]; - [auth createUserWithEmail:kTestingEmailToCreateUser - password:@"password" - completion:^(FIRAuthDataResult *result, NSError *error) { - if (error) { - NSLog(@"createUserWithEmail has error: %@", error); - } - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:kExpectationsTimeout - handler:^(NSError *error) { - if (error != nil) { - XCTFail(@"Failed to wait for expectations " - @"in creating account. Error: %@", - error.localizedDescription); - } - }]; - - XCTAssertEqualObjects(auth.currentUser.email, kTestingEmailToCreateUser); - - // Clean up the created Firebase user for future runs. - [self deleteCurrentFirebaseUser]; -} - -- (void)testUpdatingUsersEmail { - SKIP_IF_ON_MOBILE_HARNESS - FIRAuth *auth = [FIRAuth auth]; - if (!auth) { - XCTFail(@"Could not obtain auth object."); - } - - __block NSError *apiError; - XCTestExpectation *expectation = - [self expectationWithDescription:@"Created account with email and password."]; - [auth createUserWithEmail:kTestingEmailToCreateUser - password:@"password" - completion:^(FIRAuthDataResult *user, NSError *error) { - apiError = error; - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:kExpectationsTimeout handler:nil]; - expectation = [self expectationWithDescription:@"Created account with email and password."]; - XCTAssertEqualObjects(auth.currentUser.email, kTestingEmailToCreateUser); - XCTAssertNil(apiError); - [auth.currentUser updateEmail:kNewTestingEmail - completion:^(NSError *_Nullable error) { - apiError = error; - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:kExpectationsTimeout handler:nil]; - XCTAssertNil(apiError); - XCTAssertEqualObjects(auth.currentUser.email, kNewTestingEmail); - // Clean up the created Firebase user for future runs. - [self deleteCurrentFirebaseUser]; -} - -- (void)testLinkAnonymousAccountToFacebookAccount { - FIRAuth *auth = [FIRAuth auth]; - if (!auth) { - XCTFail(@"Could not obtain auth object."); - } - [self signInAnonymously]; - - NSDictionary *userInfoDict = [self createFacebookTestingAccount]; - NSString *facebookAccessToken = userInfoDict[@"access_token"]; - NSLog(@"Facebook testing account access token is: %@", facebookAccessToken); - NSString *facebookAccountId = userInfoDict[@"id"]; - NSLog(@"Facebook testing account id is: %@", facebookAccountId); - - FIRAuthCredential *credential = - [FIRFacebookAuthProvider credentialWithAccessToken:facebookAccessToken]; - - XCTestExpectation *expectation = [self expectationWithDescription:@"Facebook linking finished."]; - [auth.currentUser linkWithCredential:credential - completion:^(FIRUser *user, NSError *error) { - if (error) { - NSLog(@"Link to Facebok error: %@", error); - } - [expectation fulfill]; - }]; - - [self waitForExpectationsWithTimeout:kExpectationsTimeout - handler:^(NSError *error) { - if (error != nil) { - XCTFail(@"Failed to wait for expectations " - @"in linking to Facebook. Error: %@", - error.localizedDescription); - } - }]; - NSArray> *providerData = auth.currentUser.providerData; - XCTAssertEqual([providerData count], 1); - XCTAssertEqualObjects([providerData[0] providerID], @"facebook.com"); - - // Clean up the created Firebase/Facebook user for future runs. - [self deleteCurrentFirebaseUser]; - [self deleteFacebookTestingAccountbyId:facebookAccountId]; -} - -- (void)testSignInAnonymously { - [self signInAnonymously]; - XCTAssertTrue([FIRAuth auth].currentUser.anonymous); - [self deleteCurrentFirebaseUser]; -} - -- (void)testSignInExistingUserWithEmailAndPassword { - FIRAuth *auth = [FIRAuth auth]; - if (!auth) { - XCTFail(@"Could not obtain auth object."); - } - XCTestExpectation *expectation = - [self expectationWithDescription:@"Signed in existing account with email and password."]; - [auth signInWithEmail:kExistingTestingEmailToSignIn - password:@"password" - completion:^(FIRAuthDataResult *user, NSError *error) { - if (error) { - NSLog(@"Signing in existing account has error: %@", error); - } - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:kExpectationsTimeout - handler:^(NSError *error) { - if (error != nil) { - XCTFail(@"Failed to wait for expectations " - @"in signing in existing account. Error: %@", - error.localizedDescription); - } - }]; - - XCTAssertEqualObjects(auth.currentUser.email, kExistingTestingEmailToSignIn); -} - -- (void)testSignInWithValidCustomAuthToken { - FIRAuth *auth = [FIRAuth auth]; - if (!auth) { - XCTFail(@"Could not obtain auth object."); - } - - NSError *error; - NSString *customToken = [NSString stringWithContentsOfURL:[NSURL URLWithString:kCustomTokenUrl] - encoding:NSUTF8StringEncoding - error:&error]; - if (!customToken) { - XCTFail(@"There was an error retrieving the custom token: %@", error); - } - NSLog(@"The valid token is: %@", customToken); - - XCTestExpectation *expectation = - [self expectationWithDescription:@"CustomAuthToken sign-in finished."]; - - [auth signInWithCustomToken:customToken - completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) { - if (error) { - NSLog(@"Valid token sign in error: %@", error); - } - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:kExpectationsTimeout - handler:^(NSError *error) { - if (error != nil) { - XCTFail(@"Failed to wait for expectations " - @"in CustomAuthToken sign in. Error: %@", - error.localizedDescription); - } - }]; - - XCTAssertEqualObjects(auth.currentUser.uid, kCustomAuthTestingAccountUserID); -} - -- (void)testSignInWithValidCustomAuthExpiredToken { - FIRAuth *auth = [FIRAuth auth]; - if (!auth) { - XCTFail(@"Could not obtain auth object."); - } - - NSError *error; - NSString *customToken = - [NSString stringWithContentsOfURL:[NSURL URLWithString:kExpiredCustomTokenUrl] - encoding:NSUTF8StringEncoding - error:&error]; - if (!customToken) { - XCTFail(@"There was an error retrieving the custom token: %@", error); - } - XCTestExpectation *expectation = - [self expectationWithDescription:@"CustomAuthToken sign-in finished."]; - - __block NSError *apiError; - [auth signInWithCustomToken:customToken - completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) { - if (error) { - apiError = error; - } - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:kExpectationsTimeout - handler:^(NSError *error) { - if (error != nil) { - XCTFail(@"Failed to wait for expectations " - @"in CustomAuthToken sign in. Error: %@", - error.localizedDescription); - } - }]; - - XCTAssertNil(auth.currentUser); - XCTAssertEqual(apiError.code, FIRAuthErrorCodeInvalidCustomToken); -} - -- (void)testInMemoryUserAfterSignOut { - FIRAuth *auth = [FIRAuth auth]; - if (!auth) { - XCTFail(@"Could not obtain auth object."); - } - NSError *error; - NSString *customToken = [NSString stringWithContentsOfURL:[NSURL URLWithString:kCustomTokenUrl] - encoding:NSUTF8StringEncoding - error:&error]; - if (!customToken) { - XCTFail(@"There was an error retrieving the custom token: %@", error); - } - XCTestExpectation *expectation = - [self expectationWithDescription:@"CustomAuthToken sign-in finished."]; - __block NSError *rpcError; - [auth signInWithCustomToken:customToken - completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) { - if (error) { - rpcError = error; - } - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:kExpectationsTimeout - handler:^(NSError *error) { - if (error != nil) { - XCTFail(@"Failed to wait for expectations " - @"in CustomAuthToken sign in. Error: %@", - error.localizedDescription); - } - }]; - XCTAssertEqualObjects(auth.currentUser.uid, kCustomAuthTestingAccountUserID); - XCTAssertNil(rpcError); - FIRUser *inMemoryUser = auth.currentUser; - XCTestExpectation *expectation1 = [self expectationWithDescription:@"Profile data change."]; - [auth signOut:NULL]; - rpcError = nil; - NSString *newEmailAddress = [self fakeRandomEmail]; - XCTAssertNotEqualObjects(newEmailAddress, inMemoryUser.email); - [inMemoryUser updateEmail:newEmailAddress completion:^(NSError *_Nullable error) { - rpcError = error; - [expectation1 fulfill]; - }]; - [self waitForExpectationsWithTimeout:kExpectationsTimeout handler:nil]; - XCTAssertEqualObjects(inMemoryUser.email, newEmailAddress); - XCTAssertNil(rpcError); - XCTAssertNil(auth.currentUser); -} - -- (void)testSignInWithInvalidCustomAuthToken { - FIRAuth *auth = [FIRAuth auth]; - if (!auth) { - XCTFail(@"Could not obtain auth object."); - } - XCTestExpectation *expectation = - [self expectationWithDescription:@"Invalid CustomAuthToken sign-in finished."]; - - [auth signInWithCustomToken:kInvalidCustomToken - completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) { - - XCTAssertEqualObjects(error.localizedDescription, kInvalidTokenErrorMessage); - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:kExpectationsTimeout - handler:^(NSError *error) { - if (error != nil) { - XCTFail(@"Failed to wait for expectations " - @"in CustomAuthToken sign in. Error: %@", - error.localizedDescription); - } - }]; -} - -- (void)testSignInWithFaceboook { - FIRAuth *auth = [FIRAuth auth]; - if (!auth) { - XCTFail(@"Could not obtain auth object."); - } - - NSDictionary *userInfoDict = [self createFacebookTestingAccount]; - NSString *facebookAccessToken = userInfoDict[@"access_token"]; - NSLog(@"Facebook testing account access token is: %@", facebookAccessToken); - NSString *facebookAccountId = userInfoDict[@"id"]; - NSLog(@"Facebook testing account id is: %@", facebookAccountId); - - FIRAuthCredential *credential = - [FIRFacebookAuthProvider credentialWithAccessToken:facebookAccessToken]; - - XCTestExpectation *expectation = [self expectationWithDescription:@"Facebook sign-in finished."]; - - [auth signInWithCredential:credential - completion:^(FIRUser *user, NSError *error) { - if (error) { - NSLog(@"Facebook sign in error: %@", error); - } - [expectation fulfill]; - }]; - - [self waitForExpectationsWithTimeout:kExpectationsTimeout - handler:^(NSError *error) { - if (error != nil) { - XCTFail(@"Failed to wait for expectations " - @"in Facebook sign in. Error: %@", - error.localizedDescription); - } - }]; - XCTAssertEqualObjects(auth.currentUser.displayName, kFacebookTestAccountName); - - // Clean up the created Firebase/Facebook user for future runs. - [self deleteCurrentFirebaseUser]; - [self deleteFacebookTestingAccountbyId:facebookAccountId]; -} - -- (void)testSignInWithGoogle { - FIRAuth *auth = [FIRAuth auth]; - if (!auth) { - XCTFail(@"Could not obtain auth object."); - } - NSDictionary *userInfoDict = [self getGoogleAccessToken]; - NSString *googleAccessToken = userInfoDict[@"access_token"]; - NSString *googleIdToken = userInfoDict[@"id_token"]; - FIRAuthCredential *credential = - [FIRGoogleAuthProvider credentialWithIDToken:googleIdToken accessToken:googleAccessToken]; - - XCTestExpectation *expectation = - [self expectationWithDescription:@"Signing in with Google finished."]; - [auth signInWithCredential:credential - completion:^(FIRUser *user, NSError *error) { - if (error) { - NSLog(@"Signing in with Google had error: %@", error); - } - [expectation fulfill]; - }]; - - [self waitForExpectationsWithTimeout:kExpectationsTimeout - handler:^(NSError *error) { - if (error != nil) { - XCTFail(@"Failed to wait for expectations " - @"in Signing in with Google. Error: %@", - error.localizedDescription); - } - }]; - XCTAssertEqualObjects(auth.currentUser.displayName, kGoogleTestAccountName); - - // Clean up the created Firebase/Facebook user for future runs. - [self deleteCurrentFirebaseUser]; -} - -#pragma mark - Helpers - -/** Generate fake random email address */ -- (NSString *)fakeRandomEmail { - NSMutableString *fakeEmail = [[NSMutableString alloc] init]; - for (int i=0; i<10; i++) { - [fakeEmail appendString: - [NSString stringWithFormat:@"%c", 'a' + arc4random_uniform('z' - 'a' + 1)]]; - } - [fakeEmail appendString:@"@gmail.com"]; - return fakeEmail; -} - -/** Sign out current account. */ -- (void)signOut { - NSError *signOutError; - BOOL status = [[FIRAuth auth] signOut:&signOutError]; - - // Just log the error because we don't want to fail the test if signing out - // fails. - if (!status) { - NSLog(@"Error signing out: %@", signOutError); - } -} - -/** Creates a Facebook testing account using Facebook Graph API and return a dictionary that - * constains "id", "access_token", "login_url", "email" and "password" of the created account. - */ -- (NSDictionary *)createFacebookTestingAccount { - // Build the URL. - NSString *urltoCreateTestUser = - [NSString stringWithFormat:@"https://%@/%@/accounts/test-users", kFacebookGraphApiAuthority, - kFacebookAppID]; - // Build the POST request. - NSString *bodyString = - [NSString stringWithFormat:@"installed=true&name=%@&permissions=read_stream&access_token=%@", - kFacebookTestAccountName, kFacebookAppAccessToken]; - NSData *postData = [bodyString dataUsingEncoding:NSUTF8StringEncoding]; - GTMSessionFetcherService *service = [[GTMSessionFetcherService alloc] init]; - GTMSessionFetcher *fetcher = [service fetcherWithURLString:urltoCreateTestUser]; - fetcher.bodyData = postData; - [fetcher setRequestValue:@"text/plain" forHTTPHeaderField:@"Content-Type"]; - - XCTestExpectation *expectation = - [self expectationWithDescription:@"Creating Facebook account finished."]; - __block NSData *data = nil; - [fetcher beginFetchWithCompletionHandler:^(NSData *receivedData, NSError *error) { - if (error) { - NSLog(@"Creating Facebook account finished with error: %@", error); - return; - } - data = receivedData; - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:kExpectationsTimeout - handler:^(NSError *error) { - if (error != nil) { - XCTFail(@"Failed to wait for expectations " - @"in creating Facebook account. Error: %@", - error.localizedDescription); - } - }]; - NSString *userInfo = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - NSLog(@"The info of created Facebook testing account is: %@", userInfo); - // Parses the access token from the JSON data. - NSDictionary *userInfoDict = - [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]; - return userInfoDict; -} - -/** Clean up the created user for tests' future runs. */ -- (void)deleteCurrentFirebaseUser { - FIRAuth *auth = [FIRAuth auth]; - if (!auth) { - NSLog(@"Could not obtain auth object."); - } - - XCTestExpectation *expectation = - [self expectationWithDescription:@"Delete current user finished."]; - [auth.currentUser deleteWithCompletion:^(NSError *_Nullable error) { - if (error) { - XCTFail(@"Failed to delete user. Error: %@.", error); - } - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:kExpectationsTimeout - handler:^(NSError *error) { - if (error != nil) { - XCTFail(@"Failed to wait for expectations " - @"in deleting user. Error: %@", - error.localizedDescription); - } - }]; -} - -- (void)signInAnonymously { - FIRAuth *auth = [FIRAuth auth]; - if (!auth) { - XCTFail(@"Could not obtain auth object."); - } - - XCTestExpectation *expectation = - [self expectationWithDescription:@"Anonymousy sign-in finished."]; - [auth signInAnonymouslyWithCompletion:^(FIRAuthDataResult *result, NSError *error) { - if (error) { - NSLog(@"Anonymousy sign in error: %@", error); - } - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:kExpectationsTimeout - handler:^(NSError *error) { - if (error != nil) { - XCTFail(@"Failed to wait for expectations " - @"in anonymousy sign in. Error: %@", - error.localizedDescription); - } - }]; -} - -/** Delete a Facebook testing account by account Id using Facebook Graph API. */ -- (void)deleteFacebookTestingAccountbyId:(NSString *)accountId { - // Build the URL. - NSString *urltoDeleteTestUser = - [NSString stringWithFormat:@"https://%@/%@", kFacebookGraphApiAuthority, accountId]; - - // Build the POST request. - NSString *bodyString = - [NSString stringWithFormat:@"method=delete&access_token=%@", kFacebookAppAccessToken]; - NSData *postData = [bodyString dataUsingEncoding:NSUTF8StringEncoding]; - GTMSessionFetcherService *service = [[GTMSessionFetcherService alloc] init]; - GTMSessionFetcher *fetcher = [service fetcherWithURLString:urltoDeleteTestUser]; - fetcher.bodyData = postData; - [fetcher setRequestValue:@"text/plain" forHTTPHeaderField:@"Content-Type"]; - - XCTestExpectation *expectation = - [self expectationWithDescription:@"Deleting Facebook account finished."]; - [fetcher beginFetchWithCompletionHandler:^(NSData *receivedData, NSError *error) { - NSString *deleteResult = - [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding]; - NSLog(@"The result of deleting Facebook account is: %@", deleteResult); - if (error) { - NSLog(@"Deleting Facebook account finished with error: %@", error); - } - [expectation fulfill]; - }]; - - [self waitForExpectationsWithTimeout:kExpectationsTimeout - handler:^(NSError *error) { - if (error != nil) { - XCTFail(@"Failed to wait for expectations " - @"in deleting Facebook account. Error: %@", - error.localizedDescription); - } - }]; -} - -/** Sends http request to Google OAuth2 token server to use refresh token to exchange for Google - * access token. Returns a dictionary that constains "access_token", "token_type", "expires_in" and - * "id_token". - */ -- (NSDictionary *)getGoogleAccessToken { - NSString *googleOauth2TokenServerUrl = @"https://www.googleapis.com/oauth2/v4/token"; - NSString *bodyString = - [NSString stringWithFormat:@"client_id=%@&grant_type=refresh_token&refresh_token=%@", - kGoogleCliendId, kGoogleTestAccountRefreshToken]; - NSData *postData = [bodyString dataUsingEncoding:NSUTF8StringEncoding]; - GTMSessionFetcherService *service = [[GTMSessionFetcherService alloc] init]; - GTMSessionFetcher *fetcher = [service fetcherWithURLString:googleOauth2TokenServerUrl]; - fetcher.bodyData = postData; - [fetcher setRequestValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; - - XCTestExpectation *expectation = - [self expectationWithDescription:@"Exchanging Google account tokens finished."]; - __block NSData *data = nil; - [fetcher beginFetchWithCompletionHandler:^(NSData *receivedData, NSError *error) { - if (error) { - NSLog(@"Exchanging Google account tokens finished with error: %@", error); - return; - } - data = receivedData; - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:kExpectationsTimeout - handler:^(NSError *error) { - if (error != nil) { - XCTFail(@"Failed to wait for expectations " - @"in exchanging Google account tokens. Error: %@", - error.localizedDescription); - } - }]; - NSString *userInfo = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - NSLog(@"The info of exchanged result is: %@", userInfo); - NSDictionary *userInfoDict = - [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]; - return userInfoDict; -} -@end diff --git a/Example/Auth/ApiTests/GoogleAuthTests.m b/Example/Auth/ApiTests/GoogleAuthTests.m new file mode 100644 index 00000000000..4611a1b8edf --- /dev/null +++ b/Example/Auth/ApiTests/GoogleAuthTests.m @@ -0,0 +1,114 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FIRAuthApiTestsBase.h" + +static NSString *kGoogleCliendId = KGOOGLE_CLIENT_ID; + +static NSString *const kGoogleTestAccountName = KGOOGLE_USER_NAME; + +/** Refresh token of Google test account to exchange for access token. Refresh token never expires + * unless user revokes it. If this refresh token expires, tests in record mode will fail and this + * token needs to be updated. + */ +NSString *kGoogleTestAccountRefreshToken = KGOOGLE_TEST_ACCOUNT_REFRESH_TOKEN; + +@interface GoogleAuthTests : FIRAuthApiTestsBase + +@end + +@implementation GoogleAuthTests + +- (void)testSignInWithGoogle { + FIRAuth *auth = [FIRAuth auth]; + if (!auth) { + XCTFail(@"Could not obtain auth object."); + } + NSDictionary *userInfoDict = [self getGoogleAccessToken]; + NSString *googleAccessToken = userInfoDict[@"access_token"]; + NSString *googleIdToken = userInfoDict[@"id_token"]; + FIRAuthCredential *credential = [FIRGoogleAuthProvider credentialWithIDToken:googleIdToken + accessToken:googleAccessToken]; + + XCTestExpectation *expectation = + [self expectationWithDescription:@"Signing in with Google finished."]; + [auth signInWithCredential:credential + completion:^(FIRUser *user, NSError *error) { + if (error) { + NSLog(@"Signing in with Google had error: %@", error); + } + [expectation fulfill]; + }]; + + [self waitForExpectationsWithTimeout:kExpectationsTimeout + handler:^(NSError *error) { + if (error != nil) { + XCTFail(@"Failed to wait for expectations " + @"in Signing in with Google. Error: %@", + error.localizedDescription); + } + }]; + XCTAssertEqualObjects(auth.currentUser.displayName, kGoogleTestAccountName); + + // Clean up the created Firebase/Facebook user for future runs. + [self deleteCurrentUser]; +} + +/** Sends http request to Google OAuth2 token server to use refresh token to exchange for Google + * access token. Returns a dictionary that constains "access_token", "token_type", "expires_in" and + * "id_token". + */ +- (NSDictionary *)getGoogleAccessToken { + NSString *googleOauth2TokenServerUrl = @"https://www.googleapis.com/oauth2/v4/token"; + NSString *bodyString = + [NSString stringWithFormat:@"client_id=%@&grant_type=refresh_token&refresh_token=%@", + kGoogleCliendId, kGoogleTestAccountRefreshToken]; + NSData *postData = [bodyString dataUsingEncoding:NSUTF8StringEncoding]; + GTMSessionFetcherService *service = [[GTMSessionFetcherService alloc] init]; + GTMSessionFetcher *fetcher = [service fetcherWithURLString:googleOauth2TokenServerUrl]; + fetcher.bodyData = postData; + [fetcher setRequestValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; + + XCTestExpectation *expectation = + [self expectationWithDescription:@"Exchanging Google account tokens finished."]; + __block NSData *data = nil; + [fetcher beginFetchWithCompletionHandler:^(NSData *receivedData, NSError *error) { + if (error) { + NSLog(@"Exchanging Google account tokens finished with error: %@", error); + return; + } + data = receivedData; + [expectation fulfill]; + }]; + [self waitForExpectationsWithTimeout:kExpectationsTimeout + handler:^(NSError *error) { + if (error != nil) { + XCTFail(@"Failed to wait for expectations " + @"in exchanging Google account tokens. Error: %@", + error.localizedDescription); + } + }]; + NSString *userInfo = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + NSLog(@"The info of exchanged result is: %@", userInfo); + NSDictionary *userInfoDict = [NSJSONSerialization JSONObjectWithData:data + options:kNilOptions + error:nil]; + return userInfoDict; +} + +@end diff --git a/Example/Auth/ApiTests/GoogleAuthTests.swift b/Example/Auth/ApiTests/GoogleAuthTests.swift new file mode 100644 index 00000000000..9a2126ca614 --- /dev/null +++ b/Example/Auth/ApiTests/GoogleAuthTests.swift @@ -0,0 +1,91 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import XCTest + +class GoogleAuthTestsSwift: FIRAuthApiTestsBase { + let kGoogleCliendId = KGOOGLE_CLIENT_ID + + let kGoogleTestAccountName = KGOOGLE_USER_NAME + + let kGoogleTestAccountRefreshToken = KGOOGLE_TEST_ACCOUNT_REFRESH_TOKEN + + func testSignInWithGoogle() { + let auth = Auth.auth() + let userInfoDictOptional = getGoogleAccessToken() + if userInfoDictOptional == nil { + XCTFail("Could not obtain Google access token.") + } + let userInfoDict = userInfoDictOptional! + let googleAccessToken = userInfoDict["access_token"] as! String + let googleIdToken = userInfoDict["id_token"] as! String + let credential = GoogleAuthProvider.credential(withIDToken: googleIdToken, accessToken: googleAccessToken) + + let expectation = self.expectation(description: "Signing in with Google finished.") + auth.signInAndRetrieveData(with: credential) { _, error in + if error != nil { + print("Signing in with Google had error: %@", error!) + } + expectation.fulfill() + } + + waitForExpectations(timeout: kExpectationsTimeout) { error in + if error != nil { + XCTFail(String(format: "Failed to wait for expectations in Signing in with Google. Error: %@", error!.localizedDescription)) + } + } + + XCTAssertEqual(auth.currentUser?.displayName, kGoogleTestAccountName) + + deleteCurrentUser() + } + + func getGoogleAccessToken() -> [String: Any]? { + let googleOauth2TokenServerUrl = "https://www.googleapis.com/oauth2/v4/token" + let bodyString = String(format: "client_id=%@&grant_type=refresh_token&refresh_token=%@", kGoogleCliendId, kGoogleTestAccountRefreshToken) + let postData = bodyString.data(using: .utf8) + let service = GTMSessionFetcherService() + let fetcher = service.fetcher(withURLString: googleOauth2TokenServerUrl) + fetcher.bodyData = postData + fetcher.setRequestValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") + + let expectation = self.expectation(description: "Exchanging Google account tokens finished.") + var data: Data? + fetcher.beginFetch { receivedData, error in + if error != nil { + print("Exchanging Google account tokens finished with error: %@", error!) + return + } + data = receivedData + expectation.fulfill() + } + + waitForExpectations(timeout: kExpectationsTimeout) { error in + if error != nil { + XCTFail(String(format: "Failed to wait for expectations in exchanging Google account tokens. Error: %@", error!.localizedDescription)) + } + } + + let userInfo = String(data: data!, encoding: .utf8) + print("The info of exchanged result is: \(userInfo ?? "")") + let rawJsonObject = try? JSONSerialization.jsonObject(with: data!, options: []) + if let userInfoDict = rawJsonObject as? [String: Any] { + return userInfoDict + } else { + return nil + } + } +} diff --git a/Example/Auth/E2eTests/BYOAuthTests.m b/Example/Auth/E2eTests/BYOAuthTests.m new file mode 100644 index 00000000000..60f0904d2b0 --- /dev/null +++ b/Example/Auth/E2eTests/BYOAuthTests.m @@ -0,0 +1,86 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FIRAuthE2eTestsBase.h" + +/** The url for obtaining a valid custom token string used to test BYOAuth. */ +static NSString *const kCustomTokenUrl = @"https://fb-sa-1211.appspot.com/token"; + +/** The invalid custom token string for testing BYOAuth. */ +static NSString *const kInvalidCustomToken = @"invalid token."; + +/** The user name string for BYOAuth testing account. */ +static NSString *const kTestingAccountUserID = @"BYU_Test_User_ID"; + +@interface BYOAuthTests : FIRAuthE2eTestsBase + +@end + +@implementation BYOAuthTests + +/** Test sign in with a valid BYOAuth token retrived from a remote server. */ +- (void)testSignInWithValidBYOAuthToken { + NSError *error; + NSString *customToken = [NSString stringWithContentsOfURL:[NSURL URLWithString:kCustomTokenUrl] + encoding:NSUTF8StringEncoding + error:&error]; + if (!customToken) { + GREYFail(@"There was an error retrieving the custom token: %@", error); + } + + [[[EarlGrey selectElementWithMatcher:grey_allOf(grey_text(@"Sign In (BYOAuth)"), + grey_sufficientlyVisible(), nil)] + usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, kShortScrollDistance) + onElementWithMatcher:grey_allOf(grey_scrollView(), grey_kindOfClass([UITableView class]), + nil)] performAction:grey_tap()]; + + [[[EarlGrey selectElementWithMatcher:grey_kindOfClass([UITextView class])] + performAction:grey_replaceText(customToken)] assertWithMatcher:grey_text(customToken)]; + + [[EarlGrey selectElementWithMatcher:grey_text(@"Done")] performAction:grey_tap()]; + + [self waitForElementWithText:@"OK" withDelay:kWaitForElementTimeOut]; + + [[EarlGrey selectElementWithMatcher:grey_text(@"OK")] performAction:grey_tap()]; + + [[[EarlGrey selectElementWithMatcher:grey_allOf(grey_text(kTestingAccountUserID), + grey_sufficientlyVisible(), nil)] + usingSearchAction:grey_scrollInDirection(kGREYDirectionUp, kShortScrollDistance) + onElementWithMatcher:grey_allOf(grey_scrollView(), grey_kindOfClass([UITableView class]), + nil)] assertWithMatcher:grey_sufficientlyVisible()]; +} + +- (void)testSignInWithInvalidBYOAuthToken { + [[[EarlGrey selectElementWithMatcher:grey_allOf(grey_text(@"Sign In (BYOAuth)"), + grey_sufficientlyVisible(), nil)] + usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, kShortScrollDistance) + onElementWithMatcher:grey_allOf(grey_scrollView(), grey_kindOfClass([UITableView class]), + nil)] performAction:grey_tap()]; + + [[[EarlGrey selectElementWithMatcher:grey_kindOfClass([UITextView class])] + performAction:grey_replaceText(kInvalidCustomToken)] + assertWithMatcher:grey_text(kInvalidCustomToken)]; + + [[EarlGrey selectElementWithMatcher:grey_text(@"Done")] performAction:grey_tap()]; + + NSString *invalidTokenErrorMessage = @"Sign-In Error"; + + [self waitForElementWithText:invalidTokenErrorMessage withDelay:kWaitForElementTimeOut]; + + [[EarlGrey selectElementWithMatcher:grey_text(@"OK")] performAction:grey_tap()]; +} + +@end diff --git a/Example/Auth/E2eTests/FIRAuthE2eTests.m b/Example/Auth/E2eTests/FIRAuthE2eTests.m new file mode 100644 index 00000000000..f58e6bc850f --- /dev/null +++ b/Example/Auth/E2eTests/FIRAuthE2eTests.m @@ -0,0 +1,56 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FIRAuthE2eTestsBase.h" + +@interface FIRAuthE2eTests : FIRAuthE2eTestsBase + +@end + +@implementation FIRAuthE2eTests + +- (void)testSignInExistingUser { + NSString *email = @"123@abc.com"; + [[[EarlGrey selectElementWithMatcher:grey_allOf(grey_text(@"Sign in with Email/Password"), + grey_sufficientlyVisible(), nil)] + usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, kShortScrollDistance) + onElementWithMatcher:grey_allOf(grey_scrollView(), grey_kindOfClass([UITableView class]), + nil)] performAction:grey_tap()]; + + id comfirmationButtonMatcher = + grey_allOf(grey_kindOfClass([UILabel class]), grey_accessibilityLabel(@"OK"), nil); + + [[EarlGrey selectElementWithMatcher: +#warning TODO Add accessibilityIdentifiers for the elements. + grey_kindOfClass(NSClassFromString(@"_UIAlertControllerView"))] + performAction:grey_typeText(email)]; + + [[EarlGrey selectElementWithMatcher:comfirmationButtonMatcher] performAction:grey_tap()]; + + [[EarlGrey + selectElementWithMatcher:grey_kindOfClass(NSClassFromString(@"_UIAlertControllerView"))] + performAction:grey_typeText(@"password")]; + + [[EarlGrey selectElementWithMatcher:comfirmationButtonMatcher] performAction:grey_tap()]; + + [[[EarlGrey + selectElementWithMatcher:grey_allOf(grey_text(email), grey_sufficientlyVisible(), nil)] + usingSearchAction:grey_scrollInDirection(kGREYDirectionUp, kShortScrollDistance) + onElementWithMatcher:grey_allOf(grey_scrollView(), grey_kindOfClass([UITableView class]), + nil)] assertWithMatcher:grey_sufficientlyVisible()]; +} + +@end diff --git a/Example/Auth/E2eTests/FIRAuthE2eTestsBase.h b/Example/Auth/E2eTests/FIRAuthE2eTestsBase.h new file mode 100644 index 00000000000..e1c97f5cdb1 --- /dev/null +++ b/Example/Auth/E2eTests/FIRAuthE2eTestsBase.h @@ -0,0 +1,42 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import + +#import "FirebaseAuth.h" + +NS_ASSUME_NONNULL_BEGIN + +extern CGFloat const kShortScrollDistance; + +extern NSTimeInterval const kWaitForElementTimeOut; + +/** Convenience function for EarlGrey tests. */ +id grey_scrollView(void); + +@interface FIRAuthE2eTestsBase : XCTestCase + +/** Sign out current account. */ +- (void)signOut; + +/** Wait for an element with text to appear. */ +- (void)waitForElementWithText:(NSString *)text withDelay:(NSTimeInterval)maxDelay; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Example/Auth/E2eTests/FIRAuthE2eTestsBase.m b/Example/Auth/E2eTests/FIRAuthE2eTestsBase.m new file mode 100644 index 00000000000..08fc7be79f8 --- /dev/null +++ b/Example/Auth/E2eTests/FIRAuthE2eTestsBase.m @@ -0,0 +1,70 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FIRAuthE2eTestsBase.h" + +CGFloat const kShortScrollDistance = 400; + +NSTimeInterval const kWaitForElementTimeOut = 15; + +/** Convenience function for EarlGrey tests. */ +id grey_scrollView(void) { + return [GREYMatchers matcherForKindOfClass:[UIScrollView class]]; +} + +@implementation FIRAuthE2eTestsBase + +/** To reset the app so that each test sees the app in a clean state. */ +- (void)setUp { + [super setUp]; + + [self signOut]; + + [[EarlGrey selectElementWithMatcher:grey_allOf(grey_scrollView(), + grey_kindOfClass([UITableView class]), nil)] + performAction:grey_scrollToContentEdge(kGREYContentEdgeTop)]; +} + +- (void)tearDown { + [super tearDown]; +} + +/** Sign out current account. */ +- (void)signOut { + NSError *signOutError; + BOOL status = [[FIRAuth auth] signOut:&signOutError]; + + // Just log the error because we don't want to fail the test if signing out fails. + if (!status) { + NSLog(@"Error signing out: %@", signOutError); + } +} + +/** Wait for an element with text to appear. */ +- (void)waitForElementWithText:(NSString *)text withDelay:(NSTimeInterval)maxDelay { + GREYCondition *displayed = + [GREYCondition conditionWithName:@"Wait for element" + block:^BOOL { + NSError *error = nil; + [[EarlGrey selectElementWithMatcher:grey_text(text)] + assertWithMatcher:grey_sufficientlyVisible() + error:&error]; + return !error; + }]; + GREYAssertTrue([displayed waitWithTimeout:maxDelay], @"Failed to wait for element '%@'.", text); +} + +@end diff --git a/Example/Auth/EarlGreyTests/Info.plist b/Example/Auth/E2eTests/Info.plist similarity index 100% rename from Example/Auth/EarlGreyTests/Info.plist rename to Example/Auth/E2eTests/Info.plist diff --git a/Example/Auth/E2eTests/VerifyIOSClientTests.m b/Example/Auth/E2eTests/VerifyIOSClientTests.m new file mode 100644 index 00000000000..131a56430de --- /dev/null +++ b/Example/Auth/E2eTests/VerifyIOSClientTests.m @@ -0,0 +1,38 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FIRAuthE2eTestsBase.h" + +@interface VerifyIOSClientTests : FIRAuthE2eTestsBase + +@end + +@implementation VerifyIOSClientTests + +/** Test verify ios client*/ +- (void)testVerifyIOSClient { + [[[EarlGrey selectElementWithMatcher:grey_allOf(grey_text(@"Verify iOS client"), + grey_sufficientlyVisible(), nil)] + usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, kShortScrollDistance) + onElementWithMatcher:grey_allOf(grey_scrollView(), grey_kindOfClass([UITableView class]), + nil)] performAction:grey_tap()]; + + [self waitForElementWithText:@"OK" withDelay:kWaitForElementTimeOut]; + + [[EarlGrey selectElementWithMatcher:grey_text(@"OK")] performAction:grey_tap()]; +} + +@end diff --git a/Example/Auth/EarlGreyTests/FIRVerifyIOSClientTests.m b/Example/Auth/EarlGreyTests/FIRVerifyIOSClientTests.m deleted file mode 100644 index 1ccbd17b882..00000000000 --- a/Example/Auth/EarlGreyTests/FIRVerifyIOSClientTests.m +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2018 Google - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#import -#import -#import -#import "FirebaseAuth.h" - -static CGFloat const kShortScrollDistance = 100; - -static NSTimeInterval const kWaitForElementTimeOut = 15; - -@interface FIRVerifyIOSClientTests : XCTestCase -@end - -/** Convenience function for EarlGrey tests. */ -static id grey_scrollView(void) { - return [GREYMatchers matcherForKindOfClass:[UIScrollView class]]; -} - -@implementation FIRVerifyIOSClientTests - -/** To reset the app so that each test sees the app in a clean state. */ -- (void)setUp { - [super setUp]; - - [self signOut]; - - [[EarlGrey selectElementWithMatcher:grey_allOf(grey_scrollView(), - grey_kindOfClass([UITableView class]), nil)] - performAction:grey_scrollToContentEdge(kGREYContentEdgeTop)]; -} - -#pragma mark - Tests - -/** Test verify ios client*/ -- (void)testVerifyIOSClient { - [[[EarlGrey selectElementWithMatcher:grey_allOf(grey_text(@"Verify iOS client"), - grey_sufficientlyVisible(), nil)] - usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, kShortScrollDistance) - onElementWithMatcher:grey_allOf(grey_scrollView(), grey_kindOfClass([UITableView class]), - nil)] performAction:grey_tap()]; - - [self waitForElementWithText:@"OK" withDelay:kWaitForElementTimeOut]; - - [[EarlGrey selectElementWithMatcher:grey_text(@"OK")] performAction:grey_tap()]; -} - -#pragma mark - Helpers - -/** Sign out current account. */ -- (void)signOut { - NSError *signOutError; - BOOL status = [[FIRAuth auth] signOut:&signOutError]; - - // Just log the error because we don't want to fail the test if signing out fails. - if (!status) { - NSLog(@"Error signing out: %@", signOutError); - } -} - -/** Wait for an element with text to appear. */ -- (void)waitForElementWithText:(NSString *)text withDelay:(NSTimeInterval)maxDelay { - GREYCondition *displayed = - [GREYCondition conditionWithName:@"Wait for element" - block:^BOOL { - NSError *error = nil; - [[EarlGrey selectElementWithMatcher:grey_text(text)] - assertWithMatcher:grey_sufficientlyVisible() - error:&error]; - return !error; - }]; - GREYAssertTrue([displayed waitWithTimeout:maxDelay], @"Failed to wait for element '%@'.", text); -} - -@end diff --git a/Example/Auth/EarlGreyTests/FirebaseAuthEarlGreyTests.m b/Example/Auth/EarlGreyTests/FirebaseAuthEarlGreyTests.m deleted file mode 100644 index d8130fe0a91..00000000000 --- a/Example/Auth/EarlGreyTests/FirebaseAuthEarlGreyTests.m +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright 2017 Google - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#import -#import -#import - -#import -#import "FirebaseAuth.h" - -/** The url for obtaining a valid custom token string used to test BYOAuth. */ -static NSString *const kCustomTokenUrl = @"https://fb-sa-1211.appspot.com/token"; - -/** The invalid custom token string for testing BYOAuth. */ -static NSString *const kInvalidCustomToken = @"invalid token."; - -/** The user name string for BYOAuth testing account. */ -static NSString *const kTestingAccountUserID = @"BYU_Test_User_ID"; - -static CGFloat const kShortScrollDistance = 100; - -static NSTimeInterval const kWaitForElementTimeOut = 5; - -@interface BasicUITest :XCTestCase -@end - -/** Convenience function for EarlGrey tests. */ -static id grey_scrollView(void) { - return [GREYMatchers matcherForKindOfClass:[UIScrollView class]]; -} - -@implementation BasicUITest - -/** To reset the app so that each test sees the app in a clean state. */ -- (void)setUp { - [super setUp]; - - [self signOut]; - - [[EarlGrey selectElementWithMatcher:grey_allOf(grey_scrollView(), - grey_kindOfClass([UITableView class]), nil)] - performAction:grey_scrollToContentEdge(kGREYContentEdgeTop)]; -} - -#pragma mark - Tests - -/** - * This test runs in replay mode by default. To run in a different mode - * follow the instructions below. - * - * Blaze: - * --test_arg=\'--networkReplayMode=(replay|record|disabled|observe)\' - * - * Xcode: - * Update the following flag in the xcscheme. - * --networkReplayMode=(replay|record|disabled|observe) - */ -- (void)testSignInExistingUser { - NSString *email = @"123@abc.com"; - [[[EarlGrey selectElementWithMatcher:grey_allOf(grey_text(@"Sign in with Email/Password"), - grey_sufficientlyVisible(), nil)] - usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, kShortScrollDistance) - onElementWithMatcher:grey_allOf(grey_scrollView(), grey_kindOfClass([UITableView class]), - nil)] performAction:grey_tap()]; - - id comfirmationButtonMatcher = - grey_allOf(grey_kindOfClass([UILabel class]), grey_accessibilityLabel(@"OK"), nil); - - [[EarlGrey selectElementWithMatcher: - #warning TODO Add accessibilityIdentifiers for the elements. - grey_kindOfClass(NSClassFromString(@"_UIAlertControllerView"))] - performAction:grey_typeText(email)]; - - [[EarlGrey selectElementWithMatcher:comfirmationButtonMatcher] performAction:grey_tap()]; - - [[EarlGrey - selectElementWithMatcher:grey_kindOfClass(NSClassFromString(@"_UIAlertControllerView"))] - performAction:grey_typeText(@"password")]; - - [[EarlGrey selectElementWithMatcher:comfirmationButtonMatcher] performAction:grey_tap()]; - - [[[EarlGrey - selectElementWithMatcher:grey_allOf(grey_text(email), grey_sufficientlyVisible(), nil)] - usingSearchAction:grey_scrollInDirection(kGREYDirectionUp, kShortScrollDistance) - onElementWithMatcher:grey_allOf(grey_scrollView(), grey_kindOfClass([UITableView class]), - nil)] assertWithMatcher:grey_sufficientlyVisible()]; -} - -/** Test sign in with a valid BYOAuth token retrived from a remote server. */ -- (void)testSignInWithValidBYOAuthToken { - NSError *error; - NSString *customToken = [NSString stringWithContentsOfURL:[NSURL URLWithString:kCustomTokenUrl] - encoding:NSUTF8StringEncoding - error:&error]; - if (!customToken) { - GREYFail(@"There was an error retrieving the custom token: %@", error); - } - - [[[EarlGrey selectElementWithMatcher:grey_allOf(grey_text(@"Sign In (BYOAuth)"), - grey_sufficientlyVisible(), nil)] - usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, kShortScrollDistance) - onElementWithMatcher:grey_allOf(grey_scrollView(), grey_kindOfClass([UITableView class]), - nil)] performAction:grey_tap()]; - - [[[EarlGrey selectElementWithMatcher:grey_kindOfClass([UITextView class])] - performAction:grey_replaceText(customToken)] assertWithMatcher:grey_text(customToken)]; - - [[EarlGrey selectElementWithMatcher:grey_text(@"Done")] performAction:grey_tap()]; - - [self waitForElementWithText:@"OK" withDelay:kWaitForElementTimeOut]; - - [[EarlGrey selectElementWithMatcher:grey_text(@"OK")] performAction:grey_tap()]; - - [[[EarlGrey - selectElementWithMatcher:grey_allOf(grey_text(kTestingAccountUserID), - grey_sufficientlyVisible(), nil)] - usingSearchAction:grey_scrollInDirection(kGREYDirectionUp, - kShortScrollDistance) - onElementWithMatcher:grey_allOf(grey_scrollView(), - grey_kindOfClass([UITableView class]), - nil)] - assertWithMatcher:grey_sufficientlyVisible()]; -} - -- (void)testSignInWithInvalidBYOAuthToken { - [[[EarlGrey selectElementWithMatcher:grey_allOf(grey_text(@"Sign In (BYOAuth)"), - grey_sufficientlyVisible(), nil)] - usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, kShortScrollDistance) - onElementWithMatcher:grey_allOf(grey_scrollView(), grey_kindOfClass([UITableView class]), - nil)] performAction:grey_tap()]; - - [[[EarlGrey selectElementWithMatcher:grey_kindOfClass([UITextView class])] - performAction:grey_replaceText(kInvalidCustomToken)] - assertWithMatcher:grey_text(kInvalidCustomToken)]; - - [[EarlGrey selectElementWithMatcher:grey_text(@"Done")] performAction:grey_tap()]; - - NSString *invalidTokenErrorMessage = @"Sign-In Error"; - - [self waitForElementWithText:invalidTokenErrorMessage withDelay:kWaitForElementTimeOut]; - - [[EarlGrey selectElementWithMatcher:grey_text(@"OK")] performAction:grey_tap()]; -} - -#pragma mark - Helpers - -/** Sign out current account. */ -- (void)signOut { - NSError *signOutError; - BOOL status = [[FIRAuth auth] signOut:&signOutError]; - - // Just log the error because we don't want to fail the test if signing out fails. - if (!status) { - NSLog(@"Error signing out: %@", signOutError); - } -} - -/** Wait for an element with text to appear. */ -- (void)waitForElementWithText:(NSString *)text withDelay:(NSTimeInterval)maxDelay { - GREYCondition *displayed = - [GREYCondition conditionWithName:@"Wait for element" - block:^BOOL { - NSError *error = nil; - [[EarlGrey selectElementWithMatcher:grey_text(text)] - assertWithMatcher:grey_sufficientlyVisible() - error:&error]; - return !error; - }]; - GREYAssertTrue([displayed waitWithTimeout:maxDelay], @"Failed to wait for element '%@'.", text); -} - -@end diff --git a/Example/Firebase.xcodeproj/project.pbxproj b/Example/Firebase.xcodeproj/project.pbxproj index cb19ad1d5ce..52c40d8d1b1 100644 --- a/Example/Firebase.xcodeproj/project.pbxproj +++ b/Example/Firebase.xcodeproj/project.pbxproj @@ -107,7 +107,16 @@ 405EEF4D2216518B00B08FF4 /* FIRAuthLifeCycleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 405EEF4B2216518A00B08FF4 /* FIRAuthLifeCycleTests.m */; }; 405EEF4E2216518B00B08FF4 /* FIRAuthLifeCycleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 405EEF4B2216518A00B08FF4 /* FIRAuthLifeCycleTests.m */; }; 408870AB21AE0218008AAE73 /* FIRSignInWithGameCenterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 408870AA21AE0218008AAE73 /* FIRSignInWithGameCenterTests.m */; }; - 409E1130219FA260000E6CFC /* FIRVerifyIOSClientTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 409E112F219FA260000E6CFC /* FIRVerifyIOSClientTests.m */; }; + 4090ADFD2217948D00547281 /* FIRAuthE2eTestsBase.m in Sources */ = {isa = PBXBuildFile; fileRef = 4090ADFC2217948D00547281 /* FIRAuthE2eTestsBase.m */; }; + 4090ADFF2217978300547281 /* BYOAuthTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4090ADFE2217978300547281 /* BYOAuthTests.m */; }; + 409E1130219FA260000E6CFC /* VerifyIOSClientTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 409E112F219FA260000E6CFC /* VerifyIOSClientTests.m */; }; + 40CC550D221B9B4700032423 /* FIRAuthApiTestsBase.m in Sources */ = {isa = PBXBuildFile; fileRef = 40CC5504221B9B4600032423 /* FIRAuthApiTestsBase.m */; }; + 40CC550E221B9B4700032423 /* GoogleAuthTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40CC5505221B9B4700032423 /* GoogleAuthTests.swift */; }; + 40CC550F221B9B4700032423 /* AccountInfoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 40CC5506221B9B4700032423 /* AccountInfoTests.m */; }; + 40CC5510221B9B4700032423 /* CustomAuthTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 40CC5508221B9B4700032423 /* CustomAuthTests.m */; }; + 40CC5511221B9B4700032423 /* GoogleAuthTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 40CC5509221B9B4700032423 /* GoogleAuthTests.m */; }; + 40CC5512221B9B4700032423 /* AnonymousAuthTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 40CC550A221B9B4700032423 /* AnonymousAuthTests.m */; }; + 40CC5513221B9B4700032423 /* FacebookAuthTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 40CC550B221B9B4700032423 /* FacebookAuthTests.m */; }; 7E9485421F578AC4005A3939 /* FIRAuthURLPresenterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7E94853F1F578A9D005A3939 /* FIRAuthURLPresenterTests.m */; }; 7EE21F7A1FE89193009B1370 /* FIREmailLinkRequestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7EE21F791FE89193009B1370 /* FIREmailLinkRequestTests.m */; }; 7EE21F7C1FE8919E009B1370 /* FIREmailLinkSignInResponseTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7EE21F7B1FE8919D009B1370 /* FIREmailLinkSignInResponseTests.m */; }; @@ -331,8 +340,8 @@ DE26D2561F7040B2004AE1D3 /* UserInfoViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = DE26D1F51F70333E004AE1D3 /* UserInfoViewController.xib */; }; DE26D2571F7040E0004AE1D3 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = DE26D1DA1F70333E004AE1D3 /* Localizable.strings */; }; DE26D2581F7040E4004AE1D3 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DE26D1E41F70333E004AE1D3 /* Images.xcassets */; }; - DE26D2681F704A0C004AE1D3 /* FirebaseAuthApiTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE26D1C91F70330A004AE1D3 /* FirebaseAuthApiTests.m */; }; - DE26D2771F705CB5004AE1D3 /* FirebaseAuthEarlGreyTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE26D1FA1F70333E004AE1D3 /* FirebaseAuthEarlGreyTests.m */; }; + DE26D2681F704A0C004AE1D3 /* EmailPasswordAuthTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE26D1C91F70330A004AE1D3 /* EmailPasswordAuthTests.m */; }; + DE26D2771F705CB5004AE1D3 /* FIRAuthE2eTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE26D1FA1F70333E004AE1D3 /* FIRAuthE2eTests.m */; }; DE37C63B2163D5F30025D03E /* FIRMessagingAnalyticsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DE37C63A2163D5F30025D03E /* FIRMessagingAnalyticsTest.m */; }; DE47C0E2207AC87D00B1AEDF /* FIRSampleAppUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = AFC8BAA31EC257D800B8EEAE /* FIRSampleAppUtilities.m */; }; DE47C0E7207AC87D00B1AEDF /* Shared.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AFAF36F41EC28C25004BDEE5 /* Shared.xcassets */; }; @@ -919,7 +928,19 @@ 0697B1211EC13D8A00542174 /* Base64.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Base64.m; sourceTree = ""; }; 405EEF4B2216518A00B08FF4 /* FIRAuthLifeCycleTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRAuthLifeCycleTests.m; sourceTree = ""; }; 408870AA21AE0218008AAE73 /* FIRSignInWithGameCenterTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRSignInWithGameCenterTests.m; sourceTree = ""; }; - 409E112F219FA260000E6CFC /* FIRVerifyIOSClientTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRVerifyIOSClientTests.m; sourceTree = ""; }; + 4090ADFB2217948D00547281 /* FIRAuthE2eTestsBase.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FIRAuthE2eTestsBase.h; sourceTree = ""; }; + 4090ADFC2217948D00547281 /* FIRAuthE2eTestsBase.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FIRAuthE2eTestsBase.m; sourceTree = ""; }; + 4090ADFE2217978300547281 /* BYOAuthTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BYOAuthTests.m; sourceTree = ""; }; + 409E112F219FA260000E6CFC /* VerifyIOSClientTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VerifyIOSClientTests.m; sourceTree = ""; }; + 40CC5504221B9B4600032423 /* FIRAuthApiTestsBase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRAuthApiTestsBase.m; sourceTree = ""; }; + 40CC5505221B9B4700032423 /* GoogleAuthTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GoogleAuthTests.swift; sourceTree = ""; }; + 40CC5506221B9B4700032423 /* AccountInfoTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AccountInfoTests.m; sourceTree = ""; }; + 40CC5507221B9B4700032423 /* Auth_ApiTests-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Auth_ApiTests-Bridging-Header.h"; sourceTree = ""; }; + 40CC5508221B9B4700032423 /* CustomAuthTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CustomAuthTests.m; sourceTree = ""; }; + 40CC5509221B9B4700032423 /* GoogleAuthTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GoogleAuthTests.m; sourceTree = ""; }; + 40CC550A221B9B4700032423 /* AnonymousAuthTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AnonymousAuthTests.m; sourceTree = ""; }; + 40CC550B221B9B4700032423 /* FacebookAuthTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FacebookAuthTests.m; sourceTree = ""; }; + 40CC550C221B9B4700032423 /* FIRAuthApiTestsBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FIRAuthApiTestsBase.h; sourceTree = ""; }; 6003F58D195388D20070C39A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 6003F58F195388D20070C39A /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 6003F591195388D20070C39A /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; @@ -1007,7 +1028,7 @@ DE1FAE901FBCF5E100897AAA /* Auth_Example_tvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Auth_Example_tvOS.app; sourceTree = BUILT_PRODUCTS_DIR; }; DE26D1C71F70330A004AE1D3 /* AuthCredentials.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AuthCredentials.h; sourceTree = ""; }; DE26D1C81F70330A004AE1D3 /* AuthCredentialsTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AuthCredentialsTemplate.h; sourceTree = ""; }; - DE26D1C91F70330A004AE1D3 /* FirebaseAuthApiTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FirebaseAuthApiTests.m; sourceTree = ""; }; + DE26D1C91F70330A004AE1D3 /* EmailPasswordAuthTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EmailPasswordAuthTests.m; sourceTree = ""; }; DE26D1CA1F70330A004AE1D3 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; DE26D1CE1F70333E004AE1D3 /* Application.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Application.plist; sourceTree = ""; }; DE26D1CF1F70333E004AE1D3 /* ApplicationDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ApplicationDelegate.h; sourceTree = ""; }; @@ -1051,11 +1072,11 @@ DE26D1F61F70333E004AE1D3 /* UserTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UserTableViewCell.h; sourceTree = ""; }; DE26D1F71F70333E004AE1D3 /* UserTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UserTableViewCell.m; sourceTree = ""; }; DE26D1F81F70333E004AE1D3 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; - DE26D1FA1F70333E004AE1D3 /* FirebaseAuthEarlGreyTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FirebaseAuthEarlGreyTests.m; sourceTree = ""; }; + DE26D1FA1F70333E004AE1D3 /* FIRAuthE2eTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRAuthE2eTests.m; sourceTree = ""; }; DE26D1FB1F70333E004AE1D3 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; DE26D22E1F70398A004AE1D3 /* Sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Sample.app; sourceTree = BUILT_PRODUCTS_DIR; }; DE26D25D1F7049F1004AE1D3 /* Auth_ApiTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Auth_ApiTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - DE26D26D1F705C35004AE1D3 /* Auth_EarlGreyTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Auth_EarlGreyTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + DE26D26D1F705C35004AE1D3 /* Auth_E2eTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Auth_E2eTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; DE37C63A2163D5F30025D03E /* FIRMessagingAnalyticsTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FIRMessagingAnalyticsTest.m; sourceTree = ""; }; DE45C6641E7DA8CB009E6ACD /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Platforms/iPhoneOS.platform/Developer/Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; DE47C0ED207AC87D00B1AEDF /* Messaging_Sample_iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Messaging_Sample_iOS.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -1688,7 +1709,7 @@ D01853C61EDAD364003A645C /* Auth_Tests_macOS.xctest */, DE26D22E1F70398A004AE1D3 /* Sample.app */, DE26D25D1F7049F1004AE1D3 /* Auth_ApiTests.xctest */, - DE26D26D1F705C35004AE1D3 /* Auth_EarlGreyTests.xctest */, + DE26D26D1F705C35004AE1D3 /* Auth_E2eTests.xctest */, DEAAD3811FBA11270053BF48 /* Core_Example_tvOS.app */, DEAAD3951FBA11270053BF48 /* Core_Tests_tvOS.xctest */, DEAAD3E11FBA46AA0053BF48 /* Storage_Example_tvOS.app */, @@ -1914,9 +1935,18 @@ DE26D1C61F70330A004AE1D3 /* ApiTests */ = { isa = PBXGroup; children = ( + 40CC5506221B9B4700032423 /* AccountInfoTests.m */, + 40CC550A221B9B4700032423 /* AnonymousAuthTests.m */, + 40CC5507221B9B4700032423 /* Auth_ApiTests-Bridging-Header.h */, DE26D1C71F70330A004AE1D3 /* AuthCredentials.h */, DE26D1C81F70330A004AE1D3 /* AuthCredentialsTemplate.h */, - DE26D1C91F70330A004AE1D3 /* FirebaseAuthApiTests.m */, + 40CC5508221B9B4700032423 /* CustomAuthTests.m */, + DE26D1C91F70330A004AE1D3 /* EmailPasswordAuthTests.m */, + 40CC550B221B9B4700032423 /* FacebookAuthTests.m */, + 40CC550C221B9B4700032423 /* FIRAuthApiTestsBase.h */, + 40CC5504221B9B4600032423 /* FIRAuthApiTestsBase.m */, + 40CC5509221B9B4700032423 /* GoogleAuthTests.m */, + 40CC5505221B9B4700032423 /* GoogleAuthTests.swift */, DE26D1CA1F70330A004AE1D3 /* Info.plist */, ); path = ApiTests; @@ -1968,14 +1998,17 @@ path = Sample; sourceTree = ""; }; - DE26D1F91F70333E004AE1D3 /* EarlGreyTests */ = { + DE26D1F91F70333E004AE1D3 /* E2eTests */ = { isa = PBXGroup; children = ( - DE26D1FA1F70333E004AE1D3 /* FirebaseAuthEarlGreyTests.m */, - 409E112F219FA260000E6CFC /* FIRVerifyIOSClientTests.m */, + 4090ADFE2217978300547281 /* BYOAuthTests.m */, + DE26D1FA1F70333E004AE1D3 /* FIRAuthE2eTests.m */, + 4090ADFB2217948D00547281 /* FIRAuthE2eTestsBase.h */, + 4090ADFC2217948D00547281 /* FIRAuthE2eTestsBase.m */, + 409E112F219FA260000E6CFC /* VerifyIOSClientTests.m */, DE26D1FB1F70333E004AE1D3 /* Info.plist */, ); - path = EarlGreyTests; + path = E2eTests; sourceTree = ""; }; DE47C106207AC94A00B1AEDF /* Sample */ = { @@ -2145,7 +2178,7 @@ DE26D1CD1F70333E004AE1D3 /* Sample */, DE9314F91E86C6FF0083EDBF /* Tests */, DE26D1C61F70330A004AE1D3 /* ApiTests */, - DE26D1F91F70333E004AE1D3 /* EarlGreyTests */, + DE26D1F91F70333E004AE1D3 /* E2eTests */, DE9314EC1E86C6FF0083EDBF /* App */, ); path = Auth; @@ -2778,9 +2811,9 @@ productReference = DE26D25D1F7049F1004AE1D3 /* Auth_ApiTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; - DE26D26C1F705C35004AE1D3 /* Auth_EarlGreyTests */ = { + DE26D26C1F705C35004AE1D3 /* Auth_E2eTests */ = { isa = PBXNativeTarget; - buildConfigurationList = DE26D2741F705C35004AE1D3 /* Build configuration list for PBXNativeTarget "Auth_EarlGreyTests" */; + buildConfigurationList = DE26D2741F705C35004AE1D3 /* Build configuration list for PBXNativeTarget "Auth_E2eTests" */; buildPhases = ( DE26D2691F705C35004AE1D3 /* Sources */, DE26D26A1F705C35004AE1D3 /* Frameworks */, @@ -2791,9 +2824,9 @@ dependencies = ( DE26D2731F705C35004AE1D3 /* PBXTargetDependency */, ); - name = Auth_EarlGreyTests; + name = Auth_E2eTests; productName = Auth_EarlGreyTests; - productReference = DE26D26D1F705C35004AE1D3 /* Auth_EarlGreyTests.xctest */; + productReference = DE26D26D1F705C35004AE1D3 /* Auth_E2eTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; DE47C0DC207AC87D00B1AEDF /* Messaging_Sample_iOS */ = { @@ -3201,6 +3234,7 @@ DE26D25C1F7049F1004AE1D3 = { CreatedOnToolsVersion = 9.0; DevelopmentTeam = EQHXZ8M8AV; + LastSwiftMigration = 1010; ProvisioningStyle = Automatic; TestTargetID = DE26D22D1F70398A004AE1D3; }; @@ -3325,7 +3359,7 @@ DE53893D1FBB62E100199FC2 /* Auth_Tests_tvOS */, DE26D22D1F70398A004AE1D3 /* Auth_Sample */, DE26D25C1F7049F1004AE1D3 /* Auth_ApiTests */, - DE26D26C1F705C35004AE1D3 /* Auth_EarlGreyTests */, + DE26D26C1F705C35004AE1D3 /* Auth_E2eTests */, DEE14D401E84464D006FA992 /* Core_Example_iOS */, DEE14D581E84464D006FA992 /* Core_Tests_iOS */, D064E6951ED9B1BF001956DF /* Core_Example_macOS */, @@ -4078,7 +4112,14 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - DE26D2681F704A0C004AE1D3 /* FirebaseAuthApiTests.m in Sources */, + 40CC550E221B9B4700032423 /* GoogleAuthTests.swift in Sources */, + 40CC5512221B9B4700032423 /* AnonymousAuthTests.m in Sources */, + 40CC550F221B9B4700032423 /* AccountInfoTests.m in Sources */, + 40CC5510221B9B4700032423 /* CustomAuthTests.m in Sources */, + DE26D2681F704A0C004AE1D3 /* EmailPasswordAuthTests.m in Sources */, + 40CC5513221B9B4700032423 /* FacebookAuthTests.m in Sources */, + 40CC5511221B9B4700032423 /* GoogleAuthTests.m in Sources */, + 40CC550D221B9B4700032423 /* FIRAuthApiTestsBase.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4086,8 +4127,10 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - DE26D2771F705CB5004AE1D3 /* FirebaseAuthEarlGreyTests.m in Sources */, - 409E1130219FA260000E6CFC /* FIRVerifyIOSClientTests.m in Sources */, + 4090ADFF2217978300547281 /* BYOAuthTests.m in Sources */, + DE26D2771F705CB5004AE1D3 /* FIRAuthE2eTests.m in Sources */, + 4090ADFD2217948D00547281 /* FIRAuthE2eTestsBase.m in Sources */, + 409E1130219FA260000E6CFC /* VerifyIOSClientTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5621,7 +5664,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 4ANB9W7R3P; GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = $SRCROOT/DynamicLinks/FDLBuilderTestAppObjC/Info.plist; + INFOPLIST_FILE = "$SRCROOT/DynamicLinks/FDLBuilderTestAppObjC/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 11.4; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = YES; @@ -5655,7 +5698,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 4ANB9W7R3P; GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = $SRCROOT/DynamicLinks/FDLBuilderTestAppObjC/Info.plist; + INFOPLIST_FILE = "$SRCROOT/DynamicLinks/FDLBuilderTestAppObjC/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 11.4; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = NO; @@ -5978,6 +6021,7 @@ CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_MODULES = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; @@ -5997,6 +6041,9 @@ MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.google.Auth-ApiTests"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Auth/ApiTests/Auth_ApiTests-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Sample.app/Sample"; }; @@ -6009,6 +6056,7 @@ CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_MODULES = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; @@ -6029,6 +6077,8 @@ MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "com.google.Auth-ApiTests"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Auth/ApiTests/Auth_ApiTests-Bridging-Header.h"; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Sample.app/Sample"; }; @@ -6054,11 +6104,11 @@ DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = EQHXZ8M8AV; GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = Auth/EarlGreyTests/Info.plist; + INFOPLIST_FILE = Auth/E2eTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = YES; - PRODUCT_BUNDLE_IDENTIFIER = "com.google.Auth-EarlGreyTests"; + PRODUCT_BUNDLE_IDENTIFIER = "com.google.Auth-E2eTests"; PRODUCT_NAME = "$(TARGET_NAME)"; TARGETED_DEVICE_FAMILY = "1,2"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Sample.app/Sample"; @@ -6086,11 +6136,11 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = EQHXZ8M8AV; GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = Auth/EarlGreyTests/Info.plist; + INFOPLIST_FILE = Auth/E2eTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = NO; - PRODUCT_BUNDLE_IDENTIFIER = "com.google.Auth-EarlGreyTests"; + PRODUCT_BUNDLE_IDENTIFIER = "com.google.Auth-E2eTests"; PRODUCT_NAME = "$(TARGET_NAME)"; TARGETED_DEVICE_FAMILY = "1,2"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Sample.app/Sample"; @@ -7359,7 +7409,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - DE26D2741F705C35004AE1D3 /* Build configuration list for PBXNativeTarget "Auth_EarlGreyTests" */ = { + DE26D2741F705C35004AE1D3 /* Build configuration list for PBXNativeTarget "Auth_E2eTests" */ = { isa = XCConfigurationList; buildConfigurations = ( DE26D2751F705C35004AE1D3 /* Debug */, diff --git a/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Auth_ApiTests.xcscheme b/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Auth_ApiTests.xcscheme index 743e93966e9..9440d3317d2 100644 --- a/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Auth_ApiTests.xcscheme +++ b/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Auth_ApiTests.xcscheme @@ -7,8 +7,11 @@ buildImplicitDependencies = "YES"> + buildForProfiling = "YES" + buildForArchiving = "YES" + buildForAnalyzing = "YES"> + + + + diff --git a/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Auth_EarlGreyTests.xcscheme b/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Auth_E2eTests.xcscheme similarity index 60% rename from Example/Firebase.xcodeproj/xcshareddata/xcschemes/Auth_EarlGreyTests.xcscheme rename to Example/Firebase.xcodeproj/xcshareddata/xcschemes/Auth_E2eTests.xcscheme index fe6245d2559..94206220138 100644 --- a/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Auth_EarlGreyTests.xcscheme +++ b/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Auth_E2eTests.xcscheme @@ -7,13 +7,16 @@ buildImplicitDependencies = "YES"> + buildForProfiling = "YES" + buildForArchiving = "YES" + buildForAnalyzing = "YES"> @@ -23,7 +26,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" shouldUseLaunchSchemeArgsEnv = "YES"> + + + + @@ -44,13 +55,21 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" debugDocumentVersioning = "YES" debugServiceExtension = "internal" allowLocationSimulation = "YES"> + + + + @@ -60,6 +79,15 @@ savedToolIdentifier = "" useCustomWorkingDirectory = "NO" debugDocumentVersioning = "YES"> + + + + diff --git a/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Auth_Sample.xcscheme b/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Auth_Sample.xcscheme index a0ada521f71..79b6c5d1c25 100644 --- a/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Auth_Sample.xcscheme +++ b/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Auth_Sample.xcscheme @@ -33,8 +33,8 @@ diff --git a/Example/Podfile b/Example/Podfile index 580c0c7c6db..723d79e0ecf 100644 --- a/Example/Podfile +++ b/Example/Podfile @@ -131,7 +131,7 @@ target 'Auth_Sample' do inherit! :search_paths end - target 'Auth_EarlGreyTests' do + target 'Auth_E2eTests' do inherit! :search_paths pod 'EarlGrey' end