test: add integration test

This commit is contained in:
Lucas.Xu 2023-06-12 14:36:55 +08:00
parent 5bcf48a4f9
commit 8b4d1868e5
10 changed files with 158 additions and 8 deletions

View File

@ -0,0 +1,22 @@
# Welcome to AppFlowy!
## Here are the basics
- [ ] Click anywhere and just start typing.
- [ ] Highlight any text, and use the editing menu to _style_ **your** <u>writing</u> `however` you ~~like.~~
- [ ] As soon as you type /a menu will pop up. Select different types of content blocks you can add.
- [ ] Type `/` followed by `/bullet` or `/num` to create a list.
- [x] Click `+ New Page `button at the bottom of your sidebar to add a new page.
- [ ] Click `+` next to any page title in the sidebar to quickly add a new subpage, `Document`, `Grid`, or `Kanban Board`.
---
## Keyboard shortcuts, markdown, and code block
1. Keyboard shortcuts [guide](https://appflowy.gitbook.io/docs/essential-documentation/shortcuts)
1. Markdown [reference](https://appflowy.gitbook.io/docs/essential-documentation/markdown)
1. Type `/code` to insert a code block
## Have a question❓
> Click `?` at the bottom right for help and support.

View File

@ -0,0 +1 @@
# test

View File

@ -51,6 +51,12 @@
"import": "Import", "import": "Import",
"moreOptions": "More options" "moreOptions": "More options"
}, },
"importPanel": {
"textAndMarkdown": "Text & Markdown",
"documentFromV010": "Document from v0.1.0",
"databaseFromV010": "Database from v0.1.0",
"csv": "CSV"
},
"disclosureAction": { "disclosureAction": {
"rename": "Rename", "rename": "Rename",
"delete": "Delete", "delete": "Delete",

View File

@ -0,0 +1,60 @@
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'util/mock/mock_file_picker.dart';
import 'util/util.dart';
import 'package:path/path.dart' as p;
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('import files', () {
const location = 'import_files';
setUp(() async {
await TestFolder.cleanTestLocation(location);
await TestFolder.setTestLocation(location);
});
tearDown(() async {
await TestFolder.cleanTestLocation(location);
});
tearDownAll(() async {
await TestFolder.cleanTestLocation(null);
});
testWidgets('import multiple markdown files', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
// expect to see a readme page
tester.expectToSeePageName(readme);
await tester.tapAddButton();
await tester.tapImportButton();
final testFileNames = ['test1.md', 'test2.md'];
final fileLocation = await tester.currentFileLocation();
for (final fileName in testFileNames) {
final str = await rootBundle.loadString(
p.join(
'assets/test/workspaces/markdowns',
fileName,
),
);
File(p.join(fileLocation, fileName)).writeAsStringSync(str);
}
// mock get files
await mockPickFilePaths(testFileNames, name: location);
await tester.tapTextAndMarkdownButton();
tester.expectToSeePageName('test1');
tester.expectToSeePageName('test2');
});
});
}

View File

@ -3,6 +3,8 @@ import 'package:integration_test/integration_test.dart';
import 'switch_folder_test.dart' as switch_folder_test; import 'switch_folder_test.dart' as switch_folder_test;
import 'document_test.dart' as document_test; import 'document_test.dart' as document_test;
import 'cover_image_test.dart' as cover_image_test; import 'cover_image_test.dart' as cover_image_test;
import 'share_markdown_test.dart' as share_markdown_test;
import 'import_files_test.dart' as import_files_test;
/// The main task runner for all integration tests in AppFlowy. /// The main task runner for all integration tests in AppFlowy.
/// ///
@ -16,6 +18,8 @@ void main() {
switch_folder_test.main(); switch_folder_test.main();
cover_image_test.main(); cover_image_test.main();
document_test.main(); document_test.main();
share_markdown_test.main();
import_files_test.main();
// board_test.main(); // board_test.main();
// empty_document_test.main(); // empty_document_test.main();
// smart_menu_test.main(); // smart_menu_test.main();

View File

@ -3,6 +3,7 @@ import 'dart:io';
import 'package:appflowy/core/config/kv_keys.dart'; import 'package:appflowy/core/config/kv_keys.dart';
import 'package:appflowy/main.dart' as app; import 'package:appflowy/main.dart' as app;
import 'package:appflowy/startup/tasks/prelude.dart'; import 'package:appflowy/startup/tasks/prelude.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
@ -91,7 +92,16 @@ extension AppFlowyTestBase on WidgetTester {
String tr, { String tr, {
int milliseconds = 500, int milliseconds = 500,
}) async { }) async {
final button = find.text(tr, findRichText: true); Finder button = find.text(
tr,
findRichText: true,
skipOffstage: false,
);
if (button.evaluate().isEmpty) {
button = find.byWidgetPredicate(
(widget) => widget is FlowyText && widget.title == tr,
);
}
await tapButton( await tapButton(
button, button,
milliseconds: milliseconds, milliseconds: milliseconds,

View File

@ -19,6 +19,10 @@ import 'base.dart';
const String readme = 'Read me'; const String readme = 'Read me';
extension CommonOperations on WidgetTester { extension CommonOperations on WidgetTester {
Future<String> currentFileLocation() async {
return TestFolder.currentLocation();
}
Future<void> tapGoButton() async { Future<void> tapGoButton() async {
final goButton = find.byType(GoButton); final goButton = find.byType(GoButton);
await tapButton(goButton); await tapButton(goButton);
@ -42,6 +46,14 @@ extension CommonOperations on WidgetTester {
await tapButtonWithName(LocaleKeys.document_menuName.tr()); await tapButtonWithName(LocaleKeys.document_menuName.tr());
} }
Future<void> tapImportButton() async {
await tapButtonWithName(LocaleKeys.moreAction_import.tr());
}
Future<void> tapTextAndMarkdownButton() async {
await tapButtonWithName(LocaleKeys.importPanel_textAndMarkdown.tr());
}
Finder findPageName(String name) { Finder findPageName(String name) {
return find.byWidgetPredicate( return find.byWidgetPredicate(
(widget) => widget is ViewSectionItem && widget.view.name == name, (widget) => widget is ViewSectionItem && widget.view.name == name,

View File

@ -1,15 +1,19 @@
import 'dart:io';
import 'package:appflowy/startup/startup.dart'; import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/util/file_picker/file_picker_service.dart'; import 'package:appflowy/util/file_picker/file_picker_service.dart';
import 'package:file_picker/src/file_picker.dart' as fp; import 'package:file_picker/file_picker.dart' as fp;
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
import '../util.dart'; import '../util.dart';
class MockFilePicker implements FilePickerService { class MockFilePicker implements FilePickerService {
MockFilePicker({ MockFilePicker({
required this.mockPath, this.mockPath = '',
this.mockPaths = const [],
}); });
final String mockPath; final String mockPath;
final List<String> mockPaths;
@override @override
Future<String?> getDirectoryPath({String? title}) { Future<String?> getDirectoryPath({String? title}) {
@ -41,7 +45,14 @@ class MockFilePicker implements FilePickerService {
bool withReadStream = false, bool withReadStream = false,
bool lockParentWindow = false, bool lockParentWindow = false,
}) { }) {
throw UnimplementedError(); final platformFiles = mockPaths
.map((e) => fp.PlatformFile(path: e, name: '', size: 0))
.toList();
return Future.value(
FilePickerResult(
platformFiles,
),
);
} }
} }
@ -67,3 +78,24 @@ Future<String> mockSaveFilePath(String? name, String fileName) async {
); );
return path; return path;
} }
Future<List<String>> mockPickFilePaths(
List<String> fileNames, {
String? name,
String? customPath,
}) async {
late final Directory dir;
if (customPath != null) {
dir = Directory(customPath);
} else {
dir = await TestFolder.testLocation(name);
}
final paths = fileNames.map((e) => p.join(dir.path, e)).toList();
getIt.unregister<FilePickerService>();
getIt.registerFactory<FilePickerService>(
() => MockFilePicker(
mockPaths: paths,
),
);
return paths;
}

View File

@ -1,3 +1,5 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/image.dart'; import 'package:flowy_infra/image.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -11,13 +13,13 @@ enum ImportType {
String toString() { String toString() {
switch (this) { switch (this) {
case ImportType.historyDocument: case ImportType.historyDocument:
return 'Document from v0.1'; return LocaleKeys.importPanel_documentFromV010.tr();
case ImportType.historyDatabase: case ImportType.historyDatabase:
return 'Database from v0.1'; return LocaleKeys.importPanel_databaseFromV010.tr();
case ImportType.markdownOrText: case ImportType.markdownOrText:
return 'Text & Markdown'; return LocaleKeys.importPanel_textAndMarkdown.tr();
case ImportType.databaseCSV: case ImportType.databaseCSV:
return 'CSV'; return LocaleKeys.importPanel_csv.tr();
} }
} }

View File

@ -181,4 +181,5 @@ flutter:
# BEGIN: EXCLUDE_IN_RELEASE # BEGIN: EXCLUDE_IN_RELEASE
- assets/test/workspaces/ - assets/test/workspaces/
- assets/template/ - assets/template/
- assets/test/workspaces/markdowns/
# END: EXCLUDE_IN_RELEASE # END: EXCLUDE_IN_RELEASE