test: Folder event test (#2709)

* test: add event tests

* test: add folder event test

* ci: rust fmt
This commit is contained in:
Nathan.fooo 2023-06-05 16:09:18 +08:00 committed by GitHub
parent 80a273edae
commit 4f2585baed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 500 additions and 111 deletions

View File

@ -109,13 +109,12 @@ class ViewBackendService {
required int fromIndex,
required int toIndex,
}) {
final payload = MoveFolderItemPayloadPB.create()
..itemId = viewId
final payload = MoveViewPayloadPB.create()
..viewId = viewId
..from = fromIndex
..to = toIndex
..ty = MoveFolderItemType.MoveView;
..to = toIndex;
return FolderEventMoveItem(payload).send();
return FolderEventMoveView(payload).send();
}
Future<List<(ViewPB, List<ViewPB>)>> fetchViews(

View File

@ -5,12 +5,7 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart'
show
CreateViewPayloadPB,
MoveFolderItemPayloadPB,
MoveFolderItemType,
ViewLayoutPB,
ViewPB;
show CreateViewPayloadPB, MoveViewPayloadPB, ViewLayoutPB, ViewPB;
import 'package:appflowy_backend/protobuf/flowy-folder2/workspace.pb.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
@ -69,12 +64,11 @@ class WorkspaceService {
required int fromIndex,
required int toIndex,
}) {
final payload = MoveFolderItemPayloadPB.create()
..itemId = appId
final payload = MoveViewPayloadPB.create()
..viewId = appId
..from = fromIndex
..to = toIndex
..ty = MoveFolderItemType.MoveApp;
..to = toIndex;
return FolderEventMoveItem(payload).send();
return FolderEventMoveView(payload).send();
}
}

View File

@ -99,7 +99,7 @@ checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
[[package]]
name = "appflowy-integrate"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=13b178#13b17802de31e75255b4303914042bdbb04361b2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=cbc2e0#cbc2e0acb8420dc997921bb3f56b99f9975c2aab"
dependencies = [
"anyhow",
"collab",
@ -1024,7 +1024,7 @@ dependencies = [
[[package]]
name = "collab"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=13b178#13b17802de31e75255b4303914042bdbb04361b2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=cbc2e0#cbc2e0acb8420dc997921bb3f56b99f9975c2aab"
dependencies = [
"anyhow",
"bytes",
@ -1042,7 +1042,7 @@ dependencies = [
[[package]]
name = "collab-client-ws"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=13b178#13b17802de31e75255b4303914042bdbb04361b2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=cbc2e0#cbc2e0acb8420dc997921bb3f56b99f9975c2aab"
dependencies = [
"bytes",
"collab-sync",
@ -1060,7 +1060,7 @@ dependencies = [
[[package]]
name = "collab-database"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=13b178#13b17802de31e75255b4303914042bdbb04361b2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=cbc2e0#cbc2e0acb8420dc997921bb3f56b99f9975c2aab"
dependencies = [
"anyhow",
"async-trait",
@ -1086,7 +1086,7 @@ dependencies = [
[[package]]
name = "collab-derive"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=13b178#13b17802de31e75255b4303914042bdbb04361b2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=cbc2e0#cbc2e0acb8420dc997921bb3f56b99f9975c2aab"
dependencies = [
"proc-macro2",
"quote",
@ -1098,7 +1098,7 @@ dependencies = [
[[package]]
name = "collab-document"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=13b178#13b17802de31e75255b4303914042bdbb04361b2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=cbc2e0#cbc2e0acb8420dc997921bb3f56b99f9975c2aab"
dependencies = [
"anyhow",
"collab",
@ -1115,7 +1115,7 @@ dependencies = [
[[package]]
name = "collab-folder"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=13b178#13b17802de31e75255b4303914042bdbb04361b2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=cbc2e0#cbc2e0acb8420dc997921bb3f56b99f9975c2aab"
dependencies = [
"anyhow",
"collab",
@ -1134,7 +1134,7 @@ dependencies = [
[[package]]
name = "collab-persistence"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=13b178#13b17802de31e75255b4303914042bdbb04361b2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=cbc2e0#cbc2e0acb8420dc997921bb3f56b99f9975c2aab"
dependencies = [
"bincode",
"chrono",
@ -1154,7 +1154,7 @@ dependencies = [
[[package]]
name = "collab-plugins"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=13b178#13b17802de31e75255b4303914042bdbb04361b2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=cbc2e0#cbc2e0acb8420dc997921bb3f56b99f9975c2aab"
dependencies = [
"anyhow",
"async-trait",
@ -1184,7 +1184,7 @@ dependencies = [
[[package]]
name = "collab-sync"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=13b178#13b17802de31e75255b4303914042bdbb04361b2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=cbc2e0#cbc2e0acb8420dc997921bb3f56b99f9975c2aab"
dependencies = [
"bytes",
"collab",

View File

@ -1,7 +1,7 @@
import {
FolderEventCreateView,
FolderEventDeleteView,
FolderEventMoveItem,
FolderEventMoveView,
FolderEventReadView,
FolderEventUpdateView,
ViewLayoutPB,
@ -10,8 +10,7 @@ import {
CreateViewPayloadPB,
RepeatedViewIdPB,
ViewPB,
MoveFolderItemPayloadPB,
MoveFolderItemType,
MoveViewPayloadPB,
FlowyError,
ViewIdPB,
UpdateViewPayloadPB,
@ -95,13 +94,12 @@ export class AppBackendService {
};
moveView = (params: { view_id: string; fromIndex: number; toIndex: number }) => {
const payload = MoveFolderItemPayloadPB.fromObject({
item_id: params.view_id,
const payload = MoveViewPayloadPB.fromObject({
view_id: params.view_id,
from: params.fromIndex,
to: params.toIndex,
ty: MoveFolderItemType.MoveView,
});
return FolderEventMoveItem(payload);
return FolderEventMoveView(payload);
};
}

View File

@ -1,17 +1,11 @@
import { Err, Ok } from 'ts-results';
import {
FolderEventCreateView,
FolderEventMoveItem,
FolderEventMoveView,
FolderEventReadWorkspaceViews,
FolderEventReadAllWorkspaces,
} from '@/services/backend/events/flowy-folder2';
import {
CreateViewPayloadPB,
FlowyError,
MoveFolderItemPayloadPB,
ViewLayoutPB,
WorkspaceIdPB,
} from '@/services/backend';
import { CreateViewPayloadPB, FlowyError, MoveViewPayloadPB, ViewLayoutPB, WorkspaceIdPB } from '@/services/backend';
import assert from 'assert';
export class WorkspaceBackendService {
@ -56,11 +50,11 @@ export class WorkspaceBackendService {
};
moveApp = (params: { appId: string; fromIndex: number; toIndex: number }) => {
const payload = MoveFolderItemPayloadPB.fromObject({
item_id: params.appId,
const payload = MoveViewPayloadPB.fromObject({
view_id: params.appId,
from: params.fromIndex,
to: params.toIndex,
});
return FolderEventMoveItem(payload);
return FolderEventMoveView(payload);
};
}

View File

@ -1863,6 +1863,7 @@ dependencies = [
"flowy-core",
"flowy-folder2",
"flowy-net",
"flowy-notification",
"flowy-server",
"flowy-user",
"futures-util",

View File

@ -57,14 +57,14 @@ pub fn view_pb_with_child_views(view: View, child_views: Vec<View>) -> ViewPB {
#[derive(Eq, PartialEq, Hash, Debug, ProtoBuf_Enum, Clone)]
pub enum ViewLayoutPB {
Document = 0,
Grid = 3,
Board = 4,
Calendar = 5,
Grid = 1,
Board = 2,
Calendar = 3,
}
impl std::default::Default for ViewLayoutPB {
fn default() -> Self {
ViewLayoutPB::Grid
ViewLayoutPB::Document
}
}
@ -271,50 +271,33 @@ impl TryInto<UpdateViewParams> for UpdateViewPayloadPB {
}
}
#[derive(ProtoBuf_Enum)]
pub enum MoveFolderItemType {
MoveApp = 0,
MoveView = 1,
}
impl std::default::Default for MoveFolderItemType {
fn default() -> Self {
MoveFolderItemType::MoveApp
}
}
#[derive(Default, ProtoBuf)]
pub struct MoveFolderItemPayloadPB {
pub struct MoveViewPayloadPB {
#[pb(index = 1)]
pub item_id: String,
pub view_id: String,
#[pb(index = 2)]
pub from: i32,
#[pb(index = 3)]
pub to: i32,
#[pb(index = 4)]
pub ty: MoveFolderItemType,
}
pub struct MoveViewParams {
pub item_id: String,
pub from: usize,
pub to: usize,
pub ty: MoveFolderItemType,
}
impl TryInto<MoveViewParams> for MoveFolderItemPayloadPB {
impl TryInto<MoveViewParams> for MoveViewPayloadPB {
type Error = ErrorCode;
fn try_into(self) -> Result<MoveViewParams, Self::Error> {
let view_id = ViewIdentify::parse(self.item_id)?.0;
let view_id = ViewIdentify::parse(self.view_id)?.0;
Ok(MoveViewParams {
item_id: view_id,
from: self.from as usize,
to: self.to as usize,
ty: self.ty,
})
}
}

View File

@ -5,7 +5,7 @@ use lib_dispatch::prelude::{data_result_ok, AFPluginData, AFPluginState, DataRes
use crate::entities::{
view_pb_without_child_views, CreateViewParams, CreateViewPayloadPB, CreateWorkspaceParams,
CreateWorkspacePayloadPB, ImportPB, MoveFolderItemPayloadPB, MoveViewParams, RepeatedTrashIdPB,
CreateWorkspacePayloadPB, ImportPB, MoveViewParams, MoveViewPayloadPB, RepeatedTrashIdPB,
RepeatedTrashPB, RepeatedViewIdPB, RepeatedViewPB, RepeatedWorkspacePB, TrashIdPB,
UpdateViewParams, UpdateViewPayloadPB, ViewIdPB, ViewPB, WorkspaceIdPB, WorkspacePB,
WorkspaceSettingPB,
@ -144,7 +144,7 @@ pub(crate) async fn close_view_handler(
#[tracing::instrument(level = "debug", skip_all, err)]
pub(crate) async fn move_view_handler(
data: AFPluginData<MoveFolderItemPayloadPB>,
data: AFPluginData<MoveViewPayloadPB>,
folder: AFPluginState<Arc<Folder2Manager>>,
) -> Result<(), FlowyError> {
let params: MoveViewParams = data.into_inner().try_into()?;

View File

@ -26,7 +26,7 @@ pub fn init(folder: Arc<Folder2Manager>) -> AFPlugin {
.event(FolderEvent::DuplicateView, duplicate_view_handler)
.event(FolderEvent::SetLatestView, set_latest_view_handler)
.event(FolderEvent::CloseView, close_view_handler)
.event(FolderEvent::MoveItem, move_view_handler)
.event(FolderEvent::MoveView, move_view_handler)
// Trash
.event(FolderEvent::ReadTrash, read_trash_handler)
.event(FolderEvent::PutbackTrash, putback_trash_handler)
@ -97,8 +97,8 @@ pub enum FolderEvent {
SetLatestView = 21,
/// Move the view or app to another place
#[event(input = "MoveFolderItemPayloadPB")]
MoveItem = 22,
#[event(input = "MoveViewPayloadPB")]
MoveView = 22,
/// Read the trash that was deleted by the user
#[event(output = "RepeatedTrashPB")]

View File

@ -1,7 +1,5 @@
use crate::script::{invalid_workspace_name_test_case, FolderScript::*, FolderTest};
use crate::script::{FolderScript::*, FolderTest};
use collab_folder::core::ViewLayout;
use flowy_folder2::entities::CreateWorkspacePayloadPB;
use flowy_test::{event_builder::*, FlowyCoreTest};
#[tokio::test]
async fn read_all_workspace_test() {
@ -60,28 +58,6 @@ async fn create_parent_view_test() {
test.run_scripts(vec![ReloadParentView(app.id)]).await;
}
#[tokio::test]
async fn create_parent_view_with_invalid_name() {
for (name, code) in invalid_workspace_name_test_case() {
let sdk = FlowyCoreTest::new();
let request = CreateWorkspacePayloadPB {
name,
desc: "".to_owned(),
};
assert_eq!(
EventBuilder::new(sdk)
.event(flowy_folder2::event_map::FolderEvent::CreateWorkspace)
.payload(request)
.async_send()
.await
.error()
.unwrap()
.code,
code.value()
)
}
}
#[tokio::test]
#[should_panic]
async fn delete_parent_view_test() {

View File

@ -1,5 +1,5 @@
use collab_folder::core::ViewLayout;
use flowy_error::ErrorCode;
use flowy_folder2::entities::*;
use flowy_folder2::event_map::FolderEvent::*;
use flowy_test::event_builder::EventBuilder;
@ -161,14 +161,6 @@ impl FolderTest {
}
}
}
pub fn invalid_workspace_name_test_case() -> Vec<(String, ErrorCode)> {
vec![
("".to_owned(), ErrorCode::WorkspaceNameInvalid),
("1234".repeat(100), ErrorCode::WorkspaceNameTooLong),
]
}
pub async fn create_workspace(sdk: &FlowyCoreTest, name: &str, desc: &str) -> WorkspacePB {
let request = CreateWorkspacePayloadPB {
name: name.to_owned(),

View File

@ -14,6 +14,7 @@ lib-dispatch = { path = "../lib-dispatch" }
lib-ot = { path = "../../../shared-lib/lib-ot" }
lib-infra = { path = "../../../shared-lib/lib-infra" }
flowy-server = { path = "../flowy-server" }
flowy-notification = { path = "../flowy-notification" }
serde = { version = "1.0", features = ["derive"] }
serde_json = {version = "1.0"}

View File

@ -1,8 +1,7 @@
use crate::FlowyCoreTest;
use flowy_user::errors::FlowyError;
use lib_dispatch::prelude::{
AFPluginDispatcher, AFPluginEventResponse, AFPluginFromBytes, AFPluginRequest, StatusCode,
ToBytes, *,
AFPluginDispatcher, AFPluginEventResponse, AFPluginFromBytes, AFPluginRequest, ToBytes, *,
};
use std::{
convert::TryFrom,
@ -87,7 +86,6 @@ impl EventBuilder {
pub fn error(self) -> Option<FlowyError> {
let response = self.get_response();
assert_eq!(response.status_code, StatusCode::Err);
<AFPluginData<FlowyError>>::try_from(response.payload)
.ok()
.map(|data| data.into_inner())

View File

@ -3,7 +3,9 @@ use parking_lot::RwLock;
use std::env::temp_dir;
use std::sync::Arc;
use crate::event_builder::EventBuilder;
use flowy_core::{AppFlowyCore, AppFlowyCoreConfig};
use flowy_folder2::entities::{CreateViewPayloadPB, RepeatedViewIdPB, ViewPB, WorkspaceSettingPB};
use flowy_user::entities::{AuthTypePB, UserProfilePB};
use crate::user_event::{async_sign_up, init_user_setting, SignUpContext};
@ -36,6 +38,12 @@ impl FlowyCoreTest {
Self::default()
}
pub async fn new_with_user() -> Self {
let test = Self::default();
test.sign_up().await;
test
}
pub async fn sign_up(&self) -> SignUpContext {
let auth_type = self.auth_type.read().clone();
async_sign_up(self.inner.dispatcher(), auth_type).await
@ -51,6 +59,46 @@ impl FlowyCoreTest {
init_user_setting(self.inner.dispatcher()).await;
context.user_profile
}
pub async fn get_current_workspace(&self) -> WorkspaceSettingPB {
EventBuilder::new(self.clone())
.event(flowy_folder2::event_map::FolderEvent::GetCurrentWorkspace)
.async_send()
.await
.parse::<flowy_folder2::entities::WorkspaceSettingPB>()
}
pub async fn delete_view(&self, view_id: &str) {
let payload = RepeatedViewIdPB {
items: vec![view_id.to_string()],
};
// delete the view. the view will be moved to trash
EventBuilder::new(self.clone())
.event(flowy_folder2::event_map::FolderEvent::DeleteView)
.payload(payload)
.async_send()
.await;
}
pub async fn create_view(&self, parent_id: &str, name: String) -> ViewPB {
let payload = CreateViewPayloadPB {
parent_view_id: parent_id.to_string(),
name,
desc: "".to_string(),
thumbnail: None,
layout: Default::default(),
initial_data: vec![],
meta: Default::default(),
set_as_current: false,
};
EventBuilder::new(self.clone())
.event(flowy_folder2::event_map::FolderEvent::CreateView)
.payload(payload)
.async_send()
.await
.parse::<flowy_folder2::entities::ViewPB>()
}
}
impl std::ops::Deref for FlowyCoreTest {
@ -60,3 +108,13 @@ impl std::ops::Deref for FlowyCoreTest {
&self.inner
}
}
// pub struct TestNotificationSender {
// pub(crate) sender: tokio::sync::mpsc::Sender<()>,
// }
//
// impl NotificationSender for TestNotificationSender {
// fn send_subject(&self, subject: SubscribeObject) -> Result<(), String> {
// todo!()
// }
// }

View File

@ -0,0 +1 @@
mod test;

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@
mod test;

View File

@ -0,0 +1,390 @@
use flowy_folder2::entities::*;
use flowy_test::event_builder::EventBuilder;
use flowy_test::FlowyCoreTest;
use flowy_user::errors::ErrorCode;
#[tokio::test]
async fn create_workspace_event_test() {
let test = FlowyCoreTest::new_with_user().await;
let request = CreateWorkspacePayloadPB {
name: "my second workspace".to_owned(),
desc: "".to_owned(),
};
let resp = EventBuilder::new(test)
.event(flowy_folder2::event_map::FolderEvent::CreateWorkspace)
.payload(request)
.async_send()
.await
.parse::<flowy_folder2::entities::WorkspacePB>();
assert_eq!(resp.name, "my second workspace");
}
#[tokio::test]
async fn open_workspace_event_test() {
let test = FlowyCoreTest::new_with_user().await;
let payload = CreateWorkspacePayloadPB {
name: "my second workspace".to_owned(),
desc: "".to_owned(),
};
// create a workspace
let resp_1 = EventBuilder::new(test.clone())
.event(flowy_folder2::event_map::FolderEvent::CreateWorkspace)
.payload(payload)
.async_send()
.await
.parse::<flowy_folder2::entities::WorkspacePB>();
// open the workspace
let payload = WorkspaceIdPB {
value: Some(resp_1.id.clone()),
};
let resp_2 = EventBuilder::new(test)
.event(flowy_folder2::event_map::FolderEvent::OpenWorkspace)
.payload(payload)
.async_send()
.await
.parse::<flowy_folder2::entities::WorkspacePB>();
assert_eq!(resp_1.id, resp_2.id);
assert_eq!(resp_1.name, resp_2.name);
}
#[tokio::test]
async fn create_view_event_test() {
let test = FlowyCoreTest::new_with_user().await;
let current_workspace = test.get_current_workspace().await.workspace;
let view = test
.create_view(&current_workspace.id, format!("My first view"))
.await;
assert_eq!(view.parent_view_id, current_workspace.id);
assert_eq!(view.name, "My first view");
assert_eq!(view.layout, ViewLayoutPB::Document);
}
#[tokio::test]
async fn delete_view_event_test() {
let test = FlowyCoreTest::new_with_user().await;
let current_workspace = test.get_current_workspace().await.workspace;
let view = test
.create_view(&current_workspace.id, format!("My first view"))
.await;
test.delete_view(&view.id).await;
// Try the read the view
let payload = ViewIdPB {
value: view.id.clone(),
};
let error = EventBuilder::new(test.clone())
.event(flowy_folder2::event_map::FolderEvent::ReadView)
.payload(payload)
.async_send()
.await
.error()
.unwrap();
assert_eq!(error.code, ErrorCode::RecordNotFound.value());
}
#[tokio::test]
async fn put_back_trash_event_test() {
let test = FlowyCoreTest::new_with_user().await;
let current_workspace = test.get_current_workspace().await.workspace;
let view = test
.create_view(&current_workspace.id, format!("My first view"))
.await;
test.delete_view(&view.id).await;
// After delete view, the view will be moved to trash
let payload = ViewIdPB {
value: view.id.clone(),
};
let error = EventBuilder::new(test.clone())
.event(flowy_folder2::event_map::FolderEvent::ReadView)
.payload(payload)
.async_send()
.await
.error()
.unwrap();
assert_eq!(error.code, ErrorCode::RecordNotFound.value());
let payload = TrashIdPB {
id: view.id.clone(),
};
EventBuilder::new(test.clone())
.event(flowy_folder2::event_map::FolderEvent::PutbackTrash)
.payload(payload)
.async_send()
.await;
let payload = ViewIdPB {
value: view.id.clone(),
};
let error = EventBuilder::new(test.clone())
.event(flowy_folder2::event_map::FolderEvent::ReadView)
.payload(payload)
.async_send()
.await
.error();
assert!(error.is_none());
}
#[tokio::test]
async fn delete_view_permanently_event_test() {
let test = FlowyCoreTest::new_with_user().await;
let current_workspace = test.get_current_workspace().await.workspace;
let view = test
.create_view(&current_workspace.id, format!("My first view"))
.await;
let payload = RepeatedViewIdPB {
items: vec![view.id.clone()],
};
// delete the view. the view will be moved to trash
EventBuilder::new(test.clone())
.event(flowy_folder2::event_map::FolderEvent::DeleteView)
.payload(payload)
.async_send()
.await;
let trash = EventBuilder::new(test.clone())
.event(flowy_folder2::event_map::FolderEvent::ReadTrash)
.async_send()
.await
.parse::<flowy_folder2::entities::RepeatedTrashPB>()
.items;
assert_eq!(trash.len(), 1);
assert_eq!(trash[0].id, view.id);
// delete the view from trash
let payload = RepeatedTrashIdPB {
items: vec![TrashIdPB {
id: view.id.clone(),
}],
};
EventBuilder::new(test.clone())
.event(flowy_folder2::event_map::FolderEvent::DeleteTrash)
.payload(payload)
.async_send()
.await;
// After delete the last view, the trash should be empty
let trash = EventBuilder::new(test.clone())
.event(flowy_folder2::event_map::FolderEvent::ReadTrash)
.async_send()
.await
.parse::<flowy_folder2::entities::RepeatedTrashPB>()
.items;
assert!(trash.is_empty());
}
#[tokio::test]
async fn delete_all_trash_test() {
let test = FlowyCoreTest::new_with_user().await;
let current_workspace = test.get_current_workspace().await.workspace;
for i in 0..3 {
let view = test
.create_view(&current_workspace.id, format!("My {} view", i))
.await;
let payload = RepeatedViewIdPB {
items: vec![view.id.clone()],
};
// delete the view. the view will be moved to trash
EventBuilder::new(test.clone())
.event(flowy_folder2::event_map::FolderEvent::DeleteView)
.payload(payload)
.async_send()
.await;
}
let trash = EventBuilder::new(test.clone())
.event(flowy_folder2::event_map::FolderEvent::ReadTrash)
.async_send()
.await
.parse::<flowy_folder2::entities::RepeatedTrashPB>()
.items;
assert_eq!(trash.len(), 3);
// Delete all the trash
EventBuilder::new(test.clone())
.event(flowy_folder2::event_map::FolderEvent::DeleteAllTrash)
.async_send()
.await;
// After delete the last view, the trash should be empty
let trash = EventBuilder::new(test.clone())
.event(flowy_folder2::event_map::FolderEvent::ReadTrash)
.async_send()
.await
.parse::<flowy_folder2::entities::RepeatedTrashPB>()
.items;
assert!(trash.is_empty());
}
#[tokio::test]
async fn multiple_hierarchy_view_test() {
let test = FlowyCoreTest::new_with_user().await;
let current_workspace = test.get_current_workspace().await.workspace;
for i in 1..4 {
let parent = test
.create_view(&current_workspace.id, format!("My {} view", i))
.await;
for j in 1..3 {
let child = test
.create_view(&parent.id, format!("My {}-{} view", i, j))
.await;
for k in 1..2 {
let _sub_child = test
.create_view(&child.id, format!("My {}-{}-{} view", i, j, k))
.await;
}
}
}
let mut views = EventBuilder::new(test.clone())
.event(flowy_folder2::event_map::FolderEvent::ReadWorkspaceViews)
.async_send()
.await
.parse::<flowy_folder2::entities::RepeatedViewPB>()
.items;
// There will be one default view when AppFlowy is initialized. So there will be 4 views in total
assert_eq!(views.len(), 4);
views.remove(0);
// workspace
// - view1
// - view1-1
// - view1-1-1
// - view1-2
// - view1-2-1
// - view2
// - view2-1
// - view2-1-1
// - view2-2
// - view2-2-1
// - view3
// - view3-1
// - view3-1-1
// - view3-2
// - view3-2-1
assert_eq!(views[0].name, "My 1 view");
assert_eq!(views[1].name, "My 2 view");
assert_eq!(views[2].name, "My 3 view");
assert_eq!(views[0].child_views.len(), 2);
// By default only the first level of child views will be loaded
assert!(views[0].child_views[0].child_views.is_empty());
for (i, view) in views.into_iter().enumerate() {
for (j, child_view) in view.child_views.into_iter().enumerate() {
let payload = ViewIdPB {
value: child_view.id.clone(),
};
let child = EventBuilder::new(test.clone())
.event(flowy_folder2::event_map::FolderEvent::ReadView)
.payload(payload)
.async_send()
.await
.parse::<flowy_folder2::entities::ViewPB>();
assert_eq!(child.name, format!("My {}-{} view", i + 1, j + 1));
assert_eq!(child.child_views.len(), 1);
// By default only the first level of child views will be loaded
assert!(child.child_views[0].child_views.is_empty());
for (k, _child_view) in child_view.child_views.into_iter().enumerate() {
// Get the last level view
let sub_child = EventBuilder::new(test.clone())
.event(flowy_folder2::event_map::FolderEvent::ReadView)
.payload(ViewIdPB {
value: child.id.clone(),
})
.async_send()
.await
.parse::<flowy_folder2::entities::ViewPB>();
assert_eq!(child.name, format!("My {}-{}-{} view", i + 1, j + 1, k + 1));
assert!(sub_child.child_views.is_empty());
}
}
}
}
#[tokio::test]
async fn move_view_event_test() {
let test = FlowyCoreTest::new_with_user().await;
let current_workspace = test.get_current_workspace().await.workspace;
for i in 1..4 {
let parent = test
.create_view(&current_workspace.id, format!("My {} view", i))
.await;
for j in 1..3 {
let _ = test
.create_view(&parent.id, format!("My {}-{} view", i, j))
.await;
}
}
let views = EventBuilder::new(test.clone())
.event(flowy_folder2::event_map::FolderEvent::ReadWorkspaceViews)
.async_send()
.await
.parse::<flowy_folder2::entities::RepeatedViewPB>()
.items;
// There will be one default view when AppFlowy is initialized. So there will be 4 views in total
assert_eq!(views.len(), 4);
assert_eq!(views[1].name, "My 1 view");
assert_eq!(views[2].name, "My 2 view");
assert_eq!(views[3].name, "My 3 view");
let payload = MoveViewPayloadPB {
view_id: views[1].id.clone(),
from: 1,
to: 2,
};
let _ = EventBuilder::new(test.clone())
.event(flowy_folder2::event_map::FolderEvent::MoveView)
.payload(payload)
.async_send()
.await;
let views = EventBuilder::new(test.clone())
.event(flowy_folder2::event_map::FolderEvent::ReadWorkspaceViews)
.async_send()
.await
.parse::<flowy_folder2::entities::RepeatedViewPB>()
.items;
assert_eq!(views[1].name, "My 2 view");
assert_eq!(views[2].name, "My 1 view");
assert_eq!(views[3].name, "My 3 view");
}
#[tokio::test]
async fn create_parent_view_with_invalid_name() {
for (name, code) in invalid_workspace_name_test_case() {
let sdk = FlowyCoreTest::new();
let request = CreateWorkspacePayloadPB {
name,
desc: "".to_owned(),
};
assert_eq!(
EventBuilder::new(sdk)
.event(flowy_folder2::event_map::FolderEvent::CreateWorkspace)
.payload(request)
.async_send()
.await
.error()
.unwrap()
.code,
code.value()
)
}
}
fn invalid_workspace_name_test_case() -> Vec<(String, ErrorCode)> {
vec![
("".to_owned(), ErrorCode::WorkspaceNameInvalid),
("1234".repeat(100), ErrorCode::WorkspaceNameTooLong),
]
}

View File

@ -1 +1,3 @@
mod database;
mod folder;
mod user;