Merge pull request #1490 from AppFlowy-IO/filter_bloc_test

chore: add filter test
This commit is contained in:
Nathan.fooo 2022-11-27 17:20:24 +08:00 committed by GitHub
commit 8c7e2d341d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 241 additions and 40 deletions

View File

@ -66,7 +66,6 @@ class BoardCardBloc extends Bloc<BoardCardEvent, BoardCardState> {
state.cells.map((cell) => cell.identifier.fieldInfo).toList(), state.cells.map((cell) => cell.identifier.fieldInfo).toList(),
), ),
rowPB: state.rowPB, rowPB: state.rowPB,
visible: true,
); );
} }

View File

@ -287,7 +287,6 @@ class _BoardContentState extends State<BoardContent> {
gridId: gridId, gridId: gridId,
fields: UnmodifiableListView(fieldController.fieldInfos), fields: UnmodifiableListView(fieldController.fieldInfos),
rowPB: rowPB, rowPB: rowPB,
visible: true,
); );
final dataController = GridRowDataController( final dataController = GridRowDataController(

View File

@ -39,7 +39,6 @@ class GridRowCache {
UnmodifiableListView<RowInfo> get visibleRows { UnmodifiableListView<RowInfo> get visibleRows {
var visibleRows = [..._rowList.rows]; var visibleRows = [..._rowList.rows];
visibleRows.retainWhere((element) => element.visible);
return UnmodifiableListView(visibleRows); return UnmodifiableListView(visibleRows);
} }
@ -236,7 +235,6 @@ class GridRowCache {
gridId: gridId, gridId: gridId,
fields: _fieldNotifier.fields, fields: _fieldNotifier.fields,
rowPB: rowPB, rowPB: rowPB,
visible: true,
); );
} }
} }
@ -264,7 +262,6 @@ class RowInfo with _$RowInfo {
required String gridId, required String gridId,
required UnmodifiableListView<FieldInfo> fields, required UnmodifiableListView<FieldInfo> fields,
required RowPB rowPB, required RowPB rowPB,
required bool visible,
}) = _RowInfo; }) = _RowInfo;
} }

View File

@ -6,7 +6,7 @@ import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/select_type_option.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/select_type_option.pb.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:bloc_test/bloc_test.dart'; import 'package:bloc_test/bloc_test.dart';
import 'util.dart'; import '../util.dart';
void main() { void main() {
late AppFlowyGridCellTest cellTest; late AppFlowyGridCellTest cellTest;
@ -19,9 +19,8 @@ void main() {
setUp(() async { setUp(() async {
await cellTest.createTestGrid(); await cellTest.createTestGrid();
await cellTest.createTestRow(); await cellTest.createTestRow();
cellController = await cellTest.makeCellController( cellController =
FieldType.SingleSelect, await cellTest.makeCellController(FieldType.SingleSelect, 0);
);
}); });
blocTest<SelectOptionCellEditorBloc, SelectOptionEditorState>( blocTest<SelectOptionCellEditorBloc, SelectOptionEditorState>(

View File

@ -3,7 +3,7 @@ import 'package:app_flowy/plugins/grid/application/prelude.dart';
import 'package:bloc_test/bloc_test.dart'; import 'package:bloc_test/bloc_test.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'util.dart'; import '../util.dart';
Future<FieldEditorBloc> createEditorBloc(AppFlowyGridTest gridTest) async { Future<FieldEditorBloc> createEditorBloc(AppFlowyGridTest gridTest) async {
final context = await gridTest.createTestGrid(); final context = await gridTest.createTestGrid();

View File

@ -4,7 +4,8 @@ import 'package:app_flowy/plugins/grid/application/grid_data_controller.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/checkbox_filter.pbenum.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/checkbox_filter.pbenum.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/text_filter.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/text_filter.pb.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'util.dart';
import '../util.dart';
void main() { void main() {
late AppFlowyGridTest gridTest; late AppFlowyGridTest gridTest;
@ -16,11 +17,12 @@ void main() {
final context = await gridTest.createTestGrid(); final context = await gridTest.createTestGrid();
final service = FilterFFIService(viewId: context.gridView.id); final service = FilterFFIService(viewId: context.gridView.id);
final textField = context.textFieldContext(); final textField = context.textFieldContext();
service.insertTextFilter( await service.insertTextFilter(
fieldId: textField.id, fieldId: textField.id,
condition: TextFilterCondition.TextIsEmpty, condition: TextFilterCondition.TextIsEmpty,
content: ""); content: "");
await gridResponseFuture(); await gridResponseFuture();
assert(context.fieldController.filterInfos.length == 1); assert(context.fieldController.filterInfos.length == 1);
}); });
@ -28,14 +30,14 @@ void main() {
final context = await gridTest.createTestGrid(); final context = await gridTest.createTestGrid();
final service = FilterFFIService(viewId: context.gridView.id); final service = FilterFFIService(viewId: context.gridView.id);
final textField = context.textFieldContext(); final textField = context.textFieldContext();
service.insertTextFilter( await service.insertTextFilter(
fieldId: textField.id, fieldId: textField.id,
condition: TextFilterCondition.TextIsEmpty, condition: TextFilterCondition.TextIsEmpty,
content: ""); content: "");
await gridResponseFuture(); await gridResponseFuture();
final filterInfo = context.fieldController.filterInfos.first; final filterInfo = context.fieldController.filterInfos.first;
service.deleteFilter( await service.deleteFilter(
fieldId: textField.id, fieldId: textField.id,
filterId: filterInfo.filter.id, filterId: filterInfo.filter.id,
fieldType: textField.fieldType, fieldType: textField.fieldType,
@ -77,13 +79,13 @@ void main() {
await gridResponseFuture(); await gridResponseFuture();
final textField = context.textFieldContext(); final textField = context.textFieldContext();
service.insertTextFilter( await service.insertTextFilter(
fieldId: textField.id, fieldId: textField.id,
condition: TextFilterCondition.TextIsEmpty, condition: TextFilterCondition.TextIsEmpty,
content: ""); content: "");
await gridResponseFuture(); await gridResponseFuture();
final controller = await context.makeTextCellController(); final controller = await context.makeTextCellController(0);
controller.saveCellData("edit text cell content"); controller.saveCellData("edit text cell content");
await gridResponseFuture(); await gridResponseFuture();
assert(gridBloc.state.rowInfos.length == 2); assert(gridBloc.state.rowInfos.length == 2);
@ -98,7 +100,7 @@ void main() {
final service = FilterFFIService(viewId: context.gridView.id); final service = FilterFFIService(viewId: context.gridView.id);
final textField = context.textFieldContext(); final textField = context.textFieldContext();
await gridResponseFuture(); await gridResponseFuture();
service.insertTextFilter( await service.insertTextFilter(
fieldId: textField.id, fieldId: textField.id,
condition: TextFilterCondition.TextIsNotEmpty, condition: TextFilterCondition.TextIsNotEmpty,
content: ""); content: "");
@ -117,7 +119,7 @@ void main() {
)..add(const GridEvent.initial()); )..add(const GridEvent.initial());
await gridResponseFuture(); await gridResponseFuture();
service.insertCheckboxFilter( await service.insertCheckboxFilter(
fieldId: checkboxField.id, fieldId: checkboxField.id,
condition: CheckboxFilterCondition.IsUnChecked, condition: CheckboxFilterCondition.IsUnChecked,
); );
@ -136,7 +138,7 @@ void main() {
)..add(const GridEvent.initial()); )..add(const GridEvent.initial());
await gridResponseFuture(); await gridResponseFuture();
service.insertCheckboxFilter( await service.insertCheckboxFilter(
fieldId: checkboxField.id, fieldId: checkboxField.id,
condition: CheckboxFilterCondition.IsChecked, condition: CheckboxFilterCondition.IsChecked,
); );

View File

@ -5,7 +5,8 @@ import 'package:app_flowy/plugins/grid/application/filter/filter_service.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/text_filter.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/text_filter.pb.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'util.dart';
import '../util.dart';
void main() { void main() {
late AppFlowyGridTest gridTest; late AppFlowyGridTest gridTest;
@ -25,7 +26,7 @@ void main() {
)..add(const GridFilterMenuEvent.initial()); )..add(const GridFilterMenuEvent.initial());
// Insert filter for the text field // Insert filter for the text field
service.insertTextFilter( await service.insertTextFilter(
fieldId: textField.id, fieldId: textField.id,
condition: TextFilterCondition.TextIsEmpty, condition: TextFilterCondition.TextIsEmpty,
content: ""); content: "");

View File

@ -0,0 +1,61 @@
import 'package:app_flowy/plugins/grid/application/filter/filter_menu_bloc.dart';
import 'package:app_flowy/plugins/grid/application/filter/filter_service.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/text_filter.pb.dart';
import 'package:flutter_test/flutter_test.dart';
import '../util.dart';
void main() {
late AppFlowyGridTest gridTest;
setUpAll(() async {
gridTest = await AppFlowyGridTest.ensureInitialized();
});
test('test filter menu after create a text filter)', () async {
final context = await gridTest.createTestGrid();
final menuBloc = GridFilterMenuBloc(
viewId: context.gridView.id, fieldController: context.fieldController)
..add(const GridFilterMenuEvent.initial());
await gridResponseFuture();
assert(menuBloc.state.creatableFields.length == 1);
final service = FilterFFIService(viewId: context.gridView.id);
final textField = context.textFieldContext();
await service.insertTextFilter(
fieldId: textField.id,
condition: TextFilterCondition.TextIsEmpty,
content: "");
await gridResponseFuture();
assert(menuBloc.state.creatableFields.isEmpty);
});
test('test filter menu after update existing text filter)', () async {
final context = await gridTest.createTestGrid();
final menuBloc = GridFilterMenuBloc(
viewId: context.gridView.id, fieldController: context.fieldController)
..add(const GridFilterMenuEvent.initial());
await gridResponseFuture();
final service = FilterFFIService(viewId: context.gridView.id);
final textField = context.textFieldContext();
// Create filter
await service.insertTextFilter(
fieldId: textField.id,
condition: TextFilterCondition.TextIsEmpty,
content: "");
await gridResponseFuture();
final textFilter = context.fieldController.filterInfos.first;
// Update the existing filter
await service.insertTextFilter(
fieldId: textField.id,
filterId: textFilter.filter.id,
condition: TextFilterCondition.Is,
content: "ABC");
await gridResponseFuture();
assert(menuBloc.state.filters.first.textFilter()!.condition ==
TextFilterCondition.Is);
assert(menuBloc.state.filters.first.textFilter()!.content == "ABC");
});
}

View File

@ -0,0 +1,99 @@
import 'package:app_flowy/plugins/grid/application/filter/filter_service.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/text_filter.pb.dart';
import 'package:flutter_test/flutter_test.dart';
import '../util.dart';
import 'filter_util.dart';
void main() {
late AppFlowyGridTest gridTest;
setUpAll(() async {
gridTest = await AppFlowyGridTest.ensureInitialized();
});
test('filter rows by text is empty or is not empty condition)', () async {
final context = await createTestFilterGrid(gridTest);
final service = FilterFFIService(viewId: context.gridView.id);
final textField = context.textFieldContext();
// create a new filter
await service.insertTextFilter(
fieldId: textField.id,
condition: TextFilterCondition.TextIsEmpty,
content: "");
await gridResponseFuture();
assert(context.fieldController.filterInfos.length == 1,
"expect 1 but receive ${context.fieldController.filterInfos.length}");
assert(context.rowInfos.length == 1,
"expect 1 but receive ${context.rowInfos.length}");
// Update the existing filter
final textFilter = context.fieldController.filterInfos.first;
await service.insertTextFilter(
fieldId: textField.id,
filterId: textFilter.filter.id,
condition: TextFilterCondition.TextIsNotEmpty,
content: "");
await gridResponseFuture();
assert(context.rowInfos.length == 2);
// delete the filter
await service.deleteFilter(
fieldId: textField.id,
filterId: textFilter.filter.id,
fieldType: textField.fieldType,
);
await gridResponseFuture();
assert(context.rowInfos.length == 3);
});
test('filter rows by text is condition)', () async {
final context = await createTestFilterGrid(gridTest);
final service = FilterFFIService(viewId: context.gridView.id);
final textField = context.textFieldContext();
// create a new filter
await service.insertTextFilter(
fieldId: textField.id, condition: TextFilterCondition.Is, content: "A");
await gridResponseFuture();
assert(context.rowInfos.length == 1,
"expect 1 but receive ${context.rowInfos.length}");
// Update the existing filter's content from 'A' to 'B'
final textFilter = context.fieldController.filterInfos.first;
await service.insertTextFilter(
fieldId: textField.id,
filterId: textFilter.filter.id,
condition: TextFilterCondition.Is,
content: "B");
await gridResponseFuture();
assert(context.rowInfos.length == 1);
// Update the existing filter's content from 'B' to 'b'
await service.insertTextFilter(
fieldId: textField.id,
filterId: textFilter.filter.id,
condition: TextFilterCondition.Is,
content: "b");
await gridResponseFuture();
assert(context.rowInfos.length == 1);
// Update the existing filter with content 'C'
await service.insertTextFilter(
fieldId: textField.id,
filterId: textFilter.filter.id,
condition: TextFilterCondition.Is,
content: "C");
await gridResponseFuture();
assert(context.rowInfos.isEmpty);
// delete the filter
await service.deleteFilter(
fieldId: textField.id,
filterId: textFilter.filter.id,
fieldType: textField.fieldType,
);
await gridResponseFuture();
assert(context.rowInfos.length == 3);
});
}

View File

@ -0,0 +1,42 @@
import 'package:app_flowy/plugins/grid/application/grid_data_controller.dart';
import 'package:app_flowy/plugins/grid/grid.dart';
import 'package:app_flowy/workspace/application/app/app_service.dart';
import '../util.dart';
Future<GridTestContext> createTestFilterGrid(AppFlowyGridTest gridTest) async {
final app = await gridTest.unitTest.createTestApp();
final builder = GridPluginBuilder();
final context = await AppService()
.createView(
appId: app.id,
name: "Filter Grid",
dataFormatType: builder.dataFormatType,
pluginType: builder.pluginType,
layoutType: builder.layoutType!,
)
.then((result) {
return result.fold(
(view) async {
final context = GridTestContext(view, GridController(view: view));
final result = await context.gridController.openGrid();
await editCells(context);
await gridResponseFuture(milliseconds: 500);
result.fold((l) => null, (r) => throw Exception(r));
return context;
},
(error) => throw Exception(),
);
});
return context;
}
Future<void> editCells(GridTestContext context) async {
final controller0 = await context.makeTextCellController(0);
final controller1 = await context.makeTextCellController(1);
controller0.saveCellData('A');
controller1.saveCellData('B');
}

View File

@ -18,26 +18,26 @@ import '../../util.dart';
class GridTestContext { class GridTestContext {
final ViewPB gridView; final ViewPB gridView;
final GridController _gridController; final GridController gridController;
GridTestContext(this.gridView, this._gridController); GridTestContext(this.gridView, this.gridController);
List<RowInfo> get rowInfos { List<RowInfo> get rowInfos {
return _gridController.rowInfos; return gridController.rowInfos;
} }
UnmodifiableMapView<String, GridBlockCache> get blocks { UnmodifiableMapView<String, GridBlockCache> get blocks {
return _gridController.blocks; return gridController.blocks;
} }
List<FieldInfo> get fieldContexts => fieldController.fieldInfos; List<FieldInfo> get fieldContexts => fieldController.fieldInfos;
GridFieldController get fieldController { GridFieldController get fieldController {
return _gridController.fieldController; return gridController.fieldController;
} }
Future<void> createRow() async { Future<void> createRow() async {
return _gridController.createRow(); return gridController.createRow();
} }
FieldEditorBloc createFieldEditor({ FieldEditorBloc createFieldEditor({
@ -60,18 +60,20 @@ class GridTestContext {
return editorBloc; return editorBloc;
} }
Future<IGridCellController> makeCellController(String fieldId) async { Future<IGridCellController> makeCellController(
final builder = await makeCellControllerBuilder(fieldId); String fieldId, int rowIndex) async {
final builder = await makeCellControllerBuilder(fieldId, rowIndex);
return builder.build(); return builder.build();
} }
Future<GridCellControllerBuilder> makeCellControllerBuilder( Future<GridCellControllerBuilder> makeCellControllerBuilder(
String fieldId, String fieldId,
int rowIndex,
) async { ) async {
final RowInfo rowInfo = rowInfos.last; final RowInfo rowInfo = rowInfos[rowIndex];
final blockCache = blocks[rowInfo.rowPB.blockId]; final blockCache = blocks[rowInfo.rowPB.blockId];
final rowCache = blockCache?.rowCache; final rowCache = blockCache?.rowCache;
final fieldController = _gridController.fieldController; final fieldController = gridController.fieldController;
final rowDataController = GridRowDataController( final rowDataController = GridRowDataController(
rowInfo: rowInfo, rowInfo: rowInfo,
@ -125,22 +127,22 @@ class GridTestContext {
} }
Future<GridSelectOptionCellController> makeSelectOptionCellController( Future<GridSelectOptionCellController> makeSelectOptionCellController(
FieldType fieldType) async { FieldType fieldType, int rowIndex) async {
assert(fieldType == FieldType.SingleSelect || assert(fieldType == FieldType.SingleSelect ||
fieldType == FieldType.MultiSelect); fieldType == FieldType.MultiSelect);
final field = final field =
fieldContexts.firstWhere((element) => element.fieldType == fieldType); fieldContexts.firstWhere((element) => element.fieldType == fieldType);
final cellController = final cellController = await makeCellController(field.id, rowIndex)
await makeCellController(field.id) as GridSelectOptionCellController; as GridSelectOptionCellController;
return cellController; return cellController;
} }
Future<GridCellController> makeTextCellController() async { Future<GridCellController> makeTextCellController(int rowIndex) async {
final field = fieldContexts final field = fieldContexts
.firstWhere((element) => element.fieldType == FieldType.RichText); .firstWhere((element) => element.fieldType == FieldType.RichText);
final cellController = final cellController =
await makeCellController(field.id) as GridCellController; await makeCellController(field.id, rowIndex) as GridCellController;
return cellController; return cellController;
} }
} }
@ -171,7 +173,7 @@ class AppFlowyGridTest {
return result.fold( return result.fold(
(view) async { (view) async {
final context = GridTestContext(view, GridController(view: view)); final context = GridTestContext(view, GridController(view: view));
final result = await context._gridController.openGrid(); final result = await context.gridController.openGrid();
result.fold((l) => null, (r) => throw Exception(r)); result.fold((l) => null, (r) => throw Exception(r));
return context; return context;
}, },
@ -205,12 +207,12 @@ class AppFlowyGridCellTest {
} }
Future<GridSelectOptionCellController> makeCellController( Future<GridSelectOptionCellController> makeCellController(
FieldType fieldType) async { FieldType fieldType, int rowIndex) async {
return context.makeSelectOptionCellController(fieldType); return context.makeSelectOptionCellController(fieldType, rowIndex);
} }
} }
Future<void> gridResponseFuture({int milliseconds = 500}) { Future<void> gridResponseFuture({int milliseconds = 200}) {
return Future.delayed(gridResponseDuration(milliseconds: milliseconds)); return Future.delayed(gridResponseDuration(milliseconds: milliseconds));
} }