diff --git a/mobile/lib/features/age_gate/age_signal_provider.dart b/mobile/lib/features/age_gate/age_signal_provider.dart index 2577e342ce1..d3c9b408e6b 100644 --- a/mobile/lib/features/age_gate/age_signal_provider.dart +++ b/mobile/lib/features/age_gate/age_signal_provider.dart @@ -252,5 +252,15 @@ class AgeSignalNotifier extends Notifier { } final ageSignalProvider = NotifierProvider( - AgeSignalNotifier.new, + _DisabledAgeSignalNotifier.new, ); + +// Temporarily disable age blocking: platform age checks can lock users out of +// the app. Keep the allowed transition so push snapshots are restored normally. +class _DisabledAgeSignalNotifier extends AgeSignalNotifier { + @override + AgeSignalState build() => AgeSignalState.allowed; + + @override + Future request() async {} +} diff --git a/mobile/test/features/age_gate/age_gate_app_test.dart b/mobile/test/features/age_gate/age_gate_app_test.dart index 728505a512a..f52aa680dd8 100644 --- a/mobile/test/features/age_gate/age_gate_app_test.dart +++ b/mobile/test/features/age_gate/age_gate_app_test.dart @@ -1,5 +1,3 @@ -import 'dart:async'; - import 'package:buzz/app.dart'; import 'package:buzz/features/age_gate/age_restriction_page.dart'; import 'package:buzz/features/age_gate/age_signal_push_bootstrap.dart'; @@ -98,75 +96,65 @@ void main() { expect(badgeCounts.last, 0); }); - testWidgets('keeps app content unmounted until the signal resolves', ( - tester, - ) async { - final response = Completer(); - final relaySession = _CountingRelaySessionNotifier(); - var requests = 0; - var snapshotSuspensions = 0; - var snapshotRestorations = 0; - TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger - .setMockMethodCallHandler(ageSignalChannel, (call) { - requests += 1; - return response.future; - }); - SharedPreferences.setMockInitialValues({}); - final prefs = await SharedPreferences.getInstance(); - - await tester.pumpWidget( - ProviderScope( - overrides: [ - authProvider.overrideWith(() => _AuthenticatedAuthNotifier()), - relaySessionProvider.overrideWith(() => relaySession), - suspendCommunitySnapshotForAgeCheckProvider.overrideWithValue( - () async { - snapshotSuspensions += 1; - if (snapshotSuspensions == 1) { - throw StateError('injected suspension failure'); - } - }, - ), - resumeCommunitySnapshotAfterAgeCheckProvider.overrideWithValue( - () async { - snapshotRestorations += 1; - if (snapshotRestorations == 1) { - throw StateError('injected restoration failure'); - } - }, - ), - ageSignalPushSnapshotRetryWaitProvider.overrideWithValue( - (_) async {}, - ), - savedPrefsProvider.overrideWithValue(prefs), - ], - child: const AgeSignalPushBootstrap(child: App()), - ), - ); + testWidgets( + 'opens app and restores push snapshots without a native age check', + (tester) async { + final relaySession = _CountingRelaySessionNotifier(); + var requests = 0; + var snapshotSuspensions = 0; + var snapshotRestorations = 0; + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(ageSignalChannel, (call) { + requests += 1; + throw PlatformException(code: 'unavailable'); + }); + SharedPreferences.setMockInitialValues({}); + final prefs = await SharedPreferences.getInstance(); - expect(requests, 1); - expect(find.bySemanticsLabel('Checking age eligibility'), findsOneWidget); - expect(find.byType(HomePage), findsNothing); - expect(find.byType(Navigator), findsNothing); - expect(relaySession.builds, 0); - await tester.pump(); - await tester.pump(); - expect(snapshotSuspensions, 2); - expect(snapshotRestorations, 0); + await tester.pumpWidget( + ProviderScope( + overrides: [ + authProvider.overrideWith(() => _AuthenticatedAuthNotifier()), + relaySessionProvider.overrideWith(() => relaySession), + suspendCommunitySnapshotForAgeCheckProvider.overrideWithValue( + () async { + snapshotSuspensions += 1; + if (snapshotSuspensions == 1) { + throw StateError('injected suspension failure'); + } + }, + ), + resumeCommunitySnapshotAfterAgeCheckProvider.overrideWithValue( + () async { + snapshotRestorations += 1; + if (snapshotRestorations == 1) { + throw StateError('injected restoration failure'); + } + }, + ), + ageSignalPushSnapshotRetryWaitProvider.overrideWithValue( + (_) async {}, + ), + savedPrefsProvider.overrideWithValue(prefs), + ], + child: const AgeSignalPushBootstrap(child: App()), + ), + ); - response.complete({'status': 'noSignal', 'ageUpper': null}); - await tester.pump(); - await tester.pump(); + await tester.pump(); + await tester.pump(); + expect(snapshotSuspensions, 0); - expect(find.bySemanticsLabel('Checking age eligibility'), findsNothing); - expect(find.byType(HomePage), findsOneWidget); - expect(find.byType(Navigator), findsOneWidget); - expect(relaySession.builds, 1); - expect(requests, 1); - await tester.pump(); - await tester.pump(); - expect(snapshotRestorations, 2); - }); + expect(find.bySemanticsLabel('Checking age eligibility'), findsNothing); + expect(find.byType(HomePage), findsOneWidget); + expect(find.byType(Navigator), findsOneWidget); + expect(relaySession.builds, 1); + expect(requests, 0); + await tester.pump(); + await tester.pump(); + expect(snapshotRestorations, 2); + }, + ); testWidgets('offers a retry after the native age check fails', ( tester, diff --git a/mobile/test/features/age_gate/age_signal_provider_test.dart b/mobile/test/features/age_gate/age_signal_provider_test.dart index 3846e651a10..65df38acc13 100644 --- a/mobile/test/features/age_gate/age_signal_provider_test.dart +++ b/mobile/test/features/age_gate/age_signal_provider_test.dart @@ -13,6 +13,27 @@ void main() { .setMockMethodCallHandler(ageSignalChannel, null); }); + test( + 'production launch allows access without requesting a native age signal', + () async { + var nativeCalls = 0; + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(ageSignalChannel, (_) async { + nativeCalls += 1; + throw PlatformException(code: 'unavailable'); + }); + final container = ProviderContainer(); + addTearDown(container.dispose); + + expect(container.read(ageSignalProvider), AgeSignalState.allowed); + await container.read(ageSignalProvider.notifier).request(); + await container.read(ageSignalProvider.notifier).request(); + + expect(container.read(ageSignalProvider), AgeSignalState.allowed); + expect(nativeCalls, 0); + }, + ); + Future requestWithResponse(Object? response) async { TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(ageSignalChannel, (call) async { @@ -20,7 +41,9 @@ void main() { expect(call.arguments, isNull); return response; }); - final container = ProviderContainer(); + final container = ProviderContainer( + overrides: [ageSignalProvider.overrideWith(AgeSignalNotifier.new)], + ); addTearDown(container.dispose); await container.read(ageSignalProvider.notifier).request(); @@ -506,7 +529,9 @@ void main() { requests += 1; return {'status': 'noSignal', 'ageUpper': null}; }); - final container = ProviderContainer(); + final container = ProviderContainer( + overrides: [ageSignalProvider.overrideWith(AgeSignalNotifier.new)], + ); addTearDown(container.dispose); final notifier = container.read(ageSignalProvider.notifier);