mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-04-24 22:57:12 -04:00
Add board group test (#1376)
This commit is contained in:
parent
c8044a92d1
commit
3bbf91ab2b
19 changed files with 291 additions and 97 deletions
|
@ -47,6 +47,7 @@ PROTOBUF_DERIVE_CACHE = "../shared-lib/flowy-derive/src/derive_cache/derive_cach
|
||||||
# Test default config
|
# Test default config
|
||||||
TEST_CRATE_TYPE = "cdylib"
|
TEST_CRATE_TYPE = "cdylib"
|
||||||
TEST_LIB_EXT = "dylib"
|
TEST_LIB_EXT = "dylib"
|
||||||
|
TEST_RUST_LOG = "info"
|
||||||
TEST_BUILD_FLAG = "debug"
|
TEST_BUILD_FLAG = "debug"
|
||||||
TEST_COMPILE_TARGET = "x86_64-apple-darwin"
|
TEST_COMPILE_TARGET = "x86_64-apple-darwin"
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,8 @@ class BoardDataController {
|
||||||
|
|
||||||
// key: the block id
|
// key: the block id
|
||||||
final LinkedHashMap<String, GridBlockCache> _blocks;
|
final LinkedHashMap<String, GridBlockCache> _blocks;
|
||||||
LinkedHashMap<String, GridBlockCache> get blocks => _blocks;
|
UnmodifiableMapView<String, GridBlockCache> get blocks =>
|
||||||
|
UnmodifiableMapView(_blocks);
|
||||||
|
|
||||||
OnFieldsChanged? _onFieldsChanged;
|
OnFieldsChanged? _onFieldsChanged;
|
||||||
OnGridChanged? _onGridChanged;
|
OnGridChanged? _onGridChanged;
|
||||||
|
@ -113,15 +114,16 @@ class BoardDataController {
|
||||||
() => result.fold(
|
() => result.fold(
|
||||||
(grid) async {
|
(grid) async {
|
||||||
_onGridChanged?.call(grid);
|
_onGridChanged?.call(grid);
|
||||||
return await fieldController.loadFields(fieldIds: grid.fields).then(
|
final result = await fieldController.loadFields(
|
||||||
(result) => result.fold(
|
fieldIds: grid.fields,
|
||||||
(l) {
|
);
|
||||||
_loadGroups(grid.blocks);
|
return result.fold(
|
||||||
return left(l);
|
(l) {
|
||||||
},
|
_loadGroups(grid.blocks);
|
||||||
(err) => right(err),
|
return left(l);
|
||||||
),
|
},
|
||||||
);
|
(err) => right(err),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
(err) => right(err),
|
(err) => right(err),
|
||||||
),
|
),
|
||||||
|
|
|
@ -15,6 +15,12 @@ class TypeOptionDataController {
|
||||||
late FieldTypeOptionDataPB _data;
|
late FieldTypeOptionDataPB _data;
|
||||||
final PublishNotifier<FieldPB> _fieldNotifier = PublishNotifier();
|
final PublishNotifier<FieldPB> _fieldNotifier = PublishNotifier();
|
||||||
|
|
||||||
|
/// Returns a [TypeOptionDataController] used to modify the specified
|
||||||
|
/// [FieldPB]'s data
|
||||||
|
///
|
||||||
|
/// Should call [loadTypeOptionData] if the passed-in [GridFieldContext]
|
||||||
|
/// is null
|
||||||
|
///
|
||||||
TypeOptionDataController({
|
TypeOptionDataController({
|
||||||
required this.gridId,
|
required this.gridId,
|
||||||
required this.loader,
|
required this.loader,
|
||||||
|
@ -77,18 +83,17 @@ class TypeOptionDataController {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> switchToField(FieldType newFieldType) {
|
Future<void> switchToField(FieldType newFieldType) async {
|
||||||
return loader.switchToField(field.id, newFieldType).then((result) {
|
final result = await loader.switchToField(field.id, newFieldType);
|
||||||
return result.fold(
|
await result.fold(
|
||||||
(_) {
|
(_) {
|
||||||
// Should load the type-option data after switching to a new field.
|
// Should load the type-option data after switching to a new field.
|
||||||
// After loading the type-option data, the editor widget that uses
|
// After loading the type-option data, the editor widget that uses
|
||||||
// the type-option data will be rebuild.
|
// the type-option data will be rebuild.
|
||||||
loadTypeOptionData();
|
loadTypeOptionData();
|
||||||
},
|
},
|
||||||
(err) => Log.error(err),
|
(err) => Future(() => Log.error(err)),
|
||||||
);
|
);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Function() addFieldListener(void Function(FieldPB) callback) {
|
void Function() addFieldListener(void Function(FieldPB) callback) {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:flowy_sdk/log.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_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
@ -13,9 +14,10 @@ class GridGroupBloc extends Bloc<GridGroupEvent, GridGroupState> {
|
||||||
final SettingFFIService _settingFFIService;
|
final SettingFFIService _settingFFIService;
|
||||||
Function(List<GridFieldContext>)? _onFieldsFn;
|
Function(List<GridFieldContext>)? _onFieldsFn;
|
||||||
|
|
||||||
GridGroupBloc(
|
GridGroupBloc({
|
||||||
{required String viewId, required GridFieldController fieldController})
|
required String viewId,
|
||||||
: _fieldController = fieldController,
|
required GridFieldController fieldController,
|
||||||
|
}) : _fieldController = fieldController,
|
||||||
_settingFFIService = SettingFFIService(viewId: viewId),
|
_settingFFIService = SettingFFIService(viewId: viewId),
|
||||||
super(GridGroupState.initial(viewId, fieldController.fieldContexts)) {
|
super(GridGroupState.initial(viewId, fieldController.fieldContexts)) {
|
||||||
on<GridGroupEvent>(
|
on<GridGroupEvent>(
|
||||||
|
@ -27,11 +29,12 @@ class GridGroupBloc extends Bloc<GridGroupEvent, GridGroupState> {
|
||||||
didReceiveFieldUpdate: (fieldContexts) {
|
didReceiveFieldUpdate: (fieldContexts) {
|
||||||
emit(state.copyWith(fieldContexts: fieldContexts));
|
emit(state.copyWith(fieldContexts: fieldContexts));
|
||||||
},
|
},
|
||||||
setGroupByField: (String fieldId, FieldType fieldType) {
|
setGroupByField: (String fieldId, FieldType fieldType) async {
|
||||||
_settingFFIService.groupByField(
|
final result = await _settingFFIService.groupByField(
|
||||||
fieldId: fieldId,
|
fieldId: fieldId,
|
||||||
fieldType: fieldType,
|
fieldType: fieldType,
|
||||||
);
|
);
|
||||||
|
result.fold((l) => null, (err) => Log.error(err));
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
@ -21,8 +21,8 @@ class FieldEditor extends StatefulWidget {
|
||||||
final String fieldName;
|
final String fieldName;
|
||||||
final bool isGroupField;
|
final bool isGroupField;
|
||||||
final Function(String)? onDeleted;
|
final Function(String)? onDeleted;
|
||||||
|
|
||||||
final IFieldTypeOptionLoader typeOptionLoader;
|
final IFieldTypeOptionLoader typeOptionLoader;
|
||||||
|
|
||||||
const FieldEditor({
|
const FieldEditor({
|
||||||
required this.gridId,
|
required this.gridId,
|
||||||
this.fieldName = "",
|
this.fieldName = "",
|
||||||
|
|
|
@ -11,13 +11,13 @@ void main() {
|
||||||
boardTest = await AppFlowyBoardTest.ensureInitialized();
|
boardTest = await AppFlowyBoardTest.ensureInitialized();
|
||||||
});
|
});
|
||||||
|
|
||||||
group('description', () {
|
group('$BoardBloc', () {
|
||||||
late BoardBloc boardBloc;
|
late BoardBloc boardBloc;
|
||||||
late String groupId;
|
late String groupId;
|
||||||
|
|
||||||
setUp(() async {
|
setUp(() async {
|
||||||
await boardTest.createTestBoard();
|
await boardTest.context.createTestBoard();
|
||||||
boardBloc = BoardBloc(view: boardTest.boardView)
|
boardBloc = BoardBloc(view: boardTest.context.gridView)
|
||||||
..add(const BoardEvent.initial());
|
..add(const BoardEvent.initial());
|
||||||
await boardResponseFuture();
|
await boardResponseFuture();
|
||||||
groupId = boardBloc.state.groupIds.first;
|
groupId = boardBloc.state.groupIds.first;
|
||||||
|
|
|
@ -0,0 +1,113 @@
|
||||||
|
import 'package:app_flowy/plugins/board/application/board_bloc.dart';
|
||||||
|
import 'package:app_flowy/plugins/grid/application/field/field_editor_bloc.dart';
|
||||||
|
import 'package:app_flowy/plugins/grid/application/setting/group_bloc.dart';
|
||||||
|
import 'package:bloc_test/bloc_test.dart';
|
||||||
|
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pbserver.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
import 'util.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
late AppFlowyBoardTest boardTest;
|
||||||
|
|
||||||
|
setUpAll(() async {
|
||||||
|
boardTest = await AppFlowyBoardTest.ensureInitialized();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Group with not support grouping field
|
||||||
|
group('Group with not support grouping field:', () {
|
||||||
|
late FieldEditorBloc editorBloc;
|
||||||
|
setUpAll(() async {
|
||||||
|
await boardTest.context.createTestBoard();
|
||||||
|
final fieldContext = boardTest.context.singleSelectFieldContext();
|
||||||
|
editorBloc = boardTest.context.createFieldEditor(
|
||||||
|
fieldContext: fieldContext,
|
||||||
|
)..add(const FieldEditorEvent.initial());
|
||||||
|
|
||||||
|
await boardResponseFuture();
|
||||||
|
});
|
||||||
|
|
||||||
|
blocTest<FieldEditorBloc, FieldEditorState>(
|
||||||
|
"switch to text field",
|
||||||
|
build: () => editorBloc,
|
||||||
|
wait: boardResponseDuration(),
|
||||||
|
act: (bloc) async {
|
||||||
|
await bloc.dataController.switchToField(FieldType.RichText);
|
||||||
|
},
|
||||||
|
verify: (bloc) {
|
||||||
|
bloc.state.field.fold(
|
||||||
|
() => throw Exception(),
|
||||||
|
(field) => field.fieldType == FieldType.RichText,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
blocTest<BoardBloc, BoardState>(
|
||||||
|
'assert the number of groups is 1',
|
||||||
|
build: () => BoardBloc(view: boardTest.context.gridView)
|
||||||
|
..add(const BoardEvent.initial()),
|
||||||
|
wait: boardResponseDuration(),
|
||||||
|
verify: (bloc) {
|
||||||
|
assert(bloc.groupControllers.values.length == 1,
|
||||||
|
"Expected 1, but receive ${bloc.groupControllers.values.length}");
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Group by checkbox field
|
||||||
|
group('Group by checkbox field:', () {
|
||||||
|
late BoardBloc boardBloc;
|
||||||
|
late FieldPB checkboxField;
|
||||||
|
setUpAll(() async {
|
||||||
|
await boardTest.context.createTestBoard();
|
||||||
|
});
|
||||||
|
|
||||||
|
setUp(() async {
|
||||||
|
boardBloc = BoardBloc(view: boardTest.context.gridView)
|
||||||
|
..add(const BoardEvent.initial());
|
||||||
|
await boardResponseFuture();
|
||||||
|
});
|
||||||
|
|
||||||
|
blocTest<BoardBloc, BoardState>(
|
||||||
|
"initial",
|
||||||
|
build: () => boardBloc,
|
||||||
|
wait: boardResponseDuration(),
|
||||||
|
verify: (bloc) {
|
||||||
|
assert(bloc.groupControllers.values.length == 4);
|
||||||
|
assert(boardTest.context.fieldContexts.length == 2);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
test('create checkbox field', () async {
|
||||||
|
await boardTest.context.createFieldFromType(FieldType.Checkbox);
|
||||||
|
await boardResponseFuture();
|
||||||
|
|
||||||
|
assert(boardTest.context.fieldContexts.length == 3);
|
||||||
|
checkboxField = boardTest.context.fieldContexts.last.field;
|
||||||
|
assert(checkboxField.fieldType == FieldType.Checkbox);
|
||||||
|
});
|
||||||
|
|
||||||
|
blocTest<GridGroupBloc, GridGroupState>(
|
||||||
|
"set grouped by checkbox field",
|
||||||
|
build: () => GridGroupBloc(
|
||||||
|
viewId: boardTest.context.gridView.id,
|
||||||
|
fieldController: boardTest.context.fieldController,
|
||||||
|
),
|
||||||
|
act: (bloc) async {
|
||||||
|
bloc.add(GridGroupEvent.setGroupByField(
|
||||||
|
checkboxField.id,
|
||||||
|
checkboxField.fieldType,
|
||||||
|
));
|
||||||
|
},
|
||||||
|
wait: boardResponseDuration(),
|
||||||
|
);
|
||||||
|
|
||||||
|
blocTest<BoardBloc, BoardState>(
|
||||||
|
"check the number of groups is 2",
|
||||||
|
build: () => boardBloc,
|
||||||
|
wait: boardResponseDuration(),
|
||||||
|
verify: (bloc) {
|
||||||
|
assert(bloc.groupControllers.values.length == 2);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
|
@ -1,36 +1,13 @@
|
||||||
import 'package:app_flowy/plugins/board/board.dart';
|
import '../grid_test/util.dart';
|
||||||
import 'package:app_flowy/workspace/application/app/app_service.dart';
|
|
||||||
import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
|
|
||||||
|
|
||||||
import '../../util.dart';
|
|
||||||
|
|
||||||
class AppFlowyBoardTest {
|
class AppFlowyBoardTest {
|
||||||
final AppFlowyUnitTest _inner;
|
final AppFlowyGridTest context;
|
||||||
late ViewPB boardView;
|
AppFlowyBoardTest(this.context);
|
||||||
AppFlowyBoardTest(AppFlowyUnitTest unitTest) : _inner = unitTest;
|
|
||||||
|
|
||||||
static Future<AppFlowyBoardTest> ensureInitialized() async {
|
static Future<AppFlowyBoardTest> ensureInitialized() async {
|
||||||
final inner = await AppFlowyUnitTest.ensureInitialized();
|
final inner = await AppFlowyGridTest.ensureInitialized();
|
||||||
return AppFlowyBoardTest(inner);
|
return AppFlowyBoardTest(inner);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> createTestBoard() async {
|
|
||||||
final app = await _inner.createTestApp();
|
|
||||||
final builder = BoardPluginBuilder();
|
|
||||||
final result = await AppService().createView(
|
|
||||||
appId: app.id,
|
|
||||||
name: "Test Board",
|
|
||||||
dataFormatType: builder.dataFormatType,
|
|
||||||
pluginType: builder.pluginType,
|
|
||||||
layoutType: builder.layoutType!,
|
|
||||||
);
|
|
||||||
await result.fold(
|
|
||||||
(view) async {
|
|
||||||
boardView = view;
|
|
||||||
},
|
|
||||||
(error) {},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> boardResponseFuture() {
|
Future<void> boardResponseFuture() {
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
import 'dart:collection';
|
import 'dart:collection';
|
||||||
|
import 'package:app_flowy/plugins/board/application/board_data_controller.dart';
|
||||||
|
import 'package:app_flowy/plugins/board/board.dart';
|
||||||
import 'package:app_flowy/plugins/grid/application/block/block_cache.dart';
|
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/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_controller.dart';
|
||||||
|
import 'package:app_flowy/plugins/grid/application/field/field_editor_bloc.dart';
|
||||||
import 'package:app_flowy/plugins/grid/application/field/field_service.dart';
|
import 'package:app_flowy/plugins/grid/application/field/field_service.dart';
|
||||||
|
import 'package:app_flowy/plugins/grid/application/field/type_option/type_option_context.dart';
|
||||||
import 'package:app_flowy/plugins/grid/application/grid_data_controller.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_bloc.dart';
|
||||||
import 'package:app_flowy/plugins/grid/application/row/row_cache.dart';
|
import 'package:app_flowy/plugins/grid/application/row/row_cache.dart';
|
||||||
|
@ -16,29 +20,90 @@ import '../../util.dart';
|
||||||
|
|
||||||
/// Create a empty Grid for test
|
/// Create a empty Grid for test
|
||||||
class AppFlowyGridTest {
|
class AppFlowyGridTest {
|
||||||
final AppFlowyUnitTest _inner;
|
final AppFlowyUnitTest unitTest;
|
||||||
late ViewPB gridView;
|
late ViewPB gridView;
|
||||||
late GridDataController _dataController;
|
GridDataController? _gridDataController;
|
||||||
|
BoardDataController? _boardDataController;
|
||||||
|
|
||||||
AppFlowyGridTest(AppFlowyUnitTest unitTest) : _inner = unitTest;
|
AppFlowyGridTest({required this.unitTest});
|
||||||
|
|
||||||
static Future<AppFlowyGridTest> ensureInitialized() async {
|
static Future<AppFlowyGridTest> ensureInitialized() async {
|
||||||
final inner = await AppFlowyUnitTest.ensureInitialized();
|
final inner = await AppFlowyUnitTest.ensureInitialized();
|
||||||
return AppFlowyGridTest(inner);
|
return AppFlowyGridTest(unitTest: inner);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<RowInfo> get rowInfos => _dataController.rowInfos;
|
List<RowInfo> get rowInfos {
|
||||||
|
if (_gridDataController != null) {
|
||||||
|
return _gridDataController!.rowInfos;
|
||||||
|
}
|
||||||
|
|
||||||
UnmodifiableMapView<String, GridBlockCache> get blocks =>
|
if (_boardDataController != null) {
|
||||||
_dataController.blocks;
|
return _boardDataController!.rowInfos;
|
||||||
|
}
|
||||||
|
|
||||||
List<GridFieldContext> get fieldContexts =>
|
throw Exception();
|
||||||
_dataController.fieldController.fieldContexts;
|
}
|
||||||
|
|
||||||
GridFieldController get fieldController => _dataController.fieldController;
|
UnmodifiableMapView<String, GridBlockCache> get blocks {
|
||||||
|
if (_gridDataController != null) {
|
||||||
|
return _gridDataController!.blocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_boardDataController != null) {
|
||||||
|
return _boardDataController!.blocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw Exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<GridFieldContext> get fieldContexts => fieldController.fieldContexts;
|
||||||
|
|
||||||
|
GridFieldController get fieldController {
|
||||||
|
if (_gridDataController != null) {
|
||||||
|
return _gridDataController!.fieldController;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_boardDataController != null) {
|
||||||
|
return _boardDataController!.fieldController;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw Exception();
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> createRow() async {
|
Future<void> createRow() async {
|
||||||
await _dataController.createRow();
|
if (_gridDataController != null) {
|
||||||
|
return _gridDataController!.createRow();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw Exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
FieldEditorBloc createFieldEditor({
|
||||||
|
GridFieldContext? fieldContext,
|
||||||
|
}) {
|
||||||
|
IFieldTypeOptionLoader loader;
|
||||||
|
if (fieldContext == null) {
|
||||||
|
loader = NewFieldTypeOptionLoader(gridId: gridView.id);
|
||||||
|
} else {
|
||||||
|
loader =
|
||||||
|
FieldTypeOptionLoader(gridId: gridView.id, field: fieldContext.field);
|
||||||
|
}
|
||||||
|
|
||||||
|
final editorBloc = FieldEditorBloc(
|
||||||
|
fieldName: fieldContext?.name ?? '',
|
||||||
|
isGroupField: fieldContext?.isGroupField ?? false,
|
||||||
|
loader: loader,
|
||||||
|
gridId: gridView.id,
|
||||||
|
);
|
||||||
|
return editorBloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<FieldEditorBloc> createFieldFromType(FieldType fieldType) async {
|
||||||
|
final editor = createFieldEditor()..add(const FieldEditorEvent.initial());
|
||||||
|
await gridResponseFuture();
|
||||||
|
editor.dataController.switchToField(fieldType);
|
||||||
|
await gridResponseFuture();
|
||||||
|
return Future(() => editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
GridFieldContext singleSelectFieldContext() {
|
GridFieldContext singleSelectFieldContext() {
|
||||||
|
@ -53,7 +118,7 @@ class AppFlowyGridTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> createTestGrid() async {
|
Future<void> createTestGrid() async {
|
||||||
final app = await _inner.createTestApp();
|
final app = await unitTest.createTestApp();
|
||||||
final builder = GridPluginBuilder();
|
final builder = GridPluginBuilder();
|
||||||
final result = await AppService().createView(
|
final result = await AppService().createView(
|
||||||
appId: app.id,
|
appId: app.id,
|
||||||
|
@ -65,13 +130,34 @@ class AppFlowyGridTest {
|
||||||
await result.fold(
|
await result.fold(
|
||||||
(view) async {
|
(view) async {
|
||||||
gridView = view;
|
gridView = view;
|
||||||
_dataController = GridDataController(view: view);
|
_gridDataController = GridDataController(view: view);
|
||||||
final result = await _dataController.openGrid();
|
final result = await _gridDataController!.openGrid();
|
||||||
result.fold((l) => null, (r) => throw Exception(r));
|
result.fold((l) => null, (r) => throw Exception(r));
|
||||||
},
|
},
|
||||||
(error) {},
|
(error) {},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> createTestBoard() async {
|
||||||
|
final app = await unitTest.createTestApp();
|
||||||
|
final builder = BoardPluginBuilder();
|
||||||
|
final result = await AppService().createView(
|
||||||
|
appId: app.id,
|
||||||
|
name: "Test Board",
|
||||||
|
dataFormatType: builder.dataFormatType,
|
||||||
|
pluginType: builder.pluginType,
|
||||||
|
layoutType: builder.layoutType!,
|
||||||
|
);
|
||||||
|
await result.fold(
|
||||||
|
(view) async {
|
||||||
|
_boardDataController = BoardDataController(view: view);
|
||||||
|
final result = await _boardDataController!.openGrid();
|
||||||
|
result.fold((l) => null, (r) => throw Exception(r));
|
||||||
|
gridView = view;
|
||||||
|
},
|
||||||
|
(error) {},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new Grid for cell test
|
/// Create a new Grid for cell test
|
||||||
|
@ -101,7 +187,7 @@ class AppFlowyGridCellTest {
|
||||||
|
|
||||||
final rowDataController = GridRowDataController(
|
final rowDataController = GridRowDataController(
|
||||||
rowInfo: rowInfo,
|
rowInfo: rowInfo,
|
||||||
fieldController: _gridTest._dataController.fieldController,
|
fieldController: _gridTest._gridDataController!.fieldController,
|
||||||
rowCache: rowCache!,
|
rowCache: rowCache!,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@ void main() {
|
||||||
wait: blocResponseDuration(),
|
wait: blocResponseDuration(),
|
||||||
);
|
);
|
||||||
|
|
||||||
test('description', () async {
|
test('check the latest view is the document', () async {
|
||||||
assert(homeBloc.state.workspaceSetting.latestView.id ==
|
assert(homeBloc.state.workspaceSetting.latestView.id ==
|
||||||
latestCreatedView.id);
|
latestCreatedView.id);
|
||||||
});
|
});
|
||||||
|
|
|
@ -165,8 +165,8 @@ void main() {
|
||||||
act: (bloc) async {
|
act: (bloc) async {
|
||||||
for (final view in appBloc.state.app.belongings.items) {
|
for (final view in appBloc.state.app.belongings.items) {
|
||||||
appBloc.add(AppEvent.deleteView(view.id));
|
appBloc.add(AppEvent.deleteView(view.id));
|
||||||
|
await blocResponseFuture();
|
||||||
}
|
}
|
||||||
await blocResponseFuture();
|
|
||||||
trashBloc.add(const TrashEvent.deleteAll());
|
trashBloc.add(const TrashEvent.deleteAll());
|
||||||
},
|
},
|
||||||
wait: blocResponseDuration(),
|
wait: blocResponseDuration(),
|
||||||
|
|
|
@ -113,10 +113,10 @@ class FlowyTestApp implements EntryPoint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> blocResponseFuture({int millisecond = 100}) {
|
Future<void> blocResponseFuture({int millisecond = 200}) {
|
||||||
return Future.delayed(Duration(milliseconds: millisecond));
|
return Future.delayed(Duration(milliseconds: millisecond));
|
||||||
}
|
}
|
||||||
|
|
||||||
Duration blocResponseDuration({int milliseconds = 100}) {
|
Duration blocResponseDuration({int milliseconds = 200}) {
|
||||||
return Duration(milliseconds: milliseconds);
|
return Duration(milliseconds: milliseconds);
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ pub trait FolderPersistenceTransaction {
|
||||||
fn read_view(&self, view_id: &str) -> FlowyResult<ViewRevision>;
|
fn read_view(&self, view_id: &str) -> FlowyResult<ViewRevision>;
|
||||||
fn read_views(&self, belong_to_id: &str) -> FlowyResult<Vec<ViewRevision>>;
|
fn read_views(&self, belong_to_id: &str) -> FlowyResult<Vec<ViewRevision>>;
|
||||||
fn update_view(&self, changeset: ViewChangeset) -> FlowyResult<()>;
|
fn update_view(&self, changeset: ViewChangeset) -> FlowyResult<()>;
|
||||||
fn delete_view(&self, view_id: &str) -> FlowyResult<()>;
|
fn delete_view(&self, view_id: &str) -> FlowyResult<ViewRevision>;
|
||||||
fn move_view(&self, view_id: &str, from: usize, to: usize) -> FlowyResult<()>;
|
fn move_view(&self, view_id: &str, from: usize, to: usize) -> FlowyResult<()>;
|
||||||
|
|
||||||
fn create_trash(&self, trashes: Vec<TrashRevision>) -> FlowyResult<()>;
|
fn create_trash(&self, trashes: Vec<TrashRevision>) -> FlowyResult<()>;
|
||||||
|
|
|
@ -84,9 +84,10 @@ impl<'a> FolderPersistenceTransaction for V1Transaction<'a> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete_view(&self, view_id: &str) -> FlowyResult<()> {
|
fn delete_view(&self, view_id: &str) -> FlowyResult<ViewRevision> {
|
||||||
|
let view_revision: ViewRevision = ViewTableSql::read_view(view_id, &*self.0)?.into();
|
||||||
let _ = ViewTableSql::delete_view(view_id, &*self.0)?;
|
let _ = ViewTableSql::delete_view(view_id, &*self.0)?;
|
||||||
Ok(())
|
Ok(view_revision)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn move_view(&self, _view_id: &str, _from: usize, _to: usize) -> FlowyResult<()> {
|
fn move_view(&self, _view_id: &str, _from: usize, _to: usize) -> FlowyResult<()> {
|
||||||
|
@ -182,7 +183,7 @@ where
|
||||||
(**self).update_view(changeset)
|
(**self).update_view(changeset)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete_view(&self, view_id: &str) -> FlowyResult<()> {
|
fn delete_view(&self, view_id: &str) -> FlowyResult<ViewRevision> {
|
||||||
(**self).delete_view(view_id)
|
(**self).delete_view(view_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -113,11 +113,12 @@ impl FolderPersistenceTransaction for FolderEditor {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete_view(&self, view_id: &str) -> FlowyResult<()> {
|
fn delete_view(&self, view_id: &str) -> FlowyResult<ViewRevision> {
|
||||||
if let Some(change) = self.folder.write().delete_view(view_id)? {
|
let view = self.folder.read().read_view(view_id)?;
|
||||||
|
if let Some(change) = self.folder.write().delete_view(&view.app_id, view_id)? {
|
||||||
let _ = self.apply_change(change)?;
|
let _ = self.apply_change(change)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(view)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn move_view(&self, view_id: &str, from: usize, to: usize) -> FlowyResult<()> {
|
fn move_view(&self, view_id: &str, from: usize, to: usize) -> FlowyResult<()> {
|
||||||
|
@ -207,7 +208,7 @@ where
|
||||||
(**self).update_view(changeset)
|
(**self).update_view(changeset)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete_view(&self, view_id: &str) -> FlowyResult<()> {
|
fn delete_view(&self, view_id: &str) -> FlowyResult<ViewRevision> {
|
||||||
(**self).delete_view(view_id)
|
(**self).delete_view(view_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -462,10 +462,10 @@ async fn handle_trash_event(
|
||||||
let mut notify_ids = HashSet::new();
|
let mut notify_ids = HashSet::new();
|
||||||
let mut views = vec![];
|
let mut views = vec![];
|
||||||
for identifier in identifiers.items {
|
for identifier in identifiers.items {
|
||||||
let view = transaction.read_view(&identifier.id)?;
|
if let Ok(view_rev) = transaction.delete_view(&identifier.id) {
|
||||||
let _ = transaction.delete_view(&view.id)?;
|
notify_ids.insert(view_rev.app_id.clone());
|
||||||
notify_ids.insert(view.app_id.clone());
|
views.push(view_rev);
|
||||||
views.push(view);
|
}
|
||||||
}
|
}
|
||||||
for notify_id in notify_ids {
|
for notify_id in notify_ids {
|
||||||
let _ = notify_views_changed(¬ify_id, trash_can.clone(), &transaction)?;
|
let _ = notify_views_changed(¬ify_id, trash_can.clone(), &transaction)?;
|
||||||
|
@ -480,9 +480,7 @@ async fn handle_trash_event(
|
||||||
Ok(processor) => {
|
Ok(processor) => {
|
||||||
let _ = processor.close_view(&view.id).await?;
|
let _ = processor.close_view(&view.id).await?;
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => tracing::error!("{}", e),
|
||||||
tracing::error!("{}", e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -136,7 +136,7 @@ pub(crate) async fn switch_to_field_handler(
|
||||||
.switch_to_field_type(¶ms.field_id, ¶ms.field_type)
|
.switch_to_field_type(¶ms.field_id, ¶ms.field_type)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// Get the field_rev with field_id, if it doesn't exist, we create the default FieldMeta from the FieldType.
|
// Get the field_rev with field_id, if it doesn't exist, we create the default FieldRevision from the FieldType.
|
||||||
let field_rev = editor
|
let field_rev = editor
|
||||||
.get_field_rev(¶ms.field_id)
|
.get_field_rev(¶ms.field_id)
|
||||||
.await
|
.await
|
||||||
|
|
|
@ -1,4 +1,12 @@
|
||||||
|
|
||||||
|
[tasks.dart_unit_test]
|
||||||
|
dependencies = ["build-test-lib"]
|
||||||
|
description = "Run flutter unit tests"
|
||||||
|
script = '''
|
||||||
|
cd app_flowy
|
||||||
|
flutter test --dart-define=RUST_LOG=${TEST_RUST_LOG}
|
||||||
|
'''
|
||||||
|
|
||||||
[tasks.rust_unit_test]
|
[tasks.rust_unit_test]
|
||||||
run_task = { name = ["rust_lib_unit_test", "shared_lib_unit_test"] }
|
run_task = { name = ["rust_lib_unit_test", "shared_lib_unit_test"] }
|
||||||
|
|
||||||
|
|
|
@ -258,9 +258,8 @@ impl FolderPad {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "trace", skip(self), err)]
|
#[tracing::instrument(level = "trace", skip(self), err)]
|
||||||
pub fn delete_view(&mut self, view_id: &str) -> CollaborateResult<Option<FolderChangeset>> {
|
pub fn delete_view(&mut self, app_id: &str, view_id: &str) -> CollaborateResult<Option<FolderChangeset>> {
|
||||||
let view = self.read_view(view_id)?;
|
self.with_app(app_id, |app| {
|
||||||
self.with_app(&view.app_id, |app| {
|
|
||||||
app.belongings.retain(|view| view.id != view_id);
|
app.belongings.retain(|view| view.id != view_id);
|
||||||
Ok(Some(()))
|
Ok(Some(()))
|
||||||
})
|
})
|
||||||
|
@ -724,7 +723,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn folder_delete_view() {
|
fn folder_delete_view() {
|
||||||
let (mut folder, initial_operations, view) = test_view_folder();
|
let (mut folder, initial_operations, view) = test_view_folder();
|
||||||
let operations = folder.delete_view(&view.id).unwrap().unwrap().operations;
|
let operations = folder.delete_view(&view.app_id, &view.id).unwrap().unwrap().operations;
|
||||||
|
|
||||||
let new_folder = make_folder_from_operations(initial_operations, vec![operations]);
|
let new_folder = make_folder_from_operations(initial_operations, vec![operations]);
|
||||||
assert_folder_equal(
|
assert_folder_equal(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue