diff --git a/packages/firebase_core/firebase_core/ios/firebase_sdk_version.rb b/packages/firebase_core/firebase_core/ios/firebase_sdk_version.rb index 69abc85daeaa..d28f4a899f17 100644 --- a/packages/firebase_core/firebase_core/ios/firebase_sdk_version.rb +++ b/packages/firebase_core/firebase_core/ios/firebase_sdk_version.rb @@ -1,4 +1,4 @@ # https://firebase.google.com/support/release-notes/ios def firebase_sdk_version!() - '10.3.0' + '10.5.0' end diff --git a/packages/firebase_messaging/firebase_messaging/ios/Classes/FLTFirebaseMessagingPlugin.m b/packages/firebase_messaging/firebase_messaging/ios/Classes/FLTFirebaseMessagingPlugin.m index 0eb52b11b41b..c3937753d2bf 100644 --- a/packages/firebase_messaging/firebase_messaging/ios/Classes/FLTFirebaseMessagingPlugin.m +++ b/packages/firebase_messaging/firebase_messaging/ios/Classes/FLTFirebaseMessagingPlugin.m @@ -22,6 +22,7 @@ @implementation FLTFirebaseMessagingPlugin { NSObject *_registrar; NSData *_apnsToken; NSDictionary *_initialNotification; + bool simulatorToken; // Used to track if everything as been initialized before answering // to the initialNotification request @@ -52,6 +53,7 @@ - (instancetype)initWithFlutterMethodChannel:(FlutterMethodChannel *)channel _initialNotificationGathered = NO; _channel = channel; _registrar = registrar; + simulatorToken = false; // Application // Dart -> `getInitialNotification` // ObjC -> Initialize other delegates & observers @@ -998,6 +1000,22 @@ + (NSDictionary *)remoteMessageUserInfoToDict:(NSDictionary *)userInfo { - (void)ensureAPNSTokenSetting { FIRMessaging *messaging = [FIRMessaging messaging]; + // With iOS SDK >= 10.4, an APNS token is required for getting/deleting token. We set a dummy + // token for the simulator for test environments. Historically, a simulator will not work for + // messaging. It will work if environment: iOS 16, running on macOS 13+ & silicon chip. We check + // the `_apnsToken` is nil. If it is, then the environment does not support and we set dummy + // token. +#if TARGET_IPHONE_SIMULATOR + if (simulatorToken == false && _apnsToken == nil) { + NSString *str = @"fake-apns-token-for-simulator"; + NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding]; + [[FIRMessaging messaging] setAPNSToken:data type:FIRMessagingAPNSTokenTypeSandbox]; + } + // We set this either way. We set dummy token once as `_apnsToken` could be nil next time + // which could possibly set dummy token unnecessarily + simulatorToken = true; +#endif + if (messaging.APNSToken == nil && _apnsToken != nil) { #ifdef DEBUG [[FIRMessaging messaging] setAPNSToken:_apnsToken type:FIRMessagingAPNSTokenTypeSandbox]; diff --git a/tests/integration_test/firebase_auth/firebase_auth_instance_e2e_test.dart b/tests/integration_test/firebase_auth/firebase_auth_instance_e2e_test.dart index c2eedf8d61cb..52fb6534a86d 100644 --- a/tests/integration_test/firebase_auth/firebase_auth_instance_e2e_test.dart +++ b/tests/integration_test/firebase_auth/firebase_auth_instance_e2e_test.dart @@ -16,854 +16,867 @@ import './test_utils.dart'; void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - group('FirebaseAuth.instance', () { - Future commonSuccessCallback(currentUserCredential) async { - var currentUser = currentUserCredential.user; - - expect(currentUser, isInstanceOf()); - expect(currentUser.uid, isInstanceOf()); - expect(currentUser.email, equals(testEmail)); - expect(currentUser.isAnonymous, isFalse); - expect(currentUser.uid, equals(FirebaseAuth.instance.currentUser!.uid)); - - var additionalUserInfo = currentUserCredential.additionalUserInfo; - expect(additionalUserInfo, isInstanceOf()); - expect(additionalUserInfo.isNewUser, isFalse); - - await FirebaseAuth.instance.signOut(); - } - - group('authStateChanges()', () { - StreamSubscription? subscription; - StreamSubscription? subscription2; - - tearDown(() async { - await subscription?.cancel(); - await ensureSignedOut(); - - if (subscription2 != null) { - await Future.delayed(const Duration(seconds: 5)); - await subscription2.cancel(); - } - }); - - test('calls callback with the current user and when auth state changes', - () async { - await ensureSignedIn(testEmail); - String uid = FirebaseAuth.instance.currentUser!.uid; - - Stream stream = FirebaseAuth.instance.authStateChanges(); - int call = 0; - - subscription = stream.listen( - expectAsync1( - (User? user) { - call++; - if (call == 1) { - expect(user!.uid, isA()); - expect(user.uid, equals(uid)); // initial user - } else if (call == 2) { - expect(user, isNull); // logged out - } else if (call == 3) { - expect(user!.uid, isA()); - expect(user.uid != uid, isTrue); // anonymous user - } else { - fail('Should not have been called'); - } - }, - count: 3, - reason: 'Stream should only have been called 3 times', - ), - ); + group( + 'FirebaseAuth.instance', + () { + Future commonSuccessCallback(currentUserCredential) async { + var currentUser = currentUserCredential.user; + + expect(currentUser, isInstanceOf()); + expect(currentUser.uid, isInstanceOf()); + expect(currentUser.email, equals(testEmail)); + expect(currentUser.isAnonymous, isFalse); + expect(currentUser.uid, equals(FirebaseAuth.instance.currentUser!.uid)); + + var additionalUserInfo = currentUserCredential.additionalUserInfo; + expect(additionalUserInfo, isInstanceOf()); + expect(additionalUserInfo.isNewUser, isFalse); - // Prevent race condition where signOut is called before the stream hits await FirebaseAuth.instance.signOut(); - await FirebaseAuth.instance.signInAnonymously(); - }); - }); + } - group('idTokenChanges()', () { - StreamSubscription? subscription; - StreamSubscription? subscription2; + group('authStateChanges()', () { + StreamSubscription? subscription; + StreamSubscription? subscription2; - tearDown(() async { - await subscription?.cancel(); - await ensureSignedOut(); + tearDown(() async { + await subscription?.cancel(); + await ensureSignedOut(); - if (subscription2 != null) { - await Future.delayed(const Duration(seconds: 5)); - await subscription2.cancel(); - } - }); + if (subscription2 != null) { + await Future.delayed(const Duration(seconds: 5)); + await subscription2.cancel(); + } + }); - test('calls callback with the current user and when auth state changes', - () async { - await ensureSignedIn(testEmail); - String uid = FirebaseAuth.instance.currentUser!.uid; - - Stream stream = FirebaseAuth.instance.idTokenChanges(); - int call = 0; - - subscription = stream.listen( - expectAsync1( - (User? user) { - call++; - if (call == 1) { - expect(user!.uid, equals(uid)); // initial user - } else if (call == 2) { - expect(user, isNull); // logged out - } else if (call == 3) { - expect(user!.uid, isA()); - expect(user.uid != uid, isTrue); // anonymous user - } else { - fail('Should not have been called'); - } - }, - count: 3, - reason: 'Stream should only have been called 3 times', - ), - ); + test('calls callback with the current user and when auth state changes', + () async { + await ensureSignedIn(testEmail); + String uid = FirebaseAuth.instance.currentUser!.uid; + + Stream stream = FirebaseAuth.instance.authStateChanges(); + int call = 0; + + subscription = stream.listen( + expectAsync1( + (User? user) { + call++; + if (call == 1) { + expect(user!.uid, isA()); + expect(user.uid, equals(uid)); // initial user + } else if (call == 2) { + expect(user, isNull); // logged out + } else if (call == 3) { + expect(user!.uid, isA()); + expect(user.uid != uid, isTrue); // anonymous user + } else { + fail('Should not have been called'); + } + }, + count: 3, + reason: 'Stream should only have been called 3 times', + ), + ); - // Prevent race condition where signOut is called before the stream hits - await FirebaseAuth.instance.signOut(); - await FirebaseAuth.instance.signInAnonymously(); + // Prevent race condition where signOut is called before the stream hits + await FirebaseAuth.instance.signOut(); + await FirebaseAuth.instance.signInAnonymously(); + }); }); - }); - group('userChanges()', () { - late StreamSubscription subscription; - tearDown(() async { - await subscription.cancel(); - }); + group('idTokenChanges()', () { + StreamSubscription? subscription; + StreamSubscription? subscription2; - test('fires once on first initialization of FirebaseAuth', () async { - // Fixes a very specific bug: https://github.com/firebase/flutterfire/issues/3628 - // If the first initialization of FirebaseAuth involves the listeners userChanges() or idTokenChanges() - // the user will receive two events. Why? The native SDK listener will always fire an event upon initial - // listen. FirebaseAuth also sends an initial synthetic event. We send a synthetic event because, ordinarily, the user will - // not use a listener as the first occurrence of FirebaseAuth. We, therefore, mimic native behavior by sending an - // event. This test proves the logic of PR: https://github.com/firebase/flutterfire/pull/6560 - - // Requires a fresh app. - FirebaseApp second = await Firebase.initializeApp( - name: 'test-init', - options: DefaultFirebaseOptions.currentPlatform, - ); + tearDown(() async { + await subscription?.cancel(); + await ensureSignedOut(); - Stream stream = - FirebaseAuth.instanceFor(app: second).userChanges(); - - subscription = stream.listen( - expectAsync1( - (User? user) {}, - count: 1, - reason: 'Stream should only call once', - ), - ); - - await Future.delayed(const Duration(seconds: 2)); - }); - - test('calls callback with the current user and when user state changes', - () async { - await ensureSignedIn(testEmail); - - Stream stream = FirebaseAuth.instance.userChanges(); - int call = 0; - - subscription = stream.listen( - expectAsync1( - (User? user) { - call++; - if (call == 1) { - expect(user!.displayName, isNull); // initial user - } else if (call == 2) { - expect( - user!.displayName, - equals('updatedName'), - ); // updated profile - } else { - fail('Should not have been called'); - } - }, - count: 2, - reason: 'Stream should only have been called 2 times', - ), - ); - - await FirebaseAuth.instance.currentUser! - .updateDisplayName('updatedName'); + if (subscription2 != null) { + await Future.delayed(const Duration(seconds: 5)); + await subscription2.cancel(); + } + }); - expect( - FirebaseAuth.instance.currentUser!.displayName, - equals('updatedName'), - ); - }); - }); + test('calls callback with the current user and when auth state changes', + () async { + await ensureSignedIn(testEmail); + String uid = FirebaseAuth.instance.currentUser!.uid; + + Stream stream = FirebaseAuth.instance.idTokenChanges(); + int call = 0; + + subscription = stream.listen( + expectAsync1( + (User? user) { + call++; + if (call == 1) { + expect(user!.uid, equals(uid)); // initial user + } else if (call == 2) { + expect(user, isNull); // logged out + } else if (call == 3) { + expect(user!.uid, isA()); + expect(user.uid != uid, isTrue); // anonymous user + } else { + fail('Should not have been called'); + } + }, + count: 3, + reason: 'Stream should only have been called 3 times', + ), + ); - group('currentUser', () { - test('should return currentUser', () async { - await ensureSignedIn(testEmail); - var currentUser = FirebaseAuth.instance.currentUser; - expect(currentUser, isA()); - }); - }); - - group('applyActionCode', () { - test('throws if invalid code', () async { - try { - await FirebaseAuth.instance.applyActionCode('!!!!!!'); - fail('Should have thrown'); - } on FirebaseException catch (e) { - expect(e.code, equals('invalid-action-code')); - } catch (e) { - fail(e.toString()); - } - }); - }); - - group('checkActionCode()', () { - test('throws on invalid code', () async { - try { - await FirebaseAuth.instance.checkActionCode('!!!!!!'); - fail('Should have thrown'); - } on FirebaseException catch (e) { - expect(e.code, equals('invalid-action-code')); - } catch (e) { - fail(e.toString()); - } + // Prevent race condition where signOut is called before the stream hits + await FirebaseAuth.instance.signOut(); + await FirebaseAuth.instance.signInAnonymously(); + }); }); - }); - group('confirmPasswordReset()', () { - test('throws on invalid code', () async { - try { - await FirebaseAuth.instance - .confirmPasswordReset(code: '!!!!!!', newPassword: 'thingamajig'); - fail('Should have thrown'); - } on FirebaseException catch (e) { - expect(e.code, equals('invalid-action-code')); - } catch (e) { - fail(e.toString()); - } - }); - }); + group('userChanges()', () { + late StreamSubscription subscription; + tearDown(() async { + await subscription.cancel(); + }); - group('createUserWithEmailAndPassword', () { - test('should create a user with an email and password', () async { - var email = generateRandomEmail(); + test('fires once on first initialization of FirebaseAuth', () async { + // Fixes a very specific bug: https://github.com/firebase/flutterfire/issues/3628 + // If the first initialization of FirebaseAuth involves the listeners userChanges() or idTokenChanges() + // the user will receive two events. Why? The native SDK listener will always fire an event upon initial + // listen. FirebaseAuth also sends an initial synthetic event. We send a synthetic event because, ordinarily, the user will + // not use a listener as the first occurrence of FirebaseAuth. We, therefore, mimic native behavior by sending an + // event. This test proves the logic of PR: https://github.com/firebase/flutterfire/pull/6560 + + // Requires a fresh app. + FirebaseApp second = await Firebase.initializeApp( + name: 'test-init', + options: DefaultFirebaseOptions.currentPlatform, + ); - Function successCallback = (UserCredential newUserCredential) async { - expect(newUserCredential.user, isA()); - User newUser = newUserCredential.user!; + Stream stream = + FirebaseAuth.instanceFor(app: second).userChanges(); - expect(newUser.uid, isA()); - expect(newUser.email, equals(email)); - expect(newUser.emailVerified, isFalse); - expect(newUser.isAnonymous, isFalse); - expect(newUser.uid, equals(FirebaseAuth.instance.currentUser!.uid)); + subscription = stream.listen( + expectAsync1( + (User? user) {}, + count: 1, + reason: 'Stream should only call once', + ), + ); - var additionalUserInfo = newUserCredential.additionalUserInfo!; - expect(additionalUserInfo, isA()); - expect(additionalUserInfo.isNewUser, isTrue); + await Future.delayed(const Duration(seconds: 2)); + }); - await FirebaseAuth.instance.currentUser?.delete(); - }; + test('calls callback with the current user and when user state changes', + () async { + await ensureSignedIn(testEmail); + + Stream stream = FirebaseAuth.instance.userChanges(); + int call = 0; + + subscription = stream.listen( + expectAsync1( + (User? user) { + call++; + if (call == 1) { + expect(user!.displayName, isNull); // initial user + } else if (call == 2) { + expect( + user!.displayName, + equals('updatedName'), + ); // updated profile + } else { + fail('Should not have been called'); + } + }, + count: 2, + reason: 'Stream should only have been called 2 times', + ), + ); - await FirebaseAuth.instance - .createUserWithEmailAndPassword( - email: email, - password: testPassword, - ) - .then(successCallback as Function(UserCredential)); - }); + await FirebaseAuth.instance.currentUser! + .updateDisplayName('updatedName'); - test('fails if creating a user which already exists', () async { - await ensureSignedIn(testEmail); - try { - await FirebaseAuth.instance.createUserWithEmailAndPassword( - email: testEmail, - password: '123456', + expect( + FirebaseAuth.instance.currentUser!.displayName, + equals('updatedName'), ); - fail('Should have thrown FirebaseAuthException'); - } on FirebaseAuthException catch (e) { - expect(e.code, equals('email-already-in-use')); - } catch (e) { - fail(e.toString()); - } + }); }); - test('fails if creating a user with an invalid email', () async { - await ensureSignedIn(testEmail); - try { - await FirebaseAuth.instance.createUserWithEmailAndPassword( - email: '!!!!!', - password: '123456', - ); - fail('Should have thrown FirebaseAuthException'); - } on FirebaseAuthException catch (e) { - expect(e.code, equals('invalid-email')); - } catch (e) { - fail(e.toString()); - } + group('currentUser', () { + test('should return currentUser', () async { + await ensureSignedIn(testEmail); + var currentUser = FirebaseAuth.instance.currentUser; + expect(currentUser, isA()); + }); }); - test('fails if creating a user if providing a weak password', () async { - await ensureSignedIn(testEmail); - try { - await FirebaseAuth.instance.createUserWithEmailAndPassword( - email: generateRandomEmail(), - password: '1', - ); - fail('Should have thrown FirebaseAuthException'); - } on FirebaseAuthException catch (e) { - expect(e.code, equals('weak-password')); - } catch (e) { - fail(e.toString()); - } - }); - }); - - group('fetchSignInMethodsForEmail()', () { - test('should return password provider for an email address', () async { - var providers = - await FirebaseAuth.instance.fetchSignInMethodsForEmail(testEmail); - expect(providers, isList); - expect(providers.contains('password'), isTrue); + group('applyActionCode', () { + test('throws if invalid code', () async { + try { + await FirebaseAuth.instance.applyActionCode('!!!!!!'); + fail('Should have thrown'); + } on FirebaseException catch (e) { + expect(e.code, equals('invalid-action-code')); + } catch (e) { + fail(e.toString()); + } + }); }); - test('should return empty array for a not found email', () async { - var providers = await FirebaseAuth.instance - .fetchSignInMethodsForEmail(generateRandomEmail()); - - expect(providers, isList); - expect(providers, isEmpty); + group('checkActionCode()', () { + test('throws on invalid code', () async { + try { + await FirebaseAuth.instance.checkActionCode('!!!!!!'); + fail('Should have thrown'); + } on FirebaseException catch (e) { + expect(e.code, equals('invalid-action-code')); + } catch (e) { + fail(e.toString()); + } + }); }); - test('throws for a bad email address', () async { - try { - await FirebaseAuth.instance.fetchSignInMethodsForEmail('foobar'); - fail('Should have thrown'); - } on FirebaseAuthException catch (e) { - expect(e.code, equals('invalid-email')); - } catch (e) { - fail(e.toString()); - } - }); - }); - - group('isSignInWithEmailLink()', () { - test('should return true or false', () { - const emailLink1 = - 'https://www.example.com/action?mode=signIn&oobCode=oobCode'; - const emailLink2 = - 'https://www.example.com/action?mode=verifyEmail&oobCode=oobCode'; - const emailLink3 = 'https://www.example.com/action?mode=signIn'; - const emailLink4 = - 'https://x59dg.app.goo.gl/?link=https://rnfirebase-b9ad4.firebaseapp.com/__/auth/action?apiKey%3Dfoo%26mode%3DsignIn%26oobCode%3Dbar'; - - expect( - FirebaseAuth.instance.isSignInWithEmailLink(emailLink1), - equals(true), - ); - expect( - FirebaseAuth.instance.isSignInWithEmailLink(emailLink2), - equals(false), - ); - expect( - FirebaseAuth.instance.isSignInWithEmailLink(emailLink3), - equals(false), - ); - expect( - FirebaseAuth.instance.isSignInWithEmailLink(emailLink4), - equals(true), - ); + group('confirmPasswordReset()', () { + test('throws on invalid code', () async { + try { + await FirebaseAuth.instance.confirmPasswordReset( + code: '!!!!!!', newPassword: 'thingamajig', + ); + fail('Should have thrown'); + } on FirebaseException catch (e) { + expect(e.code, equals('invalid-action-code')); + } catch (e) { + fail(e.toString()); + } + }); }); - }); - group('sendPasswordResetEmail()', () { - test('should not error', () async { - var email = generateRandomEmail(); + group('createUserWithEmailAndPassword', () { + test('should create a user with an email and password', () async { + var email = generateRandomEmail(); - try { - await FirebaseAuth.instance.createUserWithEmailAndPassword( - email: email, - password: testPassword, - ); + Function successCallback = (UserCredential newUserCredential) async { + expect(newUserCredential.user, isA()); + User newUser = newUserCredential.user!; - await FirebaseAuth.instance.sendPasswordResetEmail(email: email); - await FirebaseAuth.instance.currentUser!.delete(); - } catch (e) { - await FirebaseAuth.instance.currentUser!.delete(); - fail(e.toString()); - } - }); + expect(newUser.uid, isA()); + expect(newUser.email, equals(email)); + expect(newUser.emailVerified, isFalse); + expect(newUser.isAnonymous, isFalse); + expect(newUser.uid, equals(FirebaseAuth.instance.currentUser!.uid)); - test('fails if the user could not be found', () async { - try { - await FirebaseAuth.instance - .sendPasswordResetEmail(email: 'does-not-exist@bar.com'); - fail('Should have thrown'); - } on FirebaseAuthException catch (e) { - expect(e.code, equals('user-not-found')); - } catch (e) { - fail(e.toString()); - } - }); - }); + var additionalUserInfo = newUserCredential.additionalUserInfo!; + expect(additionalUserInfo, isA()); + expect(additionalUserInfo.isNewUser, isTrue); - group('sendSignInLinkToEmail()', () { - test('should send email successfully', () async { - const email = 'email-signin-test@example.com'; - const continueUrl = 'http://action-code-test.com'; + await FirebaseAuth.instance.currentUser?.delete(); + }; - await FirebaseAuth.instance.createUserWithEmailAndPassword( - email: email, - password: testPassword, - ); + await FirebaseAuth.instance + .createUserWithEmailAndPassword( + email: email, + password: testPassword, + ) + .then(successCallback as Function(UserCredential)); + }); - final actionCodeSettings = ActionCodeSettings( - url: continueUrl, - handleCodeInApp: true, - ); + test('fails if creating a user which already exists', () async { + await ensureSignedIn(testEmail); + try { + await FirebaseAuth.instance.createUserWithEmailAndPassword( + email: testEmail, + password: '123456', + ); + fail('Should have thrown FirebaseAuthException'); + } on FirebaseAuthException catch (e) { + expect(e.code, equals('email-already-in-use')); + } catch (e) { + fail(e.toString()); + } + }); - await FirebaseAuth.instance.sendSignInLinkToEmail( - email: email, - actionCodeSettings: actionCodeSettings, - ); + test('fails if creating a user with an invalid email', () async { + await ensureSignedIn(testEmail); + try { + await FirebaseAuth.instance.createUserWithEmailAndPassword( + email: '!!!!!', + password: '123456', + ); + fail('Should have thrown FirebaseAuthException'); + } on FirebaseAuthException catch (e) { + expect(e.code, equals('invalid-email')); + } catch (e) { + fail(e.toString()); + } + }); - // Confirm with the emulator that it triggered an email sending code. - final oobCode = (await emulatorOutOfBandCode( - email, - EmulatorOobCodeType.emailSignIn, - ))!; - expect(oobCode, isNotNull); - expect(oobCode.email, email); - expect(oobCode.type, EmulatorOobCodeType.emailSignIn); - - // Confirm the continue url was passed through to backend correctly. - final url = Uri.parse(oobCode.oobLink!); - expect(url.queryParameters['continueUrl'], Uri.encodeFull(continueUrl)); + test('fails if creating a user if providing a weak password', () async { + await ensureSignedIn(testEmail); + try { + await FirebaseAuth.instance.createUserWithEmailAndPassword( + email: generateRandomEmail(), + password: '1', + ); + fail('Should have thrown FirebaseAuthException'); + } on FirebaseAuthException catch (e) { + expect(e.code, equals('weak-password')); + } catch (e) { + fail(e.toString()); + } + }); }); - }); - group('languageCode', () { - test('should change the language code', () async { - await FirebaseAuth.instance.setLanguageCode('en'); + group('fetchSignInMethodsForEmail()', () { + test('should return password provider for an email address', () async { + var providers = + await FirebaseAuth.instance.fetchSignInMethodsForEmail(testEmail); + expect(providers, isList); + expect(providers.contains('password'), isTrue); + }); + + test('should return empty array for a not found email', () async { + var providers = await FirebaseAuth.instance + .fetchSignInMethodsForEmail(generateRandomEmail()); + + expect(providers, isList); + expect(providers, isEmpty); + }); - expect(FirebaseAuth.instance.languageCode, equals('en')); + test('throws for a bad email address', () async { + try { + await FirebaseAuth.instance.fetchSignInMethodsForEmail('foobar'); + fail('Should have thrown'); + } on FirebaseAuthException catch (e) { + expect(e.code, equals('invalid-email')); + } catch (e) { + fail(e.toString()); + } + }); }); - test( - 'should allow null value and default the device language code', - () async { - await FirebaseAuth.instance.setLanguageCode(null); + group('isSignInWithEmailLink()', () { + test('should return true or false', () { + const emailLink1 = + 'https://www.example.com/action?mode=signIn&oobCode=oobCode'; + const emailLink2 = + 'https://www.example.com/action?mode=verifyEmail&oobCode=oobCode'; + const emailLink3 = 'https://www.example.com/action?mode=signIn'; + const emailLink4 = + 'https://x59dg.app.goo.gl/?link=https://rnfirebase-b9ad4.firebaseapp.com/__/auth/action?apiKey%3Dfoo%26mode%3DsignIn%26oobCode%3Dbar'; expect( - FirebaseAuth.instance.languageCode, - isNotNull, - ); // default to the device language or the Firebase projects default language - }, - skip: kIsWeb, - ); - - test( - 'should allow null value and set to null', - () async { - await FirebaseAuth.instance.setLanguageCode(null); + FirebaseAuth.instance.isSignInWithEmailLink(emailLink1), + equals(true), + ); + expect( + FirebaseAuth.instance.isSignInWithEmailLink(emailLink2), + equals(false), + ); + expect( + FirebaseAuth.instance.isSignInWithEmailLink(emailLink3), + equals(false), + ); + expect( + FirebaseAuth.instance.isSignInWithEmailLink(emailLink4), + equals(true), + ); + }); + }); - expect(FirebaseAuth.instance.languageCode, null); - }, - skip: !kIsWeb, - ); - }); + group('sendPasswordResetEmail()', () { + test('should not error', () async { + var email = generateRandomEmail(); - group('setPersistence()', () { - test( - 'throw an unimplemented error', - () async { try { - await FirebaseAuth.instance.setPersistence(Persistence.LOCAL); - fail('Should have thrown'); + await FirebaseAuth.instance.createUserWithEmailAndPassword( + email: email, + password: testPassword, + ); + + await FirebaseAuth.instance.sendPasswordResetEmail(email: email); + await FirebaseAuth.instance.currentUser!.delete(); } catch (e) { - expect(e, isInstanceOf()); + await FirebaseAuth.instance.currentUser!.delete(); + fail(e.toString()); } - }, - skip: kIsWeb, - ); + }); - test( - 'should set persistence', - () async { + test('fails if the user could not be found', () async { try { - await FirebaseAuth.instance.setPersistence(Persistence.LOCAL); + await FirebaseAuth.instance + .sendPasswordResetEmail(email: 'does-not-exist@bar.com'); + fail('Should have thrown'); + } on FirebaseAuthException catch (e) { + expect(e.code, equals('user-not-found')); } catch (e) { - fail('unexpected error thrown'); + fail(e.toString()); } - }, - skip: !kIsWeb, - ); - }); + }); + }); - group('signInAnonymously()', () { - test('should sign in anonymously', () async { - Future successCallback(UserCredential currentUserCredential) async { - var currentUser = currentUserCredential.user!; + group('sendSignInLinkToEmail()', () { + test('should send email successfully', () async { + const email = 'email-signin-test@example.com'; + const continueUrl = 'http://action-code-test.com'; - expect(currentUser, isA()); - expect(currentUser.uid, isA()); - expect(currentUser.email, isNull); - expect(currentUser.isAnonymous, isTrue); - expect( - currentUser.uid, - equals(FirebaseAuth.instance.currentUser!.uid), + await FirebaseAuth.instance.createUserWithEmailAndPassword( + email: email, + password: testPassword, ); - var additionalUserInfo = currentUserCredential.additionalUserInfo; - expect(additionalUserInfo, isInstanceOf()); + final actionCodeSettings = ActionCodeSettings( + url: continueUrl, + handleCodeInApp: true, + ); - await FirebaseAuth.instance.signOut(); - } + await FirebaseAuth.instance.sendSignInLinkToEmail( + email: email, + actionCodeSettings: actionCodeSettings, + ); - final userCred = await FirebaseAuth.instance.signInAnonymously(); - await successCallback(userCred); + // Confirm with the emulator that it triggered an email sending code. + final oobCode = (await emulatorOutOfBandCode( + email, + EmulatorOobCodeType.emailSignIn, + ))!; + expect(oobCode, isNotNull); + expect(oobCode.email, email); + expect(oobCode.type, EmulatorOobCodeType.emailSignIn); + + // Confirm the continue url was passed through to backend correctly. + final url = Uri.parse(oobCode.oobLink!); + expect( + url.queryParameters['continueUrl'], Uri.encodeFull(continueUrl), + ); + }); }); - }); - group('signInWithCredential()', () { - test('should login with email and password', () async { - var credential = EmailAuthProvider.credential( - email: testEmail, - password: testPassword, - ); - await FirebaseAuth.instance - .signInWithCredential(credential) - .then(commonSuccessCallback); - }); + group('languageCode', () { + test('should change the language code', () async { + await FirebaseAuth.instance.setLanguageCode('en'); - test('throws if login user is disabled', () async { - var credential = EmailAuthProvider.credential( - email: testDisabledEmail, - password: testPassword, - ); + expect(FirebaseAuth.instance.languageCode, equals('en')); + }); - try { - await FirebaseAuth.instance.signInWithCredential(credential); - fail('Should have thrown'); - } on FirebaseException catch (e) { - expect(e.code, equals('user-disabled')); - expect( - e.message, - equals( - 'The user account has been disabled by an administrator.', - ), - ); - } catch (e) { - fail(e.toString()); - } - }); + test( + 'should allow null value and default the device language code', + () async { + await FirebaseAuth.instance.setLanguageCode(null); - test('throws if login password is incorrect', () async { - var credential = - EmailAuthProvider.credential(email: testEmail, password: 'sowrong'); - try { - await FirebaseAuth.instance.signInWithCredential(credential); - fail('Should have thrown'); - } on FirebaseException catch (e) { - expect(e.code, equals('wrong-password')); - expect( - e.message, - equals( - 'The password is invalid or the user does not have a password.', - ), - ); - } catch (e) { - fail(e.toString()); - } - }); + expect( + FirebaseAuth.instance.languageCode, + isNotNull, + ); // default to the device language or the Firebase projects default language + }, + skip: kIsWeb || defaultTargetPlatform == TargetPlatform.macOS, + ); + + test( + 'should allow null value and set to null', + () async { + await FirebaseAuth.instance.setLanguageCode(null); - test('throws if login user is not found', () async { - var credential = EmailAuthProvider.credential( - email: generateRandomEmail(), - password: testPassword, + expect(FirebaseAuth.instance.languageCode, null); + }, + skip: !kIsWeb, ); - try { - await FirebaseAuth.instance.signInWithCredential(credential); - fail('Should have thrown'); - } on FirebaseException catch (e) { - expect(e.code, equals('user-not-found')); - expect( - e.message, - equals( - 'There is no user record corresponding to this identifier. The user may have been deleted.', - ), - ); - } catch (e) { - fail(e.toString()); - } }); - }); - group('signInWithCustomToken()', () { - test('signs in with custom auth token', () async { - final userCredential = await FirebaseAuth.instance.signInAnonymously(); - final uid = userCredential.user!.uid; - final claims = { - 'roles': [ - {'role': 'member'}, - {'role': 'admin'} - ] - }; - - await ensureSignedOut(); + group('setPersistence()', () { + test( + 'throw an unimplemented error', + () async { + try { + await FirebaseAuth.instance.setPersistence(Persistence.LOCAL); + fail('Should have thrown'); + } catch (e) { + expect(e, isInstanceOf()); + } + }, + skip: kIsWeb || defaultTargetPlatform == TargetPlatform.macOS, + ); - expect(FirebaseAuth.instance.currentUser, null); + test( + 'should set persistence', + () async { + try { + await FirebaseAuth.instance.setPersistence(Persistence.LOCAL); + } catch (e) { + fail('unexpected error thrown'); + } + }, + skip: !kIsWeb, + ); + }); - final customToken = emulatorCreateCustomToken(uid, claims: claims); + group('signInAnonymously()', () { + test('should sign in anonymously', () async { + Future successCallback(UserCredential currentUserCredential) async { + var currentUser = currentUserCredential.user!; - final customTokenUserCredential = - await FirebaseAuth.instance.signInWithCustomToken(customToken); + expect(currentUser, isA()); + expect(currentUser.uid, isA()); + expect(currentUser.email, isNull); + expect(currentUser.isAnonymous, isTrue); + expect( + currentUser.uid, + equals(FirebaseAuth.instance.currentUser!.uid), + ); - expect(customTokenUserCredential.user!.uid, equals(uid)); - expect(FirebaseAuth.instance.currentUser!.uid, equals(uid)); + var additionalUserInfo = currentUserCredential.additionalUserInfo; + expect(additionalUserInfo, isInstanceOf()); - final idTokenResult = - await FirebaseAuth.instance.currentUser!.getIdTokenResult(); + await FirebaseAuth.instance.signOut(); + } - expect(idTokenResult.claims!['roles'], isA()); - expect(idTokenResult.claims!['roles'][0], isA()); - expect(idTokenResult.claims!['roles'][0]['role'], 'member'); + final userCred = await FirebaseAuth.instance.signInAnonymously(); + await successCallback(userCred); + }); }); - }); - group('signInWithEmailAndPassword()', () { - test('should login with email and password', () async { - await FirebaseAuth.instance - .signInWithEmailAndPassword( - email: testEmail, - password: testPassword, - ) - .then(commonSuccessCallback); - }); + group('signInWithCredential()', () { + test('should login with email and password', () async { + var credential = EmailAuthProvider.credential( + email: testEmail, + password: testPassword, + ); + await FirebaseAuth.instance + .signInWithCredential(credential) + .then(commonSuccessCallback); + }); - test('throws if login user is disabled', () async { - try { - await FirebaseAuth.instance.signInWithEmailAndPassword( + test('throws if login user is disabled', () async { + var credential = EmailAuthProvider.credential( email: testDisabledEmail, password: testPassword, ); - fail('Should have thrown'); - } on FirebaseException catch (e) { - expect(e.code, equals('user-disabled')); - expect( - e.message, - equals( - 'The user account has been disabled by an administrator.', - ), - ); - } catch (e) { - fail(e.toString()); - } - }); - test('throws if login password is incorrect', () async { - try { - await FirebaseAuth.instance.signInWithEmailAndPassword( - email: testEmail, - password: 'sowrong', - ); - fail('Should have thrown'); - } on FirebaseException catch (e) { - expect(e.code, equals('wrong-password')); - expect( - e.message, - equals( - 'The password is invalid or the user does not have a password.', - ), + try { + await FirebaseAuth.instance.signInWithCredential(credential); + fail('Should have thrown'); + } on FirebaseException catch (e) { + expect(e.code, equals('user-disabled')); + expect( + e.message, + equals( + 'The user account has been disabled by an administrator.', + ), + ); + } catch (e) { + fail(e.toString()); + } + }); + + test('throws if login password is incorrect', () async { + var credential = EmailAuthProvider.credential( + email: testEmail, password: 'sowrong', ); - } catch (e) { - fail(e.toString()); - } - }); + try { + await FirebaseAuth.instance.signInWithCredential(credential); + fail('Should have thrown'); + } on FirebaseException catch (e) { + expect(e.code, equals('wrong-password')); + expect( + e.message, + equals( + 'The password is invalid or the user does not have a password.', + ), + ); + } catch (e) { + fail(e.toString()); + } + }); - test('throws if login user is not found', () async { - try { - await FirebaseAuth.instance.signInWithEmailAndPassword( + test('throws if login user is not found', () async { + var credential = EmailAuthProvider.credential( email: generateRandomEmail(), password: testPassword, ); - fail('Should have thrown'); - } on FirebaseException catch (e) { - expect(e.code, equals('user-not-found')); - expect( - e.message, - equals( - 'There is no user record corresponding to this identifier. The user may have been deleted.', - ), - ); - } catch (e) { - fail(e.toString()); - } + try { + await FirebaseAuth.instance.signInWithCredential(credential); + fail('Should have thrown'); + } on FirebaseException catch (e) { + expect(e.code, equals('user-not-found')); + expect( + e.message, + equals( + 'There is no user record corresponding to this identifier. The user may have been deleted.', + ), + ); + } catch (e) { + fail(e.toString()); + } + }); }); - }); - group('signOut()', () { - test('should sign out', () async { - await ensureSignedIn(testEmail); - expect(FirebaseAuth.instance.currentUser, isA()); - await FirebaseAuth.instance.signOut(); - expect(FirebaseAuth.instance.currentUser, isNull); - }); - }); - - group('verifyPasswordResetCode()', () { - test('throws on invalid code', () async { - try { - await FirebaseAuth.instance.verifyPasswordResetCode('!!!!!!'); - fail('Should have thrown'); - } on FirebaseException catch (e) { - expect(e.code, equals('invalid-action-code')); - } catch (e) { - fail(e.toString()); - } + group('signInWithCustomToken()', () { + test('signs in with custom auth token', () async { + final userCredential = + await FirebaseAuth.instance.signInAnonymously(); + final uid = userCredential.user!.uid; + final claims = { + 'roles': [ + {'role': 'member'}, + {'role': 'admin'} + ] + }; + + await ensureSignedOut(); + + expect(FirebaseAuth.instance.currentUser, null); + + final customToken = emulatorCreateCustomToken(uid, claims: claims); + + final customTokenUserCredential = + await FirebaseAuth.instance.signInWithCustomToken(customToken); + + expect(customTokenUserCredential.user!.uid, equals(uid)); + expect(FirebaseAuth.instance.currentUser!.uid, equals(uid)); + + final idTokenResult = + await FirebaseAuth.instance.currentUser!.getIdTokenResult(); + + expect(idTokenResult.claims!['roles'], isA()); + expect(idTokenResult.claims!['roles'][0], isA()); + expect(idTokenResult.claims!['roles'][0]['role'], 'member'); + }); }); - }); - - group( - 'verifyPhoneNumber()', - () { - test('should fail with an invalid phone number', () async { - Future getError() async { - Completer completer = Completer(); - - unawaited( - FirebaseAuth.instance.verifyPhoneNumber( - phoneNumber: 'foo', - verificationCompleted: (PhoneAuthCredential credential) { - return completer - .completeError(Exception('Should not have been called')); - }, - verificationFailed: (FirebaseAuthException e) { - completer.complete(e); - }, - codeSent: (String verificationId, int? resetToken) { - return completer - .completeError(Exception('Should not have been called')); - }, - codeAutoRetrievalTimeout: (String foo) { - return completer - .completeError(Exception('Should not have been called')); - }, + + group('signInWithEmailAndPassword()', () { + test('should login with email and password', () async { + await FirebaseAuth.instance + .signInWithEmailAndPassword( + email: testEmail, + password: testPassword, + ) + .then(commonSuccessCallback); + }); + + test('throws if login user is disabled', () async { + try { + await FirebaseAuth.instance.signInWithEmailAndPassword( + email: testDisabledEmail, + password: testPassword, + ); + fail('Should have thrown'); + } on FirebaseException catch (e) { + expect(e.code, equals('user-disabled')); + expect( + e.message, + equals( + 'The user account has been disabled by an administrator.', ), ); + } catch (e) { + fail(e.toString()); + } + }); - return completer.future as FutureOr; + test('throws if login password is incorrect', () async { + try { + await FirebaseAuth.instance.signInWithEmailAndPassword( + email: testEmail, + password: 'sowrong', + ); + fail('Should have thrown'); + } on FirebaseException catch (e) { + expect(e.code, equals('wrong-password')); + expect( + e.message, + equals( + 'The password is invalid or the user does not have a password.', + ), + ); + } catch (e) { + fail(e.toString()); } + }); - Exception e = await getError(); - expect(e, isA()); + test('throws if login user is not found', () async { + try { + await FirebaseAuth.instance.signInWithEmailAndPassword( + email: generateRandomEmail(), + password: testPassword, + ); + fail('Should have thrown'); + } on FirebaseException catch (e) { + expect(e.code, equals('user-not-found')); + expect( + e.message, + equals( + 'There is no user record corresponding to this identifier. The user may have been deleted.', + ), + ); + } catch (e) { + fail(e.toString()); + } + }); + }); - FirebaseAuthException exception = e as FirebaseAuthException; - expect(exception.code, equals('invalid-phone-number')); + group('signOut()', () { + test('should sign out', () async { + await ensureSignedIn(testEmail); + expect(FirebaseAuth.instance.currentUser, isA()); + await FirebaseAuth.instance.signOut(); + expect(FirebaseAuth.instance.currentUser, isNull); }); + }); - test( - 'should auto verify phone number', - () async { - String testPhoneNumber = '+447444555666'; - String testSmsCode = '123456'; - await FirebaseAuth.instance.signInAnonymously(); + group('verifyPasswordResetCode()', () { + test('throws on invalid code', () async { + try { + await FirebaseAuth.instance.verifyPasswordResetCode('!!!!!!'); + fail('Should have thrown'); + } on FirebaseException catch (e) { + expect(e.code, equals('invalid-action-code')); + } catch (e) { + fail(e.toString()); + } + }); + }); - Future getCredential() async { - Completer completer = Completer(); + group( + 'verifyPhoneNumber()', + () { + test('should fail with an invalid phone number', () async { + Future getError() async { + Completer completer = Completer(); unawaited( FirebaseAuth.instance.verifyPhoneNumber( - phoneNumber: testPhoneNumber, - // ignore: invalid_use_of_visible_for_testing_member - autoRetrievedSmsCodeForTesting: testSmsCode, + phoneNumber: 'foo', verificationCompleted: (PhoneAuthCredential credential) { - if (credential.smsCode != testSmsCode) { - return completer - .completeError(Exception('SMS code did not match')); - } - - completer.complete(credential); - }, - verificationFailed: (FirebaseException e) { return completer.completeError( - Exception('Should not have been called'), + Exception('Should not have been called'), ); }, + verificationFailed: (FirebaseAuthException e) { + completer.complete(e); + }, codeSent: (String verificationId, int? resetToken) { return completer.completeError( - Exception('Should not have been called'), + Exception('Should not have been called'), ); }, codeAutoRetrievalTimeout: (String foo) { return completer.completeError( - Exception('Should not have been called'), + Exception('Should not have been called'), ); }, ), ); - return completer.future as FutureOr; + return completer.future as FutureOr; } - PhoneAuthCredential credential = await getCredential(); - expect(credential, isA()); + Exception e = await getError(); + expect(e, isA()); + + FirebaseAuthException exception = e as FirebaseAuthException; + expect(exception.code, equals('invalid-phone-number')); + }); + + test( + 'should auto verify phone number', + () async { + String testPhoneNumber = '+447444555666'; + String testSmsCode = '123456'; + await FirebaseAuth.instance.signInAnonymously(); + + Future getCredential() async { + Completer completer = Completer(); + + unawaited( + FirebaseAuth.instance.verifyPhoneNumber( + phoneNumber: testPhoneNumber, + // ignore: invalid_use_of_visible_for_testing_member + autoRetrievedSmsCodeForTesting: testSmsCode, + verificationCompleted: (PhoneAuthCredential credential) { + if (credential.smsCode != testSmsCode) { + return completer + .completeError(Exception('SMS code did not match')); + } + + completer.complete(credential); + }, + verificationFailed: (FirebaseException e) { + return completer.completeError( + Exception('Should not have been called'), + ); + }, + codeSent: (String verificationId, int? resetToken) { + return completer.completeError( + Exception('Should not have been called'), + ); + }, + codeAutoRetrievalTimeout: (String foo) { + return completer.completeError( + Exception('Should not have been called'), + ); + }, + ), + ); + + return completer.future as FutureOr; + } + + PhoneAuthCredential credential = await getCredential(); + expect(credential, isA()); + }, + skip: kIsWeb || defaultTargetPlatform != TargetPlatform.android, + ); + }, + skip: defaultTargetPlatform == TargetPlatform.macOS || kIsWeb, + ); + + group('setSettings()', () { + test( + 'throws argument error if phoneNumber & smsCode have not been set simultaneously', + () async { + String message = + "The [smsCode] and the [phoneNumber] must both be either 'null' or a 'String''."; + await expectLater( + FirebaseAuth.instance.setSettings(phoneNumber: '123456'), + throwsA( + isA() + .having((e) => e.message, 'message', contains(message)), + ), + ); + + await expectLater( + FirebaseAuth.instance.setSettings(smsCode: '123456'), + throwsA( + isA() + .having((e) => e.message, 'message', contains(message)), + ), + ); }, skip: kIsWeb || defaultTargetPlatform != TargetPlatform.android, ); - }, - skip: defaultTargetPlatform == TargetPlatform.macOS || kIsWeb, - ); - - group('setSettings()', () { - test( - 'throws argument error if phoneNumber & smsCode have not been set simultaneously', - () async { - String message = - "The [smsCode] and the [phoneNumber] must both be either 'null' or a 'String''."; - await expectLater( - FirebaseAuth.instance.setSettings(phoneNumber: '123456'), - throwsA( - isA() - .having((e) => e.message, 'message', contains(message)), - ), - ); + }); - await expectLater( - FirebaseAuth.instance.setSettings(smsCode: '123456'), - throwsA( - isA() - .having((e) => e.message, 'message', contains(message)), - ), - ); + group( + 'tenantId', + () { + test('User associated with the tenantId correctly', () async { + // tenantId created in the GCP console + const String tenantId = 'auth-tenant-test-xukxg'; + // created User on GCP console associated with the above tenantId + final userCredential = + await FirebaseAuth.instance.signInWithEmailAndPassword( + email: 'test-tenant@email.com', + password: 'fake-password', + ); + + expect(userCredential.user!.tenantId, tenantId); + }); + // todo(russellwheatley85): get/set tenantId and authenticating user via auth emulator is not possible at the moment. }, - skip: kIsWeb || defaultTargetPlatform != TargetPlatform.android, + skip: true, ); - }); - - group( - 'tenantId', - () { - test('User associated with the tenantId correctly', () async { - // tenantId created in the GCP console - const String tenantId = 'auth-tenant-test-xukxg'; - // created User on GCP console associated with the above tenantId - final userCredential = - await FirebaseAuth.instance.signInWithEmailAndPassword( - email: 'test-tenant@email.com', - password: 'fake-password', - ); - - expect(userCredential.user!.tenantId, tenantId); - }); - // todo(russellwheatley85): get/set tenantId and authenticating user via auth emulator is not possible at the moment. - }, - skip: true, - ); - }); + }, + // macOS skipped because it needs keychain sharing entitlement. See: https://github.com/firebase/flutterfire/issues/9538 + skip: defaultTargetPlatform == TargetPlatform.macOS, + ); } diff --git a/tests/integration_test/firebase_auth/firebase_auth_user_e2e_test.dart b/tests/integration_test/firebase_auth/firebase_auth_user_e2e_test.dart index 8f63772fad0e..f97277056d85 100644 --- a/tests/integration_test/firebase_auth/firebase_auth_user_e2e_test.dart +++ b/tests/integration_test/firebase_auth/firebase_auth_user_e2e_test.dart @@ -437,7 +437,8 @@ void main() { } expect(FirebaseAuth.instance.currentUser, isNotNull); }, - skip: kIsWeb, + // macOS skipped because it needs keychain sharing entitlement. See: https://github.com/firebase/flutterfire/issues/9538 + skip: kIsWeb || defaultTargetPlatform == TargetPlatform.macOS, ); }); @@ -593,7 +594,8 @@ void main() { ); expect(FirebaseAuth.instance.currentUser!.refreshToken, equals('')); }, - skip: kIsWeb, + // macOS skipped because it needs keychain sharing entitlement. See: https://github.com/firebase/flutterfire/issues/9538 + skip: kIsWeb || defaultTargetPlatform == TargetPlatform.macOS, ); test( @@ -780,7 +782,8 @@ void main() { ); }, // setting `photoURL` on web throws an error - skip: kIsWeb, + // macOS skipped because it needs keychain sharing entitlement. See: https://github.com/firebase/flutterfire/issues/9538 + skip: kIsWeb || defaultTargetPlatform == TargetPlatform.macOS, ); }); @@ -1000,5 +1003,8 @@ void main() { fail('Should have thrown an error'); }); }); - }); + }, + // macOS skipped because it needs keychain sharing entitlement. See: https://github.com/firebase/flutterfire/issues/9538 + skip: defaultTargetPlatform == TargetPlatform.macOS, + ); } diff --git a/tests/integration_test/firebase_messaging/firebase_messaging_e2e_test.dart b/tests/integration_test/firebase_messaging/firebase_messaging_e2e_test.dart index 0587cbbab1a1..3b40eecf1b39 100644 --- a/tests/integration_test/firebase_messaging/firebase_messaging_e2e_test.dart +++ b/tests/integration_test/firebase_messaging/firebase_messaging_e2e_test.dart @@ -68,6 +68,7 @@ void main() { test( 'sets the value', () async { + await messaging.setAutoInitEnabled(true); expect(messaging.isAutoInitEnabled, isTrue); await messaging.setAutoInitEnabled(false); expect(messaging.isAutoInitEnabled, isFalse); @@ -122,12 +123,11 @@ void main() { ); test( - 'resolves null on ios if using simulator', - () async { - expect(await messaging.getAPNSToken(), null); + 'resolves dummy APNS token on ios if using simulator', + () async { + expect(await messaging.getAPNSToken(), isA()); }, - skip: !(defaultTargetPlatform == TargetPlatform.iOS || - defaultTargetPlatform != TargetPlatform.macOS), + skip: defaultTargetPlatform != TargetPlatform.iOS, ); }); @@ -141,21 +141,8 @@ void main() { 'getToken()', () { test('returns a token', () async { - final result = await messaging.requestPermission(); - - if (result.authorizationStatus == AuthorizationStatus.authorized) { final result = await messaging.getToken(); - expect(result, isA()); - } else { - await expectLater( - messaging.getToken(), - throwsA( - isA() - .having((e) => e.code, 'code', 'permission-blocked'), - ), - ); - } }); }, skip: skipManualTests, @@ -165,9 +152,6 @@ void main() { test( 'generate a new token after deleting', () async { - final result = await messaging.requestPermission(); - - if (result.authorizationStatus == AuthorizationStatus.authorized) { final token1 = await messaging.getToken(); await Future.delayed(const Duration(seconds: 3)); await messaging.deleteToken(); @@ -176,15 +160,6 @@ void main() { expect(token1, isA()); expect(token2, isA()); expect(token1, isNot(token2)); - } else { - await expectLater( - messaging.getToken(), - throwsA( - isA() - .having((e) => e.code, 'code', 'permission-blocked'), - ), - ); - } }, skip: skipManualTests, ); // only run for manual testing diff --git a/tests/ios/Runner.xcodeproj/project.pbxproj b/tests/ios/Runner.xcodeproj/project.pbxproj index c3b86276b0e3..3b108edf1bb6 100644 --- a/tests/ios/Runner.xcodeproj/project.pbxproj +++ b/tests/ios/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 51; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -142,7 +142,6 @@ 3B06AD1E1E4923F5004D2608 /* Thin Binary */, AC660AAB7696B4DD121B84D0 /* [CP] Embed Pods Frameworks */, 5F39B4E393588B005ADEE74A /* [firebase_crashlytics] Crashlytics Upload Symbols */, - 570B63470F19A77487B49310 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -203,6 +202,7 @@ /* Begin PBXShellScriptBuildPhase section */ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -215,23 +215,6 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; - 570B63470F19A77487B49310 /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Copy Pods Resources"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; 5F39B4E393588B005ADEE74A /* [firebase_crashlytics] Crashlytics Upload Symbols */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -276,6 +259,7 @@ }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); diff --git a/tests/ios/Runner/Info.plist b/tests/ios/Runner/Info.plist index fa98392a8edb..3dd732018fc0 100644 --- a/tests/ios/Runner/Info.plist +++ b/tests/ios/Runner/Info.plist @@ -67,5 +67,7 @@ https://flutterfiretests.page.link/** + UIApplicationSupportsIndirectInputEvents + diff --git a/tests/macos/Runner.xcodeproj/project.pbxproj b/tests/macos/Runner.xcodeproj/project.pbxproj index b94bb3235826..7ae45b4240bb 100644 --- a/tests/macos/Runner.xcodeproj/project.pbxproj +++ b/tests/macos/Runner.xcodeproj/project.pbxproj @@ -440,8 +440,10 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -566,9 +568,11 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -587,8 +591,10 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)",