From 5c4ef57c530f5d0e0074805925798ac154248d83 Mon Sep 17 00:00:00 2001 From: russellwheatley Date: Tue, 30 Jun 2020 14:40:47 +0100 Subject: [PATCH 1/6] feat(auth): 1st commit verifyBeforeUpdateEmail --- .../auth/ReactNativeFirebaseAuthModule.java | 46 ++++++ packages/auth/ios/RNFBAuth/RNFBAuthModule.m | 28 ++++ packages/auth/lib/User.js | 140 +++++++++++++++++- 3 files changed, 213 insertions(+), 1 deletion(-) diff --git a/packages/auth/android/src/main/java/io/invertase/firebase/auth/ReactNativeFirebaseAuthModule.java b/packages/auth/android/src/main/java/io/invertase/firebase/auth/ReactNativeFirebaseAuthModule.java index c74ba7e2a0..b0ded9473b 100644 --- a/packages/auth/android/src/main/java/io/invertase/firebase/auth/ReactNativeFirebaseAuthModule.java +++ b/packages/auth/android/src/main/java/io/invertase/firebase/auth/ReactNativeFirebaseAuthModule.java @@ -599,6 +599,52 @@ public void sendEmailVerification( } } + /** + * verifyBeforeUpdateEmail + * + * @param promise + */ + @ReactMethod + public void verifyBeforeUpdateEmail( + String appName, + String email, + ReadableMap actionCodeSettings, + final Promise promise + ) { + FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); + final FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp); + + FirebaseUser user = firebaseAuth.getCurrentUser(); + Log.d(TAG, "verifyBeforeUpdateEmail"); + + if (user == null) { + promiseNoUser(promise, false); + Log.e(TAG, "verifyBeforeUpdateEmail:failure:noCurrentUser"); + } else { + OnCompleteListener listener = task -> { + if (task.isSuccessful()) { + Log.d(TAG, "verifyBeforeUpdateEmail:onComplete:success"); + promiseWithUser(firebaseAuth.getCurrentUser(), promise); + } else { + Exception exception = task.getException(); + Log.e(TAG, "verifyBeforeUpdateEmail:onComplete:failure", exception); + promiseRejectAuthException(promise, exception); + } + }; + + if (actionCodeSettings == null) { + user + .verifyBeforeUpdateEmail(email) + .addOnCompleteListener(getExecutor(), listener); + } else { + ActionCodeSettings settings = buildActionCodeSettings(actionCodeSettings); + user + .verifyBeforeUpdateEmail(email, settings) + .addOnCompleteListener(getExecutor(), listener); + } + } + } + /** * updateEmail * diff --git a/packages/auth/ios/RNFBAuth/RNFBAuthModule.m b/packages/auth/ios/RNFBAuth/RNFBAuthModule.m index 246dbcf95c..279eb3e43b 100644 --- a/packages/auth/ios/RNFBAuth/RNFBAuthModule.m +++ b/packages/auth/ios/RNFBAuth/RNFBAuthModule.m @@ -329,6 +329,34 @@ - (void)invalidate { } } +RCT_EXPORT_METHOD(verifyBeforeUpdateEmail: + (FIRApp *) firebaseApp + :(NSString *) email + :(FIRActionCodeSettings *) actionCodeSettings + :(RCTPromiseResolveBlock) resolve + :(RCTPromiseRejectBlock) reject +) { + FIRUser *user = [FIRAuth authWithApp:firebaseApp].currentUser; + if (user) { + id handler = ^(NSError *_Nullable error) { + if (error) { + [self promiseRejectAuthException:reject error:error]; + } else { + FIRUser *userAfterUpdate = [FIRAuth authWithApp:firebaseApp].currentUser; + [self promiseWithUser:resolve rejecter:reject user:userAfterUpdate]; + } + }; + if (actionCodeSettings) { + FIRActionCodeSettings *settings = [self buildActionCodeSettings:actionCodeSettings]; + [user sendEmailVerificationBeforeUpdatingEmail:email actionCodeSettings:settings completion:handler]; + } else { + [user sendEmailVerificationBeforeUpdatingEmail:email completion:handler]; + } + } else { + [self promiseNoUser:resolve rejecter:reject isError:YES]; + } +} + RCT_EXPORT_METHOD(updateEmail: (FIRApp *) firebaseApp :(NSString *) email diff --git a/packages/auth/lib/User.js b/packages/auth/lib/User.js index 0d7472fbef..8534da2686 100644 --- a/packages/auth/lib/User.js +++ b/packages/auth/lib/User.js @@ -15,7 +15,7 @@ * */ -import { isObject, isString } from '@react-native-firebase/app/lib/common'; +import { isObject, isString, isUndefined, isBoolean } from '@react-native-firebase/app/lib/common'; export default class User { constructor(auth, user) { @@ -107,6 +107,68 @@ export default class User { "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.url' expected a string value.", ); } + + if ( + !isUndefined(actionCodeSettings.dynamicLinkDomain) && + !isString(actionCodeSettings.dynamicLinkDomain) + ) { + throw new Error( + "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.dynamicLinkDomain' expected an string value.", + ); + } + + if ( + !isUndefined(actionCodeSettings.handleCodeInApp) && + !isBoolean(actionCodeSettings.handleCodeInApp) + ) { + throw new Error( + "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.handleCodeInApp' expected an boolean value.", + ); + } + + if (!isUndefined(actionCodeSettings.iOS)) { + if (!isObject(actionCodeSettings.iOS)) { + throw new Error( + "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.iOS' expected an object value.", + ); + } + if (!isString(actionCodeSettings.iOS.bundleId)) { + throw new Error( + "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.iOS.bundleId' expected a string value.", + ); + } + } + + if (!isUndefined(actionCodeSettings.android)) { + if (!isObject(actionCodeSettings.android)) { + throw new Error( + "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.android' expected an object value.", + ); + } + if (!isString(actionCodeSettings.android.packageName)) { + throw new Error( + "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.android.packageName' expected a string value.", + ); + } + + if ( + !isUndefined(actionCodeSettings.android.installApp) && + !isBoolean(actionCodeSettings.android.installApp) + ) { + throw new Error( + "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.android.installApp' expected a boolean value.", + ); + } + + if ( + !isUndefined(actionCodeSettings.android.minimumVersion) && + !isString(actionCodeSettings.android.minimumVersion) + ) { + throw new Error( + "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.android.minimumVersion' expected a string value.", + ); + } + } } return this._auth.native.sendEmailVerification(actionCodeSettings).then(user => { @@ -148,6 +210,82 @@ export default class User { }); } + verifyBeforeUpdateEmail(newEmail, actionCodeSettings) { + if (isObject(actionCodeSettings)) { + if (!isString(actionCodeSettings.url)) { + throw new Error( + "firebase.auth.User.verifyBeforeUpdateEmail(*) 'actionCodeSettings.url' expected a string value.", + ); + } + + if ( + !isUndefined(actionCodeSettings.dynamicLinkDomain) && + !isString(actionCodeSettings.dynamicLinkDomain) + ) { + throw new Error( + "firebase.auth.User.verifyBeforeUpdateEmail(*) 'actionCodeSettings.dynamicLinkDomain' expected an string value.", + ); + } + + if ( + !isUndefined(actionCodeSettings.handleCodeInApp) && + !isBoolean(actionCodeSettings.handleCodeInApp) + ) { + throw new Error( + "firebase.auth.User.verifyBeforeUpdateEmail(*) 'actionCodeSettings.handleCodeInApp' expected an boolean value.", + ); + } + + if (!isUndefined(actionCodeSettings.iOS)) { + if (!isObject(actionCodeSettings.iOS)) { + throw new Error( + "firebase.auth.User.verifyBeforeUpdateEmail(*) 'actionCodeSettings.iOS' expected an object value.", + ); + } + if (!isString(actionCodeSettings.iOS.bundleId)) { + throw new Error( + "firebase.auth.User.verifyBeforeUpdateEmail(*) 'actionCodeSettings.iOS.bundleId' expected a string value.", + ); + } + } + + if (!isUndefined(actionCodeSettings.android)) { + if (!isObject(actionCodeSettings.android)) { + throw new Error( + "firebase.auth.User.verifyBeforeUpdateEmail(*) 'actionCodeSettings.android' expected an object value.", + ); + } + if (!isString(actionCodeSettings.android.packageName)) { + throw new Error( + "firebase.auth.User.verifyBeforeUpdateEmail(*) 'actionCodeSettings.android.packageName' expected a string value.", + ); + } + + if ( + !isUndefined(actionCodeSettings.android.installApp) && + !isBoolean(actionCodeSettings.android.installApp) + ) { + throw new Error( + "firebase.auth.User.verifyBeforeUpdateEmail(*) 'actionCodeSettings.android.installApp' expected a boolean value.", + ); + } + + if ( + !isUndefined(actionCodeSettings.android.minimumVersion) && + !isString(actionCodeSettings.android.minimumVersion) + ) { + throw new Error( + "firebase.auth.User.verifyBeforeUpdateEmail(*) 'actionCodeSettings.android.minimumVersion' expected a string value.", + ); + } + } + } + + return this._auth.native.verifyBeforeUpdateEmail(newEmail, actionCodeSettings).then(user => { + this._auth._setUser(user); + }); + } + /** * KNOWN UNSUPPORTED METHODS */ From 954572a95c54746447fdde0470e4f0a6ca580a84 Mon Sep 17 00:00:00 2001 From: russellwheatley Date: Tue, 30 Jun 2020 17:01:56 +0100 Subject: [PATCH 2/6] feat(auth): verifyBeforeUpdateEmail updates --- packages/auth/e2e/user.e2e.js | 23 +++++++ packages/auth/ios/RNFBAuth/RNFBAuthModule.m | 2 +- packages/auth/lib/index.d.ts | 24 +++++++ tests/ios/Podfile.lock | 70 ++++++++++----------- 4 files changed, 83 insertions(+), 36 deletions(-) diff --git a/packages/auth/e2e/user.e2e.js b/packages/auth/e2e/user.e2e.js index 8e38e162fe..e157e64eb8 100644 --- a/packages/auth/e2e/user.e2e.js +++ b/packages/auth/e2e/user.e2e.js @@ -204,6 +204,29 @@ describe('auth().currentUser', () => { }); }); + describe.only('verifyBeforeUpdateEmail()', () => { + it('should not error', async () => { + const random = Utils.randString(12, '#aA'); + const random2 = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + const updateEmail = `${random2}@${random2}.com`; + + try { + await firebase.auth().createUserWithEmailAndPassword(email, random); + await firebase.auth().currentUser.verifyBeforeUpdateEmail(updateEmail); + // TODO is there a way to test? Need to hit the link sent to the email for email to change + // const currentEmail = firebase.auth().currentUser.email; + // should(currentEmail).equal(updateEmail); + } finally { + await firebase.auth().currentUser.delete(); + } + }); + + it('should work with actionCodeSettings', async () => { + //TODO test with actionCodeSettings as well + }); + }); + describe('unlink()', () => { it('should unlink the email address', async () => { const random = Utils.randString(12, '#aA'); diff --git a/packages/auth/ios/RNFBAuth/RNFBAuthModule.m b/packages/auth/ios/RNFBAuth/RNFBAuthModule.m index 279eb3e43b..392e8c93f5 100644 --- a/packages/auth/ios/RNFBAuth/RNFBAuthModule.m +++ b/packages/auth/ios/RNFBAuth/RNFBAuthModule.m @@ -332,7 +332,7 @@ - (void)invalidate { RCT_EXPORT_METHOD(verifyBeforeUpdateEmail: (FIRApp *) firebaseApp :(NSString *) email - :(FIRActionCodeSettings *) actionCodeSettings + :(NSDictionary *) actionCodeSettings :(RCTPromiseResolveBlock) resolve :(RCTPromiseRejectBlock) reject ) { diff --git a/packages/auth/lib/index.d.ts b/packages/auth/lib/index.d.ts index f2bf532617..4eb53171d6 100644 --- a/packages/auth/lib/index.d.ts +++ b/packages/auth/lib/index.d.ts @@ -1037,6 +1037,30 @@ export namespace FirebaseAuthTypes { * @param actionCodeSettings Any optional additional settings to be set before sending the verification email. */ sendEmailVerification(actionCodeSettings?: ActionCodeSettings): Promise; + /** + * Sends a link to the user's email address, when clicked, the user's Authentication email address will be updated to whatever + * was passed as the first argument. + * + * #### Example + * + * ```js + * await firebase.auth().currentUser.verifyBeforeUpdateEmail( + * 'foo@emailaddress.com', + * { + * handleCodeInApp: true, + * }); + * ``` + * + * > This will Promise reject if the user is anonymous. + * + * @error auth/missing-android-pkg-name An Android package name must be provided if the Android app is required to be installed. + * @error auth/missing-continue-uri A continue URL must be provided in the request. + * @error auth/missing-ios-bundle-id An iOS bundle ID must be provided if an App Store ID is provided. + * @error auth/invalid-continue-uri The continue URL provided in the request is invalid. + * @error auth/unauthorized-continue-uri The domain of the continue URL is not whitelisted. Whitelist the domain in the Firebase console. + * @param actionCodeSettings Any optional additional settings to be set before sending the verification email. + */ + verifyBeforeUpdateEmail(email: string, actionCodeSettings?: ActionCodeSettings): Promise; /** * Returns a JSON-serializable representation of this object. diff --git a/tests/ios/Podfile.lock b/tests/ios/Podfile.lock index dcb304c737..863b38bdb6 100644 --- a/tests/ios/Podfile.lock +++ b/tests/ios/Podfile.lock @@ -498,67 +498,67 @@ PODS: - React-cxxreact (= 0.62.2) - React-jsi (= 0.62.2) - ReactCommon/callinvoker (= 0.62.2) - - RNFBAdMob (7.2.0): + - RNFBAdMob (7.2.2): - Firebase/AdMob (= 6.27.0) - PersonalizedAdConsent (~> 1.0.4) - React - RNFBApp - - RNFBAnalytics (7.1.4): + - RNFBAnalytics (7.1.6): - Firebase/Analytics (= 6.27.0) - React - RNFBApp - - RNFBApp (7.2.1): + - RNFBApp (7.3.1): - Firebase/CoreOnly (= 6.27.0) - React - - RNFBAuth (8.0.6): + - RNFBAuth (8.0.8): - Firebase/Auth (= 6.27.0) - React - RNFBApp - - RNFBCrashlytics (7.1.5): + - RNFBCrashlytics (7.1.7): - Crashlytics (~> 3.14.0) - Fabric (~> 1.10.2) - React - RNFBApp - - RNFBDatabase (7.2.2): + - RNFBDatabase (7.2.5): - Firebase/Database (= 6.27.0) - React - RNFBApp - - RNFBDynamicLinks (7.1.4): + - RNFBDynamicLinks (7.2.1): - Firebase/Analytics (= 6.27.0) - Firebase/DynamicLinks (= 6.27.0) - React - RNFBApp - - RNFBFirestore (7.1.7): + - RNFBFirestore (7.2.2): - Firebase/Firestore (= 6.27.0) - React - RNFBApp - - RNFBFunctions (7.1.4): + - RNFBFunctions (7.1.6): - Firebase/Functions (= 6.27.0) - React - RNFBApp - - RNFBIid (7.1.5): + - RNFBIid (7.1.7): - Firebase/CoreOnly (= 6.27.0) - FirebaseInstanceID - React - RNFBApp - - RNFBInAppMessaging (7.1.4): + - RNFBInAppMessaging (7.1.6): - Firebase/Analytics (= 6.27.0) - Firebase/InAppMessaging (= 6.27.0) - React - RNFBApp - - RNFBMessaging (7.1.6): + - RNFBMessaging (7.1.8): - Firebase/Analytics (= 6.27.0) - Firebase/Messaging (= 6.27.0) - React - RNFBApp - - RNFBMLNaturalLanguage (7.1.4): + - RNFBMLNaturalLanguage (7.1.6): - Firebase/MLCommon (= 6.27.0) - Firebase/MLNaturalLanguage (= 6.27.0) - Firebase/MLNLLanguageID (= 6.27.0) - Firebase/MLNLSmartReply (= 6.27.0) - React - RNFBApp - - RNFBMLVision (7.1.4): + - RNFBMLVision (7.1.7): - Firebase/MLVision (= 6.27.0) - Firebase/MLVisionBarcodeModel (= 6.27.0) - Firebase/MLVisionFaceModel (= 6.27.0) @@ -566,16 +566,16 @@ PODS: - Firebase/MLVisionTextModel (= 6.27.0) - React - RNFBApp - - RNFBPerf (7.1.4): + - RNFBPerf (7.1.6): - Firebase/Performance (= 6.27.0) - React - RNFBApp - - RNFBRemoteConfig (7.1.4): + - RNFBRemoteConfig (7.1.6): - Firebase/Analytics (= 6.27.0) - Firebase/RemoteConfig (= 6.27.0) - React - RNFBApp - - RNFBStorage (7.1.4): + - RNFBStorage (7.1.6): - Firebase/Storage (= 6.27.0) - React - RNFBApp @@ -838,25 +838,25 @@ SPEC CHECKSUMS: React-RCTText: fae545b10cfdb3d247c36c56f61a94cfd6dba41d React-RCTVibration: 4356114dbcba4ce66991096e51a66e61eda51256 ReactCommon: ed4e11d27609d571e7eee8b65548efc191116eb3 - RNFBAdMob: 00cf52cd768017c0fde99a34d90f2e1428b6cb1d - RNFBAnalytics: 96e79f9cd45fe362c06784d1facfbdb6f39bf258 - RNFBApp: 101cfd8809436e6e0cf3edd0bdcf753983269de1 - RNFBAuth: 559fe3bbd9a87c68412fdbee863ea785003480be - RNFBCrashlytics: ce4deb00692924b6c796e438a3c573baf07ed5c8 - RNFBDatabase: 63bb65d7326cd988069080eda35170b5b9deab8f - RNFBDynamicLinks: f133d6ac42db9a85d2b408093dabe0258c70146f - RNFBFirestore: be13988a8d5a6d04501c88040716cc220b4d6101 - RNFBFunctions: cb24c91d35e2dcfe25a79ec581f48aef843f0990 - RNFBIid: d0edec8b1944c3e1701b1de9c5c10864e76b72ca - RNFBInAppMessaging: 0d7ab07fc69b28f913f23347a9bc8b76ec321ed4 - RNFBMessaging: 677fa21a462cf19cdd067b6eb2b6a24db6db2096 - RNFBMLNaturalLanguage: 3b886d483a7c62180a2e221b45fc5d2bca211658 - RNFBMLVision: 8a7777d8c12911469e4cce4331f1b89c92d1a381 - RNFBPerf: f9ade59625fcbfa2d7fde719861b18260741fa3c - RNFBRemoteConfig: 31dd85444f7dd8ec98328b3207f0ec0845a4c1d7 - RNFBStorage: 9aa7e533c475dca7f7fc39a8ea8d00422cfd7c6f + RNFBAdMob: d3b6995d9702e71d37faf7d4cdb5feb96a929da2 + RNFBAnalytics: b86ef349d45139c17b1816111c718f6c297bb858 + RNFBApp: 09f59710d4670eb40274ada7ed83201e768f1c13 + RNFBAuth: 5fd739d7b8d19289970caf462c10cebd85f2b4f9 + RNFBCrashlytics: a4aceced113c1d81c6aed885774b7e648fa2f25b + RNFBDatabase: 8c224caa8fa815997df18ec00474d178be187e02 + RNFBDynamicLinks: 8c667021b47e2436223872d805c5d658223f42a2 + RNFBFirestore: 36549dd426ab175ee4611d125434f6b8b76341a2 + RNFBFunctions: 83f1e88d17cd83b38d9731be7c3a12d4cceadfb9 + RNFBIid: 97255cb4278256a0119776c1926dbb958b046c18 + RNFBInAppMessaging: 5737a93cd3df33229aa00981fe3f7fcba21c9872 + RNFBMessaging: 2929b7242fe325d76e78285fa32928ba619f0601 + RNFBMLNaturalLanguage: 195af1896ef2e78052a4713fde56397bb3f4d31a + RNFBMLVision: 98e4dd64ca3942cc55d947037212631d020d5458 + RNFBPerf: df3f02b19d54f3bbd7a49af23145cf32fa6717a0 + RNFBRemoteConfig: 8976404c7dc69ec2e9f5c8ebd78f2a80d11181ab + RNFBStorage: 0668e2093a1775d78dcea4881207b247e0175896 Yoga: 3ebccbdd559724312790e7742142d062476b698e PODFILE CHECKSUM: 1cbd09c80745bbdb0e6f1ac8f0240d2c4fc031dd -COCOAPODS: 1.9.3 +COCOAPODS: 1.9.1 From 88bfce86273e11700bb6b820f96598a49e6fcc69 Mon Sep 17 00:00:00 2001 From: russellwheatley Date: Wed, 1 Jul 2020 14:43:22 +0100 Subject: [PATCH 3/6] tests(auth): more coverage --- packages/auth/e2e/user.e2e.js | 353 +++++++++++++++++++++++++++++++++- packages/auth/lib/User.js | 8 +- 2 files changed, 355 insertions(+), 6 deletions(-) diff --git a/packages/auth/e2e/user.e2e.js b/packages/auth/e2e/user.e2e.js index e157e64eb8..2862bb86a9 100644 --- a/packages/auth/e2e/user.e2e.js +++ b/packages/auth/e2e/user.e2e.js @@ -154,6 +154,160 @@ describe('auth().currentUser', () => { }); describe('sendEmailVerification()', () => { + it('should error if actionCodeSettings.url is not present', async () => { + const random = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.sendEmailVerification({}); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql("'actionCodeSettings.url' expected a string value."); + await firebase.auth().currentUser.delete(); + } + }); + + it('should error if actionCodeSettings.url is not a string', async () => { + const random = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.sendEmailVerification({ url: 123 }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql("'actionCodeSettings.url' expected a string value."); + await firebase.auth().currentUser.delete(); + } + }); + + it('should error if actionCodeSettings.dynamicLinkDomain is not a string', async () => { + const random = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase + .auth() + .currentUser.sendEmailVerification({ url: 'string', dynamicLinkDomain: 123 }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql( + "'actionCodeSettings.dynamicLinkDomain' expected a string value.", + ); + await firebase.auth().currentUser.delete(); + } + }); + + it('should error if handleCodeInApp is not a string', async () => { + const random = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.sendEmailVerification({ url: 'string', handleCodeInApp: 123 }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql( + "'actionCodeSettings.handleCodeInApp' expected a boolean value.", + ); + await firebase.auth().currentUser.delete(); + } + }); + + it('should error if actionCodeSettings.iOS is not an object', async () => { + const random = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.sendEmailVerification({ url: 'string', iOS: 123 }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql("'actionCodeSettings.iOS' expected an object value."); + await firebase.auth().currentUser.delete(); + } + }); + + it('should error if actionCodeSettings.iOS.bundleId is not a string', async () => { + const random = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase + .auth() + .currentUser.sendEmailVerification({ url: 'string', iOS: { bundleId: 123 } }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql( + "'actionCodeSettings.iOS.bundleId' expected a string value.", + ); + await firebase.auth().currentUser.delete(); + } + }); + + it('should error if actionCodeSettings.android is not an object', async () => { + const random = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.sendEmailVerification({ url: 'string', android: 123 }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql("'actionCodeSettings.android' expected an object value."); + await firebase.auth().currentUser.delete(); + } + }); + + it('should error if actionCodeSettings.android.packageName is not a string', async () => { + const random = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase + .auth() + .currentUser.sendEmailVerification({ url: 'string', android: { packageName: 123 } }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql( + "'actionCodeSettings.android.packageName' expected a string value.", + ); + await firebase.auth().currentUser.delete(); + } + }); + + it('should error if actionCodeSettings.android.installApp is not a string', async () => { + const random = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.sendEmailVerification({ + url: 'string', + android: { packageName: 'packageName', installApp: 123 }, + }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql( + "'actionCodeSettings.android.installApp' expected a boolean value.", + ); + await firebase.auth().currentUser.delete(); + } + }); + + it('should error if actionCodeSettings.android.minimumVersion is not a string', async () => { + const random = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.sendEmailVerification({ + url: 'string', + android: { packageName: 'packageName', minimumVersion: 123 }, + }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql( + "'actionCodeSettings.android.minimumVersion' expected a string value.", + ); + await firebase.auth().currentUser.delete(); + } + }); + it('should not error', async () => { const random = Utils.randString(12, '#aA'); const email = `${random}@${random}.com`; @@ -165,7 +319,7 @@ describe('auth().currentUser', () => { } catch (error) { // Reject try { - await firebase.auth().currentUser.delete(); + // await firebase.auth().currentUser.delete(); } catch (_) { /* do nothing */ } @@ -204,7 +358,202 @@ describe('auth().currentUser', () => { }); }); - describe.only('verifyBeforeUpdateEmail()', () => { + describe('verifyBeforeUpdateEmail()', () => { + it('should error if actionCodeSettings.url is not present', async () => { + const random = Utils.randString(12, '#aA'); + const random2 = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + const updateEmail = `${random2}@${random2}.com`; + + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.verifyBeforeUpdateEmail(updateEmail, {}); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql("'actionCodeSettings.url' expected a string value."); + await firebase.auth().currentUser.delete(); + } + }); + + it('should error if actionCodeSettings.url is not a string', async () => { + const random = Utils.randString(12, '#aA'); + const random2 = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + const updateEmail = `${random2}@${random2}.com`; + + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.verifyBeforeUpdateEmail(updateEmail, { url: 123 }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql("'actionCodeSettings.url' expected a string value."); + await firebase.auth().currentUser.delete(); + } + }); + + it('should error if actionCodeSettings.dynamicLinkDomain is not a string', async () => { + const random = Utils.randString(12, '#aA'); + const random2 = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + const updateEmail = `${random2}@${random2}.com`; + + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.verifyBeforeUpdateEmail(updateEmail, { + url: 'string', + dynamicLinkDomain: 123, + }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql( + "'actionCodeSettings.dynamicLinkDomain' expected a string value.", + ); + await firebase.auth().currentUser.delete(); + } + }); + + it('should error if handleCodeInApp is not a boolean', async () => { + const random = Utils.randString(12, '#aA'); + const random2 = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + const updateEmail = `${random2}@${random2}.com`; + + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.verifyBeforeUpdateEmail(updateEmail, { + url: 'string', + handleCodeInApp: 123, + }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql( + "'actionCodeSettings.handleCodeInApp' expected a boolean value.", + ); + await firebase.auth().currentUser.delete(); + } + }); + + it('should error if actionCodeSettings.iOS is not an object', async () => { + const random = Utils.randString(12, '#aA'); + const random2 = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + const updateEmail = `${random2}@${random2}.com`; + + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.verifyBeforeUpdateEmail(updateEmail, { + url: 'string', + iOS: 123, + }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql("'actionCodeSettings.iOS' expected an object value."); + await firebase.auth().currentUser.delete(); + } + }); + + it('should error if actionCodeSettings.iOS.bundleId is not a string', async () => { + const random = Utils.randString(12, '#aA'); + const random2 = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + const updateEmail = `${random2}@${random2}.com`; + + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.verifyBeforeUpdateEmail(updateEmail, { + url: 'string', + iOS: { bundleId: 123 }, + }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql( + "'actionCodeSettings.iOS.bundleId' expected a string value.", + ); + await firebase.auth().currentUser.delete(); + } + }); + + it('should error if actionCodeSettings.android is not an object', async () => { + const random = Utils.randString(12, '#aA'); + const random2 = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + const updateEmail = `${random2}@${random2}.com`; + + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.verifyBeforeUpdateEmail(updateEmail, { + url: 'string', + android: 123, + }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql("'actionCodeSettings.android' expected an object value."); + await firebase.auth().currentUser.delete(); + } + }); + + it('should error if actionCodeSettings.android.packageName is not a string', async () => { + const random = Utils.randString(12, '#aA'); + const random2 = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + const updateEmail = `${random2}@${random2}.com`; + + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.verifyBeforeUpdateEmail(updateEmail, { + url: 'string', + android: { packageName: 123 }, + }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql( + "'actionCodeSettings.android.packageName' expected a string value.", + ); + await firebase.auth().currentUser.delete(); + } + }); + + it('should error if actionCodeSettings.android.installApp is not a boolean', async () => { + const random = Utils.randString(12, '#aA'); + const random2 = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + const updateEmail = `${random2}@${random2}.com`; + + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.verifyBeforeUpdateEmail(updateEmail, { + url: 'string', + android: { packageName: 'string', installApp: 123 }, + }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql( + "'actionCodeSettings.android.installApp' expected a boolean value.", + ); + await firebase.auth().currentUser.delete(); + } + }); + + it('should error if actionCodeSettings.android.minimumVersion is not a string', async () => { + const random = Utils.randString(12, '#aA'); + const random2 = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + const updateEmail = `${random2}@${random2}.com`; + + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.verifyBeforeUpdateEmail(updateEmail, { + url: 'string', + android: { packageName: 'string', minimumVersion: 123 }, + }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql( + "'actionCodeSettings.android.minimumVersion' expected a string value.", + ); + await firebase.auth().currentUser.delete(); + } + }); it('should not error', async () => { const random = Utils.randString(12, '#aA'); const random2 = Utils.randString(12, '#aA'); diff --git a/packages/auth/lib/User.js b/packages/auth/lib/User.js index 8534da2686..7a8276f9be 100644 --- a/packages/auth/lib/User.js +++ b/packages/auth/lib/User.js @@ -113,7 +113,7 @@ export default class User { !isString(actionCodeSettings.dynamicLinkDomain) ) { throw new Error( - "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.dynamicLinkDomain' expected an string value.", + "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.dynamicLinkDomain' expected a string value.", ); } @@ -122,7 +122,7 @@ export default class User { !isBoolean(actionCodeSettings.handleCodeInApp) ) { throw new Error( - "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.handleCodeInApp' expected an boolean value.", + "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.handleCodeInApp' expected a boolean value.", ); } @@ -223,7 +223,7 @@ export default class User { !isString(actionCodeSettings.dynamicLinkDomain) ) { throw new Error( - "firebase.auth.User.verifyBeforeUpdateEmail(*) 'actionCodeSettings.dynamicLinkDomain' expected an string value.", + "firebase.auth.User.verifyBeforeUpdateEmail(*) 'actionCodeSettings.dynamicLinkDomain' expected a string value.", ); } @@ -232,7 +232,7 @@ export default class User { !isBoolean(actionCodeSettings.handleCodeInApp) ) { throw new Error( - "firebase.auth.User.verifyBeforeUpdateEmail(*) 'actionCodeSettings.handleCodeInApp' expected an boolean value.", + "firebase.auth.User.verifyBeforeUpdateEmail(*) 'actionCodeSettings.handleCodeInApp' expected a boolean value.", ); } From 62eaf372c91688334f90aee37cdc656cd0d4778c Mon Sep 17 00:00:00 2001 From: russellwheatley Date: Fri, 3 Jul 2020 14:28:06 +0100 Subject: [PATCH 4/6] chore(ios): update podfile.lock --- tests/ios/Podfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/ios/Podfile.lock b/tests/ios/Podfile.lock index b6d97d7d59..1b6074893c 100644 --- a/tests/ios/Podfile.lock +++ b/tests/ios/Podfile.lock @@ -220,9 +220,9 @@ PODS: - glog (0.3.5) - Google-Mobile-Ads-SDK (7.61.0): - GoogleAppMeasurement (~> 6.0) - - GoogleAPIClientForREST/Core (1.4.2): + - GoogleAPIClientForREST/Core (1.4.1): - GTMSessionFetcher (>= 1.1.7) - - GoogleAPIClientForREST/Vision (1.4.2): + - GoogleAPIClientForREST/Vision (1.4.1): - GoogleAPIClientForREST/Core - GTMSessionFetcher (>= 1.1.7) - GoogleAppMeasurement (6.6.1): @@ -811,7 +811,7 @@ SPEC CHECKSUMS: Folly: 30e7936e1c45c08d884aa59369ed951a8e68cf51 glog: 1f3da668190260b06b429bb211bfbee5cd790c28 Google-Mobile-Ads-SDK: 4c3b24b04293b4bb370b2cb392cdd3ee97c87752 - GoogleAPIClientForREST: 9f49df9fac7867b459187e687fed3066b2be049a + GoogleAPIClientForREST: e50dc3267b3131ee3a25e707c10204f6bec15ae9 GoogleAppMeasurement: 2fd5c5a56c069db635c8e7b92d4809a9591d0a69 GoogleDataTransport: 9a8a16f79feffc7f42096743de2a7c4815e84020 GoogleDataTransportCCTSupport: 489c1265d2c85b68187a83a911913d190012158d From 173fc90da48eda797f351a174fa1f06ebb6732ed Mon Sep 17 00:00:00 2001 From: russellwheatley Date: Fri, 3 Jul 2020 15:20:47 +0100 Subject: [PATCH 5/6] tests(auth): update verifyBeforeUpdateEmail tests --- packages/auth/e2e/user.e2e.js | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/packages/auth/e2e/user.e2e.js b/packages/auth/e2e/user.e2e.js index 2862bb86a9..cd55a68747 100644 --- a/packages/auth/e2e/user.e2e.js +++ b/packages/auth/e2e/user.e2e.js @@ -563,16 +563,27 @@ describe('auth().currentUser', () => { try { await firebase.auth().createUserWithEmailAndPassword(email, random); await firebase.auth().currentUser.verifyBeforeUpdateEmail(updateEmail); - // TODO is there a way to test? Need to hit the link sent to the email for email to change - // const currentEmail = firebase.auth().currentUser.email; - // should(currentEmail).equal(updateEmail); + } catch (_) { + return Promise.reject("'verifyBeforeUpdateEmail()' did not work"); } finally { await firebase.auth().currentUser.delete(); } }); it('should work with actionCodeSettings', async () => { - //TODO test with actionCodeSettings as well + const random = Utils.randString(12, '#aA'); + const random2 = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + const updateEmail = `${random2}@${random2}.com`; + const actionCodeSettings = { url: 'https://invertase.io' }; + try { + await firebase.auth().createUserWithEmailAndPassword(email, random); + await firebase.auth().currentUser.verifyBeforeUpdateEmail(updateEmail, actionCodeSettings); + } catch (_) { + return Promise.reject("'verifyBeforeUpdateEmail()' with 'actionCodeSettings' did not work"); + } finally { + await firebase.auth().currentUser.delete(); + } }); }); From 6f83961d043175ed5465c1ea28f38765581b38e5 Mon Sep 17 00:00:00 2001 From: russellwheatley Date: Fri, 10 Jul 2020 11:11:20 +0100 Subject: [PATCH 6/6] tests(auth): verifyBeforeUpdateEmail updates --- packages/auth/e2e/user.e2e.js | 75 ++++++++++++++++++++++------------- packages/auth/lib/User.js | 24 ++++++----- 2 files changed, 62 insertions(+), 37 deletions(-) diff --git a/packages/auth/e2e/user.e2e.js b/packages/auth/e2e/user.e2e.js index cd55a68747..5c6602b48d 100644 --- a/packages/auth/e2e/user.e2e.js +++ b/packages/auth/e2e/user.e2e.js @@ -163,8 +163,8 @@ describe('auth().currentUser', () => { return Promise.reject(new Error('it did not error')); } catch (error) { error.message.should.containEql("'actionCodeSettings.url' expected a string value."); - await firebase.auth().currentUser.delete(); } + await firebase.auth().currentUser.delete(); }); it('should error if actionCodeSettings.url is not a string', async () => { @@ -176,8 +176,8 @@ describe('auth().currentUser', () => { return Promise.reject(new Error('it did not error')); } catch (error) { error.message.should.containEql("'actionCodeSettings.url' expected a string value."); - await firebase.auth().currentUser.delete(); } + await firebase.auth().currentUser.delete(); }); it('should error if actionCodeSettings.dynamicLinkDomain is not a string', async () => { @@ -193,8 +193,8 @@ describe('auth().currentUser', () => { error.message.should.containEql( "'actionCodeSettings.dynamicLinkDomain' expected a string value.", ); - await firebase.auth().currentUser.delete(); } + await firebase.auth().currentUser.delete(); }); it('should error if handleCodeInApp is not a string', async () => { @@ -208,8 +208,8 @@ describe('auth().currentUser', () => { error.message.should.containEql( "'actionCodeSettings.handleCodeInApp' expected a boolean value.", ); - await firebase.auth().currentUser.delete(); } + await firebase.auth().currentUser.delete(); }); it('should error if actionCodeSettings.iOS is not an object', async () => { @@ -221,8 +221,8 @@ describe('auth().currentUser', () => { return Promise.reject(new Error('it did not error')); } catch (error) { error.message.should.containEql("'actionCodeSettings.iOS' expected an object value."); - await firebase.auth().currentUser.delete(); } + await firebase.auth().currentUser.delete(); }); it('should error if actionCodeSettings.iOS.bundleId is not a string', async () => { @@ -238,8 +238,8 @@ describe('auth().currentUser', () => { error.message.should.containEql( "'actionCodeSettings.iOS.bundleId' expected a string value.", ); - await firebase.auth().currentUser.delete(); } + await firebase.auth().currentUser.delete(); }); it('should error if actionCodeSettings.android is not an object', async () => { @@ -251,8 +251,8 @@ describe('auth().currentUser', () => { return Promise.reject(new Error('it did not error')); } catch (error) { error.message.should.containEql("'actionCodeSettings.android' expected an object value."); - await firebase.auth().currentUser.delete(); } + await firebase.auth().currentUser.delete(); }); it('should error if actionCodeSettings.android.packageName is not a string', async () => { @@ -268,8 +268,8 @@ describe('auth().currentUser', () => { error.message.should.containEql( "'actionCodeSettings.android.packageName' expected a string value.", ); - await firebase.auth().currentUser.delete(); } + await firebase.auth().currentUser.delete(); }); it('should error if actionCodeSettings.android.installApp is not a string', async () => { @@ -286,8 +286,8 @@ describe('auth().currentUser', () => { error.message.should.containEql( "'actionCodeSettings.android.installApp' expected a boolean value.", ); - await firebase.auth().currentUser.delete(); } + await firebase.auth().currentUser.delete(); }); it('should error if actionCodeSettings.android.minimumVersion is not a string', async () => { @@ -304,8 +304,8 @@ describe('auth().currentUser', () => { error.message.should.containEql( "'actionCodeSettings.android.minimumVersion' expected a string value.", ); - await firebase.auth().currentUser.delete(); } + await firebase.auth().currentUser.delete(); }); it('should not error', async () => { @@ -319,7 +319,7 @@ describe('auth().currentUser', () => { } catch (error) { // Reject try { - // await firebase.auth().currentUser.delete(); + await firebase.auth().currentUser.delete(); } catch (_) { /* do nothing */ } @@ -359,6 +359,19 @@ describe('auth().currentUser', () => { }); describe('verifyBeforeUpdateEmail()', () => { + it('should error if newEmail is not a string', async () => { + const random = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.verifyBeforeUpdateEmail(123); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql("'newEmail' expected a string value"); + } + await firebase.auth().currentUser.delete(); + }); it('should error if actionCodeSettings.url is not present', async () => { const random = Utils.randString(12, '#aA'); const random2 = Utils.randString(12, '#aA'); @@ -371,8 +384,8 @@ describe('auth().currentUser', () => { return Promise.reject(new Error('it did not error')); } catch (error) { error.message.should.containEql("'actionCodeSettings.url' expected a string value."); - await firebase.auth().currentUser.delete(); } + await firebase.auth().currentUser.delete(); }); it('should error if actionCodeSettings.url is not a string', async () => { @@ -387,8 +400,8 @@ describe('auth().currentUser', () => { return Promise.reject(new Error('it did not error')); } catch (error) { error.message.should.containEql("'actionCodeSettings.url' expected a string value."); - await firebase.auth().currentUser.delete(); } + await firebase.auth().currentUser.delete(); }); it('should error if actionCodeSettings.dynamicLinkDomain is not a string', async () => { @@ -408,8 +421,8 @@ describe('auth().currentUser', () => { error.message.should.containEql( "'actionCodeSettings.dynamicLinkDomain' expected a string value.", ); - await firebase.auth().currentUser.delete(); } + await firebase.auth().currentUser.delete(); }); it('should error if handleCodeInApp is not a boolean', async () => { @@ -429,8 +442,8 @@ describe('auth().currentUser', () => { error.message.should.containEql( "'actionCodeSettings.handleCodeInApp' expected a boolean value.", ); - await firebase.auth().currentUser.delete(); } + await firebase.auth().currentUser.delete(); }); it('should error if actionCodeSettings.iOS is not an object', async () => { @@ -448,8 +461,8 @@ describe('auth().currentUser', () => { return Promise.reject(new Error('it did not error')); } catch (error) { error.message.should.containEql("'actionCodeSettings.iOS' expected an object value."); - await firebase.auth().currentUser.delete(); } + await firebase.auth().currentUser.delete(); }); it('should error if actionCodeSettings.iOS.bundleId is not a string', async () => { @@ -469,8 +482,8 @@ describe('auth().currentUser', () => { error.message.should.containEql( "'actionCodeSettings.iOS.bundleId' expected a string value.", ); - await firebase.auth().currentUser.delete(); } + await firebase.auth().currentUser.delete(); }); it('should error if actionCodeSettings.android is not an object', async () => { @@ -488,8 +501,8 @@ describe('auth().currentUser', () => { return Promise.reject(new Error('it did not error')); } catch (error) { error.message.should.containEql("'actionCodeSettings.android' expected an object value."); - await firebase.auth().currentUser.delete(); } + await firebase.auth().currentUser.delete(); }); it('should error if actionCodeSettings.android.packageName is not a string', async () => { @@ -509,8 +522,8 @@ describe('auth().currentUser', () => { error.message.should.containEql( "'actionCodeSettings.android.packageName' expected a string value.", ); - await firebase.auth().currentUser.delete(); } + await firebase.auth().currentUser.delete(); }); it('should error if actionCodeSettings.android.installApp is not a boolean', async () => { @@ -530,8 +543,8 @@ describe('auth().currentUser', () => { error.message.should.containEql( "'actionCodeSettings.android.installApp' expected a boolean value.", ); - await firebase.auth().currentUser.delete(); } + await firebase.auth().currentUser.delete(); }); it('should error if actionCodeSettings.android.minimumVersion is not a string', async () => { @@ -551,8 +564,8 @@ describe('auth().currentUser', () => { error.message.should.containEql( "'actionCodeSettings.android.minimumVersion' expected a string value.", ); - await firebase.auth().currentUser.delete(); } + await firebase.auth().currentUser.delete(); }); it('should not error', async () => { const random = Utils.randString(12, '#aA'); @@ -565,9 +578,8 @@ describe('auth().currentUser', () => { await firebase.auth().currentUser.verifyBeforeUpdateEmail(updateEmail); } catch (_) { return Promise.reject("'verifyBeforeUpdateEmail()' did not work"); - } finally { - await firebase.auth().currentUser.delete(); } + await firebase.auth().currentUser.delete(); }); it('should work with actionCodeSettings', async () => { @@ -575,18 +587,25 @@ describe('auth().currentUser', () => { const random2 = Utils.randString(12, '#aA'); const email = `${random}@${random}.com`; const updateEmail = `${random2}@${random2}.com`; - const actionCodeSettings = { url: 'https://invertase.io' }; + const actionCodeSettings = { + url: 'https://react-native-firebase-testing.firebaseapp.com/foo', + }; try { await firebase.auth().createUserWithEmailAndPassword(email, random); await firebase.auth().currentUser.verifyBeforeUpdateEmail(updateEmail, actionCodeSettings); - } catch (_) { - return Promise.reject("'verifyBeforeUpdateEmail()' with 'actionCodeSettings' did not work"); - } finally { await firebase.auth().currentUser.delete(); + } catch (error) { + try { + await firebase.auth().currentUser.delete(); + } catch (_) { + /* do nothing */ + } + + return Promise.reject("'verifyBeforeUpdateEmail()' with 'actionCodeSettings' did not work"); } + return Promise.resolve(); }); }); - describe('unlink()', () => { it('should unlink the email address', async () => { const random = Utils.randString(12, '#aA'); diff --git a/packages/auth/lib/User.js b/packages/auth/lib/User.js index 7a8276f9be..179a50c8a1 100644 --- a/packages/auth/lib/User.js +++ b/packages/auth/lib/User.js @@ -211,10 +211,16 @@ export default class User { } verifyBeforeUpdateEmail(newEmail, actionCodeSettings) { + if (!isString(newEmail)) { + throw new Error( + "firebase.auth.User.verifyBeforeUpdateEmail(*) 'newEmail' expected a string value.", + ); + } + if (isObject(actionCodeSettings)) { if (!isString(actionCodeSettings.url)) { throw new Error( - "firebase.auth.User.verifyBeforeUpdateEmail(*) 'actionCodeSettings.url' expected a string value.", + "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.url' expected a string value.", ); } @@ -223,7 +229,7 @@ export default class User { !isString(actionCodeSettings.dynamicLinkDomain) ) { throw new Error( - "firebase.auth.User.verifyBeforeUpdateEmail(*) 'actionCodeSettings.dynamicLinkDomain' expected a string value.", + "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.dynamicLinkDomain' expected a string value.", ); } @@ -232,19 +238,19 @@ export default class User { !isBoolean(actionCodeSettings.handleCodeInApp) ) { throw new Error( - "firebase.auth.User.verifyBeforeUpdateEmail(*) 'actionCodeSettings.handleCodeInApp' expected a boolean value.", + "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.handleCodeInApp' expected a boolean value.", ); } if (!isUndefined(actionCodeSettings.iOS)) { if (!isObject(actionCodeSettings.iOS)) { throw new Error( - "firebase.auth.User.verifyBeforeUpdateEmail(*) 'actionCodeSettings.iOS' expected an object value.", + "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.iOS' expected an object value.", ); } if (!isString(actionCodeSettings.iOS.bundleId)) { throw new Error( - "firebase.auth.User.verifyBeforeUpdateEmail(*) 'actionCodeSettings.iOS.bundleId' expected a string value.", + "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.iOS.bundleId' expected a string value.", ); } } @@ -252,12 +258,12 @@ export default class User { if (!isUndefined(actionCodeSettings.android)) { if (!isObject(actionCodeSettings.android)) { throw new Error( - "firebase.auth.User.verifyBeforeUpdateEmail(*) 'actionCodeSettings.android' expected an object value.", + "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.android' expected an object value.", ); } if (!isString(actionCodeSettings.android.packageName)) { throw new Error( - "firebase.auth.User.verifyBeforeUpdateEmail(*) 'actionCodeSettings.android.packageName' expected a string value.", + "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.android.packageName' expected a string value.", ); } @@ -266,7 +272,7 @@ export default class User { !isBoolean(actionCodeSettings.android.installApp) ) { throw new Error( - "firebase.auth.User.verifyBeforeUpdateEmail(*) 'actionCodeSettings.android.installApp' expected a boolean value.", + "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.android.installApp' expected a boolean value.", ); } @@ -275,7 +281,7 @@ export default class User { !isString(actionCodeSettings.android.minimumVersion) ) { throw new Error( - "firebase.auth.User.verifyBeforeUpdateEmail(*) 'actionCodeSettings.android.minimumVersion' expected a string value.", + "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.android.minimumVersion' expected a string value.", ); } }