database_cell_test.dart 12 KB

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