yubioath-flutter/test/android_settings_page_test.dart

357 lines
12 KiB
Dart
Raw Normal View History

2022-10-04 13:12:54 +03:00
/*
* Copyright (C) 2022 Yubico.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:yubico_authenticator/android/models.dart';
import 'package:yubico_authenticator/app/views/keys.dart' as app_keys;
import 'package:yubico_authenticator/android/keys.dart' as android_keys;
2022-09-23 11:17:28 +03:00
import 'package:yubico_authenticator/android/state.dart';
import 'package:yubico_authenticator/app/state.dart';
import 'package:yubico_authenticator/app/views/settings_page.dart';
import 'package:yubico_authenticator/core/state.dart';
Widget createMaterialApp({required Widget child}) {
return MaterialApp(
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [
Locale('en', ''),
],
home: child,
);
}
extension _WidgetTesterHelper on WidgetTester {
Future<void> openNfcTapOptionSelection() async {
var widget = find.byKey(android_keys.nfcTapSetting).hitTestable();
expect(widget, findsOneWidget);
await tap(widget);
await pumpAndSettle();
}
Future<void> selectLaunchOption() async {
await openNfcTapOptionSelection();
await tap(find.byKey(android_keys.nfcTapOption(NfcTapAction.launch)));
await pumpAndSettle();
}
Future<void> selectCopyOption() async {
await openNfcTapOptionSelection();
await tap(find.byKey(android_keys.nfcTapOption(NfcTapAction.copy)));
await pumpAndSettle();
}
Future<void> selectBothOption() async {
await openNfcTapOptionSelection();
await tap(find.byKey(android_keys.nfcTapOption(NfcTapAction.both)));
await pumpAndSettle();
}
ListTile keyboardLayoutListTile() =>
find.byKey(android_keys.nfcKeyboardLayoutSetting).evaluate().single.widget
as ListTile;
Future<void> openKeyboardLayoutOptionSelection() async {
var widget =
find.byKey(android_keys.nfcKeyboardLayoutSetting).hitTestable();
expect(widget, findsOneWidget);
await tap(widget);
await pumpAndSettle();
}
Future<void> selectKeyboardLayoutUSOption() async {
await openKeyboardLayoutOptionSelection();
await tap(find.byKey(android_keys.keyboardLayoutOption('US')));
await pumpAndSettle();
}
Future<void> selectKeyboardLayoutDEOption() async {
await openKeyboardLayoutOptionSelection();
await tap(find.byKey(android_keys.keyboardLayoutOption('DE')));
await pumpAndSettle();
}
Future<void> selectKeyboardLayoutDECHOption() async {
await openKeyboardLayoutOptionSelection();
await tap(find.byKey(android_keys.keyboardLayoutOption('DE-CH')));
await pumpAndSettle();
}
Future<void> tapBypassTouch() async {
await tap(find.byKey(android_keys.nfcBypassTouchSetting));
await pumpAndSettle();
}
2022-09-23 11:17:28 +03:00
2022-11-28 13:44:55 +03:00
Future<void> tapOpenAppOnUsb() async {
await ensureVisible(find.byKey(android_keys.usbOpenApp));
await tap(find.byKey(android_keys.usbOpenApp));
2022-11-28 13:44:55 +03:00
await pumpAndSettle();
}
2023-01-10 13:44:43 +03:00
Future<void> tapSilenceNfcSounds() async {
await tap(find.byKey(android_keys.nfcSilenceSoundsSettings));
2023-01-03 15:10:03 +03:00
await pumpAndSettle();
}
2022-09-23 11:17:28 +03:00
ListTile themeModeListTile() =>
find.byKey(app_keys.themeModeSetting).evaluate().single.widget
as ListTile;
2022-09-23 11:17:28 +03:00
Future<void> openAppThemeOptionSelection() async {
await ensureVisible(find.byKey(app_keys.themeModeSetting));
var widget = find.byKey(app_keys.themeModeSetting).hitTestable();
2022-09-23 11:17:28 +03:00
expect(widget, findsOneWidget);
await tap(widget);
await pumpAndSettle();
}
Future<void> selectSystemTheme() async {
await openAppThemeOptionSelection();
await tap(find.byKey(app_keys.themeModeOption(ThemeMode.system)));
2022-09-23 11:17:28 +03:00
await pumpAndSettle();
}
Future<void> selectLightTheme() async {
await openAppThemeOptionSelection();
await tap(find.byKey(app_keys.themeModeOption(ThemeMode.light)));
2022-09-23 11:17:28 +03:00
await pumpAndSettle();
}
Future<void> selectDarkTheme() async {
await openAppThemeOptionSelection();
await tap(find.byKey(app_keys.themeModeOption(ThemeMode.dark)));
2022-09-23 11:17:28 +03:00
await pumpAndSettle();
}
}
2022-09-23 11:17:28 +03:00
Widget androidWidget({
required SharedPreferences sharedPrefs,
required Widget child,
int sdkVersion = 33,
}) =>
ProviderScope(overrides: [
prefProvider.overrideWithValue(sharedPrefs),
androidSdkVersionProvider.overrideWithValue(sdkVersion),
supportedThemesProvider
.overrideWith((ref) => ref.watch(androidSupportedThemesProvider))
2022-09-23 11:17:28 +03:00
], child: child);
void main() {
debugDefaultTargetPlatformOverride = TargetPlatform.android;
var widget = createMaterialApp(child: const SettingsPage());
testWidgets('NFC Tap options', (WidgetTester tester) async {
const prefNfcOpenApp = 'prefNfcOpenApp';
const prefNfcCopyOtp = 'prefNfcCopyOtp';
SharedPreferences.setMockInitialValues(
{prefNfcOpenApp: true, prefNfcCopyOtp: false});
SharedPreferences sharedPrefs = await SharedPreferences.getInstance();
2022-09-23 11:17:28 +03:00
await tester.pumpWidget(androidWidget(
sharedPrefs: sharedPrefs,
child: widget,
));
// launch - preserves original value
await tester.selectLaunchOption();
expect(sharedPrefs.getBool(prefNfcOpenApp), equals(true));
expect(sharedPrefs.getBool(prefNfcCopyOtp), equals(false));
// copy
await tester.selectCopyOption();
expect(sharedPrefs.getBool(prefNfcOpenApp), equals(false));
expect(sharedPrefs.getBool(prefNfcCopyOtp), equals(true));
// both
await tester.selectBothOption();
expect(sharedPrefs.getBool(prefNfcOpenApp), equals(true));
expect(sharedPrefs.getBool(prefNfcCopyOtp), equals(true));
// launch - changes to value
await tester.selectLaunchOption();
expect(sharedPrefs.getBool(prefNfcOpenApp), equals(true));
expect(sharedPrefs.getBool(prefNfcCopyOtp), equals(false));
});
testWidgets('Static password keyboard layout', (WidgetTester tester) async {
const prefNfcOpenApp = 'prefNfcOpenApp';
const prefNfcCopyOtp = 'prefNfcCopyOtp';
const prefClipKbdLayout = 'prefClipKbdLayout';
SharedPreferences.setMockInitialValues(
{prefNfcOpenApp: true, prefNfcCopyOtp: false, prefClipKbdLayout: 'US'});
SharedPreferences sharedPrefs = await SharedPreferences.getInstance();
2022-09-23 11:17:28 +03:00
await tester.pumpWidget(androidWidget(
sharedPrefs: sharedPrefs,
child: widget,
));
// option is disabled for "open"
expect(tester.keyboardLayoutListTile().enabled, equals(false));
// option is enabled for "copy" and "launch"
await tester.selectCopyOption();
expect(tester.keyboardLayoutListTile().enabled, equals(true));
await tester.selectBothOption();
expect(tester.keyboardLayoutListTile().enabled, equals(true));
// US - preserves the original value value
await tester.selectKeyboardLayoutUSOption();
expect(sharedPrefs.getString(prefClipKbdLayout), equals('US'));
// DE
await tester.selectKeyboardLayoutDEOption();
expect(sharedPrefs.getString(prefClipKbdLayout), equals('DE'));
// DE-CH
await tester.selectKeyboardLayoutDECHOption();
expect(sharedPrefs.getString(prefClipKbdLayout), equals('DE-CH'));
// US
await tester.selectKeyboardLayoutUSOption();
expect(sharedPrefs.getString(prefClipKbdLayout), equals('US'));
});
testWidgets('Bypass touch req', (WidgetTester tester) async {
const prefNfcBypassTouch = 'prefNfcBypassTouch';
SharedPreferences.setMockInitialValues({prefNfcBypassTouch: false});
SharedPreferences sharedPrefs = await SharedPreferences.getInstance();
2022-09-23 11:17:28 +03:00
await tester.pumpWidget(androidWidget(
sharedPrefs: sharedPrefs,
child: widget,
));
// change to true
await tester.tapBypassTouch();
expect(sharedPrefs.getBool(prefNfcBypassTouch), equals(true));
// change to false
await tester.tapBypassTouch();
expect(sharedPrefs.getBool(prefNfcBypassTouch), equals(false));
});
2022-09-23 11:17:28 +03:00
group('Theme settings', () {
testWidgets('Theme default on Android 10+', (WidgetTester tester) async {
// no value for theme
SharedPreferences.setMockInitialValues({});
SharedPreferences sharedPrefs = await SharedPreferences.getInstance();
await tester.pumpWidget(androidWidget(
sharedPrefs: sharedPrefs,
child: widget,
// Android 10 (API Level 29)
sdkVersion: 29,
));
// we expect System theme default
expect((tester.themeModeListTile().subtitle as Text).data,
equals('System default'));
});
testWidgets('Theme default on Android <10', (WidgetTester tester) async {
// no value for theme
SharedPreferences.setMockInitialValues({});
SharedPreferences sharedPrefs = await SharedPreferences.getInstance();
await tester.pumpWidget(androidWidget(
sharedPrefs: sharedPrefs,
child: widget,
// Android 9 (API Level 28)
sdkVersion: 28,
));
// we expect System theme default
expect((tester.themeModeListTile().subtitle as Text).data,
2023-02-28 17:02:12 +03:00
equals('Light mode'));
2022-09-23 11:17:28 +03:00
});
testWidgets('Theme preferences update', (WidgetTester tester) async {
// no value for theme
SharedPreferences.setMockInitialValues({});
SharedPreferences sharedPrefs = await SharedPreferences.getInstance();
const prefTheme = 'APP_STATE_THEME';
2022-09-23 11:17:28 +03:00
await tester.pumpWidget(androidWidget(
sharedPrefs: sharedPrefs,
child: widget,
));
await tester.selectSystemTheme();
expect(sharedPrefs.getString(prefTheme), equals('system'));
await tester.selectLightTheme();
expect(sharedPrefs.getString(prefTheme), equals('light'));
await tester.selectDarkTheme();
expect(sharedPrefs.getString(prefTheme), equals('dark'));
});
});
2022-11-28 13:44:55 +03:00
testWidgets('Open app on USB', (WidgetTester tester) async {
const prefUsbOpenApp = 'prefUsbOpenApp';
2022-11-28 13:44:55 +03:00
SharedPreferences.setMockInitialValues({prefUsbOpenApp: false});
SharedPreferences sharedPrefs = await SharedPreferences.getInstance();
await tester.pumpWidget(androidWidget(
sharedPrefs: sharedPrefs,
child: widget,
));
// change to true
await tester.tapOpenAppOnUsb();
expect(sharedPrefs.getBool(prefUsbOpenApp), equals(true));
// change to false
await tester.tapOpenAppOnUsb();
expect(sharedPrefs.getBool(prefUsbOpenApp), equals(false));
});
2023-01-03 15:10:03 +03:00
2023-01-10 13:44:43 +03:00
testWidgets('Silence NFC sound', (WidgetTester tester) async {
const prefNfcSilenceSounds = 'prefNfcSilenceSounds';
2023-01-10 13:44:43 +03:00
SharedPreferences.setMockInitialValues({prefNfcSilenceSounds: false});
2023-01-03 15:10:03 +03:00
SharedPreferences sharedPrefs = await SharedPreferences.getInstance();
await tester.pumpWidget(androidWidget(
sharedPrefs: sharedPrefs,
child: widget,
));
// change to true
2023-01-10 13:44:43 +03:00
await tester.tapSilenceNfcSounds();
expect(sharedPrefs.getBool(prefNfcSilenceSounds), equals(true));
// change to false
await tester.tapSilenceNfcSounds();
expect(sharedPrefs.getBool(prefNfcSilenceSounds), equals(false));
2023-01-03 15:10:03 +03:00
});
debugDefaultTargetPlatformOverride = null;
}