diff --git a/.github/workflows/dart_test.yml b/.github/workflows/dart_test.yml index 74b20a2425ba9..10d57e117598d 100644 --- a/.github/workflows/dart_test.yml +++ b/.github/workflows/dart_test.yml @@ -8,6 +8,7 @@ on: pull_request: branches: - 'main' + - 'feat/flowy_editor' env: CARGO_TERM_COLOR: always @@ -71,3 +72,9 @@ jobs: flutter pub get flutter test + - name: Run FlowyEditor tests + working-directory: frontend/app_flowy/packages/flowy_editor + run: | + flutter pub get + flutter test + diff --git a/frontend/rust-lib/flowy-grid/src/event_handler.rs b/frontend/rust-lib/flowy-grid/src/event_handler.rs index 7d470bdfb923b..a3b1471a4e131 100644 --- a/frontend/rust-lib/flowy-grid/src/event_handler.rs +++ b/frontend/rust-lib/flowy-grid/src/event_handler.rs @@ -369,7 +369,7 @@ pub(crate) async fn get_select_option_handler( let any_cell_data: AnyCellData = match cell_rev { None => AnyCellData { data: "".to_string(), - field_type: field_rev.field_type_rev.clone().into(), + field_type: field_rev.field_type_rev.into(), }, Some(cell_rev) => cell_rev.try_into()?, }; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/block_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/block_test.rs similarity index 82% rename from frontend/rust-lib/flowy-grid/tests/grid/block_test.rs rename to frontend/rust-lib/flowy-grid/tests/grid/block_test/block_test.rs index 51094e2b3fb96..6ded1f7060866 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/block_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/block_test.rs @@ -1,5 +1,6 @@ -use crate::grid::script::EditorScript::*; -use crate::grid::script::*; +use crate::grid::block_test::script::GridRowTest; +use crate::grid::block_test::script::RowScript::*; + use flowy_grid_data_model::revision::{GridBlockMetaRevision, GridBlockMetaRevisionChangeset}; #[tokio::test] @@ -10,7 +11,7 @@ async fn grid_create_block() { CreateBlock { block: block_meta_rev }, AssertBlockCount(2), ]; - GridEditorTest::new().await.run_scripts(scripts).await; + GridRowTest::new().await.run_scripts(scripts).await; } #[tokio::test] @@ -36,5 +37,5 @@ async fn grid_update_block() { block: cloned_grid_block, }, ]; - GridEditorTest::new().await.run_scripts(scripts).await; + GridRowTest::new().await.run_scripts(scripts).await; } diff --git a/frontend/rust-lib/flowy-grid/tests/grid/block_test/mod.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/mod.rs new file mode 100644 index 0000000000000..c982869655c65 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/mod.rs @@ -0,0 +1,5 @@ +#![allow(clippy::module_inception)] +mod block_test; +mod row_test; +mod script; +pub mod util; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/row_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/row_test.rs similarity index 84% rename from frontend/rust-lib/flowy-grid/tests/grid/row_test.rs rename to frontend/rust-lib/flowy-grid/tests/grid/block_test/row_test.rs index 73b24f9afd0ff..96c23611b0b46 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/row_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/row_test.rs @@ -1,18 +1,18 @@ -use crate::grid::field_util::*; -use crate::grid::row_util::GridRowTestBuilder; -use crate::grid::script::EditorScript::*; -use crate::grid::script::*; +use crate::grid::block_test::script::GridRowTest; +use crate::grid::block_test::script::RowScript::*; +use crate::grid::block_test::util::GridRowTestBuilder; use chrono::NaiveDateTime; use flowy_grid::entities::FieldType; use flowy_grid::services::cell::decode_any_cell_data; use flowy_grid::services::field::select_option::SELECTION_IDS_SEPARATOR; use flowy_grid::services::field::{DateCellData, MultiSelectTypeOption, SingleSelectTypeOption}; -use flowy_grid::services::row::CreateRowRevisionBuilder; + +use crate::grid::field_test::util::make_date_cell_string; use flowy_grid_data_model::revision::RowMetaChangeset; #[tokio::test] async fn grid_create_row_count_test() { - let test = GridEditorTest::new().await; + let mut test = GridRowTest::new().await; let scripts = vec![ AssertRowCount(3), CreateEmptyRow, @@ -22,12 +22,12 @@ async fn grid_create_row_count_test() { }, AssertRowCount(6), ]; - GridEditorTest::new().await.run_scripts(scripts).await; + test.run_scripts(scripts).await; } #[tokio::test] async fn grid_update_row() { - let mut test = GridEditorTest::new().await; + let mut test = GridRowTest::new().await; let payload = GridRowTestBuilder::new(&test).build(); let changeset = RowMetaChangeset { row_id: payload.row_id.clone(), @@ -39,14 +39,14 @@ async fn grid_update_row() { let scripts = vec![AssertRowCount(3), CreateRow { payload }, UpdateRow { changeset }]; test.run_scripts(scripts).await; - let expected_row = (&*test.row_revs.last().cloned().unwrap()).clone(); + let expected_row = test.last_row().unwrap(); let scripts = vec![AssertRow { expected_row }, AssertRowCount(4)]; test.run_scripts(scripts).await; } #[tokio::test] async fn grid_delete_row() { - let mut test = GridEditorTest::new().await; + let mut test = GridRowTest::new().await; let payload1 = GridRowTestBuilder::new(&test).build(); let payload2 = GridRowTestBuilder::new(&test).build(); let row_ids = vec![payload1.row_id.clone(), payload2.row_id.clone()]; @@ -72,9 +72,9 @@ async fn grid_delete_row() { #[tokio::test] async fn grid_row_add_cells_test() { - let mut test = GridEditorTest::new().await; - let mut builder = CreateRowRevisionBuilder::new(&test.field_revs); - for field in &test.field_revs { + let mut test = GridRowTest::new().await; + let mut builder = test.builder(); + for field in test.field_revs() { let field_type: FieldType = field.field_type_rev.into(); match field_type { FieldType::RichText => { @@ -112,17 +112,17 @@ async fn grid_row_add_cells_test() { } } let context = builder.build(); - let scripts = vec![CreateRow { payload: context }, AssertGridRevisionPad]; + let scripts = vec![CreateRow { payload: context }]; test.run_scripts(scripts).await; } #[tokio::test] async fn grid_row_add_date_cell_test() { - let mut test = GridEditorTest::new().await; - let mut builder = CreateRowRevisionBuilder::new(&test.field_revs); + let mut test = GridRowTest::new().await; + let mut builder = test.builder(); let mut date_field = None; let timestamp = 1647390674; - for field in &test.field_revs { + for field in test.field_revs() { let field_type: FieldType = field.field_type_rev.into(); if field_type == FieldType::DateTime { date_field = Some(field.clone()); diff --git a/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs new file mode 100644 index 0000000000000..288133958ba95 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs @@ -0,0 +1,150 @@ +use crate::grid::grid_editor::GridEditorTest; +use flowy_grid::entities::RowInfo; +use flowy_grid::services::row::{CreateRowRevisionBuilder, CreateRowRevisionPayload}; +use flowy_grid_data_model::revision::{ + FieldRevision, GridBlockMetaRevision, GridBlockMetaRevisionChangeset, RowMetaChangeset, RowRevision, +}; +use std::sync::Arc; + +pub enum RowScript { + CreateEmptyRow, + CreateRow { + payload: CreateRowRevisionPayload, + }, + UpdateRow { + changeset: RowMetaChangeset, + }, + AssertRow { + expected_row: RowRevision, + }, + DeleteRows { + row_ids: Vec, + }, + AssertRowCount(usize), + CreateBlock { + block: GridBlockMetaRevision, + }, + UpdateBlock { + changeset: GridBlockMetaRevisionChangeset, + }, + AssertBlockCount(usize), + AssertBlock { + block_index: usize, + row_count: i32, + start_row_index: i32, + }, + AssertBlockEqual { + block_index: usize, + block: GridBlockMetaRevision, + }, +} + +pub struct GridRowTest { + inner: GridEditorTest, +} + +impl GridRowTest { + pub async fn new() -> Self { + let editor_test = GridEditorTest::new().await; + Self { inner: editor_test } + } + + pub fn field_revs(&self) -> &Vec> { + &self.field_revs + } + + pub fn last_row(&self) -> Option { + self.row_revs.last().map(|a| a.clone().as_ref().clone()) + } + + pub async fn run_scripts(&mut self, scripts: Vec) { + for script in scripts { + self.run_script(script).await; + } + } + + pub fn builder(&self) -> CreateRowRevisionBuilder { + CreateRowRevisionBuilder::new(&self.field_revs) + } + + pub async fn run_script(&mut self, script: RowScript) { + match script { + RowScript::CreateEmptyRow => { + let row_order = self.editor.create_row(None).await.unwrap(); + self.row_order_by_row_id + .insert(row_order.row_id().to_owned(), row_order); + self.row_revs = self.get_row_revs().await; + self.block_meta_revs = self.editor.get_block_meta_revs().await.unwrap(); + } + RowScript::CreateRow { payload: context } => { + let row_orders = self.editor.insert_rows(vec![context]).await.unwrap(); + for row_order in row_orders { + self.row_order_by_row_id + .insert(row_order.row_id().to_owned(), row_order); + } + self.row_revs = self.get_row_revs().await; + self.block_meta_revs = self.editor.get_block_meta_revs().await.unwrap(); + } + RowScript::UpdateRow { changeset: change } => self.editor.update_row(change).await.unwrap(), + RowScript::DeleteRows { row_ids } => { + let row_orders = row_ids + .into_iter() + .map(|row_id| self.row_order_by_row_id.get(&row_id).unwrap().clone()) + .collect::>(); + + self.editor.delete_rows(row_orders).await.unwrap(); + self.row_revs = self.get_row_revs().await; + self.block_meta_revs = self.editor.get_block_meta_revs().await.unwrap(); + } + RowScript::AssertRow { expected_row } => { + let row = &*self + .row_revs + .iter() + .find(|row| row.id == expected_row.id) + .cloned() + .unwrap(); + assert_eq!(&expected_row, row); + } + RowScript::AssertRowCount(expected_row_count) => { + assert_eq!(expected_row_count, self.row_revs.len()); + } + RowScript::CreateBlock { block } => { + self.editor.create_block(block).await.unwrap(); + self.block_meta_revs = self.editor.get_block_meta_revs().await.unwrap(); + } + RowScript::UpdateBlock { changeset: change } => { + self.editor.update_block(change).await.unwrap(); + } + RowScript::AssertBlockCount(count) => { + assert_eq!(self.editor.get_block_meta_revs().await.unwrap().len(), count); + } + RowScript::AssertBlock { + block_index, + row_count, + start_row_index, + } => { + assert_eq!(self.block_meta_revs[block_index].row_count, row_count); + assert_eq!(self.block_meta_revs[block_index].start_row_index, start_row_index); + } + RowScript::AssertBlockEqual { block_index, block } => { + let blocks = self.editor.get_block_meta_revs().await.unwrap(); + let compared_block = blocks[block_index].clone(); + assert_eq!(compared_block, Arc::new(block)); + } + } + } +} + +impl std::ops::Deref for GridRowTest { + type Target = GridEditorTest; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl std::ops::DerefMut for GridRowTest { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} diff --git a/frontend/rust-lib/flowy-grid/tests/grid/row_util.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs similarity index 88% rename from frontend/rust-lib/flowy-grid/tests/grid/row_util.rs rename to frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs index bdd6dd86dc6b9..49b8383feed62 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/row_util.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs @@ -1,4 +1,5 @@ -use crate::grid::script::GridEditorTest; +use crate::grid::block_test::script::GridRowTest; + use flowy_grid::entities::FieldType; use flowy_grid::services::field::DateCellChangeset; use flowy_grid::services::row::{CreateRowRevisionBuilder, CreateRowRevisionPayload}; @@ -6,15 +7,15 @@ use flowy_grid_data_model::revision::FieldRevision; use strum::EnumCount; pub struct GridRowTestBuilder<'a> { - test: &'a GridEditorTest, + test: &'a GridRowTest, inner_builder: CreateRowRevisionBuilder<'a>, } impl<'a> GridRowTestBuilder<'a> { - pub fn new(test: &'a GridEditorTest) -> Self { - assert_eq!(test.field_revs.len(), FieldType::COUNT); + pub fn new(test: &'a GridRowTest) -> Self { + assert_eq!(test.field_revs().len(), FieldType::COUNT); - let inner_builder = CreateRowRevisionBuilder::new(&test.field_revs); + let inner_builder = CreateRowRevisionBuilder::new(test.field_revs()); Self { test, inner_builder } } #[allow(dead_code)] @@ -59,7 +60,7 @@ impl<'a> GridRowTestBuilder<'a> { pub fn field_rev_with_type(&self, field_type: &FieldType) -> FieldRevision { self.test - .field_revs + .field_revs() .iter() .find(|field_rev| { let t_field_type: FieldType = field_rev.field_type_rev.into(); diff --git a/frontend/rust-lib/flowy-grid/tests/grid/cell_test/mod.rs b/frontend/rust-lib/flowy-grid/tests/grid/cell_test/mod.rs new file mode 100644 index 0000000000000..63d424afafbf4 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/tests/grid/cell_test/mod.rs @@ -0,0 +1,2 @@ +mod script; +mod test; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/cell_test/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/cell_test/script.rs new file mode 100644 index 0000000000000..a6c88ef1c9301 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/tests/grid/cell_test/script.rs @@ -0,0 +1,61 @@ +use crate::grid::grid_editor::GridEditorTest; +use flowy_grid::entities::CellChangeset; + +pub enum CellScript { + UpdateCell { changeset: CellChangeset, is_err: bool }, +} + +pub struct GridCellTest { + inner: GridEditorTest, +} + +impl GridCellTest { + pub async fn new() -> Self { + let inner = GridEditorTest::new().await; + Self { inner } + } + + pub async fn run_scripts(&mut self, scripts: Vec) { + for script in scripts { + self.run_script(script).await; + } + } + + pub async fn run_script(&mut self, script: CellScript) { + // let grid_manager = self.sdk.grid_manager.clone(); + // let pool = self.sdk.user_session.db_pool().unwrap(); + let rev_manager = self.editor.rev_manager(); + let _cache = rev_manager.revision_cache().await; + + match script { + CellScript::UpdateCell { changeset, is_err } => { + let result = self.editor.update_cell(changeset).await; + if is_err { + assert!(result.is_err()) + } else { + let _ = result.unwrap(); + self.row_revs = self.get_row_revs().await; + } + } // CellScript::AssertGridRevisionPad => { + // sleep(Duration::from_millis(2 * REVISION_WRITE_INTERVAL_IN_MILLIS)).await; + // let mut grid_rev_manager = grid_manager.make_grid_rev_manager(&self.grid_id, pool.clone()).unwrap(); + // let grid_pad = grid_rev_manager.load::(None).await.unwrap(); + // println!("{}", grid_pad.delta_str()); + // } + } + } +} + +impl std::ops::Deref for GridCellTest { + type Target = GridEditorTest; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl std::ops::DerefMut for GridCellTest { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} diff --git a/frontend/rust-lib/flowy-grid/tests/grid/cell_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/cell_test/test.rs similarity index 90% rename from frontend/rust-lib/flowy-grid/tests/grid/cell_test.rs rename to frontend/rust-lib/flowy-grid/tests/grid/cell_test/test.rs index 01d231027833d..844a230036821 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/cell_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/cell_test/test.rs @@ -1,13 +1,13 @@ -use crate::grid::field_util::make_date_cell_string; -use crate::grid::script::EditorScript::*; -use crate::grid::script::*; +use crate::grid::cell_test::script::CellScript::*; +use crate::grid::cell_test::script::GridCellTest; +use crate::grid::field_test::util::make_date_cell_string; use flowy_grid::entities::{CellChangeset, FieldType}; use flowy_grid::services::field::select_option::SelectOptionCellChangeset; use flowy_grid::services::field::{MultiSelectTypeOption, SingleSelectTypeOption}; #[tokio::test] async fn grid_cell_update() { - let mut test = GridEditorTest::new().await; + let mut test = GridCellTest::new().await; let field_revs = &test.field_revs; let row_revs = &test.row_revs; let grid_blocks = &test.block_meta_revs; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/field_test/mod.rs b/frontend/rust-lib/flowy-grid/tests/grid/field_test/mod.rs new file mode 100644 index 0000000000000..5ac4da9f24633 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/tests/grid/field_test/mod.rs @@ -0,0 +1,3 @@ +mod script; +mod test; +pub mod util; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/field_test/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/field_test/script.rs new file mode 100644 index 0000000000000..6d910f35163fe --- /dev/null +++ b/frontend/rust-lib/flowy-grid/tests/grid/field_test/script.rs @@ -0,0 +1,94 @@ +use crate::grid::grid_editor::GridEditorTest; +use flowy_grid::entities::InsertFieldParams; +use flowy_grid_data_model::revision::FieldRevision; +use flowy_sync::entities::grid::FieldChangesetParams; + +pub enum FieldScript { + CreateField { + params: InsertFieldParams, + }, + UpdateField { + changeset: FieldChangesetParams, + }, + DeleteField { + field_rev: FieldRevision, + }, + AssertFieldCount(usize), + AssertFieldEqual { + field_index: usize, + field_rev: FieldRevision, + }, +} + +pub struct GridFieldTest { + inner: GridEditorTest, +} + +impl GridFieldTest { + pub async fn new() -> Self { + let editor_test = GridEditorTest::new().await; + Self { inner: editor_test } + } + + pub fn grid_id(&self) -> String { + self.grid_id.clone() + } + + pub fn field_count(&self) -> usize { + self.field_count + } + + pub async fn run_scripts(&mut self, scripts: Vec) { + for script in scripts { + self.run_script(script).await; + } + } + + pub async fn run_script(&mut self, script: FieldScript) { + match script { + FieldScript::CreateField { params } => { + if !self.editor.contain_field(¶ms.field.id).await { + self.field_count += 1; + } + + self.editor.insert_field(params).await.unwrap(); + self.field_revs = self.editor.get_field_revs(None).await.unwrap(); + assert_eq!(self.field_count, self.field_revs.len()); + } + FieldScript::UpdateField { changeset: change } => { + self.editor.update_field(change).await.unwrap(); + self.field_revs = self.editor.get_field_revs(None).await.unwrap(); + } + FieldScript::DeleteField { field_rev } => { + if self.editor.contain_field(&field_rev.id).await { + self.field_count -= 1; + } + + self.editor.delete_field(&field_rev.id).await.unwrap(); + self.field_revs = self.editor.get_field_revs(None).await.unwrap(); + assert_eq!(self.field_count, self.field_revs.len()); + } + FieldScript::AssertFieldCount(count) => { + assert_eq!(self.editor.get_field_revs(None).await.unwrap().len(), count); + } + FieldScript::AssertFieldEqual { field_index, field_rev } => { + let field_revs = self.editor.get_field_revs(None).await.unwrap(); + assert_eq!(field_revs[field_index].as_ref(), &field_rev); + } + } + } +} + +impl std::ops::Deref for GridFieldTest { + type Target = GridEditorTest; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl std::ops::DerefMut for GridFieldTest { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} diff --git a/frontend/rust-lib/flowy-grid/tests/grid/field_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/field_test/test.rs similarity index 75% rename from frontend/rust-lib/flowy-grid/tests/grid/field_test.rs rename to frontend/rust-lib/flowy-grid/tests/grid/field_test/test.rs index 00428a8fc4705..624979e9405c4 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/field_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/field_test/test.rs @@ -1,6 +1,6 @@ -use crate::grid::field_util::*; -use crate::grid::script::EditorScript::*; -use crate::grid::script::*; +use crate::grid::field_test::script::FieldScript::*; +use crate::grid::field_test::script::GridFieldTest; +use crate::grid::field_test::util::*; use flowy_grid::services::field::select_option::SelectOption; use flowy_grid::services::field::SingleSelectTypeOption; use flowy_grid_data_model::revision::TypeOptionDataEntry; @@ -8,23 +8,23 @@ use flowy_sync::entities::grid::FieldChangesetParams; #[tokio::test] async fn grid_create_field() { - let mut test = GridEditorTest::new().await; - let (params, field_rev) = create_text_field(&test.grid_id); + let mut test = GridFieldTest::new().await; + let (params, field_rev) = create_text_field(&test.grid_id()); let scripts = vec![ CreateField { params }, AssertFieldEqual { - field_index: test.field_count, + field_index: test.field_count(), field_rev, }, ]; test.run_scripts(scripts).await; - let (params, field_rev) = create_single_select_field(&test.grid_id); + let (params, field_rev) = create_single_select_field(&test.grid_id()); let scripts = vec![ CreateField { params }, AssertFieldEqual { - field_index: test.field_count, + field_index: test.field_count(), field_rev, }, ]; @@ -33,9 +33,9 @@ async fn grid_create_field() { #[tokio::test] async fn grid_create_duplicate_field() { - let mut test = GridEditorTest::new().await; - let (params, _) = create_text_field(&test.grid_id); - let field_count = test.field_count; + let mut test = GridFieldTest::new().await; + let (params, _) = create_text_field(&test.grid_id()); + let field_count = test.field_count(); let expected_field_count = field_count + 1; let scripts = vec![ CreateField { params: params.clone() }, @@ -47,11 +47,11 @@ async fn grid_create_duplicate_field() { #[tokio::test] async fn grid_update_field_with_empty_change() { - let mut test = GridEditorTest::new().await; - let (params, field_rev) = create_single_select_field(&test.grid_id); + let mut test = GridFieldTest::new().await; + let (params, field_rev) = create_single_select_field(&test.grid_id()); let changeset = FieldChangesetParams { field_id: field_rev.id.clone(), - grid_id: test.grid_id.clone(), + grid_id: test.grid_id(), ..Default::default() }; @@ -59,7 +59,7 @@ async fn grid_update_field_with_empty_change() { CreateField { params }, UpdateField { changeset }, AssertFieldEqual { - field_index: test.field_count, + field_index: test.field_count(), field_rev, }, ]; @@ -68,14 +68,14 @@ async fn grid_update_field_with_empty_change() { #[tokio::test] async fn grid_update_field() { - let mut test = GridEditorTest::new().await; - let (params, single_select_field) = create_single_select_field(&test.grid_id); + let mut test = GridFieldTest::new().await; + let (params, single_select_field) = create_single_select_field(&test.grid_id()); let mut single_select_type_option = SingleSelectTypeOption::from(&single_select_field); single_select_type_option.options.push(SelectOption::new("Unknown")); let changeset = FieldChangesetParams { field_id: single_select_field.id.clone(), - grid_id: test.grid_id.clone(), + grid_id: test.grid_id(), frozen: Some(true), width: Some(1000), type_option_data: Some(single_select_type_option.protobuf_bytes().to_vec()), @@ -92,7 +92,7 @@ async fn grid_update_field() { CreateField { params }, UpdateField { changeset }, AssertFieldEqual { - field_index: test.field_count, + field_index: test.field_count(), field_rev: expected_field_rev, }, ]; @@ -101,9 +101,9 @@ async fn grid_update_field() { #[tokio::test] async fn grid_delete_field() { - let mut test = GridEditorTest::new().await; - let original_field_count = test.field_count; - let (params, text_field_rev) = create_text_field(&test.grid_id); + let mut test = GridFieldTest::new().await; + let original_field_count = test.field_count(); + let (params, text_field_rev) = create_text_field(&test.grid_id()); let scripts = vec![ CreateField { params }, DeleteField { diff --git a/frontend/rust-lib/flowy-grid/tests/grid/field_util.rs b/frontend/rust-lib/flowy-grid/tests/grid/field_test/util.rs similarity index 100% rename from frontend/rust-lib/flowy-grid/tests/grid/field_util.rs rename to frontend/rust-lib/flowy-grid/tests/grid/field_test/util.rs diff --git a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/script.rs index d89b6a66a1def..4a1ef3af83193 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/script.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/script.rs @@ -7,7 +7,7 @@ use flowy_grid::entities::{CreateGridFilterPayload, GridLayoutType, GridSetting} use flowy_grid::services::setting::GridSettingChangesetBuilder; use flowy_grid_data_model::revision::{FieldRevision, FieldTypeRevision}; use flowy_sync::entities::grid::{CreateGridFilterParams, DeleteFilterParams, GridSettingChangesetParams}; -use crate::grid::script::GridEditorTest; +use crate::grid::grid_editor::GridEditorTest; pub enum FilterScript { #[allow(dead_code)] @@ -31,14 +31,14 @@ pub enum FilterScript { } pub struct GridFilterTest { - pub editor_test: GridEditorTest, + inner: GridEditorTest, } impl GridFilterTest { pub async fn new() -> Self { let editor_test = GridEditorTest::new().await; Self { - editor_test + inner: editor_test } } @@ -49,7 +49,6 @@ impl GridFilterTest { } pub async fn run_script(&mut self, script: FilterScript) { - match script { FilterScript::UpdateGridSetting { params } => { let _ = self.editor.update_grid_setting(params).await.unwrap(); @@ -82,10 +81,17 @@ impl GridFilterTest { } } + impl std::ops::Deref for GridFilterTest { type Target = GridEditorTest; fn deref(&self) -> &Self::Target { - &self.editor_test + &self.inner + } +} + +impl std::ops::DerefMut for GridFilterTest { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner } } diff --git a/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs b/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs new file mode 100644 index 0000000000000..d944aac6c5155 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs @@ -0,0 +1,164 @@ +#![allow(clippy::all)] +#![allow(dead_code)] +#![allow(unused_imports)] +use bytes::Bytes; +use flowy_grid::entities::*; +use flowy_grid::services::field::select_option::SelectOption; +use flowy_grid::services::field::*; +use flowy_grid::services::grid_editor::{GridPadBuilder, GridRevisionEditor}; +use flowy_grid::services::row::CreateRowRevisionPayload; +use flowy_grid::services::setting::GridSettingChangesetBuilder; +use flowy_grid_data_model::revision::*; +use flowy_revision::REVISION_WRITE_INTERVAL_IN_MILLIS; +use flowy_sync::client_grid::GridBuilder; +use flowy_sync::entities::grid::{ + CreateGridFilterParams, DeleteFilterParams, FieldChangesetParams, GridSettingChangesetParams, +}; +use flowy_test::helper::ViewTest; +use flowy_test::FlowySDKTest; +use std::collections::HashMap; +use std::sync::Arc; +use std::time::Duration; +use strum::EnumCount; +use tokio::time::sleep; + +pub struct GridEditorTest { + pub sdk: FlowySDKTest, + pub grid_id: String, + pub editor: Arc, + pub field_revs: Vec>, + pub block_meta_revs: Vec>, + pub row_revs: Vec>, + pub field_count: usize, + pub row_order_by_row_id: HashMap, +} + +impl GridEditorTest { + pub async fn new() -> Self { + let sdk = FlowySDKTest::default(); + let _ = sdk.init_user().await; + let build_context = make_all_field_test_grid(); + let view_data: Bytes = build_context.into(); + let test = ViewTest::new_grid_view(&sdk, view_data.to_vec()).await; + let editor = sdk.grid_manager.open_grid(&test.view.id).await.unwrap(); + let field_revs = editor.get_field_revs(None).await.unwrap(); + let block_meta_revs = editor.get_block_meta_revs().await.unwrap(); + let row_revs = editor.grid_block_snapshots(None).await.unwrap().pop().unwrap().row_revs; + assert_eq!(row_revs.len(), 3); + assert_eq!(block_meta_revs.len(), 1); + + // It seems like you should add the field in the make_test_grid() function. + // Because we assert the initialize count of the fields is equal to FieldType::COUNT. + assert_eq!(field_revs.len(), FieldType::COUNT); + + let grid_id = test.view.id; + Self { + sdk, + grid_id, + editor, + field_revs, + block_meta_revs, + row_revs, + field_count: FieldType::COUNT, + row_order_by_row_id: HashMap::default(), + } + } + + pub(crate) async fn get_row_revs(&self) -> Vec> { + self.editor + .grid_block_snapshots(None) + .await + .unwrap() + .pop() + .unwrap() + .row_revs + } + + pub async fn grid_filters(&self) -> Vec { + let layout_type = GridLayoutType::Table; + self.editor.get_grid_filter(&layout_type).await.unwrap() + } + + pub fn text_field(&self) -> &FieldRevision { + self.field_revs + .iter() + .filter(|field_rev| { + let t_field_type: FieldType = field_rev.field_type_rev.into(); + t_field_type == FieldType::RichText + }) + .collect::>() + .pop() + .unwrap() + } +} + +fn make_all_field_test_grid() -> BuildGridContext { + let text_field = FieldBuilder::new(RichTextTypeOptionBuilder::default()) + .name("Name") + .visibility(true) + .build(); + + // Single Select + let single_select = SingleSelectTypeOptionBuilder::default() + .option(SelectOption::new("Live")) + .option(SelectOption::new("Completed")) + .option(SelectOption::new("Planned")) + .option(SelectOption::new("Paused")); + let single_select_field = FieldBuilder::new(single_select).name("Status").visibility(true).build(); + + // MultiSelect + let multi_select = MultiSelectTypeOptionBuilder::default() + .option(SelectOption::new("Google")) + .option(SelectOption::new("Facebook")) + .option(SelectOption::new("Twitter")); + let multi_select_field = FieldBuilder::new(multi_select) + .name("Platform") + .visibility(true) + .build(); + + // Number + let number = NumberTypeOptionBuilder::default().set_format(NumberFormat::USD); + let number_field = FieldBuilder::new(number).name("Price").visibility(true).build(); + + // Date + let date = DateTypeOptionBuilder::default() + .date_format(DateFormat::US) + .time_format(TimeFormat::TwentyFourHour); + let date_field = FieldBuilder::new(date).name("Time").visibility(true).build(); + + // Checkbox + let checkbox = CheckboxTypeOptionBuilder::default(); + let checkbox_field = FieldBuilder::new(checkbox).name("is done").visibility(true).build(); + + // URL + let url = URLTypeOptionBuilder::default(); + let url_field = FieldBuilder::new(url).name("link").visibility(true).build(); + + // for i in 0..3 { + // for field_type in FieldType::iter() { + // let field_type: FieldType = field_type; + // match field_type { + // FieldType::RichText => {} + // FieldType::Number => {} + // FieldType::DateTime => {} + // FieldType::SingleSelect => {} + // FieldType::MultiSelect => {} + // FieldType::Checkbox => {} + // FieldType::URL => {} + // } + // } + // } + + GridBuilder::default() + .add_field(text_field) + .add_field(single_select_field) + .add_field(multi_select_field) + .add_field(number_field) + .add_field(date_field) + .add_field(checkbox_field) + .add_field(url_field) + .add_empty_row() + .add_empty_row() + .add_empty_row() + .build() +} diff --git a/frontend/rust-lib/flowy-grid/tests/grid/mod.rs b/frontend/rust-lib/flowy-grid/tests/grid/mod.rs index 4d746661eb92e..8865bf01c25cf 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/mod.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/mod.rs @@ -1,8 +1,5 @@ mod block_test; mod cell_test; mod field_test; -mod field_util; mod filter_test; -mod row_test; -mod row_util; -mod script; +mod grid_editor; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/script.rs deleted file mode 100644 index 915749fb0ef1f..0000000000000 --- a/frontend/rust-lib/flowy-grid/tests/grid/script.rs +++ /dev/null @@ -1,380 +0,0 @@ -#![allow(clippy::all)] -#![allow(dead_code)] -#![allow(unused_imports)] -use bytes::Bytes; -use flowy_grid::entities::*; -use flowy_grid::services::field::select_option::SelectOption; -use flowy_grid::services::field::*; -use flowy_grid::services::grid_editor::{GridPadBuilder, GridRevisionEditor}; -use flowy_grid::services::row::CreateRowRevisionPayload; -use flowy_grid::services::setting::GridSettingChangesetBuilder; -use flowy_grid_data_model::revision::*; -use flowy_revision::REVISION_WRITE_INTERVAL_IN_MILLIS; -use flowy_sync::client_grid::GridBuilder; -use flowy_sync::entities::grid::{ - CreateGridFilterParams, DeleteFilterParams, FieldChangesetParams, GridSettingChangesetParams, -}; -use flowy_test::helper::ViewTest; -use flowy_test::FlowySDKTest; -use std::collections::HashMap; -use std::sync::Arc; -use std::time::Duration; -use strum::EnumCount; -use tokio::time::sleep; - -pub enum EditorScript { - CreateField { - params: InsertFieldParams, - }, - UpdateField { - changeset: FieldChangesetParams, - }, - DeleteField { - field_rev: FieldRevision, - }, - AssertFieldCount(usize), - AssertFieldEqual { - field_index: usize, - field_rev: FieldRevision, - }, - CreateBlock { - block: GridBlockMetaRevision, - }, - UpdateBlock { - changeset: GridBlockMetaRevisionChangeset, - }, - AssertBlockCount(usize), - AssertBlock { - block_index: usize, - row_count: i32, - start_row_index: i32, - }, - AssertBlockEqual { - block_index: usize, - block: GridBlockMetaRevision, - }, - CreateEmptyRow, - CreateRow { - payload: CreateRowRevisionPayload, - }, - UpdateRow { - changeset: RowMetaChangeset, - }, - AssertRow { - expected_row: RowRevision, - }, - DeleteRows { - row_ids: Vec, - }, - UpdateCell { - changeset: CellChangeset, - is_err: bool, - }, - AssertRowCount(usize), - #[allow(dead_code)] - UpdateGridSetting { - params: GridSettingChangesetParams, - }, - InsertGridTableFilter { - payload: CreateGridFilterPayload, - }, - AssertTableFilterCount { - count: i32, - }, - DeleteGridTableFilter { - filter_id: String, - field_rev: FieldRevision, - }, - #[allow(dead_code)] - AssertGridSetting { - expected_setting: GridSetting, - }, - AssertGridRevisionPad, -} - -pub struct GridEditorTest { - pub sdk: FlowySDKTest, - pub grid_id: String, - pub editor: Arc, - pub field_revs: Vec>, - pub block_meta_revs: Vec>, - pub row_revs: Vec>, - pub field_count: usize, - - pub row_order_by_row_id: HashMap, -} - -impl GridEditorTest { - pub async fn new() -> Self { - let sdk = FlowySDKTest::default(); - let _ = sdk.init_user().await; - let build_context = make_all_field_test_grid(); - let view_data: Bytes = build_context.into(); - let test = ViewTest::new_grid_view(&sdk, view_data.to_vec()).await; - let editor = sdk.grid_manager.open_grid(&test.view.id).await.unwrap(); - let field_revs = editor.get_field_revs(None).await.unwrap(); - let block_meta_revs = editor.get_block_meta_revs().await.unwrap(); - let row_revs = editor.grid_block_snapshots(None).await.unwrap().pop().unwrap().row_revs; - assert_eq!(row_revs.len(), 3); - assert_eq!(block_meta_revs.len(), 1); - - // It seems like you should add the field in the make_test_grid() function. - // Because we assert the initialize count of the fields is equal to FieldType::COUNT. - assert_eq!(field_revs.len(), FieldType::COUNT); - - let grid_id = test.view.id; - Self { - sdk, - grid_id, - editor, - field_revs, - block_meta_revs, - row_revs, - field_count: FieldType::COUNT, - row_order_by_row_id: HashMap::default(), - } - } - - pub async fn run_scripts(&mut self, scripts: Vec) { - for script in scripts { - self.run_script(script).await; - } - } - - pub async fn run_script(&mut self, script: EditorScript) { - let grid_manager = self.sdk.grid_manager.clone(); - let pool = self.sdk.user_session.db_pool().unwrap(); - let rev_manager = self.editor.rev_manager(); - let _cache = rev_manager.revision_cache().await; - - match script { - EditorScript::CreateField { params } => { - if !self.editor.contain_field(¶ms.field.id).await { - self.field_count += 1; - } - - self.editor.insert_field(params).await.unwrap(); - self.field_revs = self.editor.get_field_revs(None).await.unwrap(); - assert_eq!(self.field_count, self.field_revs.len()); - } - EditorScript::UpdateField { changeset: change } => { - self.editor.update_field(change).await.unwrap(); - self.field_revs = self.editor.get_field_revs(None).await.unwrap(); - } - EditorScript::DeleteField { field_rev } => { - if self.editor.contain_field(&field_rev.id).await { - self.field_count -= 1; - } - - self.editor.delete_field(&field_rev.id).await.unwrap(); - self.field_revs = self.editor.get_field_revs(None).await.unwrap(); - assert_eq!(self.field_count, self.field_revs.len()); - } - EditorScript::AssertFieldCount(count) => { - assert_eq!(self.editor.get_field_revs(None).await.unwrap().len(), count); - } - EditorScript::AssertFieldEqual { field_index, field_rev } => { - let field_revs = self.editor.get_field_revs(None).await.unwrap(); - assert_eq!(field_revs[field_index].as_ref(), &field_rev); - } - EditorScript::CreateBlock { block } => { - self.editor.create_block(block).await.unwrap(); - self.block_meta_revs = self.editor.get_block_meta_revs().await.unwrap(); - } - EditorScript::UpdateBlock { changeset: change } => { - self.editor.update_block(change).await.unwrap(); - } - EditorScript::AssertBlockCount(count) => { - assert_eq!(self.editor.get_block_meta_revs().await.unwrap().len(), count); - } - EditorScript::AssertBlock { - block_index, - row_count, - start_row_index, - } => { - assert_eq!(self.block_meta_revs[block_index].row_count, row_count); - assert_eq!(self.block_meta_revs[block_index].start_row_index, start_row_index); - } - EditorScript::AssertBlockEqual { block_index, block } => { - let blocks = self.editor.get_block_meta_revs().await.unwrap(); - let compared_block = blocks[block_index].clone(); - assert_eq!(compared_block, Arc::new(block)); - } - EditorScript::CreateEmptyRow => { - let row_order = self.editor.create_row(None).await.unwrap(); - self.row_order_by_row_id - .insert(row_order.row_id().to_owned(), row_order); - self.row_revs = self.get_row_revs().await; - self.block_meta_revs = self.editor.get_block_meta_revs().await.unwrap(); - } - EditorScript::CreateRow { payload: context } => { - let row_orders = self.editor.insert_rows(vec![context]).await.unwrap(); - for row_order in row_orders { - self.row_order_by_row_id - .insert(row_order.row_id().to_owned(), row_order); - } - self.row_revs = self.get_row_revs().await; - self.block_meta_revs = self.editor.get_block_meta_revs().await.unwrap(); - } - EditorScript::UpdateRow { changeset: change } => self.editor.update_row(change).await.unwrap(), - EditorScript::DeleteRows { row_ids } => { - let row_orders = row_ids - .into_iter() - .map(|row_id| self.row_order_by_row_id.get(&row_id).unwrap().clone()) - .collect::>(); - - self.editor.delete_rows(row_orders).await.unwrap(); - self.row_revs = self.get_row_revs().await; - self.block_meta_revs = self.editor.get_block_meta_revs().await.unwrap(); - } - EditorScript::AssertRow { expected_row } => { - let row = &*self - .row_revs - .iter() - .find(|row| row.id == expected_row.id) - .cloned() - .unwrap(); - assert_eq!(&expected_row, row); - // if let Some(visibility) = changeset.visibility { - // assert_eq!(row.visibility, visibility); - // } - // - // if let Some(height) = changeset.height { - // assert_eq!(row.height, height); - // } - } - EditorScript::UpdateCell { changeset, is_err } => { - let result = self.editor.update_cell(changeset).await; - if is_err { - assert!(result.is_err()) - } else { - let _ = result.unwrap(); - self.row_revs = self.get_row_revs().await; - } - } - EditorScript::AssertRowCount(expected_row_count) => { - assert_eq!(expected_row_count, self.row_revs.len()); - } - EditorScript::UpdateGridSetting { params } => { - let _ = self.editor.update_grid_setting(params).await.unwrap(); - } - EditorScript::InsertGridTableFilter { payload } => { - let params: CreateGridFilterParams = payload.try_into().unwrap(); - let layout_type = GridLayoutType::Table; - let params = GridSettingChangesetBuilder::new(&self.grid_id, &layout_type) - .insert_filter(params) - .build(); - let _ = self.editor.update_grid_setting(params).await.unwrap(); - } - EditorScript::AssertTableFilterCount { count } => { - let layout_type = GridLayoutType::Table; - let filters = self.editor.get_grid_filter(&layout_type).await.unwrap(); - assert_eq!(count as usize, filters.len()); - } - EditorScript::DeleteGridTableFilter { filter_id, field_rev } => { - let layout_type = GridLayoutType::Table; - let params = GridSettingChangesetBuilder::new(&self.grid_id, &layout_type) - .delete_filter(DeleteFilterParams { - field_id: field_rev.id, - filter_id, - field_type_rev: field_rev.field_type_rev, - }) - .build(); - let _ = self.editor.update_grid_setting(params).await.unwrap(); - } - EditorScript::AssertGridSetting { expected_setting } => { - let setting = self.editor.get_grid_setting().await.unwrap(); - assert_eq!(expected_setting, setting); - } - EditorScript::AssertGridRevisionPad => { - sleep(Duration::from_millis(2 * REVISION_WRITE_INTERVAL_IN_MILLIS)).await; - let mut grid_rev_manager = grid_manager.make_grid_rev_manager(&self.grid_id, pool.clone()).unwrap(); - let grid_pad = grid_rev_manager.load::(None).await.unwrap(); - println!("{}", grid_pad.delta_str()); - } - } - } - - async fn get_row_revs(&self) -> Vec> { - self.editor - .grid_block_snapshots(None) - .await - .unwrap() - .pop() - .unwrap() - .row_revs - } - - pub async fn grid_filters(&self) -> Vec { - let layout_type = GridLayoutType::Table; - self.editor.get_grid_filter(&layout_type).await.unwrap() - } - - pub fn text_field(&self) -> &FieldRevision { - self.field_revs - .iter() - .filter(|field_rev| { - let t_field_type: FieldType = field_rev.field_type_rev.into(); - t_field_type == FieldType::RichText - }) - .collect::>() - .pop() - .unwrap() - } -} - -fn make_all_field_test_grid() -> BuildGridContext { - let text_field = FieldBuilder::new(RichTextTypeOptionBuilder::default()) - .name("Name") - .visibility(true) - .build(); - - // Single Select - let single_select = SingleSelectTypeOptionBuilder::default() - .option(SelectOption::new("Live")) - .option(SelectOption::new("Completed")) - .option(SelectOption::new("Planned")) - .option(SelectOption::new("Paused")); - let single_select_field = FieldBuilder::new(single_select).name("Status").visibility(true).build(); - - // MultiSelect - let multi_select = MultiSelectTypeOptionBuilder::default() - .option(SelectOption::new("Google")) - .option(SelectOption::new("Facebook")) - .option(SelectOption::new("Twitter")); - let multi_select_field = FieldBuilder::new(multi_select) - .name("Platform") - .visibility(true) - .build(); - - // Number - let number = NumberTypeOptionBuilder::default().set_format(NumberFormat::USD); - let number_field = FieldBuilder::new(number).name("Price").visibility(true).build(); - - // Date - let date = DateTypeOptionBuilder::default() - .date_format(DateFormat::US) - .time_format(TimeFormat::TwentyFourHour); - let date_field = FieldBuilder::new(date).name("Time").visibility(true).build(); - - // Checkbox - let checkbox = CheckboxTypeOptionBuilder::default(); - let checkbox_field = FieldBuilder::new(checkbox).name("is done").visibility(true).build(); - - // URL - let url = URLTypeOptionBuilder::default(); - let url_field = FieldBuilder::new(url).name("link").visibility(true).build(); - - GridBuilder::default() - .add_field(text_field) - .add_field(single_select_field) - .add_field(multi_select_field) - .add_field(number_field) - .add_field(date_field) - .add_field(checkbox_field) - .add_field(url_field) - .add_empty_row() - .add_empty_row() - .add_empty_row() - .build() -}