diff --git a/lib/onboarding/activate_biometircs/view/activate_biometrics_page.dart b/lib/onboarding/activate_biometircs/view/activate_biometrics_page.dart index bbdd40d02..0949c33d1 100644 --- a/lib/onboarding/activate_biometircs/view/activate_biometrics_page.dart +++ b/lib/onboarding/activate_biometircs/view/activate_biometrics_page.dart @@ -11,19 +11,23 @@ class ActiviateBiometricsPage extends StatelessWidget { super.key, required this.isFromOnboarding, required this.onAction, + required this.localAuthApi, }); final bool isFromOnboarding; final void Function({required bool isEnabled}) onAction; + final LocalAuthApi localAuthApi; static Route route({ required void Function({required bool isEnabled}) onAction, required bool isFromOnboarding, + required LocalAuthApi localAuthApi, }) => RightToLeftRoute( builder: (context) => ActiviateBiometricsPage( onAction: onAction, isFromOnboarding: isFromOnboarding, + localAuthApi: localAuthApi, ), settings: const RouteSettings(name: '/activiateBiometricsPage'), ); @@ -37,6 +41,7 @@ class ActiviateBiometricsPage extends StatelessWidget { child: ActivateBiometricsView( isFromOnboarding: isFromOnboarding, onAction: onAction, + localAuthApi: localAuthApi, ), ); } @@ -47,18 +52,18 @@ class ActivateBiometricsView extends StatefulWidget { super.key, required this.isFromOnboarding, required this.onAction, + required this.localAuthApi, }); final bool isFromOnboarding; final void Function({required bool isEnabled}) onAction; + final LocalAuthApi localAuthApi; @override State createState() => _ActivateBiometricsViewState(); } class _ActivateBiometricsViewState extends State { - final localAuthApi = LocalAuthApi(); - @override void initState() { context.read().load(); @@ -104,11 +109,14 @@ class _ActivateBiometricsViewState extends State { BiometricsSwitch( value: isEnabled, onChange: (value) async { - final hasBiometrics = await localAuthApi.hasBiometrics(); + final hasBiometrics = + await widget.localAuthApi.hasBiometrics(); + if (hasBiometrics) { - final result = await localAuthApi.authenticate( + final result = await widget.localAuthApi.authenticate( localizedReason: l10n.scanFingerprintToAuthenticate, ); + if (result) { context .read() diff --git a/lib/onboarding/protect_wallet/view/protect_wallet_page.dart b/lib/onboarding/protect_wallet/view/protect_wallet_page.dart index 8c415ef6b..aa6844b62 100644 --- a/lib/onboarding/protect_wallet/view/protect_wallet_page.dart +++ b/lib/onboarding/protect_wallet/view/protect_wallet_page.dart @@ -186,6 +186,7 @@ class _ProtectWalletViewState extends State { Navigator.of(context).push( ActiviateBiometricsPage.route( isFromOnboarding: isFromOnboarding, + localAuthApi: LocalAuthApi(), onAction: ({required bool isEnabled}) async { if (isEnabled) { await context @@ -226,6 +227,7 @@ class _ProtectWalletViewState extends State { Navigator.of(context).pushReplacement( ActiviateBiometricsPage.route( isFromOnboarding: isFromOnboarding, + localAuthApi: LocalAuthApi(), onAction: ({required bool isEnabled}) async { if (isEnabled) { await context diff --git a/test/onboarding/activate_biometircs/view/activate_biometrics_page_test.dart b/test/onboarding/activate_biometircs/view/activate_biometrics_page_test.dart new file mode 100644 index 000000000..060745264 --- /dev/null +++ b/test/onboarding/activate_biometircs/view/activate_biometrics_page_test.dart @@ -0,0 +1,208 @@ +import 'package:altme/app/app.dart'; +import 'package:altme/dashboard/dashboard.dart'; +import 'package:altme/onboarding/onboarding.dart'; +import 'package:bloc_test/bloc_test.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockingjay/mockingjay.dart'; + +import '../../../helpers/helpers.dart'; + +class MockProfileCubit extends MockCubit implements ProfileCubit { + @override + final state = ProfileState( + model: ProfileModel( + polygonIdNetwork: PolygonIdNetwork.PolygonMainnet, + walletType: WalletType.personal, + walletProtectionType: WalletProtectionType.FA2, + isDeveloperMode: false, + profileType: ProfileType.custom, + profileSetting: ProfileSetting.initial(), + ), + ); +} + +class MockLocalAuthApi extends Mock implements LocalAuthApi {} + +void main() { + late ActiveBiometricsCubit activeBiometricsCubit; + late MockLocalAuthApi localAuthApi; + late MockProfileCubit mockProfileCubit; + + setUpAll(() { + WidgetsFlutterBinding.ensureInitialized(); + mockProfileCubit = MockProfileCubit(); + activeBiometricsCubit = + ActiveBiometricsCubit(profileCubit: mockProfileCubit); + localAuthApi = MockLocalAuthApi(); + }); + + group('OnBoarding GenPhrase Page', () { + late MockNavigator navigator; + + setUpAll(() { + navigator = MockNavigator(); + when(navigator.canPop).thenReturn(true); + + when(() => navigator.push(any())).thenAnswer((_) async {}); + }); + + testWidgets('is routable', (tester) async { + await tester.pumpApp( + MockNavigatorProvider( + navigator: navigator, + child: Builder( + builder: (context) => Scaffold( + floatingActionButton: FloatingActionButton( + onPressed: () { + Navigator.of(context).push( + ActiviateBiometricsPage.route( + isFromOnboarding: true, + onAction: ({required bool isEnabled}) {}, + localAuthApi: localAuthApi, + ), + ); + }, + ), + ), + ), + ), + ); + await tester.tap(find.byType(FloatingActionButton)); + await tester.pumpAndSettle(); + + verify( + () => navigator.push( + any( + that: isRoute( + whereName: equals('/activiateBiometricsPage'), + ), + ), + ), + ).called(1); + }); + + testWidgets('renders ActivateBiometricsView', (tester) async { + await tester.pumpApp( + MultiBlocProvider( + providers: [ + BlocProvider.value( + value: activeBiometricsCubit, + ), + BlocProvider.value(value: mockProfileCubit), + ], + child: ActiviateBiometricsPage( + isFromOnboarding: true, + onAction: ({required bool isEnabled}) {}, + localAuthApi: localAuthApi, + ), + ), + ); + + expect(find.byType(ActivateBiometricsView), findsOneWidget); + }); + + testWidgets('renders UI correctly', (tester) async { + await tester.pumpApp( + BlocProvider.value( + value: activeBiometricsCubit, + child: ActivateBiometricsView( + isFromOnboarding: true, + onAction: ({required bool isEnabled}) {}, + localAuthApi: localAuthApi, + ), + ), + ); + + expect(find.byType(BasePage), findsOneWidget); + expect(find.byType(BiometricsSwitch), findsOneWidget); + expect( + find.text('Activate Biometrics\nto add a securtiy layer'), + findsOneWidget, + ); + }); + + testWidgets( + 'MyElevatedButton should be enabled and trigger onAction callback', + (tester) async { + bool callbackCalled = false; + + await tester.pumpApp( + MockNavigatorProvider( + navigator: navigator, + child: BlocProvider.value( + value: activeBiometricsCubit, + child: ActivateBiometricsView( + isFromOnboarding: true, + localAuthApi: localAuthApi, + onAction: ({required bool isEnabled}) { + callbackCalled = isEnabled; + }, + ), + ), + ), + ); + + await tester.tap(find.text('Next'.toUpperCase())); + + expect(callbackCalled, true); + }); + + group('BiometricsSwitch', () { + testWidgets('show Diloag when biometrics is not available', + (tester) async { + when(() => localAuthApi.hasBiometrics()) + .thenAnswer((_) => Future.value(false)); + + await tester.pumpApp( + MockNavigatorProvider( + navigator: navigator, + child: BlocProvider.value( + value: activeBiometricsCubit, + child: ActivateBiometricsView( + isFromOnboarding: true, + localAuthApi: localAuthApi, + onAction: ({required bool isEnabled}) {}, + ), + ), + ), + ); + + await tester.tap(find.byType(CupertinoSwitch)); + await tester.pump(); + expect(find.byType(ConfirmDialog), findsOneWidget); + expect(find.text('Biometrics not supported'), findsOneWidget); + }); + + testWidgets('show Diloag when biometrics is available', (tester) async { + when(() => localAuthApi.hasBiometrics()) + .thenAnswer((_) => Future.value(true)); + when( + () => localAuthApi.authenticate( + localizedReason: 'Scan Fingerprint to Authenticate', + ), + ).thenAnswer((_) => Future.value(true)); + + await tester.pumpApp( + MockNavigatorProvider( + navigator: navigator, + child: BlocProvider.value( + value: activeBiometricsCubit, + child: ActivateBiometricsView( + isFromOnboarding: true, + localAuthApi: localAuthApi, + onAction: ({required bool isEnabled}) {}, + ), + ), + ), + ); + + await tester.tap(find.byType(CupertinoSwitch)); + expect(find.byType(ConfirmDialog), findsNothing); + expect(activeBiometricsCubit.state, false); + }); + }); + }); +}