Browse Source

chore: add grid header bloc test (#1341)

Co-authored-by: nathan <[email protected]>
Nathan.fooo 2 years ago
parent
commit
96b1c6a540

+ 18 - 3
frontend/app_flowy/lib/plugins/grid/application/field/field_action_sheet_bloc.dart

@@ -11,9 +11,16 @@ class FieldActionSheetBloc
     extends Bloc<FieldActionSheetEvent, FieldActionSheetState> {
   final FieldService fieldService;
 
-  FieldActionSheetBloc({required FieldPB field, required this.fieldService})
-      : super(FieldActionSheetState.initial(
-            FieldTypeOptionDataPB.create()..field_2 = field)) {
+  FieldActionSheetBloc({required GridFieldCellContext fieldCellContext})
+      : fieldService = FieldService(
+          gridId: fieldCellContext.gridId,
+          fieldId: fieldCellContext.field.id,
+        ),
+        super(
+          FieldActionSheetState.initial(
+            FieldTypeOptionDataPB.create()..field_2 = fieldCellContext.field,
+          ),
+        ) {
     on<FieldActionSheetEvent>(
       (event, emit) async {
         await event.map(
@@ -31,6 +38,13 @@ class FieldActionSheetBloc
               (err) => Log.error(err),
             );
           },
+          showField: (_ShowField value) async {
+            final result = await fieldService.updateField(visibility: true);
+            result.fold(
+              (l) => null,
+              (err) => Log.error(err),
+            );
+          },
           deleteField: (_DeleteField value) async {
             final result = await fieldService.deleteField();
             result.fold(
@@ -62,6 +76,7 @@ class FieldActionSheetEvent with _$FieldActionSheetEvent {
   const factory FieldActionSheetEvent.updateFieldName(String name) =
       _UpdateFieldName;
   const factory FieldActionSheetEvent.hideField() = _HideField;
+  const factory FieldActionSheetEvent.showField() = _ShowField;
   const factory FieldActionSheetEvent.duplicateField() = _DuplicateField;
   const factory FieldActionSheetEvent.deleteField() = _DeleteField;
   const factory FieldActionSheetEvent.saveField() = _SaveField;

+ 1 - 2
frontend/app_flowy/lib/plugins/grid/application/field/field_controller.dart

@@ -16,8 +16,7 @@ class _GridFieldNotifier extends ChangeNotifier {
   List<GridFieldContext> _fieldContexts = [];
 
   set fieldContexts(List<GridFieldContext> fieldContexts) {
-    _fieldContexts =
-        fieldContexts.where((element) => element.visibility).toList();
+    _fieldContexts = fieldContexts;
     notifyListeners();
   }
 

+ 7 - 1
frontend/app_flowy/lib/plugins/grid/application/grid_header_bloc.dart

@@ -23,7 +23,13 @@ class GridHeaderBloc extends Bloc<GridHeaderEvent, GridHeaderState> {
             _startListening();
           },
           didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) {
-            emit(state.copyWith(fields: value.fields));
+            emit(
+              state.copyWith(
+                fields: value.fields
+                    .where((element) => element.visibility)
+                    .toList(),
+              ),
+            );
           },
           moveField: (_MoveField value) async {
             await _moveField(value, emit);

+ 1 - 4
frontend/app_flowy/lib/startup/deps_resolver.dart

@@ -158,10 +158,7 @@ void _resolveGridDeps(GetIt getIt) {
   );
 
   getIt.registerFactoryParam<FieldActionSheetBloc, GridFieldCellContext, void>(
-    (data, _) => FieldActionSheetBloc(
-      field: data.field,
-      fieldService: FieldService(gridId: data.gridId, fieldId: data.field.id),
-    ),
+    (data, _) => FieldActionSheetBloc(fieldCellContext: data),
   );
 
   getIt.registerFactoryParam<TextCellBloc, GridCellController, void>(

+ 125 - 0
frontend/app_flowy/test/bloc_test/grid_test/grid_header_bloc_test.dart

@@ -0,0 +1,125 @@
+import 'package:app_flowy/plugins/grid/application/field/field_action_sheet_bloc.dart';
+import 'package:app_flowy/plugins/grid/application/grid_header_bloc.dart';
+import 'package:bloc_test/bloc_test.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+import 'util.dart';
+
+void main() {
+  late AppFlowyGridTest gridTest;
+
+  setUpAll(() async {
+    gridTest = await AppFlowyGridTest.ensureInitialized();
+  });
+
+  group('GridHeaderBloc', () {
+    late FieldActionSheetBloc actionSheetBloc;
+    setUp(() async {
+      await gridTest.createTestGrid();
+      actionSheetBloc = FieldActionSheetBloc(
+        fieldCellContext: gridTest.singleSelectFieldCellContext(),
+      );
+    });
+
+    blocTest<GridHeaderBloc, GridHeaderState>(
+      "hides property",
+      build: () {
+        final bloc = GridHeaderBloc(
+          gridId: gridTest.gridView.id,
+          fieldController: gridTest.fieldController,
+        )..add(const GridHeaderEvent.initial());
+        return bloc;
+      },
+      act: (bloc) async {
+        actionSheetBloc.add(const FieldActionSheetEvent.hideField());
+        await Future.delayed(gridResponseDuration());
+      },
+      wait: gridResponseDuration(),
+      verify: (bloc) {
+        assert(bloc.state.fields.length == 2);
+      },
+    );
+
+    blocTest<GridHeaderBloc, GridHeaderState>(
+      "shows property",
+      build: () {
+        final bloc = GridHeaderBloc(
+          gridId: gridTest.gridView.id,
+          fieldController: gridTest.fieldController,
+        )..add(const GridHeaderEvent.initial());
+        return bloc;
+      },
+      act: (bloc) async {
+        actionSheetBloc.add(const FieldActionSheetEvent.hideField());
+        await Future.delayed(gridResponseDuration());
+        actionSheetBloc.add(const FieldActionSheetEvent.showField());
+        await Future.delayed(gridResponseDuration());
+      },
+      wait: gridResponseDuration(),
+      verify: (bloc) {
+        assert(bloc.state.fields.length == 3);
+      },
+    );
+
+    blocTest<GridHeaderBloc, GridHeaderState>(
+      "duplicate property",
+      build: () {
+        final bloc = GridHeaderBloc(
+          gridId: gridTest.gridView.id,
+          fieldController: gridTest.fieldController,
+        )..add(const GridHeaderEvent.initial());
+        return bloc;
+      },
+      act: (bloc) async {
+        actionSheetBloc.add(const FieldActionSheetEvent.duplicateField());
+        await Future.delayed(gridResponseDuration());
+      },
+      wait: gridResponseDuration(),
+      verify: (bloc) {
+        assert(bloc.state.fields.length == 4);
+      },
+    );
+
+    blocTest<GridHeaderBloc, GridHeaderState>(
+      "delete property",
+      build: () {
+        final bloc = GridHeaderBloc(
+          gridId: gridTest.gridView.id,
+          fieldController: gridTest.fieldController,
+        )..add(const GridHeaderEvent.initial());
+        return bloc;
+      },
+      act: (bloc) async {
+        actionSheetBloc.add(const FieldActionSheetEvent.deleteField());
+        await Future.delayed(gridResponseDuration());
+      },
+      wait: gridResponseDuration(),
+      verify: (bloc) {
+        assert(bloc.state.fields.length == 2);
+      },
+    );
+
+    blocTest<GridHeaderBloc, GridHeaderState>(
+      "update name",
+      build: () {
+        final bloc = GridHeaderBloc(
+          gridId: gridTest.gridView.id,
+          fieldController: gridTest.fieldController,
+        )..add(const GridHeaderEvent.initial());
+        return bloc;
+      },
+      act: (bloc) async {
+        actionSheetBloc
+            .add(const FieldActionSheetEvent.updateFieldName("Hello world"));
+        await Future.delayed(gridResponseDuration());
+      },
+      wait: gridResponseDuration(),
+      verify: (bloc) {
+        final field = bloc.state.fields.firstWhere(
+            (element) => element.id == actionSheetBloc.fieldService.fieldId);
+
+        assert(field.name == "Hello world");
+      },
+    );
+  });
+}

+ 75 - 45
frontend/app_flowy/test/bloc_test/grid_test/util.dart

@@ -1,4 +1,8 @@
+import 'dart:collection';
+import 'package:app_flowy/plugins/grid/application/block/block_cache.dart';
 import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
+import 'package:app_flowy/plugins/grid/application/field/field_controller.dart';
+import 'package:app_flowy/plugins/grid/application/field/field_service.dart';
 import 'package:app_flowy/plugins/grid/application/grid_data_controller.dart';
 import 'package:app_flowy/plugins/grid/application/row/row_bloc.dart';
 import 'package:app_flowy/plugins/grid/application/row/row_cache.dart';
@@ -12,9 +16,10 @@ import '../../util.dart';
 
 /// Create a empty Grid for test
 class AppFlowyGridTest {
-  // ignore: unused_field
   final AppFlowyUnitTest _inner;
   late ViewPB gridView;
+  late GridDataController _dataController;
+
   AppFlowyGridTest(AppFlowyUnitTest unitTest) : _inner = unitTest;
 
   static Future<AppFlowyGridTest> ensureInitialized() async {
@@ -22,6 +27,31 @@ class AppFlowyGridTest {
     return AppFlowyGridTest(inner);
   }
 
+  List<RowInfo> get rowInfos => _dataController.rowInfos;
+
+  UnmodifiableMapView<String, GridBlockCache> get blocks =>
+      _dataController.blocks;
+
+  List<GridFieldContext> get fieldContexts =>
+      _dataController.fieldController.fieldContexts;
+
+  GridFieldController get fieldController => _dataController.fieldController;
+
+  Future<void> createRow() async {
+    await _dataController.createRow();
+  }
+
+  GridFieldContext singleSelectFieldContext() {
+    final fieldContext = fieldContexts
+        .firstWhere((element) => element.fieldType == FieldType.SingleSelect);
+    return fieldContext;
+  }
+
+  GridFieldCellContext singleSelectFieldCellContext() {
+    final field = singleSelectFieldContext().field;
+    return GridFieldCellContext(gridId: gridView.id, field: field);
+  }
+
   Future<void> createTestGrid() async {
     final app = await _inner.createTestApp();
     final builder = GridPluginBuilder();
@@ -32,51 +62,21 @@ class AppFlowyGridTest {
       pluginType: builder.pluginType,
       layoutType: builder.layoutType!,
     );
-    result.fold(
-      (view) => gridView = view,
+    await result.fold(
+      (view) async {
+        gridView = view;
+        _dataController = GridDataController(view: view);
+        final result = await _dataController.loadData();
+        result.fold((l) => null, (r) => throw Exception(r));
+      },
       (error) {},
     );
   }
 }
 
-class AppFlowyGridSelectOptionCellTest {
-  final AppFlowyGridCellTest _gridCellTest;
-
-  AppFlowyGridSelectOptionCellTest(AppFlowyGridCellTest cellTest)
-      : _gridCellTest = cellTest;
-
-  static Future<AppFlowyGridSelectOptionCellTest> ensureInitialized() async {
-    final gridTest = await AppFlowyGridCellTest.ensureInitialized();
-    return AppFlowyGridSelectOptionCellTest(gridTest);
-  }
-
-  Future<void> createTestGrid() async {
-    await _gridCellTest.createTestGrid();
-  }
-
-  Future<void> createTestRow() async {
-    await _gridCellTest.createTestRow();
-  }
-
-  Future<GridSelectOptionCellController> makeCellController(
-      FieldType fieldType) async {
-    assert(fieldType == FieldType.SingleSelect ||
-        fieldType == FieldType.MultiSelect);
-
-    final fieldContexts =
-        _gridCellTest._dataController.fieldController.fieldContexts;
-    final field =
-        fieldContexts.firstWhere((element) => element.fieldType == fieldType);
-    final builder = await _gridCellTest.cellControllerBuilder(field.id);
-    final cellController = builder.build() as GridSelectOptionCellController;
-    return cellController;
-  }
-}
-
 /// Create a new Grid for cell test
 class AppFlowyGridCellTest {
   final AppFlowyGridTest _gridTest;
-  late GridDataController _dataController;
   AppFlowyGridCellTest(AppFlowyGridTest gridTest) : _gridTest = gridTest;
 
   static Future<AppFlowyGridCellTest> ensureInitialized() async {
@@ -85,26 +85,23 @@ class AppFlowyGridCellTest {
   }
 
   Future<void> createTestRow() async {
-    await _dataController.createRow();
+    await _gridTest.createRow();
   }
 
   Future<void> createTestGrid() async {
     await _gridTest.createTestGrid();
-    _dataController = GridDataController(view: _gridTest.gridView);
-    final result = await _dataController.loadData();
-    result.fold((l) => null, (r) => throw Exception(r));
   }
 
   Future<GridCellControllerBuilder> cellControllerBuilder(
     String fieldId,
   ) async {
-    final RowInfo rowInfo = _dataController.rowInfos.last;
-    final blockCache = _dataController.blocks[rowInfo.rowPB.blockId];
+    final RowInfo rowInfo = _gridTest.rowInfos.last;
+    final blockCache = _gridTest.blocks[rowInfo.rowPB.blockId];
     final rowCache = blockCache?.rowCache;
 
     final rowDataController = GridRowDataController(
       rowInfo: rowInfo,
-      fieldController: _dataController.fieldController,
+      fieldController: _gridTest._dataController.fieldController,
       rowCache: rowCache!,
     );
 
@@ -122,6 +119,39 @@ class AppFlowyGridCellTest {
   }
 }
 
+class AppFlowyGridSelectOptionCellTest {
+  final AppFlowyGridCellTest _gridCellTest;
+
+  AppFlowyGridSelectOptionCellTest(AppFlowyGridCellTest cellTest)
+      : _gridCellTest = cellTest;
+
+  static Future<AppFlowyGridSelectOptionCellTest> ensureInitialized() async {
+    final gridTest = await AppFlowyGridCellTest.ensureInitialized();
+    return AppFlowyGridSelectOptionCellTest(gridTest);
+  }
+
+  Future<void> createTestGrid() async {
+    await _gridCellTest.createTestGrid();
+  }
+
+  Future<void> createTestRow() async {
+    await _gridCellTest.createTestRow();
+  }
+
+  Future<GridSelectOptionCellController> makeCellController(
+      FieldType fieldType) async {
+    assert(fieldType == FieldType.SingleSelect ||
+        fieldType == FieldType.MultiSelect);
+
+    final fieldContexts = _gridCellTest._gridTest.fieldContexts;
+    final field =
+        fieldContexts.firstWhere((element) => element.fieldType == fieldType);
+    final builder = await _gridCellTest.cellControllerBuilder(field.id);
+    final cellController = builder.build() as GridSelectOptionCellController;
+    return cellController;
+  }
+}
+
 Future<void> gridResponseFuture() {
   return Future.delayed(gridResponseDuration(milliseconds: 200));
 }