Add board group test (#1376)

This commit is contained in:
Nathan.fooo 2022-10-26 22:36:34 +08:00 committed by GitHub
parent c8044a92d1
commit 3bbf91ab2b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 291 additions and 97 deletions

View file

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

View file

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

View file

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

View file

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

View file

@ -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 = "",

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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(&notify_id, trash_can.clone(), &transaction)?; let _ = notify_views_changed(&notify_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(())

View file

@ -136,7 +136,7 @@ pub(crate) async fn switch_to_field_handler(
.switch_to_field_type(&params.field_id, &params.field_type) .switch_to_field_type(&params.field_id, &params.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(&params.field_id) .get_field_rev(&params.field_id)
.await .await

View file

@ -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"] }

View file

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