| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893 |
- // Copyright 2023 Google LLC
- //
- // 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 Foundation
- import XCTest
- @testable import FirebaseAuth
- import FirebaseCore
- @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
- class UserTests: RPCBaseTests {
- static let kFakeAPIKey = "FAKE_API_KEY"
- let kFacebookAccessToken = "FACEBOOK_ACCESS_TOKEN"
- let kFacebookID = "FACEBOOK_ID"
- let kFacebookEmail = "user@facebook.com"
- let kFacebookDisplayName = "Facebook Doe"
- let kFacebookIDToken: String? = nil // Facebook id Token is always nil.
- let kNewEmail = "newuser@company.com"
- let kNewPassword = "newpassword"
- let kNewDisplayName = "New User Doe"
- let kVerificationCode = "12345678"
- let kVerificationID = "55432"
- let kPhoneNumber = "555-1234"
- var auth: Auth?
- override func setUp() {
- super.setUp()
- let options = FirebaseOptions(googleAppID: "0:0000000000000:ios:0000000000000000",
- gcmSenderID: "00000000000000000-00000000000-000000000")
- options.apiKey = Self.kFakeAPIKey
- options.projectID = "myUserProjectID"
- FirebaseApp.configure(name: "test-UserTests", options: options)
- #if (os(macOS) && !FIREBASE_AUTH_TESTING_USE_MACOS_KEYCHAIN) || SWIFT_PACKAGE
- let keychainStorageProvider = FakeAuthKeychainStorage()
- #else
- let keychainStorageProvider = AuthKeychainStorageReal.shared
- #endif // (os(macOS) && !FIREBASE_AUTH_TESTING_USE_MACOS_KEYCHAIN) || SWIFT_PACKAGE
- auth = Auth(
- app: FirebaseApp.app(name: "test-UserTests")!,
- keychainStorageProvider: keychainStorageProvider,
- backend: authBackend
- )
- }
- override func tearDown() {
- // Verifies that no tasks are left suspended on the AuthSerialTaskQueue.
- try? auth?.signOut()
- auth = nil
- FirebaseApp.resetApps()
- super.tearDown()
- }
- /** @fn testUserPropertiesAndNSSecureCoding
- @brief Tests properties of the @c User instance before and after being
- serialized/deserialized.
- */
- func testUserPropertiesAndNSSecureCoding() throws {
- let kProviderUserInfoKey = "providerUserInfo"
- let kPhotoUrlKey = "photoUrl"
- let kProviderIDkey = "providerId"
- let kDisplayNameKey = "displayName"
- let kFederatedIDKey = "federatedId"
- let kEmailKey = "email"
- let kPasswordHashKey = "passwordHash"
- let kTestPasswordHash = "testPasswordHash"
- let kEmailVerifiedKey = "emailVerified"
- let kLocalIDKey = "localId"
- let kGoogleID = "GOOGLE_ID"
- let kGoogleDisplayName = "Google Doe"
- let kGoogleEmail = "user@gmail.com"
- let kGooglePhotoURL = "https://googleusercontents.com/user/profile"
- let kFacebookID = "FACEBOOK_ID"
- let kFacebookEmail = "user@facebook.com"
- let kEnrollmentID = "fakeEnrollment"
- let kPhoneInfo = "+15555555555"
- let kEnrolledAt = "2022-08-01T18:31:15.426458Z"
- let kEnrolledAtMatch = "2022-08-01 18:31:15 +0000"
- let kTwitterID = "TwitterID"
- let kGitHubID = "GitHubID"
- let kGameCenterID = "GameCenterID"
- var providerUserInfos = [[
- kProviderIDkey: EmailAuthProvider.id,
- kFederatedIDKey: kEmail,
- kEmailKey: kEmail,
- ],
- [
- kProviderIDkey: GoogleAuthProvider.id,
- kDisplayNameKey: kGoogleDisplayName,
- kPhotoUrlKey: kGooglePhotoURL,
- kFederatedIDKey: kGoogleID,
- kEmailKey: kGoogleEmail,
- ],
- [
- kProviderIDkey: FacebookAuthProvider.id,
- kFederatedIDKey: kFacebookID,
- kEmailKey: kFacebookEmail,
- ],
- [
- kProviderIDkey: GitHubAuthProvider.id,
- kFederatedIDKey: kGitHubID,
- kEmailKey: kGoogleEmail,
- ],
- [
- kProviderIDkey: TwitterAuthProvider.id,
- kFederatedIDKey: kTwitterID,
- kEmailKey: kFacebookEmail,
- ]]
- #if !os(watchOS)
- providerUserInfos.append([
- kProviderIDkey: GameCenterAuthProvider.id,
- kFederatedIDKey: kGameCenterID,
- kEmailKey: kFacebookEmail,
- ])
- #endif
- #if os(iOS)
- providerUserInfos.append([
- kProviderIDkey: PhoneAuthProvider.id,
- kFederatedIDKey: kPhoneNumber,
- "phoneNumber": kPhoneNumber,
- ])
- #endif
- rpcIssuer?.fakeGetAccountProviderJSON = [[
- kProviderUserInfoKey: providerUserInfos,
- kLocalIDKey: kLocalID,
- kDisplayNameKey: kDisplayName,
- kEmailKey: kEmail,
- kPhotoUrlKey: kTestPhotoURL,
- kEmailVerifiedKey: true,
- kPasswordHashKey: kTestPasswordHash,
- "phoneNumber": kPhoneNumber,
- "createdAt": String(Int(kCreationDateTimeIntervalInSeconds) * 1000), // to nanoseconds
- "lastLoginAt": String(Int(kLastSignInDateTimeIntervalInSeconds) * 1000),
- "mfaInfo": [
- [
- "phoneInfo": kPhoneInfo,
- "mfaEnrollmentId": kEnrollmentID,
- "displayName": kDisplayName,
- "enrolledAt": kEnrolledAt,
- ],
- [
- // In practice, this will be an empty dictionary.
- "totpInfo": [AnyHashable: AnyHashable](),
- "mfaEnrollmentId": kEnrollmentID,
- "displayName": kDisplayName,
- "enrolledAt": kEnrolledAt,
- ] as [AnyHashable: AnyHashable],
- ],
- ]]
- let expectation = self.expectation(description: #function)
- signInWithEmailPasswordReturnFakeUser { user in
- do {
- XCTAssertEqual(user.providerID, "Firebase")
- XCTAssertEqual(user.uid, self.kLocalID)
- XCTAssertEqual(user.displayName, self.kDisplayName)
- XCTAssertEqual(user.photoURL, URL(string: self.kTestPhotoURL))
- XCTAssertEqual(user.email, self.kEmail)
- XCTAssertEqual(user.metadata.creationDate, Date(timeIntervalSince1970:
- self.kCreationDateTimeIntervalInSeconds))
- XCTAssertEqual(user.metadata.lastSignInDate,
- Date(timeIntervalSince1970: self.kLastSignInDateTimeIntervalInSeconds))
- // Verify FIRUser properties besides providerData contents.
- XCTAssertFalse(user.isAnonymous)
- XCTAssertTrue(user.isEmailVerified)
- XCTAssertEqual(user.refreshToken, self.kRefreshToken)
- XCTAssertEqual(user.providerData.count, providerUserInfos.count)
- let providerMap = user.providerData.reduce(into: [String: UserInfo]()) {
- $0[$1.providerID] = $1
- }
- // Verify FIRUserInfo properties from email/password.
- let passwordUserInfo = try XCTUnwrap(providerMap[EmailAuthProvider.id])
- XCTAssertEqual(passwordUserInfo.uid, self.kEmail)
- XCTAssertNil(passwordUserInfo.displayName)
- XCTAssertNil(passwordUserInfo.photoURL)
- XCTAssertEqual(passwordUserInfo.email, self.kEmail)
- // Verify FIRUserInfo properties from the Google auth provider.
- let googleUserInfo = try XCTUnwrap(providerMap[GoogleAuthProvider.id])
- XCTAssertEqual(googleUserInfo.uid, kGoogleID)
- XCTAssertEqual(googleUserInfo.displayName, kGoogleDisplayName)
- XCTAssertEqual(googleUserInfo.photoURL, URL(string: kGooglePhotoURL))
- XCTAssertEqual(googleUserInfo.email, kGoogleEmail)
- // Verify FIRUserInfo properties from the Facebook auth provider.
- let facebookUserInfo = try XCTUnwrap(providerMap[FacebookAuthProvider.id])
- XCTAssertEqual(facebookUserInfo.uid, kFacebookID)
- XCTAssertNil(facebookUserInfo.displayName)
- XCTAssertNil(facebookUserInfo.photoURL)
- XCTAssertEqual(facebookUserInfo.email, kFacebookEmail)
- // Verify FIRUserInfo properties from the GitHub auth provider.
- let gitHubUserInfo = try XCTUnwrap(providerMap[GitHubAuthProvider.id])
- XCTAssertEqual(gitHubUserInfo.uid, kGitHubID)
- XCTAssertNil(gitHubUserInfo.displayName)
- XCTAssertNil(gitHubUserInfo.photoURL)
- XCTAssertEqual(gitHubUserInfo.email, kGoogleEmail)
- // Verify FIRUserInfo properties from the Twitter auth provider.
- let twitterUserInfo = try XCTUnwrap(providerMap[TwitterAuthProvider.id])
- XCTAssertEqual(twitterUserInfo.uid, kTwitterID)
- XCTAssertNil(twitterUserInfo.displayName)
- XCTAssertNil(twitterUserInfo.photoURL)
- XCTAssertEqual(twitterUserInfo.email, kFacebookEmail)
- #if os(iOS)
- // Verify UserInfo properties from the phone auth provider.
- let phoneUserInfo = try XCTUnwrap(providerMap[PhoneAuthProvider.id])
- XCTAssertEqual(phoneUserInfo.phoneNumber, self.kPhoneNumber)
- #endif
- #if !os(watchOS)
- // Verify FIRUserInfo properties from the Game Center auth provider.
- let gameCenterUserInfo = try XCTUnwrap(providerMap[GameCenterAuthProvider.id])
- XCTAssertEqual(gameCenterUserInfo.uid, kGameCenterID)
- XCTAssertNil(gameCenterUserInfo.displayName)
- XCTAssertNil(gameCenterUserInfo.photoURL)
- XCTAssertEqual(gameCenterUserInfo.email, kFacebookEmail)
- #endif
- // Test NSSecureCoding
- XCTAssertTrue(User.supportsSecureCoding)
- let data = try NSKeyedArchiver.archivedData(
- withRootObject: user,
- requiringSecureCoding: true
- )
- var encodedClasses = [User.self, NSDictionary.self, NSURL.self, SecureTokenService.self,
- UserInfoImpl.self, NSDate.self, UserMetadata.self, NSString.self,
- NSArray.self]
- #if os(iOS)
- encodedClasses.append(MultiFactor.self)
- encodedClasses.append(PhoneMultiFactorInfo.self)
- #endif
- let unarchivedUser = try XCTUnwrap(NSKeyedUnarchiver.unarchivedObject(
- ofClasses: encodedClasses, from: data
- )
- as? User)
- // Verify NSSecureCoding for FIRUser
- XCTAssertEqual(unarchivedUser.providerID, user.providerID)
- XCTAssertEqual(unarchivedUser.uid, user.uid)
- XCTAssertEqual(unarchivedUser.email, user.email)
- XCTAssertEqual(unarchivedUser.photoURL, user.photoURL)
- XCTAssertEqual(unarchivedUser.displayName, user.displayName)
- // Verify NSSecureCoding properties besides providerData contents.
- XCTAssertEqual(unarchivedUser.isAnonymous, user.isAnonymous)
- XCTAssertEqual(unarchivedUser.isEmailVerified, user.isEmailVerified)
- XCTAssertEqual(unarchivedUser.refreshToken, user.refreshToken)
- XCTAssertEqual(unarchivedUser.metadata.creationDate, user.metadata.creationDate)
- XCTAssertEqual(unarchivedUser.metadata.lastSignInDate, user.metadata.lastSignInDate)
- XCTAssertEqual(unarchivedUser.providerData.count, user.providerData.count)
- let unarchivedProviderMap = unarchivedUser.providerData.reduce(into: [String: UserInfo]()) {
- $0[$1.providerID] = $1
- }
- // Verify NSSecureCoding properties for AuthDataResult
- let kFakeProfile = ["email": "user@mail.com", "given_name": "User", "family_name": "Doe"]
- let kUserName = "User Doe"
- let kProviderID = "PROVIDER_ID"
- let userInfo = AdditionalUserInfo(providerID: kProviderID,
- profile: kFakeProfile,
- username: kUserName,
- isNewUser: true)
- let authDataResult = AuthDataResult(withUser: user, additionalUserInfo: userInfo)
- XCTAssertTrue(AuthDataResult.supportsSecureCoding)
- let authDataResultData = try NSKeyedArchiver.archivedData(
- withRootObject: authDataResult,
- requiringSecureCoding: true
- )
- encodedClasses.append(AuthDataResult.self)
- encodedClasses.append(AdditionalUserInfo.self)
- let unarchivedDataResult = try XCTUnwrap(NSKeyedUnarchiver.unarchivedObject(
- ofClasses: encodedClasses, from: authDataResultData
- ) as? AuthDataResult)
- XCTAssertEqual(unarchivedDataResult.user.providerID, user.providerID)
- XCTAssertEqual(unarchivedDataResult.user.uid, user.uid)
- XCTAssertEqual(unarchivedDataResult.user.email, user.email)
- XCTAssertEqual(unarchivedDataResult.user.photoURL, user.photoURL)
- XCTAssertEqual(unarchivedDataResult.user.displayName, user.displayName)
- XCTAssertEqual(unarchivedDataResult.additionalUserInfo?.providerID, kProviderID)
- XCTAssertEqual(unarchivedDataResult.additionalUserInfo?.profile as? [String: String],
- kFakeProfile)
- XCTAssertEqual(unarchivedDataResult.additionalUserInfo?.username, kUserName)
- // Verify NSSecureCoding properties from email/password.
- let unarchivedPasswordUserInfo = try XCTUnwrap(unarchivedProviderMap[EmailAuthProvider.id])
- XCTAssertEqual(unarchivedPasswordUserInfo.uid, passwordUserInfo.uid)
- XCTAssertEqual(unarchivedPasswordUserInfo.displayName, passwordUserInfo.displayName)
- XCTAssertEqual(unarchivedPasswordUserInfo.photoURL, passwordUserInfo.photoURL)
- XCTAssertEqual(unarchivedPasswordUserInfo.email, passwordUserInfo.email)
- // Verify NSSecureCoding properties from the Google auth provider.
- let unarchivedGoogleUserInfo = try XCTUnwrap(unarchivedProviderMap[GoogleAuthProvider.id])
- XCTAssertEqual(unarchivedGoogleUserInfo.uid, googleUserInfo.uid)
- XCTAssertEqual(unarchivedGoogleUserInfo.displayName, googleUserInfo.displayName)
- XCTAssertEqual(unarchivedGoogleUserInfo.photoURL, googleUserInfo.photoURL)
- XCTAssertEqual(unarchivedGoogleUserInfo.email, googleUserInfo.email)
- // Verify NSSecureCoding properties from the Facebook auth provider.
- let unarchivedFacebookUserInfo =
- try XCTUnwrap(unarchivedProviderMap[FacebookAuthProvider.id])
- XCTAssertEqual(unarchivedFacebookUserInfo.uid, facebookUserInfo.uid)
- XCTAssertEqual(unarchivedFacebookUserInfo.displayName, facebookUserInfo.displayName)
- XCTAssertEqual(unarchivedFacebookUserInfo.photoURL, facebookUserInfo.photoURL)
- XCTAssertEqual(unarchivedFacebookUserInfo.email, facebookUserInfo.email)
- #if !os(watchOS)
- // Verify NSSecureCoding properties from the GameCenter auth provider.
- let unarchivedGameCenterUserInfo =
- try XCTUnwrap(unarchivedProviderMap[GameCenterAuthProvider.id])
- XCTAssertEqual(unarchivedGameCenterUserInfo.uid, gameCenterUserInfo.uid)
- XCTAssertEqual(unarchivedGameCenterUserInfo.displayName, gameCenterUserInfo.displayName)
- XCTAssertEqual(unarchivedGameCenterUserInfo.photoURL, gameCenterUserInfo.photoURL)
- XCTAssertEqual(unarchivedGameCenterUserInfo.email, gameCenterUserInfo.email)
- #endif
- // Verify NSSecureCoding properties from the GitHub auth provider.
- let unarchivedGitHubUserInfo =
- try XCTUnwrap(unarchivedProviderMap[GitHubAuthProvider.id])
- XCTAssertEqual(unarchivedGitHubUserInfo.uid, gitHubUserInfo.uid)
- XCTAssertEqual(unarchivedGitHubUserInfo.displayName, gitHubUserInfo.displayName)
- XCTAssertEqual(unarchivedGitHubUserInfo.photoURL, gitHubUserInfo.photoURL)
- XCTAssertEqual(unarchivedGitHubUserInfo.email, gitHubUserInfo.email)
- // Verify NSSecureCoding properties from the Twitter auth provider.
- let unarchivedTwitterUserInfo =
- try XCTUnwrap(unarchivedProviderMap[TwitterAuthProvider.id])
- XCTAssertEqual(unarchivedTwitterUserInfo.uid, twitterUserInfo.uid)
- XCTAssertEqual(unarchivedTwitterUserInfo.displayName, twitterUserInfo.displayName)
- XCTAssertEqual(unarchivedTwitterUserInfo.photoURL, twitterUserInfo.photoURL)
- XCTAssertEqual(unarchivedTwitterUserInfo.email, twitterUserInfo.email)
- #if os(iOS)
- // Verify NSSecureCoding properties from the phone auth provider.
- let unarchivedPhoneUserInfo = try XCTUnwrap(unarchivedProviderMap[PhoneAuthProvider.id])
- XCTAssertEqual(unarchivedPhoneUserInfo.phoneNumber, phoneUserInfo.phoneNumber)
- // Verify MultiFactorInfo properties.
- let enrolledFactors = try XCTUnwrap(user.multiFactor.enrolledFactors)
- XCTAssertEqual(enrolledFactors.count, 2)
- XCTAssertEqual(enrolledFactors[0].factorID, PhoneMultiFactorInfo.PhoneMultiFactorID)
- XCTAssertEqual(enrolledFactors[1].factorID, PhoneMultiFactorInfo.TOTPMultiFactorID)
- for enrolledFactor in enrolledFactors {
- XCTAssertEqual(enrolledFactor.uid, kEnrollmentID)
- XCTAssertEqual(enrolledFactor.displayName, self.kDisplayName)
- let date = try XCTUnwrap(enrolledFactor.enrollmentDate)
- XCTAssertEqual("\(date)", kEnrolledAtMatch)
- }
- #endif
- } catch {
- XCTFail("Caught an error in \(#function): \(error)")
- }
- expectation.fulfill()
- }
- waitForExpectations(timeout: 5)
- }
- /** @fn testUpdateEmailSuccess
- @brief Tests the flow of a successful @c updateEmail:completion: call.
- */
- func testUpdateEmailSuccess() {
- setFakeGetAccountProvider(withPasswordHash: kFakePassword)
- let expectation = self.expectation(description: #function)
- signInWithEmailPasswordReturnFakeUser { user in
- self.changeUserEmail(user: user, changeEmail: true, expectation: expectation)
- }
- waitForExpectations(timeout: 5)
- }
- /** @fn testUpdateEmailWithAuthLinkAccountSuccess
- @brief Tests a successful @c updateEmail:completion: call updates provider info.
- */
- func testUpdateEmailWithAuthLinkAccountSuccess() {
- setFakeGetAccountProvider()
- let expectation = self.expectation(description: #function)
- signInWithEmailPasswordReturnFakeUserLink { user in
- self.changeUserEmail(user: user, expectation: expectation)
- }
- waitForExpectations(timeout: 5)
- }
- /** @fn testUpdateEmailFailure
- @brief Tests the flow of a failed @c updateEmail:completion: call.
- */
- func testUpdateEmailFailure() {
- setFakeGetAccountProvider()
- let expectation = self.expectation(description: #function)
- signInWithEmailPasswordReturnFakeUser { user in
- do {
- self.rpcIssuer.respondBlock = {
- try self.rpcIssuer.respond(serverErrorMessage: "INVALID_EMAIL")
- }
- user.updateEmail(to: self.kNewEmail) { rawError in
- XCTAssertTrue(Thread.isMainThread)
- let error = try! XCTUnwrap(rawError)
- XCTAssertEqual((error as NSError).code, AuthErrorCode.invalidEmail.rawValue)
- // Email should not have changed on the client side.
- XCTAssertEqual(user.email, self.kEmail)
- // User is still signed in.
- XCTAssertEqual(self.auth?.currentUser, user)
- expectation.fulfill()
- }
- }
- }
- waitForExpectations(timeout: 5)
- }
- /** @fn testUpdateEmailAutoSignOut
- @brief Tests the flow of a failed @c updateEmail:completion: call that automatically signs out.
- */
- func testUpdateEmailAutoSignOut() {
- setFakeGetAccountProvider()
- let expectation = self.expectation(description: #function)
- signInWithEmailPasswordReturnFakeUser { user in
- do {
- self.rpcIssuer.respondBlock = {
- try self.rpcIssuer.respond(serverErrorMessage: "INVALID_ID_TOKEN")
- }
- user.updateEmail(to: self.kNewEmail) { rawError in
- XCTAssertTrue(Thread.isMainThread)
- let error = try! XCTUnwrap(rawError)
- XCTAssertEqual((error as NSError).code, AuthErrorCode.invalidUserToken.rawValue)
- // Email should not have changed on the client side.
- XCTAssertEqual(user.email, self.kEmail)
- // User is no longer signed in..
- XCTAssertNil(self.auth?.currentUser)
- expectation.fulfill()
- }
- }
- }
- waitForExpectations(timeout: 5)
- }
- #if os(iOS)
- /** @fn testUpdatePhoneSuccess
- @brief Tests the flow of a successful @c updatePhoneNumberCredential:completion: call.
- */
- func testUpdatePhoneSuccess() throws {
- setFakeGetAccountProvider()
- let expectation = self.expectation(description: #function)
- let auth = try XCTUnwrap(self.auth)
- signInWithEmailPasswordReturnFakeUser { user in
- do {
- self.rpcIssuer.respondBlock = {
- try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
- "refreshToken": self.kRefreshToken])
- }
- self.expectVerifyPhoneNumberRequest()
- self.rpcIssuer?.fakeGetAccountProviderJSON = [[
- "phoneNumber": self.kPhoneNumber,
- ]]
- let credential = PhoneAuthProvider.provider(auth: auth).credential(
- withVerificationID: self.kVerificationID,
- verificationCode: self.kVerificationCode
- )
- user.updatePhoneNumber(credential) { error in
- XCTAssertTrue(Thread.isMainThread)
- XCTAssertNil(error)
- XCTAssertEqual(auth.currentUser?.phoneNumber, self.kPhoneNumber)
- expectation.fulfill()
- }
- }
- }
- waitForExpectations(timeout: 5)
- }
- /** @fn testUpdatePhoneNumberFailure
- @brief Tests the flow of a failed @c updatePhoneNumberCredential:completion: call.
- */
- func testUpdatePhoneNumberFailure() throws {
- setFakeGetAccountProvider()
- let expectation = self.expectation(description: #function)
- let auth = try XCTUnwrap(self.auth)
- signInWithEmailPasswordReturnFakeUser { user in
- do {
- self.rpcIssuer.respondBlock = {
- try self.rpcIssuer.respond(serverErrorMessage: "INVALID_PHONE_NUMBER")
- }
- self.expectVerifyPhoneNumberRequest()
- let credential = PhoneAuthProvider.provider(auth: auth).credential(
- withVerificationID: self.kVerificationID,
- verificationCode: self.kVerificationCode
- )
- user.updatePhoneNumber(credential) { rawError in
- XCTAssertTrue(Thread.isMainThread)
- let error = try! XCTUnwrap(rawError)
- XCTAssertEqual((error as NSError).code, AuthErrorCode.invalidPhoneNumber.rawValue)
- XCTAssertEqual(auth.currentUser, user)
- expectation.fulfill()
- }
- }
- }
- waitForExpectations(timeout: 5)
- }
- /** @fn testUpdatePhoneNumberFailureAutoSignOut
- @brief Tests the flow of a failed @c updatePhoneNumberCredential:completion: call that
- automatically signs out.
- */
- func testUpdatePhoneNumberFailureAutoSignOut() throws {
- setFakeGetAccountProvider()
- let expectation = self.expectation(description: #function)
- let auth = try XCTUnwrap(self.auth)
- signInWithEmailPasswordReturnFakeUser { user in
- do {
- self.rpcIssuer.respondBlock = {
- try self.rpcIssuer.respond(serverErrorMessage: "TOKEN_EXPIRED")
- }
- self.expectVerifyPhoneNumberRequest()
- let credential = PhoneAuthProvider.provider(auth: auth).credential(
- withVerificationID: self.kVerificationID,
- verificationCode: self.kVerificationCode
- )
- user.updatePhoneNumber(credential) { rawError in
- XCTAssertTrue(Thread.isMainThread)
- let error = try! XCTUnwrap(rawError)
- XCTAssertEqual((error as NSError).code, AuthErrorCode.userTokenExpired.rawValue)
- // User is no longer signed in.
- XCTAssertNil(self.auth?.currentUser)
- expectation.fulfill()
- }
- }
- }
- waitForExpectations(timeout: 5)
- }
- #endif
- /** @fn testUpdatePasswordSuccess
- @brief Tests the flow of a successful @c updatePassword:completion: call.
- */
- func testUpdatePasswordSuccess() {
- setFakeGetAccountProvider()
- let expectation = self.expectation(description: #function)
- signInWithEmailPasswordReturnFakeUser { user in
- self.changeUserEmail(user: user, expectation: expectation)
- }
- waitForExpectations(timeout: 5)
- }
- /** @fn testUpdatePasswordFailure
- @brief Tests the flow of a failed @c updatePassword:completion: call.
- */
- func testUpdatePasswordFailure() {
- setFakeGetAccountProvider()
- let expectation = self.expectation(description: #function)
- signInWithEmailPasswordReturnFakeUser { user in
- do {
- self.rpcIssuer.respondBlock = {
- try self.rpcIssuer.respond(serverErrorMessage: "CREDENTIAL_TOO_OLD_LOGIN_AGAIN")
- }
- user.updatePassword(to: self.kNewPassword) { rawError in
- XCTAssertTrue(Thread.isMainThread)
- let error = try! XCTUnwrap(rawError)
- XCTAssertEqual((error as NSError).code, AuthErrorCode.requiresRecentLogin.rawValue)
- // Email should not have changed on the client side.
- XCTAssertEqual(user.email, self.kEmail)
- // User is still signed in.
- XCTAssertEqual(self.auth?.currentUser, user)
- expectation.fulfill()
- }
- }
- }
- waitForExpectations(timeout: 5)
- }
- /** @fn testUpdateEmptyPasswordFailure
- @brief Tests the flow of a failed @c updatePassword:completion: call due to an empty password.
- */
- func testUpdateEmptyPasswordFailure() {
- setFakeGetAccountProvider()
- let expectation = self.expectation(description: #function)
- signInWithEmailPasswordReturnFakeUser { user in
- do {
- self.rpcIssuer.respondBlock = {
- try self.rpcIssuer.respond(serverErrorMessage: "WEAK_PASSWORD")
- }
- user.updatePassword(to: self.kNewPassword) { rawError in
- XCTAssertTrue(Thread.isMainThread)
- let error = try! XCTUnwrap(rawError)
- XCTAssertEqual((error as NSError).code, AuthErrorCode.weakPassword.rawValue)
- // Email should not have changed on the client side.
- XCTAssertEqual(user.email, self.kEmail)
- // User is still signed in.
- XCTAssertEqual(self.auth?.currentUser, user)
- expectation.fulfill()
- }
- }
- }
- waitForExpectations(timeout: 5)
- }
- /** @fn testUpdatePasswordFailureAutoSignOut
- @brief Tests the flow of a failed @c updatePassword:completion: call that automatically signs
- out.
- */
- func testUpdatePasswordFailureAutoSignOut() {
- setFakeGetAccountProvider()
- let expectation = self.expectation(description: #function)
- signInWithEmailPasswordReturnFakeUser { user in
- do {
- self.rpcIssuer.respondBlock = {
- try self.rpcIssuer.respond(serverErrorMessage: "USER_DISABLED")
- }
- user.updatePassword(to: self.kNewPassword) { rawError in
- XCTAssertTrue(Thread.isMainThread)
- let error = try! XCTUnwrap(rawError)
- XCTAssertEqual((error as NSError).code, AuthErrorCode.userDisabled.rawValue)
- // Email should not have changed on the client side.
- XCTAssertEqual(user.email, self.kEmail)
- // User is signed out.
- XCTAssertNil(self.auth?.currentUser)
- expectation.fulfill()
- }
- }
- }
- waitForExpectations(timeout: 5)
- }
- /** @fn testChangeProfileSuccess
- @brief Tests a successful user profile change flow.
- */
- func testChangeProfileSuccess() {
- setFakeGetAccountProvider()
- let expectation = self.expectation(description: #function)
- signInWithEmailPasswordReturnFakeUser { user in
- do {
- self.rpcIssuer.respondBlock = {
- try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
- "refreshToken": self.kRefreshToken])
- }
- let profileChange = user.createProfileChangeRequest()
- profileChange.photoURL = URL(string: self.kTestPhotoURL)
- profileChange.displayName = self.kNewDisplayName
- profileChange.commitChanges { error in
- XCTAssertTrue(Thread.isMainThread)
- XCTAssertNil(error)
- XCTAssertEqual(user.displayName, self.kNewDisplayName)
- XCTAssertEqual(user.photoURL, URL(string: self.kTestPhotoURL))
- expectation.fulfill()
- }
- }
- }
- waitForExpectations(timeout: 5)
- }
- /** @fn testChangeProfileFailure
- @brief Tests a failed user profile change flow.
- */
- func testChangeProfileFailure() {
- setFakeGetAccountProvider()
- let expectation = self.expectation(description: #function)
- signInWithEmailPasswordReturnFakeUser { user in
- do {
- self.rpcIssuer.respondBlock = {
- try self.rpcIssuer.respond(serverErrorMessage: "TOO_MANY_ATTEMPTS_TRY_LATER")
- }
- let profileChange = user.createProfileChangeRequest()
- profileChange.displayName = self.kNewDisplayName
- profileChange.commitChanges { rawError in
- XCTAssertTrue(Thread.isMainThread)
- let error = try! XCTUnwrap(rawError)
- XCTAssertEqual((error as NSError).code, AuthErrorCode.tooManyRequests.rawValue)
- // Email should not have changed on the client side.
- XCTAssertEqual(user.email, self.kEmail)
- XCTAssertEqual(user.displayName, self.kDisplayName)
- // User is still signed in.
- XCTAssertEqual(self.auth?.currentUser, user)
- expectation.fulfill()
- }
- }
- }
- waitForExpectations(timeout: 5)
- }
- /** @fn testChangeProfileFailureAutoSignOut
- @brief Tests a failed user profile change flow that automatically signs out.
- */
- func testChangeProfileFailureAutoSignOut() {
- setFakeGetAccountProvider()
- let expectation = self.expectation(description: #function)
- signInWithEmailPasswordReturnFakeUser { user in
- do {
- self.rpcIssuer.respondBlock = {
- try self.rpcIssuer.respond(serverErrorMessage: "USER_NOT_FOUND")
- }
- let profileChange = user.createProfileChangeRequest()
- profileChange.displayName = self.kNewDisplayName
- profileChange.commitChanges { rawError in
- XCTAssertTrue(Thread.isMainThread)
- let error = try! XCTUnwrap(rawError)
- XCTAssertEqual((error as NSError).code, AuthErrorCode.userNotFound.rawValue)
- // Email should not have changed on the client side.
- XCTAssertEqual(user.email, self.kEmail)
- // User is signed out.
- XCTAssertNil(self.auth?.currentUser)
- expectation.fulfill()
- }
- }
- }
- waitForExpectations(timeout: 5)
- }
- /** @fn testGetIDTokenResultSuccess
- @brief Tests the flow of a successful @c getIDTokenResultWithCompletion: call.
- */
- func testGetIDTokenResultSuccess() {
- internalGetIDTokenResult(token: RPCBaseTests.kFakeAccessToken, forceRefresh: false)
- }
- /** @fn testGetIDTokenResultForcingRefreshSameAccessTokenSuccess
- @brief Tests the flow of a successful @c getIDTokenResultForcingRefresh:completion: call when
- the returned access token is the same as the stored access token.
- */
- func testGetIDTokenResultForcingRefreshSameAccessTokenSuccess() {
- internalGetIDTokenResult(token: RPCBaseTests.kFakeAccessToken)
- }
- /** @fn testGetIDTokenResultForcingRefreshSuccess
- @brief Tests the flow successful @c getIDTokenResultForcingRefresh:completion: calls.
- */
- func testGetIDTokenResultForcingRefreshSuccess() {
- internalGetIDTokenResult(token: RPCBaseTests.kFakeAccessTokenLength415)
- internalGetIDTokenResult(token: RPCBaseTests.kFakeAccessTokenLength416)
- internalGetIDTokenResult(token: RPCBaseTests.kFakeAccessTokenLength523,
- emailMatch: "aunitestuser4@gmail.com")
- }
- /** @fn testGetIDTokenResultSuccessWithBase64EncodedURL
- @brief Tests the flow of a successful @c getIDTokenResultWithCompletion: call using a base64 url
- encoded string.
- */
- func testGetIDTokenResultSuccessWithBase64EncodedURL() {
- internalGetIDTokenResult(token: RPCBaseTests.kFakeAccessTokenWithBase64,
- emailMatch: ">>>>>>>>????????@gmail.com",
- audMatch: "??????????>>>>>>>>>>")
- }
- /** @fn testGetIDTokenResultForcingRefreshFailure
- @brief Tests the flow of a failed @c getIDTokenResultForcingRefresh:completion: call.
- */
- func testGetIDTokenResultForcingRefreshFailure() {
- setFakeGetAccountProvider()
- let expectation = self.expectation(description: #function)
- signInWithEmailPasswordReturnFakeUser(fakeAccessToken: RPCBaseTests.kFakeAccessToken) { user in
- let underlying = NSError(domain: "Test Error", code: 1)
- self.rpcIssuer?.secureTokenNetworkError =
- AuthErrorUtils.networkError(underlyingError: underlying) as NSError
- user.getIDTokenResult(forcingRefresh: true) { tokenResult, rawError in
- do {
- XCTAssertTrue(Thread.isMainThread)
- XCTAssertNil(tokenResult)
- let error = try XCTUnwrap(rawError)
- XCTAssertEqual((error as NSError).code, AuthErrorCode.networkError.rawValue)
- } catch {
- XCTFail("Caught an error in \(#function): \(error)")
- }
- expectation.fulfill()
- }
- }
- waitForExpectations(timeout: 5)
- }
- /** @fn testReloadSuccess
- @brief Tests the flow of a successful @c reloadWithCompletion: call.
- */
- func testReloadSuccess() {
- setFakeGetAccountProvider()
- let expectation = self.expectation(description: #function)
- signInWithEmailPasswordReturnFakeUser { user in
- user.reload { error in
- XCTAssertTrue(Thread.isMainThread)
- XCTAssertNil(error)
- XCTAssertEqual(user.displayName, self.kDisplayName)
- XCTAssertEqual(user.email, self.kEmail)
- expectation.fulfill()
- }
- }
- waitForExpectations(timeout: 5)
- }
- /** @fn testReloadFailure
- @brief Tests the flow of a failed @c reloadWithCompletion: call.
- */
- func testReloadFailure() {
- setFakeGetAccountProvider()
- let expectation = self.expectation(description: #function)
- signInWithEmailPasswordReturnFakeUser { user in
- do {
- self.rpcIssuer.respondBlock = {
- try self.rpcIssuer.respond(serverErrorMessage: "QUOTA_EXCEEDED")
- }
- // Clear fake so we can inject error
- self.rpcIssuer?.fakeGetAccountProviderJSON = nil
- user.reload { rawError in
- XCTAssertTrue(Thread.isMainThread)
- let error = try! XCTUnwrap(rawError)
- XCTAssertEqual((error as NSError).code, AuthErrorCode.quotaExceeded.rawValue)
- // User is still signed in.
- XCTAssertEqual(self.auth?.currentUser, user)
- expectation.fulfill()
- }
- }
- }
- waitForExpectations(timeout: 5)
- }
- /** @fn testReloadFailureAutoSignOut
- @brief Tests the flow of a failed @c reloadWithCompletion: call that automtatically signs out.
- */
- func testReloadFailureAutoSignOut() {
- setFakeGetAccountProvider()
- let expectation = self.expectation(description: #function)
- signInWithEmailPasswordReturnFakeUser { user in
- do {
- self.rpcIssuer.respondBlock = {
- try self.rpcIssuer.respond(serverErrorMessage: "TOKEN_EXPIRED")
- }
- // Clear fake so we can inject error
- self.rpcIssuer?.fakeGetAccountProviderJSON = nil
- user.reload { rawError in
- XCTAssertTrue(Thread.isMainThread)
- let error = try! XCTUnwrap(rawError)
- XCTAssertEqual((error as NSError).code, AuthErrorCode.userTokenExpired.rawValue)
- // User is no longer signed in.
- XCTAssertNil(self.auth?.currentUser)
- expectation.fulfill()
- }
- }
- }
- waitForExpectations(timeout: 5)
- }
- /** @fn testReauthenticateSuccess
- @brief Tests the flow of a successful @c reauthenticateWithCredential:completion: call.
- */
- func testReauthenticateSuccess() {
- setFakeGetAccountProvider()
- let expectation = self.expectation(description: #function)
- signInWithEmailPasswordReturnFakeUser { user in
- do {
- self.rpcIssuer.respondBlock = {
- try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
- "refreshToken": self.kRefreshToken])
- }
- let emailCredential = EmailAuthProvider.credential(withEmail: self.kEmail,
- password: self.kFakePassword)
- user.reauthenticate(with: emailCredential) { rawResult, error in
- XCTAssertTrue(Thread.isMainThread)
- XCTAssertNil(error)
- let result = try! XCTUnwrap(rawResult)
- XCTAssertEqual(result.user.uid, user.uid)
- XCTAssertEqual(result.user.email, user.email)
- XCTAssertEqual(result.additionalUserInfo?.isNewUser, false)
- // User is still signed in.
- XCTAssertEqual(self.auth?.currentUser, user)
- expectation.fulfill()
- }
- }
- }
- waitForExpectations(timeout: 5)
- }
- /** @fn testReauthenticateWithCredentialSuccess
- @brief Tests the flow of a successful @c reauthenticateWithCredential call.
- */
- func testReauthenticateWithCredentialSuccess() throws {
- let expectation = self.expectation(description: #function)
- signInWithGoogleCredential { user in
- do {
- self.rpcIssuer.respondBlock = {
- try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
- "refreshToken": self.kRefreshToken,
- "federatedId": self.kGoogleID,
- "providerId": GoogleAuthProvider.id,
- "localId": self.kLocalID,
- "displayName": self.kGoogleDisplayName,
- "rawUserInfo": self.kGoogleProfile,
- "username": self.kUserName])
- }
- let googleCredential = GoogleAuthProvider.credential(withIDToken: self.kGoogleIDToken,
- accessToken: self.kGoogleAccessToken)
- user.reauthenticate(with: googleCredential) { reauthenticatedAuthResult, error in
- XCTAssertTrue(Thread.isMainThread)
- do {
- try self.assertUserGoogle(reauthenticatedAuthResult?.user)
- } catch {
- XCTFail("\(error)")
- }
- XCTAssertNil(error)
- // Verify that the current user is unchanged.
- XCTAssertEqual(self.auth?.currentUser, user)
- // Verify that the current user and reauthenticated user are not same pointers.
- XCTAssertNotEqual(user, reauthenticatedAuthResult?.user)
- // Verify that anyway the current user and reauthenticated user have same IDs.
- XCTAssertEqual(reauthenticatedAuthResult?.user.uid, user.uid)
- XCTAssertEqual(reauthenticatedAuthResult?.user.email, user.email)
- XCTAssertEqual(reauthenticatedAuthResult?.user.displayName, user.displayName)
- XCTAssertEqual(reauthenticatedAuthResult?.additionalUserInfo?.username, self.kUserName)
- XCTAssertEqual(reauthenticatedAuthResult?.additionalUserInfo?.providerID,
- GoogleAuthProvider.id)
- XCTAssertEqual(
- reauthenticatedAuthResult?.additionalUserInfo?.profile as? [String: String],
- self.kGoogleProfile
- )
- expectation.fulfill()
- }
- }
- }
- waitForExpectations(timeout: 5)
- try assertUserGoogle(auth?.currentUser)
- }
- /** @fn testReauthenticateFailure
- @brief Tests the flow of a failed @c reauthenticateWithCredential:completion: call.
- */
- func testReauthenticateFailure() {
- setFakeGetAccountProvider()
- let expectation = self.expectation(description: #function)
- signInWithEmailPasswordReturnFakeUser { user in
- do {
- self.rpcIssuer.respondBlock = {
- try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
- "refreshToken": self.kRefreshToken])
- }
- self.setFakeGetAccountProvider(withLocalID: "A different Local ID")
- let emailCredential = EmailAuthProvider.credential(withEmail: self.kEmail,
- password: self.kFakePassword)
- user.reauthenticate(with: emailCredential) { reauthenticatedAuthResult, rawError in
- XCTAssertTrue(Thread.isMainThread)
- let error = try! XCTUnwrap(rawError)
- XCTAssertEqual((error as NSError).code, AuthErrorCode.userMismatch.rawValue)
- // Email should not have changed on the client side.
- XCTAssertEqual(user.email, self.kEmail)
- // User is still signed in.
- XCTAssertEqual(self.auth?.currentUser, user)
- expectation.fulfill()
- }
- }
- }
- waitForExpectations(timeout: 5)
- }
- /** @fn testReauthenticateUserMismatchFailure
- @brief Tests the flow of a failed @c reauthenticateWithCredential:completion: call due to trying
- to reauthenticate a user that does not exist.
- */
- func testReauthenticateUserMismatchFailure() {
- setFakeGetAccountProvider()
- let expectation = self.expectation(description: #function)
- signInWithEmailPasswordReturnFakeUser { user in
- do {
- self.rpcIssuer.respondBlock = {
- try self.rpcIssuer.respond(serverErrorMessage: "USER_NOT_FOUND")
- }
- let googleCredential = GoogleAuthProvider.credential(withIDToken: self.kGoogleIDToken,
- accessToken: self.kGoogleAccessToken)
- user.reauthenticate(with: googleCredential) { reauthenticatedAuthResult, rawError in
- XCTAssertTrue(Thread.isMainThread)
- let error = try! XCTUnwrap(rawError)
- XCTAssertEqual((error as NSError).code, AuthErrorCode.userMismatch.rawValue)
- // Email should not have changed on the client side.
- XCTAssertEqual(user.email, self.kEmail)
- // User is still signed in.
- XCTAssertEqual(self.auth?.currentUser, user)
- expectation.fulfill()
- }
- }
- }
- waitForExpectations(timeout: 5)
- }
- /** @fn testLinkAndRetrieveDataSuccess (and old testLinkCredentialSuccess)
- @brief Tests the flow of a successful @c linkWithCredential call.
- */
- func testLinkAndRetrieveDataSuccess() throws {
- setFakeGetAccountProvider()
- let expectation = self.expectation(description: #function)
- let auth = try XCTUnwrap(self.auth)
- signInWithFacebookCredential { user in
- XCTAssertNotNil(user)
- do {
- self.setFakeGoogleGetAccountProvider()
- self.rpcIssuer.respondBlock = {
- try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
- "refreshToken": self.kRefreshToken,
- "federatedId": self.kGoogleID,
- "providerId": GoogleAuthProvider.id,
- "localId": self.kLocalID,
- "displayName": self.kGoogleDisplayName,
- "rawUserInfo": self.kGoogleProfile,
- "username": self.kUserName])
- }
- let googleCredential = GoogleAuthProvider.credential(withIDToken: self.kGoogleIDToken,
- accessToken: self.kGoogleAccessToken)
- user.link(with: googleCredential) { linkAuthResult, error in
- XCTAssertTrue(Thread.isMainThread)
- XCTAssertNil(error)
- // Verify that the current user is unchanged.
- XCTAssertEqual(auth.currentUser, user)
- // Verify that the current user and reauthenticated user are the same pointers.
- XCTAssertEqual(user, linkAuthResult?.user)
- // Verify that anyway the current user and reauthenticated user have same IDs.
- XCTAssertEqual(linkAuthResult?.user.uid, user.uid)
- XCTAssertEqual(linkAuthResult?.user.email, user.email)
- XCTAssertEqual(linkAuthResult?.user.displayName, user.displayName)
- XCTAssertEqual(linkAuthResult?.additionalUserInfo?.username, self.kUserName)
- XCTAssertEqual(linkAuthResult?.additionalUserInfo?.providerID,
- GoogleAuthProvider.id)
- XCTAssertEqual(
- linkAuthResult?.additionalUserInfo?.profile as? [String: String],
- self.kGoogleProfile
- )
- XCTAssertEqual(linkAuthResult?.user.providerData.first?.providerID, GoogleAuthProvider.id)
- expectation.fulfill()
- }
- }
- }
- waitForExpectations(timeout: 5)
- try assertUserGoogle(auth.currentUser)
- }
- /** @fn testLinkAndRetrieveDataError
- @brief Tests the flow of an unsuccessful @c linkWithCredential:completion:
- call with an error from the backend.
- */
- func testLinkAndRetrieveDataError() throws {
- setFakeGetAccountProvider()
- let expectation = self.expectation(description: #function)
- signInWithFacebookCredential { user in
- XCTAssertNotNil(user)
- do {
- self.setFakeGetAccountProvider()
- self.rpcIssuer.respondBlock = {
- try self.rpcIssuer.respond(serverErrorMessage: "CREDENTIAL_TOO_OLD_LOGIN_AGAIN")
- }
- let googleCredential = GoogleAuthProvider.credential(withIDToken: self.kGoogleIDToken,
- accessToken: self.kGoogleAccessToken)
- user.link(with: googleCredential) { linkAuthResult, rawError in
- XCTAssertTrue(Thread.isMainThread)
- XCTAssertNil(linkAuthResult)
- let error = try! XCTUnwrap(rawError)
- XCTAssertEqual((error as NSError).code, AuthErrorCode.requiresRecentLogin.rawValue)
- // Email should not have changed on the client side.
- XCTAssertEqual(user.email, self.kFacebookEmail)
- // User is still signed in.
- XCTAssertEqual(self.auth?.currentUser, user)
- expectation.fulfill()
- }
- }
- }
- waitForExpectations(timeout: 5)
- }
- /** @fn testLinkAndRetrieveDataProviderAlreadyLinked and old testLinkCredentialProviderAlreadyLinkedError
- @brief Tests the flow of an unsuccessful @c linkWithCredential:completion:
- call with FIRAuthErrorCodeProviderAlreadyLinked, which is a client side error.
- */
- func testLinkAndRetrieveDataProviderAlreadyLinked() throws {
- setFakeGetAccountProvider()
- let expectation = self.expectation(description: #function)
- signInWithFacebookCredential { user in
- XCTAssertNotNil(user)
- do {
- self.setFakeGetAccountProvider()
- let facebookCredential =
- FacebookAuthProvider.credential(withAccessToken: self.kFacebookAccessToken)
- user.link(with: facebookCredential) { linkAuthResult, rawError in
- XCTAssertTrue(Thread.isMainThread)
- XCTAssertNil(linkAuthResult)
- do {
- let error = try XCTUnwrap(rawError)
- XCTAssertEqual((error as NSError).code, AuthErrorCode.providerAlreadyLinked.rawValue)
- } catch {
- XCTFail("Expected to throw providerAlreadyLinked error.")
- }
- // User is still signed in.
- XCTAssertEqual(self.auth?.currentUser, user)
- expectation.fulfill()
- }
- }
- }
- waitForExpectations(timeout: 5)
- }
- /** @fn testLinkAndRetrieveDataErrorAutoSignOut (and old testLinkCredentialError)
- @brief Tests the flow of an unsuccessful @c linkWithCredential:completion:
- call that automatically signs out.
- */
- func testLinkAndRetrieveDataErrorAutoSignOut() throws {
- setFakeGetAccountProvider()
- let expectation = self.expectation(description: #function)
- signInWithFacebookCredential { user in
- XCTAssertNotNil(user)
- do {
- self.setFakeGetAccountProvider()
- self.rpcIssuer.respondBlock = {
- try self.rpcIssuer.respond(serverErrorMessage: "USER_DISABLED")
- }
- let googleCredential = GoogleAuthProvider.credential(withIDToken: self.kGoogleIDToken,
- accessToken: self.kGoogleAccessToken)
- user.link(with: googleCredential) { linkAuthResult, rawError in
- XCTAssertTrue(Thread.isMainThread)
- XCTAssertNil(linkAuthResult)
- let error = try! XCTUnwrap(rawError)
- XCTAssertEqual((error as NSError).code, AuthErrorCode.userDisabled.rawValue)
- // User is signed out.
- XCTAssertNil(self.auth?.currentUser)
- expectation.fulfill()
- }
- }
- }
- waitForExpectations(timeout: 5)
- }
- /** @fn testLinkEmailAndRetrieveDataSuccess
- @brief Tests the flow of a successful @c linkWithCredential:completion:
- invocation for email credential.
- */
- func testLinkEmailAndRetrieveDataSuccess() throws {
- setFakeGetAccountProvider()
- let expectation = self.expectation(description: #function)
- let auth = try XCTUnwrap(self.auth)
- signInWithFacebookCredential { user in
- XCTAssertNotNil(user)
- do {
- self.rpcIssuer.respondBlock = {
- let request = self.rpcIssuer?.request as? SignUpNewUserRequest
- XCTAssertNotNil(request)
- XCTAssertEqual(request?.email, self.kEmail)
- XCTAssertEqual(request?.password, self.kFakePassword)
- XCTAssertNil(request?.displayName)
- let (data, error) = try self.rpcIssuer.respond(withJSON: [
- "idToken": RPCBaseTests.kFakeAccessToken,
- "refreshToken": self.kRefreshToken,
- ])
- self.setFakeGetAccountProvider(withProviderID: EmailAuthProvider.id)
- return (data, error)
- }
- let emailCredential = EmailAuthProvider.credential(withEmail: self.kEmail,
- password: self.kFakePassword)
- user.link(with: emailCredential) { linkAuthResult, error in
- XCTAssertTrue(Thread.isMainThread)
- XCTAssertNil(error)
- // Verify that the current user is unchanged.
- XCTAssertEqual(auth.currentUser, user)
- // Verify that the current user and reauthenticated user are the same pointers.
- XCTAssertEqual(user, linkAuthResult?.user)
- // Verify that anyway the current user and reauthenticated user have same IDs.
- XCTAssertEqual(linkAuthResult?.user.uid, user.uid)
- XCTAssertEqual(linkAuthResult?.user.email, user.email)
- XCTAssertEqual(linkAuthResult?.user.displayName, user.displayName)
- expectation.fulfill()
- }
- }
- }
- waitForExpectations(timeout: 5)
- }
- /** @fn tesLlinkEmailProviderAlreadyLinkedError
- @brief Tests the flow of an unsuccessful @c linkWithCredential:completion:
- invocation for email credential and FIRAuthErrorCodeProviderAlreadyLinked which is a client
- side error.
- */
- func testLinkEmailProviderAlreadyLinkedError() throws {
- setFakeGetAccountProvider()
- let expectation = self.expectation(description: #function)
- signInWithFacebookCredential { user in
- XCTAssertNotNil(user)
- do {
- self.rpcIssuer.respondBlock = {
- let request = self.rpcIssuer?.request as? SignUpNewUserRequest
- XCTAssertNotNil(request)
- XCTAssertEqual(request?.email, self.kEmail)
- XCTAssertEqual(request?.password, self.kFakePassword)
- let (data, error) = try self.rpcIssuer.respond(withJSON: [
- "idToken": RPCBaseTests.kFakeAccessToken,
- "refreshToken": self.kRefreshToken,
- ])
- self.setFakeGetAccountProvider(withProviderID: EmailAuthProvider.id)
- return (data, error)
- }
- let emailCredential = EmailAuthProvider.credential(withEmail: self.kEmail,
- password: self.kFakePassword)
- user.link(with: emailCredential) { linkAuthResult, error in
- XCTAssertEqual(user, linkAuthResult?.user)
- linkAuthResult?.user.link(with: emailCredential) { linkLinkAuthResult, rawError in
- XCTAssertTrue(Thread.isMainThread)
- XCTAssertNil(linkLinkAuthResult)
- do {
- let error = try XCTUnwrap(rawError)
- XCTAssertEqual((error as NSError).code, AuthErrorCode.providerAlreadyLinked.rawValue)
- } catch {
- XCTFail("Expected to throw providerAlreadyLinked error.")
- }
- // User is still signed in.
- XCTAssertEqual(self.auth?.currentUser, user)
- expectation.fulfill()
- }
- }
- }
- }
- waitForExpectations(timeout: 5)
- }
- /** @fn testLinkEmailAndRetrieveDataError
- @brief Tests the flow of an unsuccessful @c linkWithCredential:completion:
- invocation for email credential and an error from the backend.
- */
- func testLinkEmailAndRetrieveDataError() throws {
- setFakeGetAccountProvider()
- let expectation = self.expectation(description: #function)
- signInWithFacebookCredential { user in
- XCTAssertNotNil(user)
- do {
- self.rpcIssuer.respondBlock = {
- let request = self.rpcIssuer?.request as? SignUpNewUserRequest
- XCTAssertNotNil(request)
- XCTAssertEqual(request?.email, self.kEmail)
- XCTAssertEqual(request?.password, self.kFakePassword)
- return try self.rpcIssuer.respond(serverErrorMessage: "TOO_MANY_ATTEMPTS_TRY_LATER")
- }
- let emailCredential = EmailAuthProvider.credential(withEmail: self.kEmail,
- password: self.kFakePassword)
- user.link(with: emailCredential) { linkAuthResult, rawError in
- XCTAssertTrue(Thread.isMainThread)
- XCTAssertNil(linkAuthResult)
- let error = try! XCTUnwrap(rawError)
- XCTAssertEqual((error as NSError).code, AuthErrorCode.tooManyRequests.rawValue)
- // User is still signed in.
- XCTAssertEqual(self.auth?.currentUser, user)
- expectation.fulfill()
- }
- }
- }
- waitForExpectations(timeout: 5)
- }
- /** @fn testLinkEmailAndRetrieveDataErrorAutoSignOut
- @brief Tests the flow of an unsuccessful @c linkWithCredential:completion:
- invocation that automatically signs out.
- */
- func testLinkEmailAndRetrieveDataErrorAutoSignOut() throws {
- setFakeGetAccountProvider()
- let expectation = self.expectation(description: #function)
- signInWithFacebookCredential { user in
- XCTAssertNotNil(user)
- do {
- self.rpcIssuer.respondBlock = {
- XCTAssertNotNil(self.rpcIssuer?.request as? SignUpNewUserRequest)
- return try self.rpcIssuer.respond(serverErrorMessage: "TOKEN_EXPIRED")
- }
- let emailCredential = EmailAuthProvider.credential(withEmail: self.kEmail,
- password: self.kFakePassword)
- user.link(with: emailCredential) { linkAuthResult, rawError in
- XCTAssertTrue(Thread.isMainThread)
- XCTAssertNil(linkAuthResult)
- let error = try! XCTUnwrap(rawError)
- XCTAssertEqual((error as NSError).code, AuthErrorCode.userTokenExpired.rawValue)
- // User is signed out.
- XCTAssertNil(self.auth?.currentUser)
- expectation.fulfill()
- }
- }
- }
- waitForExpectations(timeout: 5)
- }
- #if os(iOS)
- private class FakeOAuthProvider: OAuthProvider {
- override func credential(with uiDelegate: AuthUIDelegate?) async throws -> AuthCredential {
- return OAuthCredential(
- withProviderID: GoogleAuthProvider.id,
- sessionID: UserTests.kOAuthSessionID,
- OAuthResponseURLString: UserTests.kOAuthRequestURI
- )
- }
- }
- /** @fn testLinkProviderFailure
- @brief Tests the flow of a failed @c linkWithProvider:completion:
- call.
- */
- func testLinkProviderFailure() throws {
- setFakeGetAccountProvider()
- let expectation = self.expectation(description: #function)
- let auth = try XCTUnwrap(self.auth)
- signInWithFacebookCredential { user in
- XCTAssertNotNil(user)
- do {
- self.setFakeGetAccountProvider()
- self.rpcIssuer.respondBlock = {
- try self.rpcIssuer.respond(serverErrorMessage: "TOKEN_EXPIRED")
- }
- user.link(with: FakeOAuthProvider(providerID: "foo", auth: auth),
- uiDelegate: nil) { linkAuthResult, rawError in
- XCTAssertTrue(Thread.isMainThread)
- XCTAssertNil(linkAuthResult)
- let error = try! XCTUnwrap(rawError)
- XCTAssertEqual((error as NSError).code, AuthErrorCode.userTokenExpired.rawValue)
- // User is signed out.
- XCTAssertNil(self.auth?.currentUser)
- expectation.fulfill()
- }
- }
- }
- waitForExpectations(timeout: 5)
- }
- /** @fn testReauthenticateWithProviderFailure
- @brief Tests the flow of a failed @c reauthenticateWithProvider:completion: call.
- */
- func testReauthenticateWithProviderFailure() throws {
- setFakeGetAccountProvider()
- let expectation = self.expectation(description: #function)
- let auth = try XCTUnwrap(self.auth)
- signInWithFacebookCredential { user in
- XCTAssertNotNil(user)
- do {
- self.setFakeGetAccountProvider()
- self.rpcIssuer.respondBlock = {
- try self.rpcIssuer.respond(serverErrorMessage: "TOKEN_EXPIRED")
- }
- user.reauthenticate(with: FakeOAuthProvider(providerID: "foo", auth: auth),
- uiDelegate: nil) { linkAuthResult, rawError in
- XCTAssertTrue(Thread.isMainThread)
- XCTAssertNil(linkAuthResult)
- let error = try! XCTUnwrap(rawError)
- XCTAssertEqual((error as NSError).code, AuthErrorCode.userTokenExpired.rawValue)
- // User is still signed in.
- XCTAssertEqual(self.auth?.currentUser, user)
- expectation.fulfill()
- }
- }
- }
- waitForExpectations(timeout: 5)
- }
- /** @fn testLinkPhoneAuthCredentialSuccess
- @brief Tests the flow of a successful @c linkWithCredential call using a phoneAuthCredential.
- */
- func testLinkPhoneAuthCredentialSuccess() throws {
- setFakeGetAccountProvider()
- let expectation = self.expectation(description: #function)
- let auth = try XCTUnwrap(self.auth)
- signInWithEmailPasswordReturnFakeUser { user in
- XCTAssertNotNil(user)
- self.expectVerifyPhoneNumberRequest(isLink: true)
- do {
- self.setFakeGetAccountProvider(withProviderID: PhoneAuthProvider.id)
- self.rpcIssuer.respondBlock = {
- try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
- "refreshToken": self.kRefreshToken])
- }
- let credential = PhoneAuthProvider.provider(auth: auth).credential(
- withVerificationID: self.kVerificationID,
- verificationCode: self.kVerificationCode
- )
- user.link(with: credential) { linkAuthResult, error in
- XCTAssertTrue(Thread.isMainThread)
- XCTAssertNil(error)
- // Verify that the current user is unchanged.
- XCTAssertEqual(auth.currentUser, user)
- // Verify that the current user and reauthenticated user are the same pointers.
- XCTAssertEqual(user, linkAuthResult?.user)
- // Verify that anyway the current user and reauthenticated user have same IDs.
- XCTAssertEqual(linkAuthResult?.user.uid, user.uid)
- XCTAssertEqual(linkAuthResult?.user.email, user.email)
- XCTAssertEqual(linkAuthResult?.user.displayName, user.displayName)
- XCTAssertEqual(auth.currentUser?.providerData.first?.providerID, PhoneAuthProvider.id)
- XCTAssertEqual(
- linkAuthResult?.user.providerData.first?.providerID,
- PhoneAuthProvider.id
- )
- XCTAssertEqual(auth.currentUser?.phoneNumber, self.kTestPhoneNumber)
- expectation.fulfill()
- }
- }
- }
- waitForExpectations(timeout: 5)
- }
- /** @fn testUnlinkPhoneAuthCredentialSuccess
- @brief Tests the flow of a successful @c unlinkFromProvider:completion: call using a
- @c FIRPhoneAuthProvider.
- */
- func testUnlinkPhoneAuthCredentialSuccess() throws {
- setFakeGetAccountProvider()
- let expectation = self.expectation(description: #function)
- let auth = try XCTUnwrap(self.auth)
- signInWithEmailPasswordReturnFakeUser { user in
- XCTAssertNotNil(user)
- self.expectVerifyPhoneNumberRequest(isLink: true)
- do {
- self.setFakeGetAccountProvider(withProviderID: PhoneAuthProvider.id)
- self.rpcIssuer.respondBlock = {
- try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
- "refreshToken": self.kRefreshToken])
- }
- let credential = PhoneAuthProvider.provider(auth: auth).credential(
- withVerificationID: self.kVerificationID,
- verificationCode: self.kVerificationCode
- )
- user.link(with: credential) { linkAuthResult, error in
- XCTAssertTrue(Thread.isMainThread)
- XCTAssertNil(error)
- // Verify that the current user is unchanged.
- XCTAssertEqual(auth.currentUser, user)
- // Verify that the current user and reauthenticated user are the same pointers.
- XCTAssertEqual(user, linkAuthResult?.user)
- // Verify that anyway the current user and reauthenticated user have same IDs.
- XCTAssertEqual(linkAuthResult?.user.uid, user.uid)
- XCTAssertEqual(linkAuthResult?.user.email, user.email)
- XCTAssertEqual(linkAuthResult?.user.displayName, user.displayName)
- XCTAssertEqual(auth.currentUser?.providerData.first?.providerID, PhoneAuthProvider.id)
- XCTAssertEqual(
- linkAuthResult?.user.providerData.first?.providerID,
- PhoneAuthProvider.id
- )
- XCTAssertEqual(auth.currentUser?.phoneNumber, self.kTestPhoneNumber)
- // Immediately unlink the phone auth provider.
- self.rpcIssuer.respondBlock = {
- let request = try XCTUnwrap(self.rpcIssuer?.request as? SetAccountInfoRequest)
- XCTAssertEqual(request.apiKey, UserTests.kFakeAPIKey)
- XCTAssertEqual(request.accessToken, RPCBaseTests.kFakeAccessToken)
- XCTAssertNil(request.email)
- XCTAssertNil(request.password)
- XCTAssertNil(request.localID)
- XCTAssertNil(request.displayName)
- XCTAssertNil(request.photoURL)
- XCTAssertNil(request.providers)
- XCTAssertNil(request.deleteAttributes)
- XCTAssertEqual(try XCTUnwrap(request.deleteProviders?.first), PhoneAuthProvider.id)
- return try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
- "refreshToken": self.kRefreshToken])
- }
- user.unlink(fromProvider: PhoneAuthProvider.id) { user, error in
- XCTAssertNil(error)
- XCTAssertEqual(auth.currentUser, user)
- XCTAssertNil(auth.currentUser?.phoneNumber)
- expectation.fulfill()
- }
- }
- }
- }
- waitForExpectations(timeout: 5)
- }
- /** @fn testlinkPhoneAuthCredentialFailure
- @brief Tests the flow of a failed call to @c linkWithCredential:completion: due
- to a phone provider already being linked.
- */
- func testlinkPhoneAuthCredentialFailure() throws {
- setFakeGetAccountProvider(withPasswordHash: kFakePassword)
- let expectation = self.expectation(description: #function)
- signInWithEmailPasswordReturnFakeUser { user in
- XCTAssertNotNil(user)
- self.expectVerifyPhoneNumberRequest(isLink: true)
- self.setFakeGetAccountProvider(withProviderID: PhoneAuthProvider.id)
- let credential = EmailAuthCredential(withEmail: self.kEmail, password: self.kFakePassword)
- user.link(with: credential) { linkAuthResult, rawError in
- XCTAssertTrue(Thread.isMainThread)
- XCTAssertNil(linkAuthResult)
- if let error = try? XCTUnwrap(rawError) {
- XCTAssertEqual((error as NSError).code, AuthErrorCode.providerAlreadyLinked.rawValue)
- } else {
- XCTFail("Did not throw expected error")
- }
- expectation.fulfill()
- }
- }
- waitForExpectations(timeout: 5)
- }
- /** @fn testlinkPhoneCredentialAlreadyExistsError
- @brief Tests the flow of @c linkWithCredential:completion:
- call using a phoneAuthCredential and a credential already exists error. In this case we
- should get a AuthCredential in the error object.
- */
- func testlinkPhoneCredentialAlreadyExistsError() throws {
- setFakeGetAccountProvider()
- let expectation = self.expectation(description: #function)
- let auth = try XCTUnwrap(self.auth)
- signInWithEmailPasswordReturnFakeUser { user in
- XCTAssertNotNil(user)
- self.expectVerifyPhoneNumberRequest(isLink: true)
- do {
- self.setFakeGetAccountProvider(withProviderID: PhoneAuthProvider.id)
- self.rpcIssuer.respondBlock = {
- try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
- "refreshToken": self.kRefreshToken,
- "phoneNumber": self.kTestPhoneNumber,
- "temporaryProof": "Fake Temporary Proof"])
- }
- let credential = PhoneAuthProvider.provider(auth: auth).credential(
- withVerificationID: self.kVerificationID,
- verificationCode: self.kVerificationCode
- )
- user.link(with: credential) { linkAuthResult, rawError in
- XCTAssertTrue(Thread.isMainThread)
- XCTAssertNil(linkAuthResult)
- do {
- let error = try XCTUnwrap(rawError)
- XCTAssertEqual((error as NSError).code, AuthErrorCode.credentialAlreadyInUse.rawValue)
- let credential = try XCTUnwrap((error as NSError)
- .userInfo[AuthErrors.userInfoUpdatedCredentialKey] as? PhoneAuthCredential)
- switch credential.credentialKind {
- case let .phoneNumber(phoneNumber, temporaryProof):
- XCTAssertEqual(temporaryProof, "Fake Temporary Proof")
- XCTAssertEqual(phoneNumber, self.kTestPhoneNumber)
- case .verification: XCTFail("Should be phoneNumber case")
- }
- } catch {
- XCTFail("Did not throw expected error \(error)")
- }
- expectation.fulfill()
- }
- }
- }
- waitForExpectations(timeout: 5)
- }
- #endif
- func testRetrieveUserWithInvalidToken() async throws {
- let auth = try XCTUnwrap(self.auth)
- do {
- _ = try await User.retrieveUser(
- withAuth: auth,
- accessToken: nil,
- accessTokenExpirationDate: Date(),
- refreshToken: nil,
- anonymous: false
- )
- XCTFail("Expected an error to be thrown")
- } catch let error as NSError {
- XCTAssertEqual(error.domain, AuthErrors.domain)
- XCTAssertEqual(error.code, AuthErrorCode.invalidUserToken.rawValue)
- }
- }
- // MARK: Private helper functions
- private func expectVerifyPhoneNumberRequest(isLink: Bool = false) {
- rpcIssuer?.verifyPhoneNumberRequester = { request in
- XCTAssertEqual(request.verificationID, self.kVerificationID)
- XCTAssertEqual(request.verificationCode, self.kVerificationCode)
- XCTAssertEqual(request.accessToken, RPCBaseTests.kFakeAccessToken)
- if isLink {
- XCTAssertEqual(request.operation, AuthOperationType.link)
- } else {
- XCTAssertEqual(request.operation, AuthOperationType.update)
- }
- }
- }
- private func internalGetIDTokenResult(token: String, forceRefresh: Bool = true,
- emailMatch: String = "aunitestuser@gmail.com",
- audMatch: String = "test_aud") {
- setFakeGetAccountProvider()
- let expectation = self.expectation(description: #function)
- signInWithEmailPasswordReturnFakeUser(fakeAccessToken: token) { user in
- user.getIDTokenResult(forcingRefresh: forceRefresh) { rawTokenResult, error in
- XCTAssertTrue(Thread.isMainThread)
- XCTAssertNil(error)
- XCTAssertEqual(user.displayName, self.kDisplayName)
- XCTAssertEqual(user.email, self.kEmail)
- let tokenResult = try! XCTUnwrap(rawTokenResult)
- XCTAssertEqual(tokenResult.token, token)
- XCTAssertNotNil(tokenResult.issuedAtDate)
- XCTAssertNotNil(tokenResult.authDate)
- XCTAssertNotNil(tokenResult.expirationDate)
- XCTAssertNotNil(tokenResult.signInProvider)
- // The lowercased is for the base64 test which seems to be an erroneously uppercased
- // "Password"?
- XCTAssertEqual(tokenResult.signInProvider.lowercased(), EmailAuthProvider.id)
- XCTAssertEqual(tokenResult.claims["email"] as! String, emailMatch)
- XCTAssertEqual(tokenResult.claims["aud"] as! String, audMatch)
- XCTAssertEqual(tokenResult.signInSecondFactor, "")
- expectation.fulfill()
- }
- }
- waitForExpectations(timeout: 5)
- }
- private func changeUserEmail(user: User, changeEmail: Bool = false,
- expectation: XCTestExpectation) {
- do {
- XCTAssertEqual(user.providerID, "Firebase")
- XCTAssertEqual(user.uid, kLocalID)
- XCTAssertEqual(user.displayName, kDisplayName)
- XCTAssertEqual(user.photoURL, URL(string: kTestPhotoURL))
- XCTAssertEqual(user.email, kEmail)
- // Pretend that the display name on the server has been changed since the original signin.
- setFakeGetAccountProvider(withNewDisplayName: kNewDisplayName)
- rpcIssuer.respondBlock = {
- let request = try XCTUnwrap(self.rpcIssuer?.request as? SetAccountInfoRequest)
- XCTAssertEqual(request.apiKey, UserTests.kFakeAPIKey)
- XCTAssertEqual(request.accessToken, RPCBaseTests.kFakeAccessToken)
- if changeEmail {
- XCTAssertEqual(request.email, self.kNewEmail)
- XCTAssertNil(request.password)
- } else {
- XCTAssertEqual(request.password, self.kNewPassword)
- XCTAssertNil(request.email)
- }
- XCTAssertNil(request.localID)
- XCTAssertNil(request.displayName)
- XCTAssertNil(request.photoURL)
- XCTAssertNil(request.providers)
- XCTAssertNil(request.deleteAttributes)
- XCTAssertNil(request.deleteProviders)
- return try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
- "email": self.kNewEmail,
- "refreshToken": self.kRefreshToken])
- }
- if changeEmail {
- user.updateEmail(to: kNewEmail) { error in
- XCTAssertNil(error)
- XCTAssertEqual(user.email, self.kNewEmail)
- XCTAssertEqual(user.displayName, self.kNewDisplayName)
- XCTAssertFalse(user.isAnonymous)
- expectation.fulfill()
- }
- } else {
- user.updatePassword(to: kNewPassword) { error in
- XCTAssertNil(error)
- XCTAssertEqual(user.displayName, self.kNewDisplayName)
- XCTAssertFalse(user.isAnonymous)
- expectation.fulfill()
- }
- }
- }
- }
- private func signInWithEmailPasswordReturnFakeUser(fakeAccessToken: String = RPCBaseTests
- .kFakeAccessToken,
- completion: @escaping (User) -> Void) {
- let kRefreshToken = "fakeRefreshToken"
- setFakeSecureTokenService(fakeAccessToken: fakeAccessToken)
- rpcIssuer?.verifyPasswordRequester = { request in
- // 2. Validate the created Request instance.
- XCTAssertEqual(request.email, self.kEmail)
- XCTAssertEqual(request.password, self.kFakePassword)
- XCTAssertEqual(request.apiKey, UserTests.kFakeAPIKey)
- XCTAssertTrue(request.returnSecureToken)
- do {
- // 3. Send the response from the fake backend.
- return try self.rpcIssuer.respond(withJSON: ["idToken": fakeAccessToken,
- "isNewUser": true,
- "refreshToken": kRefreshToken])
- } catch {
- XCTFail("Failure sending response: \(error)")
- return (nil, nil)
- }
- }
- // 1. After setting up fakes, sign out and sign in.
- do {
- try auth?.signOut()
- } catch {
- XCTFail("Sign out failed: \(error)")
- return
- }
- auth?.signIn(withEmail: kEmail, password: kFakePassword) { authResult, error in
- // 4. After the response triggers the callback, verify the returned result.
- XCTAssertTrue(Thread.isMainThread)
- guard let user = authResult?.user else {
- XCTFail("authResult.user is missing")
- return
- }
- XCTAssertEqual(user.refreshToken, kRefreshToken)
- XCTAssertFalse(user.isAnonymous)
- XCTAssertEqual(user.email, self.kEmail)
- guard let additionalUserInfo = authResult?.additionalUserInfo else {
- XCTFail("authResult.additionalUserInfo is missing")
- return
- }
- XCTAssertFalse(additionalUserInfo.isNewUser)
- XCTAssertEqual(additionalUserInfo.providerID, EmailAuthProvider.id)
- XCTAssertNil(error)
- // Clear the password Requester to avoid being called again by reauthenticate tests.
- self.rpcIssuer?.verifyPasswordRequester = nil
- completion(user)
- }
- }
- private func signInWithGoogleCredential(completion: @escaping (User) -> Void) {
- setFakeSecureTokenService(fakeAccessToken: RPCBaseTests.kFakeAccessToken)
- setFakeGoogleGetAccountProvider()
- rpcIssuer.respondBlock = {
- try self.verifyGoogleAssertionRequest(
- XCTUnwrap(self.rpcIssuer?.request as? VerifyAssertionRequest)
- )
- // 3. Send the response from the fake backend.
- return try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
- "providerId": GoogleAuthProvider.id,
- "refreshToken": self.kRefreshToken,
- "localId": self.kLocalID,
- "displayName": self.kDisplayName,
- "rawUserInfo": self.kGoogleProfile,
- "username": self.kUserName])
- }
- do {
- try auth?.signOut()
- let googleCredential = GoogleAuthProvider.credential(withIDToken: kGoogleIDToken,
- accessToken: kGoogleAccessToken)
- auth?.signIn(with: googleCredential) { authResult, error in
- // 4. After the response triggers the callback, verify the returned result.
- XCTAssertTrue(Thread.isMainThread)
- guard let user = authResult?.user else {
- XCTFail("authResult.user is missing")
- return
- }
- XCTAssertEqual(user.refreshToken, self.kRefreshToken)
- XCTAssertFalse(user.isAnonymous)
- XCTAssertEqual(user.email, self.kGoogleEmail)
- guard let additionalUserInfo = authResult?.additionalUserInfo,
- let profile = additionalUserInfo.profile as? [String: String] else {
- XCTFail("authResult.additionalUserInfo and/or profile is missing")
- return
- }
- XCTAssertEqual(profile, self.kGoogleProfile)
- XCTAssertFalse(additionalUserInfo.isNewUser)
- XCTAssertEqual(additionalUserInfo.providerID, GoogleAuthProvider.id)
- XCTAssertEqual(additionalUserInfo.username, self.kUserName)
- XCTAssertNil(error)
- completion(user)
- }
- } catch {
- XCTFail("Throw in \(#function): \(error)")
- }
- }
- private func verifyGoogleAssertionRequest(_ request: VerifyAssertionRequest) {
- XCTAssertEqual(request.providerID, GoogleAuthProvider.id)
- XCTAssertEqual(request.providerIDToken, kGoogleIDToken)
- XCTAssertEqual(request.providerAccessToken, kGoogleAccessToken)
- XCTAssertTrue(request.returnSecureToken)
- XCTAssertEqual(request.apiKey, UserTests.kFakeAPIKey)
- XCTAssertTrue(request.returnSecureToken)
- }
- private func signInWithFacebookCredential(completion: @escaping (User) -> Void) {
- setFakeSecureTokenService(fakeAccessToken: RPCBaseTests.kFakeAccessToken)
- setFakeGetAccountProvider(withNewDisplayName: kFacebookDisplayName,
- withProviderID: FacebookAuthProvider.id,
- withFederatedID: kFacebookID,
- withEmail: kFacebookEmail)
- rpcIssuer.respondBlock = {
- let request = try XCTUnwrap(self.rpcIssuer?.request as? VerifyAssertionRequest)
- XCTAssertEqual(request.providerID, FacebookAuthProvider.id)
- XCTAssertEqual(request.providerIDToken, self.kFacebookIDToken)
- XCTAssertEqual(request.providerAccessToken, self.kFacebookAccessToken)
- XCTAssertTrue(request.returnSecureToken)
- XCTAssertEqual(request.apiKey, UserTests.kFakeAPIKey)
- XCTAssertTrue(request.returnSecureToken)
- // 3. Send the response from the fake backend.
- return try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
- "refreshToken": self.kRefreshToken,
- "federatedId": self.kFacebookID,
- "providerId": FacebookAuthProvider.id,
- "localId": self.kLocalID,
- "displayName": self.kDisplayName,
- "rawUserInfo": self.kGoogleProfile,
- "username": self.kUserName])
- }
- do {
- try auth?.signOut()
- let facebookCredential = FacebookAuthProvider
- .credential(withAccessToken: kFacebookAccessToken)
- auth?.signIn(with: facebookCredential) { authResult, error in
- // 4. After the response triggers the callback, verify the returned result.
- XCTAssertTrue(Thread.isMainThread)
- guard let user = authResult?.user else {
- XCTFail("authResult.user is missing")
- return
- }
- XCTAssertEqual(user.refreshToken, self.kRefreshToken)
- XCTAssertFalse(user.isAnonymous)
- XCTAssertEqual(user.email, self.kFacebookEmail)
- XCTAssertEqual(user.displayName, self.kFacebookDisplayName)
- XCTAssertEqual(user.providerData.count, 1)
- guard let additionalUserInfo = authResult?.additionalUserInfo,
- let facebookUserInfo = user.providerData.first,
- let profile = additionalUserInfo.profile as? [String: String] else {
- XCTFail("authResult.additionalUserInfo and/or profile is missing")
- return
- }
- XCTAssertEqual(facebookUserInfo.providerID, FacebookAuthProvider.id)
- XCTAssertEqual(facebookUserInfo.uid, self.kFacebookID)
- XCTAssertEqual(facebookUserInfo.displayName, self.kFacebookDisplayName)
- XCTAssertEqual(facebookUserInfo.email, self.kFacebookEmail)
- XCTAssertEqual(profile, self.kGoogleProfile)
- XCTAssertFalse(additionalUserInfo.isNewUser)
- XCTAssertEqual(additionalUserInfo.providerID, FacebookAuthProvider.id)
- XCTAssertEqual(additionalUserInfo.username, self.kUserName)
- XCTAssertNil(error)
- completion(user)
- }
- } catch {
- XCTFail("Throw in \(#function): \(error)")
- }
- }
- private func signInWithEmailPasswordReturnFakeUserLink(completion: @escaping (User) -> Void) {
- let kRefreshToken = "fakeRefreshToken"
- setFakeSecureTokenService()
- rpcIssuer.respondBlock = {
- let request = try XCTUnwrap(self.rpcIssuer?.request as? EmailLinkSignInRequest)
- XCTAssertEqual(request.email, self.kEmail)
- XCTAssertEqual(request.apiKey, UserTests.kFakeAPIKey)
- XCTAssertEqual(request.oobCode, "aCode")
- XCTAssertNil(request.idToken)
- // Send the response from the fake backend.
- return try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken,
- "isNewUser": true,
- "refreshToken": kRefreshToken])
- }
- do {
- try auth?.signOut()
- auth?.signIn(
- withEmail: kEmail,
- link: "https://www.google.com?oobCode=aCode&mode=signIn"
- ) { authResult, error in
- // 4. After the response triggers the callback, verify the returned result.
- XCTAssertTrue(Thread.isMainThread)
- guard let user = authResult?.user else {
- XCTFail("authResult.user is missing")
- return
- }
- XCTAssertEqual(user.refreshToken, kRefreshToken)
- XCTAssertFalse(user.isAnonymous)
- XCTAssertEqual(user.email, self.kEmail)
- guard let additionalUserInfo = authResult?.additionalUserInfo else {
- XCTFail("authResult.additionalUserInfo is missing")
- return
- }
- XCTAssertTrue(additionalUserInfo.isNewUser)
- XCTAssertEqual(additionalUserInfo.providerID, EmailAuthProvider.id)
- XCTAssertNil(error)
- completion(user)
- }
- } catch {
- XCTFail("Throw in \(#function): \(error)")
- }
- }
- }
|