Skip to content

Commit

Permalink
Add test for active biometrics
Browse files Browse the repository at this point in the history
  • Loading branch information
bibash28 committed May 24, 2024
1 parent d6a8815 commit 4ce34a1
Show file tree
Hide file tree
Showing 3 changed files with 222 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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<dynamic> route({
required void Function({required bool isEnabled}) onAction,
required bool isFromOnboarding,
required LocalAuthApi localAuthApi,
}) =>
RightToLeftRoute<void>(
builder: (context) => ActiviateBiometricsPage(
onAction: onAction,
isFromOnboarding: isFromOnboarding,
localAuthApi: localAuthApi,
),
settings: const RouteSettings(name: '/activiateBiometricsPage'),
);
Expand All @@ -37,6 +41,7 @@ class ActiviateBiometricsPage extends StatelessWidget {
child: ActivateBiometricsView(
isFromOnboarding: isFromOnboarding,
onAction: onAction,
localAuthApi: localAuthApi,
),
);
}
Expand All @@ -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<ActivateBiometricsView> createState() => _ActivateBiometricsViewState();
}

class _ActivateBiometricsViewState extends State<ActivateBiometricsView> {
final localAuthApi = LocalAuthApi();

@override
void initState() {
context.read<ActiveBiometricsCubit>().load();
Expand Down Expand Up @@ -104,11 +109,14 @@ class _ActivateBiometricsViewState extends State<ActivateBiometricsView> {
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<ActiveBiometricsCubit>()
Expand Down
2 changes: 2 additions & 0 deletions lib/onboarding/protect_wallet/view/protect_wallet_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ class _ProtectWalletViewState extends State<ProtectWalletView> {
Navigator.of(context).push<void>(
ActiviateBiometricsPage.route(
isFromOnboarding: isFromOnboarding,
localAuthApi: LocalAuthApi(),
onAction: ({required bool isEnabled}) async {
if (isEnabled) {
await context
Expand Down Expand Up @@ -226,6 +227,7 @@ class _ProtectWalletViewState extends State<ProtectWalletView> {
Navigator.of(context).pushReplacement<void, void>(
ActiviateBiometricsPage.route(
isFromOnboarding: isFromOnboarding,
localAuthApi: LocalAuthApi(),
onAction: ({required bool isEnabled}) async {
if (isEnabled) {
await context
Expand Down
Original file line number Diff line number Diff line change
@@ -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<ProfileState> 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<void>(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<void>(
ActiviateBiometricsPage.route(
isFromOnboarding: true,
onAction: ({required bool isEnabled}) {},
localAuthApi: localAuthApi,
),
);
},
),
),
),
),
);
await tester.tap(find.byType(FloatingActionButton));
await tester.pumpAndSettle();

verify(
() => navigator.push<void>(
any(
that: isRoute<void>(
whereName: equals('/activiateBiometricsPage'),
),
),
),
).called(1);
});

testWidgets('renders ActivateBiometricsView', (tester) async {
await tester.pumpApp(
MultiBlocProvider(
providers: [
BlocProvider.value(
value: activeBiometricsCubit,
),
BlocProvider<ProfileCubit>.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);
});
});
});
}

0 comments on commit 4ce34a1

Please sign in to comment.