mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
test: add integration test
This commit is contained in:
parent
5bcf48a4f9
commit
8b4d1868e5
@ -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.
|
@ -0,0 +1 @@
|
|||||||
|
# test
|
@ -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",
|
||||||
|
@ -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');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
@ -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();
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user