database_cell_test.dart 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
  2. import 'package:appflowy_backend/protobuf/flowy-folder2/protobuf.dart';
  3. import 'package:flutter_test/flutter_test.dart';
  4. import 'package:integration_test/integration_test.dart';
  5. import 'package:intl/intl.dart';
  6. import 'util/database_test_op.dart';
  7. import 'util/util.dart';
  8. void main() {
  9. IntegrationTestWidgetsFlutterBinding.ensureInitialized();
  10. group('grid cell', () {
  11. testWidgets('edit text cell', (tester) async {
  12. await tester.initializeAppFlowy();
  13. await tester.tapGoButton();
  14. await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
  15. await tester.editCell(
  16. rowIndex: 0,
  17. fieldType: FieldType.RichText,
  18. input: 'hello world',
  19. );
  20. await tester.assertCellContent(
  21. rowIndex: 0,
  22. fieldType: FieldType.RichText,
  23. content: 'hello world',
  24. );
  25. await tester.pumpAndSettle();
  26. });
  27. // Makesure the text cells are filled with the right content when there are
  28. // multiple text cell
  29. testWidgets('edit multiple text cells', (tester) async {
  30. await tester.initializeAppFlowy();
  31. await tester.tapGoButton();
  32. await tester.createNewPageWithName(
  33. name: 'my grid',
  34. layout: ViewLayoutPB.Grid,
  35. );
  36. await tester.createField(FieldType.RichText, 'description');
  37. await tester.editCell(
  38. rowIndex: 0,
  39. fieldType: FieldType.RichText,
  40. input: 'hello',
  41. );
  42. await tester.editCell(
  43. rowIndex: 0,
  44. fieldType: FieldType.RichText,
  45. input: 'world',
  46. cellIndex: 1,
  47. );
  48. await tester.assertCellContent(
  49. rowIndex: 0,
  50. fieldType: FieldType.RichText,
  51. content: 'hello',
  52. cellIndex: 0,
  53. );
  54. await tester.assertCellContent(
  55. rowIndex: 0,
  56. fieldType: FieldType.RichText,
  57. content: 'world',
  58. cellIndex: 1,
  59. );
  60. await tester.pumpAndSettle();
  61. });
  62. testWidgets('edit number cell', (tester) async {
  63. await tester.initializeAppFlowy();
  64. await tester.tapGoButton();
  65. await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
  66. const fieldType = FieldType.Number;
  67. // Create a number field
  68. await tester.createField(fieldType, fieldType.name);
  69. await tester.editCell(
  70. rowIndex: 0,
  71. fieldType: fieldType,
  72. input: '-1',
  73. );
  74. // edit the next cell to force the previous cell at row 0 to lose focus
  75. await tester.editCell(
  76. rowIndex: 1,
  77. fieldType: fieldType,
  78. input: '0.2',
  79. );
  80. // -1 -> -1
  81. await tester.assertCellContent(
  82. rowIndex: 0,
  83. fieldType: fieldType,
  84. content: '-1',
  85. );
  86. // edit the next cell to force the previous cell at row 1 to lose focus
  87. await tester.editCell(
  88. rowIndex: 2,
  89. fieldType: fieldType,
  90. input: '.1',
  91. );
  92. // 0.2 -> 0.2
  93. await tester.assertCellContent(
  94. rowIndex: 1,
  95. fieldType: fieldType,
  96. content: '0.2',
  97. );
  98. // edit the next cell to force the previous cell at row 2 to lose focus
  99. await tester.editCell(
  100. rowIndex: 0,
  101. fieldType: fieldType,
  102. input: '',
  103. );
  104. // .1 -> 0.1
  105. await tester.assertCellContent(
  106. rowIndex: 2,
  107. fieldType: fieldType,
  108. content: '0.1',
  109. );
  110. await tester.pumpAndSettle();
  111. });
  112. testWidgets('edit checkbox cell', (tester) async {
  113. await tester.initializeAppFlowy();
  114. await tester.tapGoButton();
  115. await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
  116. await tester.assertCheckboxCell(rowIndex: 0, isSelected: false);
  117. await tester.tapCheckboxCellInGrid(rowIndex: 0);
  118. await tester.assertCheckboxCell(rowIndex: 0, isSelected: true);
  119. await tester.tapCheckboxCellInGrid(rowIndex: 1);
  120. await tester.tapCheckboxCellInGrid(rowIndex: 2);
  121. await tester.assertCheckboxCell(rowIndex: 1, isSelected: true);
  122. await tester.assertCheckboxCell(rowIndex: 2, isSelected: true);
  123. await tester.pumpAndSettle();
  124. });
  125. testWidgets('edit create time cell', (tester) async {
  126. await tester.initializeAppFlowy();
  127. await tester.tapGoButton();
  128. await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
  129. const fieldType = FieldType.CreatedTime;
  130. // Create a create time field
  131. // The create time field is not editable
  132. await tester.createField(fieldType, fieldType.name);
  133. await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
  134. await tester.findDateEditor(findsNothing);
  135. await tester.pumpAndSettle();
  136. });
  137. testWidgets('edit last time cell', (tester) async {
  138. await tester.initializeAppFlowy();
  139. await tester.tapGoButton();
  140. await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
  141. const fieldType = FieldType.LastEditedTime;
  142. // Create a last time field
  143. // The last time field is not editable
  144. await tester.createField(fieldType, fieldType.name);
  145. await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
  146. await tester.findDateEditor(findsNothing);
  147. await tester.pumpAndSettle();
  148. });
  149. testWidgets('edit time cell', (tester) async {
  150. await tester.initializeAppFlowy();
  151. await tester.tapGoButton();
  152. await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
  153. const fieldType = FieldType.DateTime;
  154. await tester.createField(fieldType, fieldType.name);
  155. // Tap the cell to invoke the field editor
  156. await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
  157. await tester.findDateEditor(findsOneWidget);
  158. // Toggle include time
  159. await tester.toggleIncludeTime();
  160. // Dismiss the cell editor
  161. await tester.dismissCellEditor();
  162. await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
  163. await tester.findDateEditor(findsOneWidget);
  164. // Turn off include time
  165. await tester.toggleIncludeTime();
  166. // Select a date
  167. final today = DateTime.now();
  168. await tester.selectDay(content: today.day);
  169. await tester.dismissCellEditor();
  170. await tester.assertDateCellInGrid(
  171. rowIndex: 0,
  172. fieldType: fieldType,
  173. content: DateFormat('MMM dd, y').format(today),
  174. );
  175. await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
  176. await tester.findDateEditor(findsOneWidget);
  177. // Toggle include time
  178. final now = DateTime.now();
  179. await tester.toggleIncludeTime();
  180. await tester.dismissCellEditor();
  181. await tester.assertDateCellInGrid(
  182. rowIndex: 0,
  183. fieldType: fieldType,
  184. content: DateFormat('MMM dd, y HH:mm').format(now),
  185. );
  186. await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
  187. await tester.findDateEditor(findsOneWidget);
  188. // Change date format
  189. await tester.changeDateFormat();
  190. await tester.dismissCellEditor();
  191. await tester.assertDateCellInGrid(
  192. rowIndex: 0,
  193. fieldType: fieldType,
  194. content: DateFormat('dd/MM/y HH:mm').format(now),
  195. );
  196. await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
  197. await tester.findDateEditor(findsOneWidget);
  198. // Change time format
  199. await tester.changeTimeFormat();
  200. await tester.dismissCellEditor();
  201. await tester.assertDateCellInGrid(
  202. rowIndex: 0,
  203. fieldType: fieldType,
  204. content: DateFormat('dd/MM/y hh:mm a').format(now),
  205. );
  206. await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
  207. await tester.findDateEditor(findsOneWidget);
  208. // Clear the date and time
  209. await tester.clearDate();
  210. await tester.assertDateCellInGrid(
  211. rowIndex: 0,
  212. fieldType: fieldType,
  213. content: '',
  214. );
  215. await tester.pumpAndSettle();
  216. });
  217. testWidgets('edit single select cell', (tester) async {
  218. await tester.initializeAppFlowy();
  219. await tester.tapGoButton();
  220. const fieldType = FieldType.SingleSelect;
  221. // When create a grid, it will create a single select field by default
  222. await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
  223. // Tap the cell to invoke the selection option editor
  224. await tester.tapSelectOptionCellInGrid(rowIndex: 0, fieldType: fieldType);
  225. await tester.findSelectOptionEditor(findsOneWidget);
  226. // Create a new select option
  227. await tester.createOption(name: 'tag 1');
  228. await tester.dismissCellEditor();
  229. // Make sure the option is created and displayed in the cell
  230. await tester.findSelectOptionWithNameInGrid(
  231. rowIndex: 0,
  232. name: 'tag 1',
  233. );
  234. await tester.tapSelectOptionCellInGrid(rowIndex: 0, fieldType: fieldType);
  235. await tester.findSelectOptionEditor(findsOneWidget);
  236. // Create another select option
  237. await tester.createOption(name: 'tag 2');
  238. await tester.dismissCellEditor();
  239. await tester.findSelectOptionWithNameInGrid(
  240. rowIndex: 0,
  241. name: 'tag 2',
  242. );
  243. await tester.assertNumberOfSelectedOptionsInGrid(
  244. rowIndex: 0,
  245. matcher: findsOneWidget,
  246. );
  247. await tester.tapSelectOptionCellInGrid(rowIndex: 0, fieldType: fieldType);
  248. await tester.findSelectOptionEditor(findsOneWidget);
  249. // switch to first option
  250. await tester.selectOption(name: 'tag 1');
  251. await tester.dismissCellEditor();
  252. await tester.findSelectOptionWithNameInGrid(
  253. rowIndex: 0,
  254. name: 'tag 1',
  255. );
  256. await tester.assertNumberOfSelectedOptionsInGrid(
  257. rowIndex: 0,
  258. matcher: findsOneWidget,
  259. );
  260. await tester.tapSelectOptionCellInGrid(rowIndex: 0, fieldType: fieldType);
  261. await tester.findSelectOptionEditor(findsOneWidget);
  262. // Deselect the currently-selected option
  263. await tester.selectOption(name: 'tag 1');
  264. await tester.dismissCellEditor();
  265. await tester.assertNumberOfSelectedOptionsInGrid(
  266. rowIndex: 0,
  267. matcher: findsNothing,
  268. );
  269. await tester.pumpAndSettle();
  270. });
  271. testWidgets('edit multi select cell', (tester) async {
  272. final tags = [
  273. 'tag 1',
  274. 'tag 2',
  275. 'tag 3',
  276. 'tag 4',
  277. ];
  278. await tester.initializeAppFlowy();
  279. await tester.tapGoButton();
  280. await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
  281. const fieldType = FieldType.MultiSelect;
  282. await tester.createField(fieldType, fieldType.name);
  283. // Tap the cell to invoke the selection option editor
  284. await tester.tapSelectOptionCellInGrid(rowIndex: 0, fieldType: fieldType);
  285. await tester.findSelectOptionEditor(findsOneWidget);
  286. // Create a new select option
  287. await tester.createOption(name: tags.first);
  288. await tester.dismissCellEditor();
  289. // Make sure the option is created and displayed in the cell
  290. await tester.findSelectOptionWithNameInGrid(
  291. rowIndex: 0,
  292. name: tags.first,
  293. );
  294. await tester.tapSelectOptionCellInGrid(rowIndex: 0, fieldType: fieldType);
  295. await tester.findSelectOptionEditor(findsOneWidget);
  296. // Create some other select options
  297. await tester.createOption(name: tags[1]);
  298. await tester.createOption(name: tags[2]);
  299. await tester.createOption(name: tags[3]);
  300. await tester.dismissCellEditor();
  301. for (final tag in tags) {
  302. await tester.findSelectOptionWithNameInGrid(
  303. rowIndex: 0,
  304. name: tag,
  305. );
  306. }
  307. await tester.assertNumberOfSelectedOptionsInGrid(
  308. rowIndex: 0,
  309. matcher: findsNWidgets(4),
  310. );
  311. await tester.tapSelectOptionCellInGrid(rowIndex: 0, fieldType: fieldType);
  312. await tester.findSelectOptionEditor(findsOneWidget);
  313. // Deselect all options
  314. for (final tag in tags) {
  315. await tester.selectOption(name: tag);
  316. }
  317. await tester.dismissCellEditor();
  318. await tester.assertNumberOfSelectedOptionsInGrid(
  319. rowIndex: 0,
  320. matcher: findsNothing,
  321. );
  322. await tester.tapSelectOptionCellInGrid(rowIndex: 0, fieldType: fieldType);
  323. await tester.findSelectOptionEditor(findsOneWidget);
  324. // Select some options
  325. await tester.selectOption(name: tags[1]);
  326. await tester.selectOption(name: tags[3]);
  327. await tester.dismissCellEditor();
  328. await tester.findSelectOptionWithNameInGrid(
  329. rowIndex: 0,
  330. name: tags[1],
  331. );
  332. await tester.findSelectOptionWithNameInGrid(
  333. rowIndex: 0,
  334. name: tags[3],
  335. );
  336. await tester.assertNumberOfSelectedOptionsInGrid(
  337. rowIndex: 0,
  338. matcher: findsNWidgets(2),
  339. );
  340. await tester.pumpAndSettle();
  341. });
  342. });
  343. }