theme preferences tests

This commit is contained in:
Adam Velebil 2022-09-23 10:17:28 +02:00
parent 8a7ba46a48
commit a43bacc073
No known key found for this signature in database
GPG Key ID: AC6D6B9D715FC084
7 changed files with 129 additions and 12 deletions

View File

@ -4,3 +4,4 @@ const prefNfcOpenApp = 'prefNfcOpenApp';
const prefNfcBypassTouch = 'prefNfcBypassTouch';
const prefNfcCopyOtp = 'prefNfcCopyOtp';
const prefClipKbdLayout = 'prefClipKbdLayout';
const prefTheme = 'APP_STATE_THEME';

View File

@ -7,6 +7,7 @@ const betaDialogView = Key('$_prefix.beta_dialog');
const nfcTapSetting = Key('$_prefix.nfc_tap');
const nfcKeyboardLayoutSetting = Key('$_prefix.nfc_keyboard_layout');
const nfcBypassTouchSetting = Key('$_prefix.nfc_bypass_touch');
const themeModeSetting = Key('$_prefix.theme_mode');
const okButton = Key('$_prefix.ok');
const manualEntryButton = Key('$_prefix.manual_entry');
@ -15,4 +16,9 @@ const launchTapAction = Key('$_prefix.tap_action_launch');
const copyTapAction = Key('$_prefix.tap_action_copy');
const bothTapAction = Key('$_prefix.tap_action_both');
const themeModeSystem = Key('$_prefix.theme_mode_system');
const themeModeLight = Key('$_prefix.theme_mode_light');
const themeModeDark = Key('$_prefix.theme_mode_dark');
Key keyboardLayoutOption(String name) => Key('$_prefix.keyboard_layout.$name');

View File

@ -152,6 +152,7 @@ class _AndroidSettingsPageState extends ConsumerState<AndroidSettingsPage> {
ListTile(
title: const Text('App theme'),
subtitle: Text(themeMode.displayName),
key: keys.themeModeSetting,
onTap: () async {
final newMode = await _selectAppearance(
ref.read(supportedThemesProvider), context, themeMode);
@ -223,6 +224,7 @@ class _AndroidSettingsPageState extends ConsumerState<AndroidSettingsPage> {
.map((e) => RadioListTile(
title: Text(e.displayName),
value: e,
key: Key('android.keys.theme_mode_${e.name}'),
groupValue: themeMode,
toggleable: true,
onChanged: (mode) {

View File

@ -20,8 +20,9 @@ final windowStateProvider = Provider<WindowState>(
(ref) => WindowState(focused: true, visible: true, active: true),
);
final supportedThemesProvider =
StateProvider<List<ThemeMode>>((ref) => ThemeMode.values);
final supportedThemesProvider = StateProvider<List<ThemeMode>>(
(ref) => throw UnimplementedError(),
);
final themeModeProvider = StateNotifierProvider<ThemeModeNotifier, ThemeMode>(
(ref) => ThemeModeNotifier(

View File

@ -118,7 +118,8 @@ Future<Widget> initialize(List<String> argv) async {
fidoStateProvider.overrideWithProvider(desktopFidoState),
fingerprintProvider.overrideWithProvider(desktopFingerprintProvider),
credentialProvider.overrideWithProvider(desktopCredentialProvider),
clipboardProvider.overrideWithProvider(desktopClipboardProvider)
clipboardProvider.overrideWithProvider(desktopClipboardProvider),
supportedThemesProvider.overrideWithProvider(desktopSupportedThemesProvider)
],
child: YubicoAuthenticatorApp(
page: Consumer(

View File

@ -1,6 +1,7 @@
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:logging/logging.dart';
@ -130,6 +131,10 @@ class _DesktopClipboard extends AppClipboard {
}
}
final desktopSupportedThemesProvider = StateProvider<List<ThemeMode>>(
(ref) => ThemeMode.values,
);
final desktopCurrentDeviceProvider =
StateNotifierProvider<CurrentDeviceNotifier, DeviceNode?>((ref) {
final provider = _DesktopCurrentDeviceNotifier(ref.watch(prefProvider));

View File

@ -5,7 +5,9 @@ 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/keys.dart' as keys;
import 'package:yubico_authenticator/android/state.dart';
import 'package:yubico_authenticator/android/views/android_settings_page.dart';
import 'package:yubico_authenticator/app/state.dart';
import 'package:yubico_authenticator/core/state.dart';
import '../integration_test/android/constants.dart';
@ -84,8 +86,48 @@ extension _WidgetTesterHelper on WidgetTester {
await tap(find.byKey(keys.nfcBypassTouchSetting));
await pumpAndSettle();
}
ListTile themeModeListTile() =>
find.byKey(keys.themeModeSetting).evaluate().single.widget as ListTile;
Future<void> openAppThemeOptionSelection() async {
var widget = find.byKey(keys.themeModeSetting).hitTestable();
expect(widget, findsOneWidget);
await tap(widget);
await pumpAndSettle();
}
Future<void> selectSystemTheme() async {
await openAppThemeOptionSelection();
await tap(find.byKey(keys.themeModeSystem));
await pumpAndSettle();
}
Future<void> selectLightTheme() async {
await openAppThemeOptionSelection();
await tap(find.byKey(keys.themeModeLight));
await pumpAndSettle();
}
Future<void> selectDarkTheme() async {
await openAppThemeOptionSelection();
await tap(find.byKey(keys.themeModeDark));
await pumpAndSettle();
}
}
Widget androidWidget({
required SharedPreferences sharedPrefs,
required Widget child,
int sdkVersion = 33,
}) =>
ProviderScope(overrides: [
prefProvider.overrideWithValue(sharedPrefs),
androidSdkVersionProvider.overrideWithValue(sdkVersion),
supportedThemesProvider
.overrideWithProvider(androidSupportedThemesProvider)
], child: child);
void main() {
var widget = createMaterialApp(child: const AndroidSettingsPage());
@ -95,9 +137,10 @@ void main() {
SharedPreferences sharedPrefs = await SharedPreferences.getInstance();
await tester.pumpWidget(ProviderScope(
overrides: [prefProvider.overrideWithValue(sharedPrefs)],
child: widget));
await tester.pumpWidget(androidWidget(
sharedPrefs: sharedPrefs,
child: widget,
));
// launch - preserves original value
await tester.selectLaunchOption();
@ -126,9 +169,10 @@ void main() {
SharedPreferences sharedPrefs = await SharedPreferences.getInstance();
await tester.pumpWidget(ProviderScope(
overrides: [prefProvider.overrideWithValue(sharedPrefs)],
child: widget));
await tester.pumpWidget(androidWidget(
sharedPrefs: sharedPrefs,
child: widget,
));
// option is disabled for "open"
expect(tester.keyboardLayoutListTile().enabled, equals(false));
@ -161,9 +205,10 @@ void main() {
SharedPreferences.setMockInitialValues({prefNfcBypassTouch: false});
SharedPreferences sharedPrefs = await SharedPreferences.getInstance();
await tester.pumpWidget(ProviderScope(
overrides: [prefProvider.overrideWithValue(sharedPrefs)],
child: widget));
await tester.pumpWidget(androidWidget(
sharedPrefs: sharedPrefs,
child: widget,
));
// change to true
await tester.tapBypassTouch();
@ -173,4 +218,60 @@ void main() {
await tester.tapBypassTouch();
expect(sharedPrefs.getBool(prefNfcBypassTouch), equals(false));
});
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,
equals('Light theme'));
});
testWidgets('Theme preferences update', (WidgetTester tester) async {
// no value for theme
SharedPreferences.setMockInitialValues({});
SharedPreferences sharedPrefs = await SharedPreferences.getInstance();
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'));
});
});
}