chore: add app setting test (#1361)

This commit is contained in:
Nathan.fooo 2022-10-25 17:30:57 +08:00 committed by GitHub
parent 67e4a759c7
commit 18185cc90c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 163 additions and 48 deletions

View File

@ -19,9 +19,9 @@ class InitAppWidgetTask extends LaunchTask {
Future<void> initialize(LaunchContext context) async { Future<void> initialize(LaunchContext context) async {
final widget = context.getIt<EntryPoint>().create(); final widget = context.getIt<EntryPoint>().create();
final setting = await SettingsFFIService().getAppearanceSetting(); final setting = await SettingsFFIService().getAppearanceSetting();
final settingModel = AppearanceSetting(setting); final appearanceSetting = AppearanceSetting(setting);
final app = ApplicationWidget( final app = ApplicationWidget(
settingModel: settingModel, appearanceSetting: appearanceSetting,
child: widget, child: widget,
); );
Bloc.observer = ApplicationBlocObserver(); Bloc.observer = ApplicationBlocObserver();
@ -61,23 +61,23 @@ class InitAppWidgetTask extends LaunchTask {
class ApplicationWidget extends StatelessWidget { class ApplicationWidget extends StatelessWidget {
final Widget child; final Widget child;
final AppearanceSetting settingModel; final AppearanceSetting appearanceSetting;
const ApplicationWidget({ const ApplicationWidget({
Key? key, Key? key,
required this.child, required this.child,
required this.settingModel, required this.appearanceSetting,
}) : super(key: key); }) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ChangeNotifierProvider.value( return ChangeNotifierProvider.value(
value: settingModel, value: appearanceSetting,
builder: (context, _) { builder: (context, _) {
const ratio = 1.73; const ratio = 1.73;
const minWidth = 600.0; const minWidth = 600.0;
setWindowMinSize(const Size(minWidth, minWidth / ratio)); setWindowMinSize(const Size(minWidth, minWidth / ratio));
settingModel.readLocaleWhenAppLaunch(context); appearanceSetting.readLocaleWhenAppLaunch(context);
AppTheme theme = context.select<AppearanceSetting, AppTheme>( AppTheme theme = context.select<AppearanceSetting, AppTheme>(
(value) => value.theme, (value) => value.theme,
); );

View File

@ -13,7 +13,6 @@ class AppearanceSetting extends ChangeNotifier with EquatableMixin {
final AppearanceSettingsPB _setting; final AppearanceSettingsPB _setting;
AppTheme _theme; AppTheme _theme;
Locale _locale; Locale _locale;
Timer? _debounceSaveOperation;
AppearanceSetting(AppearanceSettingsPB setting) AppearanceSetting(AppearanceSettingsPB setting)
: _setting = setting, : _setting = setting,
@ -83,10 +82,17 @@ class AppearanceSetting extends ChangeNotifier with EquatableMixin {
} else { } else {
_setting.settingKeyValue[key] = value; _setting.settingKeyValue[key] = value;
} }
_saveAppearSetting();
notifyListeners();
} }
_saveAppearSetting();
notifyListeners();
}
String? getValue(String key) {
if (key.isEmpty) {
Log.warn("The key should not be empty");
return null;
}
return _setting.settingKeyValue[key];
} }
/// Called when the application launch. /// Called when the application launch.
@ -103,15 +109,12 @@ class AppearanceSetting extends ChangeNotifier with EquatableMixin {
} }
Future<void> _saveAppearSetting() async { Future<void> _saveAppearSetting() async {
_debounceSaveOperation?.cancel(); SettingsFFIService().setAppearanceSetting(_setting).then((result) {
_debounceSaveOperation = Timer( result.fold(
const Duration(seconds: 1), (l) => null,
() { (error) => Log.error(error),
SettingsFFIService().setAppearanceSetting(_setting).then((result) { );
result.fold((l) => null, (error) => Log.error(error)); });
});
},
);
} }
@override @override

View File

@ -0,0 +1,43 @@
import 'package:app_flowy/user/application/user_settings_service.dart';
import 'package:app_flowy/workspace/application/appearance.dart';
import 'package:flowy_infra/theme.dart';
import 'package:flutter_test/flutter_test.dart';
import '../../util.dart';
void main() {
// ignore: unused_local_variable
late AppFlowyUnitTest context;
setUpAll(() async {
context = await AppFlowyUnitTest.ensureInitialized();
});
group('$AppearanceSetting', () {
late AppearanceSetting appearanceSetting;
setUp(() async {
final setting = await SettingsFFIService().getAppearanceSetting();
appearanceSetting = AppearanceSetting(setting);
await blocResponseFuture();
});
test('default theme', () {
expect(appearanceSetting.theme.ty, ThemeType.light);
});
test('save key/value', () async {
appearanceSetting.setKeyValue("123", "456");
});
test('read key/value', () {
expect(appearanceSetting.getValue("123"), "456");
});
test('remove key/value', () {
appearanceSetting.setKeyValue("123", null);
});
test('read key/value', () {
expect(appearanceSetting.getValue("123"), null);
});
});
}

View File

@ -12,38 +12,42 @@ void main() {
late AppFlowyUnitTest test; late AppFlowyUnitTest test;
late AppPB app; late AppPB app;
late AppBloc appBloc; late AppBloc appBloc;
late List<ViewPB> allViews; late TrashBloc trashBloc;
setUpAll(() async { setUpAll(() async {
test = await AppFlowyUnitTest.ensureInitialized(); test = await AppFlowyUnitTest.ensureInitialized();
/// Create a new app with three documents
app = await test.createTestApp();
appBloc = AppBloc(app: app)
..add(const AppEvent.initial())
..add(AppEvent.createView(
"Document 1",
DocumentPluginBuilder(),
))
..add(AppEvent.createView(
"Document 2",
DocumentPluginBuilder(),
))
..add(
AppEvent.createView(
"Document 3",
DocumentPluginBuilder(),
),
);
await blocResponseFuture(millisecond: 200);
allViews = [...appBloc.state.app.belongings.items];
assert(allViews.length == 3);
}); });
// 1. Create three views
// 2. Delete a view and check the state
// 3. Delete all views and check the state
// 4. Put back a view
// 5. Put back all views
group('$TrashBloc', () { group('$TrashBloc', () {
late TrashBloc trashBloc;
late ViewPB deletedView; late ViewPB deletedView;
late List<ViewPB> allViews;
setUpAll(() {}); setUpAll(() async {
/// Create a new app with three documents
app = await test.createTestApp();
appBloc = AppBloc(app: app)
..add(const AppEvent.initial())
..add(AppEvent.createView(
"Document 1",
DocumentPluginBuilder(),
))
..add(AppEvent.createView(
"Document 2",
DocumentPluginBuilder(),
))
..add(
AppEvent.createView(
"Document 3",
DocumentPluginBuilder(),
),
);
await blocResponseFuture(millisecond: 200);
allViews = [...appBloc.state.app.belongings.items];
assert(allViews.length == 3);
});
setUp(() async { setUp(() async {
trashBloc = TrashBloc()..add(const TrashEvent.initial()); trashBloc = TrashBloc()..add(const TrashEvent.initial());
@ -51,7 +55,7 @@ void main() {
}); });
blocTest<TrashBloc, TrashState>( blocTest<TrashBloc, TrashState>(
"delete view", "delete a view",
build: () => trashBloc, build: () => trashBloc,
act: (bloc) async { act: (bloc) async {
deletedView = appBloc.state.app.belongings.items[0]; deletedView = appBloc.state.app.belongings.items[0];
@ -82,7 +86,7 @@ void main() {
}, },
); );
blocTest<TrashBloc, TrashState>( blocTest<TrashBloc, TrashState>(
"put back", "put back a trash",
build: () => trashBloc, build: () => trashBloc,
act: (bloc) async { act: (bloc) async {
bloc.add(TrashEvent.putback(allViews[0].id)); bloc.add(TrashEvent.putback(allViews[0].id));
@ -94,7 +98,7 @@ void main() {
}, },
); );
blocTest<TrashBloc, TrashState>( blocTest<TrashBloc, TrashState>(
"put back all", "put back all trash",
build: () => trashBloc, build: () => trashBloc,
act: (bloc) async { act: (bloc) async {
bloc.add(const TrashEvent.restoreAll()); bloc.add(const TrashEvent.restoreAll());
@ -107,4 +111,69 @@ void main() {
); );
// //
}); });
// 1. Create three views
// 2. Delete a trash permanently and check the state
// 3. Delete all views permanently
group('$TrashBloc', () {
setUpAll(() async {
/// Create a new app with three documents
app = await test.createTestApp();
appBloc = AppBloc(app: app)
..add(const AppEvent.initial())
..add(AppEvent.createView(
"Document 1",
DocumentPluginBuilder(),
))
..add(AppEvent.createView(
"Document 2",
DocumentPluginBuilder(),
))
..add(
AppEvent.createView(
"Document 3",
DocumentPluginBuilder(),
),
);
await blocResponseFuture(millisecond: 200);
});
setUp(() async {
trashBloc = TrashBloc()..add(const TrashEvent.initial());
await blocResponseFuture();
});
blocTest<TrashBloc, TrashState>(
"delete a view permanently",
build: () => trashBloc,
act: (bloc) async {
final view = appBloc.state.app.belongings.items[0];
appBloc.add(AppEvent.deleteView(view.id));
await blocResponseFuture();
trashBloc.add(TrashEvent.delete(trashBloc.state.objects[0]));
},
wait: blocResponseDuration(),
verify: (bloc) {
assert(appBloc.state.app.belongings.items.length == 2);
assert(bloc.state.objects.isEmpty);
},
);
blocTest<TrashBloc, TrashState>(
"delete all view permanently",
build: () => trashBloc,
act: (bloc) async {
for (final view in appBloc.state.app.belongings.items) {
appBloc.add(AppEvent.deleteView(view.id));
}
await blocResponseFuture();
trashBloc.add(const TrashEvent.deleteAll());
},
wait: blocResponseDuration(),
verify: (bloc) {
assert(appBloc.state.app.belongings.items.isEmpty);
assert(bloc.state.objects.isEmpty);
},
);
});
} }