test: add app bloc test (#1370)

This commit is contained in:
Nathan.fooo
2022-10-26 10:38:57 +08:00
committed by GitHub
parent 23ffc3d0a8
commit 2eea57aefa
21 changed files with 226 additions and 77 deletions

View File

@ -70,7 +70,7 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
await event.when( await event.when(
initial: () async { initial: () async {
_startListening(); _startListening();
await _loadGrid(emit); await _openGrid(emit);
}, },
createBottomRow: (groupId) async { createBottomRow: (groupId) async {
final startRowId = groupControllers[groupId]?.lastRow()?.id; final startRowId = groupControllers[groupId]?.lastRow()?.id;
@ -285,8 +285,8 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
return <AppFlowyGroupItem>[...items]; return <AppFlowyGroupItem>[...items];
} }
Future<void> _loadGrid(Emitter<BoardState> emit) async { Future<void> _openGrid(Emitter<BoardState> emit) async {
final result = await _gridDataController.loadData(); final result = await _gridDataController.openGrid();
result.fold( result.fold(
(grid) => emit( (grid) => emit(
state.copyWith(loadingState: GridLoadingState.finish(left(unit))), state.copyWith(loadingState: GridLoadingState.finish(left(unit))),

View File

@ -107,8 +107,8 @@ class BoardDataController {
); );
} }
Future<Either<Unit, FlowyError>> loadData() async { Future<Either<Unit, FlowyError>> openGrid() async {
final result = await _gridFFIService.loadGrid(); final result = await _gridFFIService.openGrid();
return Future( return Future(
() => result.fold( () => result.fold(
(grid) async { (grid) async {

View File

@ -17,19 +17,19 @@ part 'doc_bloc.freezed.dart';
class DocumentBloc extends Bloc<DocumentEvent, DocumentState> { class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
final ViewPB view; final ViewPB view;
final DocumentService service; final DocumentService _documentService;
final ViewListener listener; final ViewListener _listener;
final TrashService trashService; final TrashService _trashService;
late EditorState editorState; late EditorState editorState;
StreamSubscription? _subscription; StreamSubscription? _subscription;
DocumentBloc({ DocumentBloc({
required this.view, required this.view,
required this.service, }) : _documentService = DocumentService(),
required this.listener, _listener = ViewListener(view: view),
required this.trashService, _trashService = TrashService(),
}) : super(DocumentState.initial()) { super(DocumentState.initial()) {
on<DocumentEvent>((event, emit) async { on<DocumentEvent>((event, emit) async {
await event.map( await event.map(
initial: (Initial value) async { initial: (Initial value) async {
@ -43,7 +43,7 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
emit(state.copyWith(isDeleted: false)); emit(state.copyWith(isDeleted: false));
}, },
deletePermanently: (DeletePermanently value) async { deletePermanently: (DeletePermanently value) async {
final result = await trashService final result = await _trashService
.deleteViews([Tuple2(view.id, TrashType.TrashView)]); .deleteViews([Tuple2(view.id, TrashType.TrashView)]);
final newState = result.fold( final newState = result.fold(
@ -51,7 +51,7 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
emit(newState); emit(newState);
}, },
restorePage: (RestorePage value) async { restorePage: (RestorePage value) async {
final result = await trashService.putback(view.id); final result = await _trashService.putback(view.id);
final newState = result.fold( final newState = result.fold(
(l) => state.copyWith(isDeleted: false), (r) => state); (l) => state.copyWith(isDeleted: false), (r) => state);
emit(newState); emit(newState);
@ -62,18 +62,18 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
@override @override
Future<void> close() async { Future<void> close() async {
await listener.stop(); await _listener.stop();
if (_subscription != null) { if (_subscription != null) {
await _subscription?.cancel(); await _subscription?.cancel();
} }
await service.closeDocument(docId: view.id); await _documentService.closeDocument(docId: view.id);
return super.close(); return super.close();
} }
Future<void> _initial(Initial value, Emitter<DocumentState> emit) async { Future<void> _initial(Initial value, Emitter<DocumentState> emit) async {
final result = await service.openDocument(view: view); final result = await _documentService.openDocument(view: view);
result.fold( result.fold(
(block) { (block) {
final document = Document.fromJson(jsonDecode(block.snapshot)); final document = Document.fromJson(jsonDecode(block.snapshot));
@ -96,7 +96,7 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
} }
void _listenOnViewChange() { void _listenOnViewChange() {
listener.start( _listener.start(
onViewDeleted: (result) { onViewDeleted: (result) {
result.fold( result.fold(
(view) => add(const DocumentEvent.deleted()), (view) => add(const DocumentEvent.deleted()),
@ -115,7 +115,9 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
void _listenOnDocumentChange() { void _listenOnDocumentChange() {
_subscription = editorState.transactionStream.listen((transaction) { _subscription = editorState.transactionStream.listen((transaction) {
final json = jsonEncode(TransactionAdaptor(transaction).toJson()); final json = jsonEncode(TransactionAdaptor(transaction).toJson());
service.applyEdit(docId: view.id, operations: json).then((result) { _documentService
.applyEdit(docId: view.id, operations: json)
.then((result) {
result.fold( result.fold(
(l) => null, (l) => null,
(err) => Log.error(err), (err) => Log.error(err),

View File

@ -30,7 +30,7 @@ class _DocumentPageState extends State<DocumentPage> {
@override @override
void initState() { void initState() {
// The appflowy editor use Intl as locatization, set the default language as fallback. // The appflowy editor use Intl as localization, set the default language as fallback.
Intl.defaultLocale = 'en_US'; Intl.defaultLocale = 'en_US';
documentBloc = getIt<DocumentBloc>(param1: super.widget.view) documentBloc = getIt<DocumentBloc>(param1: super.widget.view)
..add(const DocumentEvent.initial()); ..add(const DocumentEvent.initial());

View File

@ -27,7 +27,7 @@ class GridBloc extends Bloc<GridEvent, GridState> {
await event.when( await event.when(
initial: () async { initial: () async {
_startListening(); _startListening();
await _loadGrid(emit); await _openGrid(emit);
}, },
createRow: () { createRow: () {
state.loadingState.when( state.loadingState.when(
@ -95,8 +95,8 @@ class GridBloc extends Bloc<GridEvent, GridState> {
); );
} }
Future<void> _loadGrid(Emitter<GridState> emit) async { Future<void> _openGrid(Emitter<GridState> emit) async {
final result = await dataController.loadData(); final result = await dataController.openGrid();
result.fold( result.fold(
(grid) { (grid) {
if (_createRowOperation != null) { if (_createRowOperation != null) {

View File

@ -65,8 +65,8 @@ class GridDataController {
} }
// Loads the rows from each block // Loads the rows from each block
Future<Either<Unit, FlowyError>> loadData() async { Future<Either<Unit, FlowyError>> openGrid() async {
final result = await _gridFFIService.loadGrid(); final result = await _gridFFIService.openGrid();
return Future( return Future(
() => result.fold( () => result.fold(
(grid) async { (grid) async {

View File

@ -14,7 +14,7 @@ class GridFFIService {
required this.gridId, required this.gridId,
}); });
Future<Either<GridPB, FlowyError>> loadGrid() async { Future<Either<GridPB, FlowyError>> openGrid() async {
await FolderEventSetLatestView(ViewIdPB(value: gridId)).send(); await FolderEventSetLatestView(ViewIdPB(value: gridId)).send();
final payload = GridIdPB(value: gridId); final payload = GridIdPB(value: gridId);

View File

@ -122,12 +122,7 @@ void _resolveFolderDeps(GetIt getIt) {
void _resolveDocDeps(GetIt getIt) { void _resolveDocDeps(GetIt getIt) {
// Doc // Doc
getIt.registerFactoryParam<DocumentBloc, ViewPB, void>( getIt.registerFactoryParam<DocumentBloc, ViewPB, void>(
(view, _) => DocumentBloc( (view, _) => DocumentBloc(view: view),
view: view,
service: DocumentService(),
listener: getIt<ViewListener>(param1: view),
trashService: getIt<TrashService>(),
),
); );
} }

View File

@ -10,7 +10,8 @@ import 'package:flowy_infra/notifier.dart';
import 'package:flowy_sdk/protobuf/dart-notify/protobuf.dart'; import 'package:flowy_sdk/protobuf/dart-notify/protobuf.dart';
import 'package:flowy_sdk/protobuf/flowy-folder/dart_notification.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder/dart_notification.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-user/user_profile.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-user/user_profile.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-user/dart_notification.pb.dart' as user; import 'package:flowy_sdk/protobuf/flowy-user/dart_notification.pb.dart'
as user;
import 'package:flowy_sdk/rust_stream.dart'; import 'package:flowy_sdk/rust_stream.dart';
typedef UserProfileNotifyValue = Either<UserProfilePB, FlowyError>; typedef UserProfileNotifyValue = Either<UserProfilePB, FlowyError>;
@ -39,7 +40,8 @@ class UserListener {
_authNotifier?.addPublishListener(onAuthChanged); _authNotifier?.addPublishListener(onAuthChanged);
} }
_userParser = UserNotificationParser(id: _userProfile.token, callback: _userNotificationCallback); _userParser = UserNotificationParser(
id: _userProfile.token, callback: _userNotificationCallback);
_subscription = RustStreamReceiver.listen((observable) { _subscription = RustStreamReceiver.listen((observable) {
_userParser?.parse(observable); _userParser?.parse(observable);
}); });
@ -55,7 +57,8 @@ class UserListener {
_authNotifier = null; _authNotifier = null;
} }
void _userNotificationCallback(user.UserNotification ty, Either<Uint8List, FlowyError> result) { void _userNotificationCallback(
user.UserNotification ty, Either<Uint8List, FlowyError> result) {
switch (ty) { switch (ty) {
case user.UserNotification.UserUnauthorized: case user.UserNotification.UserUnauthorized:
result.fold( result.fold(
@ -65,7 +68,8 @@ class UserListener {
break; break;
case user.UserNotification.UserProfileUpdated: case user.UserNotification.UserProfileUpdated:
result.fold( result.fold(
(payload) => _profileNotifier?.value = left(UserProfilePB.fromBuffer(payload)), (payload) =>
_profileNotifier?.value = left(UserProfilePB.fromBuffer(payload)),
(error) => _profileNotifier?.value = right(error), (error) => _profileNotifier?.value = right(error),
); );
break; break;
@ -76,12 +80,14 @@ class UserListener {
} }
typedef WorkspaceListNotifyValue = Either<List<WorkspacePB>, FlowyError>; typedef WorkspaceListNotifyValue = Either<List<WorkspacePB>, FlowyError>;
typedef WorkspaceSettingNotifyValue = Either<CurrentWorkspaceSettingPB, FlowyError>; typedef WorkspaceSettingNotifyValue = Either<WorkspaceSettingPB, FlowyError>;
class UserWorkspaceListener { class UserWorkspaceListener {
PublishNotifier<AuthNotifyValue>? _authNotifier = PublishNotifier(); PublishNotifier<AuthNotifyValue>? _authNotifier = PublishNotifier();
PublishNotifier<WorkspaceListNotifyValue>? _workspacesChangedNotifier = PublishNotifier(); PublishNotifier<WorkspaceListNotifyValue>? _workspacesChangedNotifier =
PublishNotifier<WorkspaceSettingNotifyValue>? _settingChangedNotifier = PublishNotifier(); PublishNotifier();
PublishNotifier<WorkspaceSettingNotifyValue>? _settingChangedNotifier =
PublishNotifier();
FolderNotificationListener? _listener; FolderNotificationListener? _listener;
final UserProfilePB _userProfile; final UserProfilePB _userProfile;
@ -113,26 +119,30 @@ class UserWorkspaceListener {
); );
} }
void _handleObservableType(FolderNotification ty, Either<Uint8List, FlowyError> result) { void _handleObservableType(
FolderNotification ty, Either<Uint8List, FlowyError> result) {
switch (ty) { switch (ty) {
case FolderNotification.UserCreateWorkspace: case FolderNotification.UserCreateWorkspace:
case FolderNotification.UserDeleteWorkspace: case FolderNotification.UserDeleteWorkspace:
case FolderNotification.WorkspaceListUpdated: case FolderNotification.WorkspaceListUpdated:
result.fold( result.fold(
(payload) => _workspacesChangedNotifier?.value = left(RepeatedWorkspacePB.fromBuffer(payload).items), (payload) => _workspacesChangedNotifier?.value =
left(RepeatedWorkspacePB.fromBuffer(payload).items),
(error) => _workspacesChangedNotifier?.value = right(error), (error) => _workspacesChangedNotifier?.value = right(error),
); );
break; break;
case FolderNotification.WorkspaceSetting: case FolderNotification.WorkspaceSetting:
result.fold( result.fold(
(payload) => _settingChangedNotifier?.value = left(CurrentWorkspaceSettingPB.fromBuffer(payload)), (payload) => _settingChangedNotifier?.value =
left(WorkspaceSettingPB.fromBuffer(payload)),
(error) => _settingChangedNotifier?.value = right(error), (error) => _settingChangedNotifier?.value = right(error),
); );
break; break;
case FolderNotification.UserUnauthorized: case FolderNotification.UserUnauthorized:
result.fold( result.fold(
(_) {}, (_) {},
(error) => _authNotifier?.value = right(FlowyError.create()..code = ErrorCode.UserUnauthorized.value), (error) => _authNotifier?.value = right(
FlowyError.create()..code = ErrorCode.UserUnauthorized.value),
); );
break; break;
default: default:

View File

@ -29,7 +29,7 @@ class AuthRouter {
} }
void pushHomeScreen(BuildContext context, UserProfilePB profile, void pushHomeScreen(BuildContext context, UserProfilePB profile,
CurrentWorkspaceSettingPB workspaceSetting) { WorkspaceSettingPB workspaceSetting) {
Navigator.push( Navigator.push(
context, context,
PageRoutes.fade(() => HomeScreen(profile, workspaceSetting), PageRoutes.fade(() => HomeScreen(profile, workspaceSetting),
@ -54,7 +54,7 @@ class SplashRoute {
} }
void pushHomeScreen(BuildContext context, UserProfilePB userProfile, void pushHomeScreen(BuildContext context, UserProfilePB userProfile,
CurrentWorkspaceSettingPB workspaceSetting) { WorkspaceSettingPB workspaceSetting) {
Navigator.push( Navigator.push(
context, context,
PageRoutes.fade(() => HomeScreen(userProfile, workspaceSetting), PageRoutes.fade(() => HomeScreen(userProfile, workspaceSetting),

View File

@ -106,7 +106,7 @@ class _SkipLogInScreenState extends State<SkipLogInScreen> {
); );
result.fold( result.fold(
(user) { (user) {
FolderEventReadCurWorkspace().send().then((result) { FolderEventReadCurrentWorkspace().send().then((result) {
_openCurrentWorkspace(context, user, result); _openCurrentWorkspace(context, user, result);
}); });
}, },
@ -119,7 +119,7 @@ class _SkipLogInScreenState extends State<SkipLogInScreen> {
void _openCurrentWorkspace( void _openCurrentWorkspace(
BuildContext context, BuildContext context,
UserProfilePB user, UserProfilePB user,
dartz.Either<CurrentWorkspaceSettingPB, FlowyError> workspacesOrError, dartz.Either<WorkspaceSettingPB, FlowyError> workspacesOrError,
) { ) {
workspacesOrError.fold( workspacesOrError.fold(
(workspaceSetting) { (workspaceSetting) {

View File

@ -44,10 +44,11 @@ class SplashScreen extends StatelessWidget {
void _handleAuthenticated(BuildContext context, Authenticated result) { void _handleAuthenticated(BuildContext context, Authenticated result) {
final userProfile = result.userProfile; final userProfile = result.userProfile;
FolderEventReadCurWorkspace().send().then( FolderEventReadCurrentWorkspace().send().then(
(result) { (result) {
return result.fold( return result.fold(
(workspaceSetting) => getIt<SplashRoute>().pushHomeScreen(context, userProfile, workspaceSetting), (workspaceSetting) => getIt<SplashRoute>()
.pushHomeScreen(context, userProfile, workspaceSetting),
(error) async { (error) async {
Log.error(error); Log.error(error);
assert(error.code == ErrorCode.RecordNotFound.value); assert(error.code == ErrorCode.RecordNotFound.value);
@ -80,7 +81,8 @@ class Body extends StatelessWidget {
fit: BoxFit.cover, fit: BoxFit.cover,
width: size.width, width: size.width,
height: size.height, height: size.height,
image: const AssetImage('assets/images/appflowy_launch_splash.jpg')), image: const AssetImage(
'assets/images/appflowy_launch_splash.jpg')),
const CircularProgressIndicator.adaptive(), const CircularProgressIndicator.adaptive(),
], ],
), ),

View File

@ -5,7 +5,7 @@ import 'package:flowy_sdk/log.dart';
import 'package:flowy_sdk/protobuf/flowy-error-code/code.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-error-code/code.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-folder/workspace.pb.dart' import 'package:flowy_sdk/protobuf/flowy-folder/workspace.pb.dart'
show CurrentWorkspaceSettingPB; show WorkspaceSettingPB;
import 'package:flowy_sdk/protobuf/flowy-user/user_profile.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-user/user_profile.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';
@ -15,8 +15,10 @@ part 'home_bloc.freezed.dart';
class HomeBloc extends Bloc<HomeEvent, HomeState> { class HomeBloc extends Bloc<HomeEvent, HomeState> {
final UserWorkspaceListener _listener; final UserWorkspaceListener _listener;
HomeBloc(UserProfilePB user, CurrentWorkspaceSettingPB workspaceSetting) HomeBloc(
: _listener = UserWorkspaceListener(userProfile: user), UserProfilePB user,
WorkspaceSettingPB workspaceSetting,
) : _listener = UserWorkspaceListener(userProfile: user),
super(HomeState.initial(workspaceSetting)) { super(HomeState.initial(workspaceSetting)) {
on<HomeEvent>( on<HomeEvent>(
(event, emit) async { (event, emit) async {
@ -115,7 +117,7 @@ class HomeEvent with _$HomeEvent {
_ShowEditPanel; _ShowEditPanel;
const factory HomeEvent.dismissEditPanel() = _DismissEditPanel; const factory HomeEvent.dismissEditPanel() = _DismissEditPanel;
const factory HomeEvent.didReceiveWorkspaceSetting( const factory HomeEvent.didReceiveWorkspaceSetting(
CurrentWorkspaceSettingPB setting) = _DidReceiveWorkspaceSetting; WorkspaceSettingPB setting) = _DidReceiveWorkspaceSetting;
const factory HomeEvent.unauthorized(String msg) = _Unauthorized; const factory HomeEvent.unauthorized(String msg) = _Unauthorized;
const factory HomeEvent.collapseMenu() = _CollapseMenu; const factory HomeEvent.collapseMenu() = _CollapseMenu;
const factory HomeEvent.editPanelResized(double offset) = _EditPanelResized; const factory HomeEvent.editPanelResized(double offset) = _EditPanelResized;
@ -129,7 +131,7 @@ class HomeState with _$HomeState {
required bool isLoading, required bool isLoading,
required bool forceCollapse, required bool forceCollapse,
required Option<EditPanelContext> panelContext, required Option<EditPanelContext> panelContext,
required CurrentWorkspaceSettingPB workspaceSetting, required WorkspaceSettingPB workspaceSetting,
required bool unauthorized, required bool unauthorized,
required bool isMenuCollapsed, required bool isMenuCollapsed,
required double resizeOffset, required double resizeOffset,
@ -137,8 +139,7 @@ class HomeState with _$HomeState {
required MenuResizeType resizeType, required MenuResizeType resizeType,
}) = _HomeState; }) = _HomeState;
factory HomeState.initial(CurrentWorkspaceSettingPB workspaceSetting) => factory HomeState.initial(WorkspaceSettingPB workspaceSetting) => HomeState(
HomeState(
isLoading: false, isLoading: false,
forceCollapse: false, forceCollapse: false,
panelContext: none(), panelContext: none(),

View File

@ -25,7 +25,7 @@ import 'menu/menu.dart';
class HomeScreen extends StatefulWidget { class HomeScreen extends StatefulWidget {
final UserProfilePB user; final UserProfilePB user;
final CurrentWorkspaceSettingPB workspaceSetting; final WorkspaceSettingPB workspaceSetting;
const HomeScreen(this.user, this.workspaceSetting, {Key? key}) const HomeScreen(this.user, this.workspaceSetting, {Key? key})
: super(key: key); : super(key: key);

View File

@ -34,7 +34,7 @@ import 'menu_user.dart';
class HomeMenu extends StatelessWidget { class HomeMenu extends StatelessWidget {
final PublishNotifier<bool> _collapsedNotifier; final PublishNotifier<bool> _collapsedNotifier;
final UserProfilePB user; final UserProfilePB user;
final CurrentWorkspaceSettingPB workspaceSetting; final WorkspaceSettingPB workspaceSetting;
const HomeMenu({ const HomeMenu({
Key? key, Key? key,

View File

@ -66,7 +66,7 @@ class AppFlowyGridTest {
(view) async { (view) async {
gridView = view; gridView = view;
_dataController = GridDataController(view: view); _dataController = GridDataController(view: view);
final result = await _dataController.loadData(); final result = await _dataController.openGrid();
result.fold((l) => null, (r) => throw Exception(r)); result.fold((l) => null, (r) => throw Exception(r));
}, },
(error) {}, (error) {},

View File

@ -1,8 +1,12 @@
import 'package:app_flowy/plugins/board/application/board_bloc.dart';
import 'package:app_flowy/plugins/board/board.dart'; import 'package:app_flowy/plugins/board/board.dart';
import 'package:app_flowy/plugins/doc/application/doc_bloc.dart';
import 'package:app_flowy/plugins/doc/document.dart'; import 'package:app_flowy/plugins/doc/document.dart';
import 'package:app_flowy/plugins/grid/application/grid_bloc.dart';
import 'package:app_flowy/plugins/grid/grid.dart'; import 'package:app_flowy/plugins/grid/grid.dart';
import 'package:app_flowy/workspace/application/app/app_bloc.dart'; import 'package:app_flowy/workspace/application/app/app_bloc.dart';
import 'package:app_flowy/workspace/application/menu/menu_view_section_bloc.dart'; import 'package:app_flowy/workspace/application/menu/menu_view_section_bloc.dart';
import 'package:flowy_sdk/dispatch/dispatch.dart';
import 'package:flowy_sdk/protobuf/flowy-folder/app.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder/app.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
@ -10,9 +14,9 @@ import 'package:bloc_test/bloc_test.dart';
import '../../util.dart'; import '../../util.dart';
void main() { void main() {
late AppFlowyUnitTest test; late AppFlowyUnitTest testContext;
setUpAll(() async { setUpAll(() async {
test = await AppFlowyUnitTest.ensureInitialized(); testContext = await AppFlowyUnitTest.ensureInitialized();
}); });
group( group(
@ -20,7 +24,7 @@ void main() {
() { () {
late AppPB app; late AppPB app;
setUp(() async { setUp(() async {
app = await test.createTestApp(); app = await testContext.createTestApp();
}); });
blocTest<AppBloc, AppState>( blocTest<AppBloc, AppState>(
@ -71,7 +75,7 @@ void main() {
group('$AppBloc', () { group('$AppBloc', () {
late AppPB app; late AppPB app;
setUpAll(() async { setUpAll(() async {
app = await test.createTestApp(); app = await testContext.createTestApp();
}); });
blocTest<AppBloc, AppState>( blocTest<AppBloc, AppState>(
@ -90,7 +94,7 @@ void main() {
wait: blocResponseDuration(), wait: blocResponseDuration(),
act: (bloc) => bloc.add(const AppEvent.delete()), act: (bloc) => bloc.add(const AppEvent.delete()),
verify: (bloc) async { verify: (bloc) async {
final apps = await test.loadApps(); final apps = await testContext.loadApps();
assert(apps.where((element) => element.id == app.id).isEmpty); assert(apps.where((element) => element.id == app.id).isEmpty);
}, },
); );
@ -100,7 +104,7 @@ void main() {
late ViewPB view; late ViewPB view;
late AppPB app; late AppPB app;
setUpAll(() async { setUpAll(() async {
app = await test.createTestApp(); app = await testContext.createTestApp();
}); });
blocTest<AppBloc, AppState>( blocTest<AppBloc, AppState>(
@ -130,7 +134,7 @@ void main() {
group('$AppBloc', () { group('$AppBloc', () {
late AppPB app; late AppPB app;
setUpAll(() async { setUpAll(() async {
app = await test.createTestApp(); app = await testContext.createTestApp();
}); });
blocTest<AppBloc, AppState>( blocTest<AppBloc, AppState>(
"create documents' order test", "create documents' order test",
@ -155,7 +159,7 @@ void main() {
group('$AppBloc', () { group('$AppBloc', () {
late AppPB app; late AppPB app;
setUpAll(() async { setUpAll(() async {
app = await test.createTestApp(); app = await testContext.createTestApp();
}); });
blocTest<AppBloc, AppState>( blocTest<AppBloc, AppState>(
"reorder documents", "reorder documents",
@ -186,4 +190,139 @@ void main() {
}, },
); );
}); });
group('$AppBloc', () {
late AppPB app;
setUpAll(() async {
app = await testContext.createTestApp();
});
blocTest<AppBloc, AppState>(
"assert initial latest create view is null after initialize",
build: () => AppBloc(app: app)..add(const AppEvent.initial()),
wait: blocResponseDuration(),
verify: (bloc) {
assert(bloc.state.latestCreatedView == null);
},
);
blocTest<AppBloc, AppState>(
"create a view and assert the latest create view is this view",
build: () => AppBloc(app: app)..add(const AppEvent.initial()),
act: (bloc) async {
bloc.add(AppEvent.createView("1", DocumentPluginBuilder()));
},
wait: blocResponseDuration(),
verify: (bloc) {
assert(bloc.state.latestCreatedView!.id == bloc.state.views.last.id);
},
);
blocTest<AppBloc, AppState>(
"create a view and assert the latest create view is this view",
build: () => AppBloc(app: app)..add(const AppEvent.initial()),
act: (bloc) async {
bloc.add(AppEvent.createView("2", DocumentPluginBuilder()));
},
wait: blocResponseDuration(),
verify: (bloc) {
assert(bloc.state.views[0].name == "1");
assert(bloc.state.latestCreatedView!.id == bloc.state.views.last.id);
},
);
blocTest<AppBloc, AppState>(
"check latest create view is null after reinitialize",
build: () => AppBloc(app: app)..add(const AppEvent.initial()),
wait: blocResponseDuration(),
verify: (bloc) {
assert(bloc.state.latestCreatedView == null);
},
);
});
group('$AppBloc', () {
late AppPB app;
late ViewPB latestCreatedView;
setUpAll(() async {
app = await testContext.createTestApp();
});
// Document
blocTest<AppBloc, AppState>(
"create a document view",
build: () => AppBloc(app: app)..add(const AppEvent.initial()),
act: (bloc) async {
bloc.add(AppEvent.createView("New document", DocumentPluginBuilder()));
},
wait: blocResponseDuration(),
verify: (bloc) {
latestCreatedView = bloc.state.views.last;
},
);
blocTest<DocumentBloc, DocumentState>(
"open the document",
build: () => DocumentBloc(view: latestCreatedView)
..add(const DocumentEvent.initial()),
wait: blocResponseDuration(),
);
test('check latest opened view is this document', () async {
final workspaceSetting = await FolderEventReadCurrentWorkspace()
.send()
.then((result) => result.fold((l) => l, (r) => throw Exception()));
workspaceSetting.latestView.id == latestCreatedView.id;
});
// Grid
blocTest<AppBloc, AppState>(
"create a grid view",
build: () => AppBloc(app: app)..add(const AppEvent.initial()),
act: (bloc) async {
bloc.add(AppEvent.createView("New grid", GridPluginBuilder()));
},
wait: blocResponseDuration(),
verify: (bloc) {
latestCreatedView = bloc.state.views.last;
},
);
blocTest<GridBloc, GridState>(
"open the grid",
build: () =>
GridBloc(view: latestCreatedView)..add(const GridEvent.initial()),
wait: blocResponseDuration(),
);
test('check latest opened view is this grid', () async {
final workspaceSetting = await FolderEventReadCurrentWorkspace()
.send()
.then((result) => result.fold((l) => l, (r) => throw Exception()));
workspaceSetting.latestView.id == latestCreatedView.id;
});
// Board
blocTest<AppBloc, AppState>(
"create a board view",
build: () => AppBloc(app: app)..add(const AppEvent.initial()),
act: (bloc) async {
bloc.add(AppEvent.createView("New board", BoardPluginBuilder()));
},
wait: blocResponseDuration(),
verify: (bloc) {
latestCreatedView = bloc.state.views.last;
},
);
blocTest<BoardBloc, BoardState>(
"open the board",
build: () =>
BoardBloc(view: latestCreatedView)..add(const BoardEvent.initial()),
wait: blocResponseDuration(),
);
test('check latest opened view is this board', () async {
final workspaceSetting = await FolderEventReadCurrentWorkspace()
.send()
.then((result) => result.fold((l) => l, (r) => throw Exception()));
workspaceSetting.latestView.id == latestCreatedView.id;
});
});
} }

View File

@ -92,7 +92,7 @@ impl WorkspaceIdPB {
} }
#[derive(Default, ProtoBuf, Clone)] #[derive(Default, ProtoBuf, Clone)]
pub struct CurrentWorkspaceSettingPB { pub struct WorkspaceSettingPB {
#[pb(index = 1)] #[pb(index = 1)]
pub workspace: WorkspacePB, pub workspace: WorkspacePB,

View File

@ -46,7 +46,7 @@ pub fn create(folder: Arc<FolderManager>) -> Module {
// Workspace // Workspace
module = module module = module
.event(FolderEvent::CreateWorkspace, create_workspace_handler) .event(FolderEvent::CreateWorkspace, create_workspace_handler)
.event(FolderEvent::ReadCurWorkspace, read_cur_workspace_handler) .event(FolderEvent::ReadCurrentWorkspace, read_cur_workspace_handler)
.event(FolderEvent::ReadWorkspaces, read_workspaces_handler) .event(FolderEvent::ReadWorkspaces, read_workspaces_handler)
.event(FolderEvent::OpenWorkspace, open_workspace_handler) .event(FolderEvent::OpenWorkspace, open_workspace_handler)
.event(FolderEvent::ReadWorkspaceApps, read_workspace_apps_handler); .event(FolderEvent::ReadWorkspaceApps, read_workspace_apps_handler);
@ -87,8 +87,8 @@ pub enum FolderEvent {
#[event(input = "CreateWorkspacePayloadPB", output = "WorkspacePB")] #[event(input = "CreateWorkspacePayloadPB", output = "WorkspacePB")]
CreateWorkspace = 0, CreateWorkspace = 0,
#[event(output = "CurrentWorkspaceSettingPB")] #[event(output = "WorkspaceSettingPB")]
ReadCurWorkspace = 1, ReadCurrentWorkspace = 1,
#[event(input = "WorkspaceIdPB", output = "RepeatedWorkspacePB")] #[event(input = "WorkspaceIdPB", output = "RepeatedWorkspacePB")]
ReadWorkspaces = 2, ReadWorkspaces = 2,

View File

@ -221,11 +221,11 @@ pub async fn notify_workspace_setting_did_change(
)?; )?;
let setting = match transaction.read_view(view_id) { let setting = match transaction.read_view(view_id) {
Ok(latest_view) => CurrentWorkspaceSettingPB { Ok(latest_view) => WorkspaceSettingPB {
workspace, workspace,
latest_view: Some(latest_view.into()), latest_view: Some(latest_view.into()),
}, },
Err(_) => CurrentWorkspaceSettingPB { Err(_) => WorkspaceSettingPB {
workspace, workspace,
latest_view: None, latest_view: None,
}, },

View File

@ -1,7 +1,7 @@
use crate::entities::{ use crate::entities::{
app::RepeatedAppPB, app::RepeatedAppPB,
view::ViewPB, view::ViewPB,
workspace::{CurrentWorkspaceSettingPB, RepeatedWorkspacePB, WorkspaceIdPB, *}, workspace::{RepeatedWorkspacePB, WorkspaceIdPB, WorkspaceSettingPB, *},
}; };
use crate::{ use crate::{
dart_notification::{send_dart_notification, FolderNotification}, dart_notification::{send_dart_notification, FolderNotification},
@ -79,7 +79,7 @@ pub(crate) async fn read_workspaces_handler(
#[tracing::instrument(level = "debug", skip(folder), err)] #[tracing::instrument(level = "debug", skip(folder), err)]
pub async fn read_cur_workspace_handler( pub async fn read_cur_workspace_handler(
folder: AppData<Arc<FolderManager>>, folder: AppData<Arc<FolderManager>>,
) -> DataResult<CurrentWorkspaceSettingPB, FlowyError> { ) -> DataResult<WorkspaceSettingPB, FlowyError> {
let workspace_id = get_current_workspace()?; let workspace_id = get_current_workspace()?;
let user_id = folder.user.user_id()?; let user_id = folder.user.user_id()?;
let params = WorkspaceIdPB { let params = WorkspaceIdPB {
@ -101,7 +101,7 @@ pub async fn read_cur_workspace_handler(
.await .await
.unwrap_or(None) .unwrap_or(None)
.map(|view_rev| view_rev.into()); .map(|view_rev| view_rev.into());
let setting = CurrentWorkspaceSettingPB { workspace, latest_view }; let setting = WorkspaceSettingPB { workspace, latest_view };
let _ = read_workspaces_on_server(folder, user_id, params); let _ = read_workspaces_on_server(folder, user_id, params);
data_result(setting) data_result(setting)
} }