chore: add grid header bloc test (#1341)

Co-authored-by: nathan <nathan@appflowy.io>
This commit is contained in:
Nathan.fooo 2022-10-23 16:44:10 +08:00 committed by GitHub
parent aa58c79dbb
commit 96b1c6a540
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 236 additions and 64 deletions

View File

@ -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;

View File

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

View File

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

View File

@ -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>(

View File

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

View File

@ -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,13 +62,63 @@ 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) {},
);
}
}
/// Create a new Grid for cell test
class AppFlowyGridCellTest {
final AppFlowyGridTest _gridTest;
AppFlowyGridCellTest(AppFlowyGridTest gridTest) : _gridTest = gridTest;
static Future<AppFlowyGridCellTest> ensureInitialized() async {
final gridTest = await AppFlowyGridTest.ensureInitialized();
return AppFlowyGridCellTest(gridTest);
}
Future<void> createTestRow() async {
await _gridTest.createRow();
}
Future<void> createTestGrid() async {
await _gridTest.createTestGrid();
}
Future<GridCellControllerBuilder> cellControllerBuilder(
String fieldId,
) async {
final RowInfo rowInfo = _gridTest.rowInfos.last;
final blockCache = _gridTest.blocks[rowInfo.rowPB.blockId];
final rowCache = blockCache?.rowCache;
final rowDataController = GridRowDataController(
rowInfo: rowInfo,
fieldController: _gridTest._dataController.fieldController,
rowCache: rowCache!,
);
final rowBloc = RowBloc(
rowInfo: rowInfo,
dataController: rowDataController,
)..add(const RowEvent.initial());
await gridResponseFuture();
return GridCellControllerBuilder(
cellId: rowBloc.state.gridCellMap[fieldId]!,
cellCache: rowCache.cellCache,
delegate: rowDataController,
);
}
}
class AppFlowyGridSelectOptionCellTest {
final AppFlowyGridCellTest _gridCellTest;
@ -63,8 +143,7 @@ class AppFlowyGridSelectOptionCellTest {
assert(fieldType == FieldType.SingleSelect ||
fieldType == FieldType.MultiSelect);
final fieldContexts =
_gridCellTest._dataController.fieldController.fieldContexts;
final fieldContexts = _gridCellTest._gridTest.fieldContexts;
final field =
fieldContexts.firstWhere((element) => element.fieldType == fieldType);
final builder = await _gridCellTest.cellControllerBuilder(field.id);
@ -73,55 +152,6 @@ class AppFlowyGridSelectOptionCellTest {
}
}
/// 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 {
final gridTest = await AppFlowyGridTest.ensureInitialized();
return AppFlowyGridCellTest(gridTest);
}
Future<void> createTestRow() async {
await _dataController.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 rowCache = blockCache?.rowCache;
final rowDataController = GridRowDataController(
rowInfo: rowInfo,
fieldController: _dataController.fieldController,
rowCache: rowCache!,
);
final rowBloc = RowBloc(
rowInfo: rowInfo,
dataController: rowDataController,
)..add(const RowEvent.initial());
await gridResponseFuture();
return GridCellControllerBuilder(
cellId: rowBloc.state.gridCellMap[fieldId]!,
cellCache: rowCache.cellCache,
delegate: rowDataController,
);
}
}
Future<void> gridResponseFuture() {
return Future.delayed(gridResponseDuration(milliseconds: 200));
}