mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-07-09 18:16:17 +00:00

* chore: ux flow redesign * chore: remove unused imports * fix: allow creation of tasks of the same name * chore: apply code suggestions from Mathias
543 lines
15 KiB
Dart
543 lines
15 KiB
Dart
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
|
|
import 'package:appflowy_backend/protobuf/flowy-folder2/protobuf.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:integration_test/integration_test.dart';
|
|
import 'package:intl/intl.dart';
|
|
|
|
import 'util/database_test_op.dart';
|
|
import 'util/util.dart';
|
|
|
|
void main() {
|
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
|
|
|
group('grid cell', () {
|
|
testWidgets('edit text cell', (tester) async {
|
|
await tester.initializeAppFlowy();
|
|
await tester.tapGoButton();
|
|
|
|
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
|
|
|
await tester.editCell(
|
|
rowIndex: 0,
|
|
fieldType: FieldType.RichText,
|
|
input: 'hello world',
|
|
);
|
|
|
|
await tester.assertCellContent(
|
|
rowIndex: 0,
|
|
fieldType: FieldType.RichText,
|
|
content: 'hello world',
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
});
|
|
|
|
// Makesure the text cells are filled with the right content when there are
|
|
// multiple text cell
|
|
testWidgets('edit multiple text cells', (tester) async {
|
|
await tester.initializeAppFlowy();
|
|
await tester.tapGoButton();
|
|
await tester.createNewPageWithName(
|
|
name: 'my grid',
|
|
layout: ViewLayoutPB.Grid,
|
|
);
|
|
await tester.createField(FieldType.RichText, 'description');
|
|
|
|
await tester.editCell(
|
|
rowIndex: 0,
|
|
fieldType: FieldType.RichText,
|
|
input: 'hello',
|
|
);
|
|
|
|
await tester.editCell(
|
|
rowIndex: 0,
|
|
fieldType: FieldType.RichText,
|
|
input: 'world',
|
|
cellIndex: 1,
|
|
);
|
|
|
|
await tester.assertCellContent(
|
|
rowIndex: 0,
|
|
fieldType: FieldType.RichText,
|
|
content: 'hello',
|
|
cellIndex: 0,
|
|
);
|
|
|
|
await tester.assertCellContent(
|
|
rowIndex: 0,
|
|
fieldType: FieldType.RichText,
|
|
content: 'world',
|
|
cellIndex: 1,
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
});
|
|
|
|
testWidgets('edit number cell', (tester) async {
|
|
await tester.initializeAppFlowy();
|
|
await tester.tapGoButton();
|
|
|
|
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
|
|
|
const fieldType = FieldType.Number;
|
|
|
|
// Create a number field
|
|
await tester.createField(fieldType, fieldType.name);
|
|
|
|
await tester.editCell(
|
|
rowIndex: 0,
|
|
fieldType: fieldType,
|
|
input: '-1',
|
|
);
|
|
// edit the next cell to force the previous cell at row 0 to lose focus
|
|
await tester.editCell(
|
|
rowIndex: 1,
|
|
fieldType: fieldType,
|
|
input: '0.2',
|
|
);
|
|
// -1 -> -1
|
|
await tester.assertCellContent(
|
|
rowIndex: 0,
|
|
fieldType: fieldType,
|
|
content: '-1',
|
|
);
|
|
|
|
// edit the next cell to force the previous cell at row 1 to lose focus
|
|
await tester.editCell(
|
|
rowIndex: 2,
|
|
fieldType: fieldType,
|
|
input: '.1',
|
|
);
|
|
// 0.2 -> 0.2
|
|
await tester.assertCellContent(
|
|
rowIndex: 1,
|
|
fieldType: fieldType,
|
|
content: '0.2',
|
|
);
|
|
|
|
// edit the next cell to force the previous cell at row 2 to lose focus
|
|
await tester.editCell(
|
|
rowIndex: 0,
|
|
fieldType: fieldType,
|
|
input: '',
|
|
);
|
|
// .1 -> 0.1
|
|
await tester.assertCellContent(
|
|
rowIndex: 2,
|
|
fieldType: fieldType,
|
|
content: '0.1',
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
});
|
|
|
|
testWidgets('edit checkbox cell', (tester) async {
|
|
await tester.initializeAppFlowy();
|
|
await tester.tapGoButton();
|
|
|
|
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
|
|
|
await tester.assertCheckboxCell(rowIndex: 0, isSelected: false);
|
|
await tester.tapCheckboxCellInGrid(rowIndex: 0);
|
|
await tester.assertCheckboxCell(rowIndex: 0, isSelected: true);
|
|
|
|
await tester.tapCheckboxCellInGrid(rowIndex: 1);
|
|
await tester.tapCheckboxCellInGrid(rowIndex: 2);
|
|
await tester.assertCheckboxCell(rowIndex: 1, isSelected: true);
|
|
await tester.assertCheckboxCell(rowIndex: 2, isSelected: true);
|
|
|
|
await tester.pumpAndSettle();
|
|
});
|
|
|
|
testWidgets('edit create time cell', (tester) async {
|
|
await tester.initializeAppFlowy();
|
|
await tester.tapGoButton();
|
|
|
|
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
|
|
|
const fieldType = FieldType.CreatedTime;
|
|
// Create a create time field
|
|
// The create time field is not editable
|
|
await tester.createField(fieldType, fieldType.name);
|
|
|
|
await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
|
|
|
|
await tester.findDateEditor(findsNothing);
|
|
|
|
await tester.pumpAndSettle();
|
|
});
|
|
|
|
testWidgets('edit last time cell', (tester) async {
|
|
await tester.initializeAppFlowy();
|
|
await tester.tapGoButton();
|
|
|
|
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
|
|
|
const fieldType = FieldType.LastEditedTime;
|
|
// Create a last time field
|
|
// The last time field is not editable
|
|
await tester.createField(fieldType, fieldType.name);
|
|
|
|
await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
|
|
|
|
await tester.findDateEditor(findsNothing);
|
|
|
|
await tester.pumpAndSettle();
|
|
});
|
|
|
|
testWidgets('edit date time cell', (tester) async {
|
|
await tester.initializeAppFlowy();
|
|
await tester.tapGoButton();
|
|
|
|
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
|
|
|
const fieldType = FieldType.DateTime;
|
|
await tester.createField(fieldType, fieldType.name);
|
|
|
|
// Tap the cell to invoke the field editor
|
|
await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
|
|
await tester.findDateEditor(findsOneWidget);
|
|
|
|
// Toggle include time
|
|
await tester.toggleIncludeTime();
|
|
|
|
// Dismiss the cell editor
|
|
await tester.dismissCellEditor();
|
|
|
|
await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
|
|
await tester.findDateEditor(findsOneWidget);
|
|
|
|
// Turn off include time
|
|
await tester.toggleIncludeTime();
|
|
|
|
// Select a date
|
|
final today = DateTime.now();
|
|
await tester.selectDay(content: today.day);
|
|
|
|
await tester.dismissCellEditor();
|
|
|
|
await tester.assertDateCellInGrid(
|
|
rowIndex: 0,
|
|
content: DateFormat('MMM dd, y').format(today),
|
|
);
|
|
|
|
await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
|
|
await tester.findDateEditor(findsOneWidget);
|
|
|
|
// Toggle include time
|
|
final now = DateTime.now();
|
|
await tester.toggleIncludeTime();
|
|
|
|
await tester.dismissCellEditor();
|
|
|
|
await tester.assertDateCellInGrid(
|
|
rowIndex: 0,
|
|
content: DateFormat('MMM dd, y HH:mm').format(now),
|
|
);
|
|
|
|
await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
|
|
await tester.findDateEditor(findsOneWidget);
|
|
|
|
// Change date format
|
|
await tester.changeDateFormat();
|
|
|
|
await tester.dismissCellEditor();
|
|
|
|
await tester.assertDateCellInGrid(
|
|
rowIndex: 0,
|
|
content: DateFormat('dd/MM/y HH:mm').format(now),
|
|
);
|
|
|
|
await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
|
|
await tester.findDateEditor(findsOneWidget);
|
|
|
|
// Change time format
|
|
await tester.changeTimeFormat();
|
|
|
|
await tester.dismissCellEditor();
|
|
|
|
await tester.assertDateCellInGrid(
|
|
rowIndex: 0,
|
|
content: DateFormat('dd/MM/y hh:mm a').format(now),
|
|
);
|
|
|
|
await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
|
|
await tester.findDateEditor(findsOneWidget);
|
|
|
|
// Clear the date and time
|
|
await tester.clearDate();
|
|
|
|
await tester.assertDateCellInGrid(
|
|
rowIndex: 0,
|
|
content: '',
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
});
|
|
|
|
testWidgets('edit single select cell', (tester) async {
|
|
await tester.initializeAppFlowy();
|
|
await tester.tapGoButton();
|
|
|
|
const fieldType = FieldType.SingleSelect;
|
|
|
|
// When create a grid, it will create a single select field by default
|
|
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
|
|
|
// Tap the cell to invoke the selection option editor
|
|
await tester.tapSelectOptionCellInGrid(rowIndex: 0, fieldType: fieldType);
|
|
await tester.findSelectOptionEditor(findsOneWidget);
|
|
|
|
// Create a new select option
|
|
await tester.createOption(name: 'tag 1');
|
|
await tester.dismissCellEditor();
|
|
|
|
// Make sure the option is created and displayed in the cell
|
|
await tester.findSelectOptionWithNameInGrid(
|
|
rowIndex: 0,
|
|
name: 'tag 1',
|
|
);
|
|
|
|
await tester.tapSelectOptionCellInGrid(rowIndex: 0, fieldType: fieldType);
|
|
await tester.findSelectOptionEditor(findsOneWidget);
|
|
|
|
// Create another select option
|
|
await tester.createOption(name: 'tag 2');
|
|
await tester.dismissCellEditor();
|
|
|
|
await tester.findSelectOptionWithNameInGrid(
|
|
rowIndex: 0,
|
|
name: 'tag 2',
|
|
);
|
|
|
|
await tester.assertNumberOfSelectedOptionsInGrid(
|
|
rowIndex: 0,
|
|
matcher: findsOneWidget,
|
|
);
|
|
|
|
await tester.tapSelectOptionCellInGrid(rowIndex: 0, fieldType: fieldType);
|
|
await tester.findSelectOptionEditor(findsOneWidget);
|
|
|
|
// switch to first option
|
|
await tester.selectOption(name: 'tag 1');
|
|
await tester.dismissCellEditor();
|
|
|
|
await tester.findSelectOptionWithNameInGrid(
|
|
rowIndex: 0,
|
|
name: 'tag 1',
|
|
);
|
|
|
|
await tester.assertNumberOfSelectedOptionsInGrid(
|
|
rowIndex: 0,
|
|
matcher: findsOneWidget,
|
|
);
|
|
|
|
await tester.tapSelectOptionCellInGrid(rowIndex: 0, fieldType: fieldType);
|
|
await tester.findSelectOptionEditor(findsOneWidget);
|
|
|
|
// Deselect the currently-selected option
|
|
await tester.selectOption(name: 'tag 1');
|
|
await tester.dismissCellEditor();
|
|
|
|
await tester.assertNumberOfSelectedOptionsInGrid(
|
|
rowIndex: 0,
|
|
matcher: findsNothing,
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
});
|
|
|
|
testWidgets('edit multi select cell', (tester) async {
|
|
final tags = [
|
|
'tag 1',
|
|
'tag 2',
|
|
'tag 3',
|
|
'tag 4',
|
|
];
|
|
|
|
await tester.initializeAppFlowy();
|
|
await tester.tapGoButton();
|
|
|
|
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
|
|
|
const fieldType = FieldType.MultiSelect;
|
|
await tester.createField(fieldType, fieldType.name);
|
|
|
|
// Tap the cell to invoke the selection option editor
|
|
await tester.tapSelectOptionCellInGrid(rowIndex: 0, fieldType: fieldType);
|
|
await tester.findSelectOptionEditor(findsOneWidget);
|
|
|
|
// Create a new select option
|
|
await tester.createOption(name: tags.first);
|
|
await tester.dismissCellEditor();
|
|
|
|
// Make sure the option is created and displayed in the cell
|
|
await tester.findSelectOptionWithNameInGrid(
|
|
rowIndex: 0,
|
|
name: tags.first,
|
|
);
|
|
|
|
await tester.tapSelectOptionCellInGrid(rowIndex: 0, fieldType: fieldType);
|
|
await tester.findSelectOptionEditor(findsOneWidget);
|
|
|
|
// Create some other select options
|
|
await tester.createOption(name: tags[1]);
|
|
await tester.createOption(name: tags[2]);
|
|
await tester.createOption(name: tags[3]);
|
|
await tester.dismissCellEditor();
|
|
|
|
for (final tag in tags) {
|
|
await tester.findSelectOptionWithNameInGrid(
|
|
rowIndex: 0,
|
|
name: tag,
|
|
);
|
|
}
|
|
|
|
await tester.assertNumberOfSelectedOptionsInGrid(
|
|
rowIndex: 0,
|
|
matcher: findsNWidgets(4),
|
|
);
|
|
|
|
await tester.tapSelectOptionCellInGrid(rowIndex: 0, fieldType: fieldType);
|
|
await tester.findSelectOptionEditor(findsOneWidget);
|
|
|
|
// Deselect all options
|
|
for (final tag in tags) {
|
|
await tester.selectOption(name: tag);
|
|
}
|
|
await tester.dismissCellEditor();
|
|
|
|
await tester.assertNumberOfSelectedOptionsInGrid(
|
|
rowIndex: 0,
|
|
matcher: findsNothing,
|
|
);
|
|
|
|
await tester.tapSelectOptionCellInGrid(rowIndex: 0, fieldType: fieldType);
|
|
await tester.findSelectOptionEditor(findsOneWidget);
|
|
|
|
// Select some options
|
|
await tester.selectOption(name: tags[1]);
|
|
await tester.selectOption(name: tags[3]);
|
|
await tester.dismissCellEditor();
|
|
|
|
await tester.findSelectOptionWithNameInGrid(
|
|
rowIndex: 0,
|
|
name: tags[1],
|
|
);
|
|
await tester.findSelectOptionWithNameInGrid(
|
|
rowIndex: 0,
|
|
name: tags[3],
|
|
);
|
|
|
|
await tester.assertNumberOfSelectedOptionsInGrid(
|
|
rowIndex: 0,
|
|
matcher: findsNWidgets(2),
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
});
|
|
});
|
|
|
|
testWidgets('edit checklist cell', (tester) async {
|
|
await tester.initializeAppFlowy();
|
|
await tester.tapGoButton();
|
|
|
|
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
|
|
|
|
const fieldType = FieldType.Checklist;
|
|
await tester.createField(fieldType, fieldType.name);
|
|
|
|
// assert that there is no progress bar in the grid
|
|
tester.assertChecklistCellInGrid(rowIndex: 0, percent: null);
|
|
|
|
// tap on the first checklist cell
|
|
await tester.tapChecklistCellInGrid(rowIndex: 0);
|
|
|
|
// assert that the checklist editor is shown
|
|
tester.assertChecklistEditorVisible(visible: true);
|
|
|
|
// create a new task with enter
|
|
await tester.createNewChecklistTask(name: "task 0", enter: true);
|
|
|
|
// assert that the task is displayed
|
|
tester.assertChecklistTaskInEditor(
|
|
index: 0,
|
|
name: "task 0",
|
|
isChecked: false,
|
|
);
|
|
|
|
// update the task's name
|
|
await tester.renameChecklistTask(index: 0, name: "task 1");
|
|
|
|
// assert that the task's name is updated
|
|
tester.assertChecklistTaskInEditor(
|
|
index: 0,
|
|
name: "task 1",
|
|
isChecked: false,
|
|
);
|
|
|
|
// dismiss new task editor
|
|
await tester.dismissCellEditor();
|
|
|
|
// dismiss checklist cell editor
|
|
await tester.dismissCellEditor();
|
|
|
|
// assert that progress bar is shown in grid at 0%
|
|
tester.assertChecklistCellInGrid(rowIndex: 0, percent: 0);
|
|
|
|
// start editing the first checklist cell again
|
|
await tester.tapChecklistCellInGrid(rowIndex: 0);
|
|
|
|
// create another task with the create button
|
|
await tester.createNewChecklistTask(name: "task 2", button: true);
|
|
|
|
// assert that the task was inserted
|
|
tester.assertChecklistTaskInEditor(
|
|
index: 1,
|
|
name: "task 2",
|
|
isChecked: false,
|
|
);
|
|
|
|
// mark it as complete
|
|
await tester.checkChecklistTask(index: 1);
|
|
|
|
// assert that the task was checked in the editor
|
|
tester.assertChecklistTaskInEditor(
|
|
index: 1,
|
|
name: "task 2",
|
|
isChecked: true,
|
|
);
|
|
|
|
// dismiss checklist editor
|
|
await tester.dismissCellEditor();
|
|
await tester.dismissCellEditor();
|
|
|
|
// assert that progressbar is shown in grid at 50%
|
|
tester.assertChecklistCellInGrid(rowIndex: 0, percent: 0.5);
|
|
|
|
// re-open the cell editor
|
|
await tester.tapChecklistCellInGrid(rowIndex: 0);
|
|
|
|
// hover over first task and delete it
|
|
await tester.deleteChecklistTask(index: 0);
|
|
|
|
// dismiss cell editor
|
|
await tester.dismissCellEditor();
|
|
|
|
// assert that progressbar is shown in grid at 100%
|
|
tester.assertChecklistCellInGrid(rowIndex: 0, percent: 1);
|
|
|
|
// re-open the cell edior
|
|
await tester.tapChecklistCellInGrid(rowIndex: 0);
|
|
|
|
// delete the remaining task
|
|
await tester.deleteChecklistTask(index: 0);
|
|
|
|
// dismiss the cell editor
|
|
await tester.dismissCellEditor();
|
|
|
|
// check that the progress bar is not viisble
|
|
tester.assertChecklistCellInGrid(rowIndex: 0, percent: null);
|
|
});
|
|
}
|