浏览代码

chore: add app setting test (#1361)

Nathan.fooo 2 年之前
父节点
当前提交
18185cc90c

+ 6 - 6
frontend/app_flowy/lib/startup/tasks/app_widget.dart

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

+ 15 - 12
frontend/app_flowy/lib/workspace/application/appearance.dart

@@ -13,7 +13,6 @@ class AppearanceSetting extends ChangeNotifier with EquatableMixin {
   final AppearanceSettingsPB _setting;
   AppTheme _theme;
   Locale _locale;
-  Timer? _debounceSaveOperation;
 
   AppearanceSetting(AppearanceSettingsPB setting)
       : _setting = setting,
@@ -83,10 +82,17 @@ class AppearanceSetting extends ChangeNotifier with EquatableMixin {
       } else {
         _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.
@@ -103,15 +109,12 @@ class AppearanceSetting extends ChangeNotifier with EquatableMixin {
   }
 
   Future<void> _saveAppearSetting() async {
-    _debounceSaveOperation?.cancel();
-    _debounceSaveOperation = Timer(
-      const Duration(seconds: 1),
-      () {
-        SettingsFFIService().setAppearanceSetting(_setting).then((result) {
-          result.fold((l) => null, (error) => Log.error(error));
-        });
-      },
-    );
+    SettingsFFIService().setAppearanceSetting(_setting).then((result) {
+      result.fold(
+        (l) => null,
+        (error) => Log.error(error),
+      );
+    });
   }
 
   @override

+ 43 - 0
frontend/app_flowy/test/bloc_test/app_setting_test/appearance_test.dart

@@ -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);
+    });
+  });
+}

+ 98 - 29
frontend/app_flowy/test/bloc_test/menu_test/trash_bloc_test.dart

@@ -12,38 +12,42 @@ void main() {
   late AppFlowyUnitTest test;
   late AppPB app;
   late AppBloc appBloc;
-  late List<ViewPB> allViews;
+  late TrashBloc trashBloc;
   setUpAll(() async {
     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', () {
-    late TrashBloc trashBloc;
     late ViewPB deletedView;
-
-    setUpAll(() {});
+    late List<ViewPB> allViews;
+    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 {
       trashBloc = TrashBloc()..add(const TrashEvent.initial());
@@ -51,7 +55,7 @@ void main() {
     });
 
     blocTest<TrashBloc, TrashState>(
-      "delete view",
+      "delete a view",
       build: () => trashBloc,
       act: (bloc) async {
         deletedView = appBloc.state.app.belongings.items[0];
@@ -82,7 +86,7 @@ void main() {
       },
     );
     blocTest<TrashBloc, TrashState>(
-      "put back",
+      "put back a trash",
       build: () => trashBloc,
       act: (bloc) async {
         bloc.add(TrashEvent.putback(allViews[0].id));
@@ -94,7 +98,7 @@ void main() {
       },
     );
     blocTest<TrashBloc, TrashState>(
-      "put back all",
+      "put back all trash",
       build: () => trashBloc,
       act: (bloc) async {
         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);
+      },
+    );
+  });
 }