test.rs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. use flowy_folder2::entities::icon::{UpdateViewIconPayloadPB, ViewIconPB, ViewIconTypePB};
  2. use flowy_folder2::entities::*;
  3. use flowy_test::event_builder::EventBuilder;
  4. use flowy_test::FlowyCoreTest;
  5. use flowy_user::errors::ErrorCode;
  6. #[tokio::test]
  7. async fn create_workspace_event_test() {
  8. let test = FlowyCoreTest::new_with_guest_user().await;
  9. let request = CreateWorkspacePayloadPB {
  10. name: "my second workspace".to_owned(),
  11. desc: "".to_owned(),
  12. };
  13. let resp = EventBuilder::new(test)
  14. .event(flowy_folder2::event_map::FolderEvent::CreateWorkspace)
  15. .payload(request)
  16. .async_send()
  17. .await
  18. .parse::<flowy_folder2::entities::WorkspacePB>();
  19. assert_eq!(resp.name, "my second workspace");
  20. }
  21. #[tokio::test]
  22. async fn open_workspace_event_test() {
  23. let test = FlowyCoreTest::new_with_guest_user().await;
  24. let payload = CreateWorkspacePayloadPB {
  25. name: "my second workspace".to_owned(),
  26. desc: "".to_owned(),
  27. };
  28. // create a workspace
  29. let resp_1 = EventBuilder::new(test.clone())
  30. .event(flowy_folder2::event_map::FolderEvent::CreateWorkspace)
  31. .payload(payload)
  32. .async_send()
  33. .await
  34. .parse::<flowy_folder2::entities::WorkspacePB>();
  35. // open the workspace
  36. let payload = WorkspaceIdPB {
  37. value: Some(resp_1.id.clone()),
  38. };
  39. let resp_2 = EventBuilder::new(test)
  40. .event(flowy_folder2::event_map::FolderEvent::OpenWorkspace)
  41. .payload(payload)
  42. .async_send()
  43. .await
  44. .parse::<flowy_folder2::entities::WorkspacePB>();
  45. assert_eq!(resp_1.id, resp_2.id);
  46. assert_eq!(resp_1.name, resp_2.name);
  47. }
  48. #[tokio::test]
  49. async fn create_view_event_test() {
  50. let test = FlowyCoreTest::new_with_guest_user().await;
  51. let current_workspace = test.get_current_workspace().await.workspace;
  52. let view = test
  53. .create_view(&current_workspace.id, "My first view".to_string())
  54. .await;
  55. assert_eq!(view.parent_view_id, current_workspace.id);
  56. assert_eq!(view.name, "My first view");
  57. assert_eq!(view.layout, ViewLayoutPB::Document);
  58. }
  59. #[tokio::test]
  60. async fn update_view_event_with_name_test() {
  61. let test = FlowyCoreTest::new_with_guest_user().await;
  62. let current_workspace = test.get_current_workspace().await.workspace;
  63. let view = test
  64. .create_view(&current_workspace.id, "My first view".to_string())
  65. .await;
  66. let error = test
  67. .update_view(UpdateViewPayloadPB {
  68. view_id: view.id.clone(),
  69. name: Some("My second view".to_string()),
  70. ..Default::default()
  71. })
  72. .await;
  73. assert!(error.is_none());
  74. let view = test.get_view(&view.id).await;
  75. assert_eq!(view.name, "My second view");
  76. }
  77. #[tokio::test]
  78. async fn update_view_icon_event_test() {
  79. let test = FlowyCoreTest::new_with_guest_user().await;
  80. let current_workspace = test.get_current_workspace().await.workspace;
  81. let view = test
  82. .create_view(&current_workspace.id, "My first view".to_string())
  83. .await;
  84. let new_icon = ViewIconPB {
  85. ty: ViewIconTypePB::Emoji,
  86. value: "👍".to_owned(),
  87. };
  88. let error = test
  89. .update_view_icon(UpdateViewIconPayloadPB {
  90. view_id: view.id.clone(),
  91. icon: Some(new_icon.clone()),
  92. })
  93. .await;
  94. assert!(error.is_none());
  95. let view = test.get_view(&view.id).await;
  96. assert_eq!(view.icon, Some(new_icon));
  97. }
  98. #[tokio::test]
  99. async fn delete_view_event_test() {
  100. let test = FlowyCoreTest::new_with_guest_user().await;
  101. let current_workspace = test.get_current_workspace().await.workspace;
  102. let view = test
  103. .create_view(&current_workspace.id, "My first view".to_string())
  104. .await;
  105. test.delete_view(&view.id).await;
  106. // Try the read the view
  107. let payload = ViewIdPB {
  108. value: view.id.clone(),
  109. };
  110. let error = EventBuilder::new(test.clone())
  111. .event(flowy_folder2::event_map::FolderEvent::ReadView)
  112. .payload(payload)
  113. .async_send()
  114. .await
  115. .error()
  116. .unwrap();
  117. assert_eq!(error.code, ErrorCode::RecordNotFound);
  118. }
  119. #[tokio::test]
  120. async fn put_back_trash_event_test() {
  121. let test = FlowyCoreTest::new_with_guest_user().await;
  122. let current_workspace = test.get_current_workspace().await.workspace;
  123. let view = test
  124. .create_view(&current_workspace.id, "My first view".to_string())
  125. .await;
  126. test.delete_view(&view.id).await;
  127. // After delete view, the view will be moved to trash
  128. let payload = ViewIdPB {
  129. value: view.id.clone(),
  130. };
  131. let error = EventBuilder::new(test.clone())
  132. .event(flowy_folder2::event_map::FolderEvent::ReadView)
  133. .payload(payload)
  134. .async_send()
  135. .await
  136. .error()
  137. .unwrap();
  138. assert_eq!(error.code, ErrorCode::RecordNotFound);
  139. let payload = TrashIdPB {
  140. id: view.id.clone(),
  141. };
  142. EventBuilder::new(test.clone())
  143. .event(flowy_folder2::event_map::FolderEvent::PutbackTrash)
  144. .payload(payload)
  145. .async_send()
  146. .await;
  147. let payload = ViewIdPB {
  148. value: view.id.clone(),
  149. };
  150. let error = EventBuilder::new(test.clone())
  151. .event(flowy_folder2::event_map::FolderEvent::ReadView)
  152. .payload(payload)
  153. .async_send()
  154. .await
  155. .error();
  156. assert!(error.is_none());
  157. }
  158. #[tokio::test]
  159. async fn delete_view_permanently_event_test() {
  160. let test = FlowyCoreTest::new_with_guest_user().await;
  161. let current_workspace = test.get_current_workspace().await.workspace;
  162. let view = test
  163. .create_view(&current_workspace.id, "My first view".to_string())
  164. .await;
  165. let payload = RepeatedViewIdPB {
  166. items: vec![view.id.clone()],
  167. };
  168. // delete the view. the view will be moved to trash
  169. EventBuilder::new(test.clone())
  170. .event(flowy_folder2::event_map::FolderEvent::DeleteView)
  171. .payload(payload)
  172. .async_send()
  173. .await;
  174. let trash = EventBuilder::new(test.clone())
  175. .event(flowy_folder2::event_map::FolderEvent::ReadTrash)
  176. .async_send()
  177. .await
  178. .parse::<flowy_folder2::entities::RepeatedTrashPB>()
  179. .items;
  180. assert_eq!(trash.len(), 1);
  181. assert_eq!(trash[0].id, view.id);
  182. // delete the view from trash
  183. let payload = RepeatedTrashIdPB {
  184. items: vec![TrashIdPB {
  185. id: view.id.clone(),
  186. }],
  187. };
  188. EventBuilder::new(test.clone())
  189. .event(flowy_folder2::event_map::FolderEvent::DeleteTrash)
  190. .payload(payload)
  191. .async_send()
  192. .await;
  193. // After delete the last view, the trash should be empty
  194. let trash = EventBuilder::new(test.clone())
  195. .event(flowy_folder2::event_map::FolderEvent::ReadTrash)
  196. .async_send()
  197. .await
  198. .parse::<flowy_folder2::entities::RepeatedTrashPB>()
  199. .items;
  200. assert!(trash.is_empty());
  201. }
  202. #[tokio::test]
  203. async fn delete_all_trash_test() {
  204. let test = FlowyCoreTest::new_with_guest_user().await;
  205. let current_workspace = test.get_current_workspace().await.workspace;
  206. for i in 0..3 {
  207. let view = test
  208. .create_view(&current_workspace.id, format!("My {} view", i))
  209. .await;
  210. let payload = RepeatedViewIdPB {
  211. items: vec![view.id.clone()],
  212. };
  213. // delete the view. the view will be moved to trash
  214. EventBuilder::new(test.clone())
  215. .event(flowy_folder2::event_map::FolderEvent::DeleteView)
  216. .payload(payload)
  217. .async_send()
  218. .await;
  219. }
  220. let trash = EventBuilder::new(test.clone())
  221. .event(flowy_folder2::event_map::FolderEvent::ReadTrash)
  222. .async_send()
  223. .await
  224. .parse::<flowy_folder2::entities::RepeatedTrashPB>()
  225. .items;
  226. assert_eq!(trash.len(), 3);
  227. // Delete all the trash
  228. EventBuilder::new(test.clone())
  229. .event(flowy_folder2::event_map::FolderEvent::DeleteAllTrash)
  230. .async_send()
  231. .await;
  232. // After delete the last view, the trash should be empty
  233. let trash = EventBuilder::new(test.clone())
  234. .event(flowy_folder2::event_map::FolderEvent::ReadTrash)
  235. .async_send()
  236. .await
  237. .parse::<flowy_folder2::entities::RepeatedTrashPB>()
  238. .items;
  239. assert!(trash.is_empty());
  240. }
  241. #[tokio::test]
  242. async fn multiple_hierarchy_view_test() {
  243. let test = FlowyCoreTest::new_with_guest_user().await;
  244. let current_workspace = test.get_current_workspace().await.workspace;
  245. for i in 1..4 {
  246. let parent = test
  247. .create_view(&current_workspace.id, format!("My {} view", i))
  248. .await;
  249. for j in 1..3 {
  250. let child = test
  251. .create_view(&parent.id, format!("My {}-{} view", i, j))
  252. .await;
  253. for k in 1..2 {
  254. let _sub_child = test
  255. .create_view(&child.id, format!("My {}-{}-{} view", i, j, k))
  256. .await;
  257. }
  258. }
  259. }
  260. let mut views = test.get_all_workspace_views().await;
  261. // There will be one default view when AppFlowy is initialized. So there will be 4 views in total
  262. assert_eq!(views.len(), 4);
  263. views.remove(0);
  264. // workspace
  265. // - view1
  266. // - view1-1
  267. // - view1-1-1
  268. // - view1-2
  269. // - view1-2-1
  270. // - view2
  271. // - view2-1
  272. // - view2-1-1
  273. // - view2-2
  274. // - view2-2-1
  275. // - view3
  276. // - view3-1
  277. // - view3-1-1
  278. // - view3-2
  279. // - view3-2-1
  280. assert_eq!(views[0].name, "My 1 view");
  281. assert_eq!(views[1].name, "My 2 view");
  282. assert_eq!(views[2].name, "My 3 view");
  283. assert_eq!(views[0].child_views.len(), 2);
  284. // By default only the first level of child views will be loaded
  285. assert!(views[0].child_views[0].child_views.is_empty());
  286. for (i, view) in views.into_iter().enumerate() {
  287. for (j, child_view) in view.child_views.into_iter().enumerate() {
  288. let payload = ViewIdPB {
  289. value: child_view.id.clone(),
  290. };
  291. let child = EventBuilder::new(test.clone())
  292. .event(flowy_folder2::event_map::FolderEvent::ReadView)
  293. .payload(payload)
  294. .async_send()
  295. .await
  296. .parse::<flowy_folder2::entities::ViewPB>();
  297. assert_eq!(child.name, format!("My {}-{} view", i + 1, j + 1));
  298. assert_eq!(child.child_views.len(), 1);
  299. // By default only the first level of child views will be loaded
  300. assert!(child.child_views[0].child_views.is_empty());
  301. for (k, _child_view) in child_view.child_views.into_iter().enumerate() {
  302. // Get the last level view
  303. let sub_child = test.get_view(&child.id).await;
  304. assert_eq!(child.name, format!("My {}-{}-{} view", i + 1, j + 1, k + 1));
  305. assert!(sub_child.child_views.is_empty());
  306. }
  307. }
  308. }
  309. }
  310. #[tokio::test]
  311. async fn move_view_event_test() {
  312. let test = FlowyCoreTest::new_with_guest_user().await;
  313. let current_workspace = test.get_current_workspace().await.workspace;
  314. for i in 1..4 {
  315. let parent = test
  316. .create_view(&current_workspace.id, format!("My {} view", i))
  317. .await;
  318. for j in 1..3 {
  319. let _ = test
  320. .create_view(&parent.id, format!("My {}-{} view", i, j))
  321. .await;
  322. }
  323. }
  324. let views = test.get_all_workspace_views().await;
  325. // There will be one default view when AppFlowy is initialized. So there will be 4 views in total
  326. assert_eq!(views.len(), 4);
  327. assert_eq!(views[1].name, "My 1 view");
  328. assert_eq!(views[2].name, "My 2 view");
  329. assert_eq!(views[3].name, "My 3 view");
  330. let payload = MoveViewPayloadPB {
  331. view_id: views[1].id.clone(),
  332. from: 1,
  333. to: 2,
  334. };
  335. let _ = EventBuilder::new(test.clone())
  336. .event(flowy_folder2::event_map::FolderEvent::MoveView)
  337. .payload(payload)
  338. .async_send()
  339. .await;
  340. let views = test.get_all_workspace_views().await;
  341. assert_eq!(views[1].name, "My 2 view");
  342. assert_eq!(views[2].name, "My 1 view");
  343. assert_eq!(views[3].name, "My 3 view");
  344. }
  345. #[tokio::test]
  346. async fn move_view_event_after_delete_view_test() {
  347. let test = FlowyCoreTest::new_with_guest_user().await;
  348. let current_workspace = test.get_current_workspace().await.workspace;
  349. for i in 1..6 {
  350. let _ = test
  351. .create_view(&current_workspace.id, format!("My {} view", i))
  352. .await;
  353. }
  354. let views = test.get_all_workspace_views().await;
  355. assert_eq!(views[1].name, "My 1 view");
  356. assert_eq!(views[2].name, "My 2 view");
  357. assert_eq!(views[3].name, "My 3 view");
  358. assert_eq!(views[4].name, "My 4 view");
  359. assert_eq!(views[5].name, "My 5 view");
  360. test.delete_view(&views[3].id).await;
  361. // There will be one default view when AppFlowy is initialized. So there will be 4 views in total
  362. let views = test.get_all_workspace_views().await;
  363. assert_eq!(views[1].name, "My 1 view");
  364. assert_eq!(views[2].name, "My 2 view");
  365. assert_eq!(views[3].name, "My 4 view");
  366. assert_eq!(views[4].name, "My 5 view");
  367. let payload = MoveViewPayloadPB {
  368. view_id: views[1].id.clone(),
  369. from: 1,
  370. to: 3,
  371. };
  372. let _ = EventBuilder::new(test.clone())
  373. .event(flowy_folder2::event_map::FolderEvent::MoveView)
  374. .payload(payload)
  375. .async_send()
  376. .await;
  377. let views = test.get_all_workspace_views().await;
  378. assert_eq!(views[1].name, "My 2 view");
  379. assert_eq!(views[2].name, "My 4 view");
  380. assert_eq!(views[3].name, "My 1 view");
  381. assert_eq!(views[4].name, "My 5 view");
  382. }
  383. #[tokio::test]
  384. async fn move_view_event_after_delete_view_test2() {
  385. let test = FlowyCoreTest::new_with_guest_user().await;
  386. let current_workspace = test.get_current_workspace().await.workspace;
  387. let parent = test
  388. .create_view(&current_workspace.id, "My view".to_string())
  389. .await;
  390. for j in 1..6 {
  391. let _ = test
  392. .create_view(&parent.id, format!("My 1-{} view", j))
  393. .await;
  394. }
  395. let views = test.get_view(&parent.id).await.child_views;
  396. assert_eq!(views.len(), 5);
  397. assert_eq!(views[0].name, "My 1-1 view");
  398. assert_eq!(views[1].name, "My 1-2 view");
  399. assert_eq!(views[2].name, "My 1-3 view");
  400. assert_eq!(views[3].name, "My 1-4 view");
  401. assert_eq!(views[4].name, "My 1-5 view");
  402. test.delete_view(&views[2].id).await;
  403. let payload = MoveViewPayloadPB {
  404. view_id: views[0].id.clone(),
  405. from: 0,
  406. to: 2,
  407. };
  408. let _ = EventBuilder::new(test.clone())
  409. .event(flowy_folder2::event_map::FolderEvent::MoveView)
  410. .payload(payload)
  411. .async_send()
  412. .await;
  413. let views = test.get_view(&parent.id).await.child_views;
  414. assert_eq!(views[0].name, "My 1-2 view");
  415. assert_eq!(views[1].name, "My 1-4 view");
  416. assert_eq!(views[2].name, "My 1-1 view");
  417. assert_eq!(views[3].name, "My 1-5 view");
  418. }
  419. #[tokio::test]
  420. async fn create_parent_view_with_invalid_name() {
  421. for (name, code) in invalid_workspace_name_test_case() {
  422. let sdk = FlowyCoreTest::new();
  423. let request = CreateWorkspacePayloadPB {
  424. name,
  425. desc: "".to_owned(),
  426. };
  427. assert_eq!(
  428. EventBuilder::new(sdk)
  429. .event(flowy_folder2::event_map::FolderEvent::CreateWorkspace)
  430. .payload(request)
  431. .async_send()
  432. .await
  433. .error()
  434. .unwrap()
  435. .code,
  436. code
  437. )
  438. }
  439. }
  440. fn invalid_workspace_name_test_case() -> Vec<(String, ErrorCode)> {
  441. vec![
  442. ("".to_owned(), ErrorCode::WorkspaceNameInvalid),
  443. ("1234".repeat(100), ErrorCode::WorkspaceNameTooLong),
  444. ]
  445. }
  446. #[tokio::test]
  447. async fn move_view_across_parent_test() {
  448. let test = FlowyCoreTest::new_with_guest_user().await;
  449. let current_workspace = test.get_current_workspace().await.workspace;
  450. let parent_1 = test
  451. .create_view(&current_workspace.id, "My view 1".to_string())
  452. .await;
  453. let parent_2 = test
  454. .create_view(&current_workspace.id, "My view 2".to_string())
  455. .await;
  456. for j in 1..6 {
  457. let _ = test
  458. .create_view(&parent_1.id, format!("My 1-{} view 1", j))
  459. .await;
  460. }
  461. let views = test.get_view(&parent_1.id).await.child_views;
  462. // Move `My 1-1 view 1` to `My view 2`
  463. let move_view_id = views[0].id.clone();
  464. let new_parent_id = parent_2.id.clone();
  465. let prev_id = None;
  466. move_folder_nested_view(test.clone(), move_view_id, new_parent_id, prev_id).await;
  467. let parent1_views = test.get_view(&parent_1.id).await.child_views;
  468. let parent2_views = test.get_view(&parent_2.id).await.child_views;
  469. assert_eq!(parent2_views.len(), 1);
  470. assert_eq!(parent2_views[0].name, "My 1-1 view 1");
  471. assert_eq!(parent1_views[0].name, "My 1-2 view 1");
  472. // Move My 1-2 view 1 from My view 1 to the current workspace and insert it after My view 1.
  473. let move_view_id = parent1_views[0].id.clone();
  474. let new_parent_id = current_workspace.id.clone();
  475. let prev_id = Some(parent_1.id.clone());
  476. move_folder_nested_view(test.clone(), move_view_id, new_parent_id, prev_id).await;
  477. let parent1_views = test.get_view(&parent_1.id).await.child_views;
  478. let workspace_views = test.get_all_workspace_views().await;
  479. let workspace_views_len = workspace_views.len();
  480. assert_eq!(parent1_views[0].name, "My 1-3 view 1");
  481. assert_eq!(workspace_views[workspace_views_len - 3].name, "My view 1");
  482. assert_eq!(
  483. workspace_views[workspace_views_len - 2].name,
  484. "My 1-2 view 1"
  485. );
  486. assert_eq!(workspace_views[workspace_views_len - 1].name, "My view 2");
  487. }
  488. async fn move_folder_nested_view(
  489. sdk: FlowyCoreTest,
  490. view_id: String,
  491. new_parent_id: String,
  492. prev_view_id: Option<String>,
  493. ) {
  494. let payload = MoveNestedViewPayloadPB {
  495. view_id,
  496. new_parent_id,
  497. prev_view_id,
  498. };
  499. EventBuilder::new(sdk)
  500. .event(flowy_folder2::event_map::FolderEvent::MoveNestedView)
  501. .payload(payload)
  502. .async_send()
  503. .await;
  504. }