|
@@ -1,5 +1,7 @@
|
|
import 'dart:io';
|
|
import 'dart:io';
|
|
|
|
|
|
|
|
+import 'package:appflowy/plugins/document/presentation/editor_plugins/copy_and_paste/clipboard_service.dart';
|
|
|
|
+import 'package:appflowy/startup/startup.dart';
|
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
|
import 'package:appflowy_editor/appflowy_editor.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';
|
|
@@ -12,36 +14,220 @@ void main() {
|
|
|
|
|
|
group('copy and paste in document', () {
|
|
group('copy and paste in document', () {
|
|
testWidgets('paste multiple lines at the first line', (tester) async {
|
|
testWidgets('paste multiple lines at the first line', (tester) async {
|
|
- await tester.initializeAppFlowy();
|
|
|
|
- await tester.tapGoButton();
|
|
|
|
-
|
|
|
|
- // create a new document
|
|
|
|
- await tester.createNewPageWithName();
|
|
|
|
-
|
|
|
|
// mock the clipboard
|
|
// mock the clipboard
|
|
const lines = 3;
|
|
const lines = 3;
|
|
- AppFlowyClipboard.mockSetData(
|
|
|
|
- AppFlowyClipboardData(
|
|
|
|
- text: List.generate(lines, (index) => 'line $index').join('\n'),
|
|
|
|
- ),
|
|
|
|
|
|
+ await tester.pasteContent(
|
|
|
|
+ plainText: List.generate(lines, (index) => 'line $index').join('\n'),
|
|
|
|
+ (editorState) {
|
|
|
|
+ expect(editorState.document.root.children.length, 3);
|
|
|
|
+ for (var i = 0; i < lines; i++) {
|
|
|
|
+ expect(
|
|
|
|
+ editorState.getNodeAtPath([i])!.delta!.toPlainText(),
|
|
|
|
+ 'line $i',
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+ },
|
|
);
|
|
);
|
|
|
|
+ });
|
|
|
|
|
|
- // paste the text
|
|
|
|
- await tester.simulateKeyEvent(
|
|
|
|
- LogicalKeyboardKey.keyV,
|
|
|
|
- isControlPressed: Platform.isLinux || Platform.isWindows,
|
|
|
|
- isMetaPressed: Platform.isMacOS,
|
|
|
|
|
|
+ // ## **User Installation**
|
|
|
|
+ // - [Windows/Mac/Linux](https://appflowy.gitbook.io/docs/essential-documentation/install-appflowy/installation-methods/mac-windows-linux-packages)
|
|
|
|
+ // - [Docker](https://appflowy.gitbook.io/docs/essential-documentation/install-appflowy/installation-methods/installing-with-docker)
|
|
|
|
+ // - [Source](https://appflowy.gitbook.io/docs/essential-documentation/install-appflowy/installation-methods/from-source)
|
|
|
|
+ testWidgets('paste content from html, sample 1', (tester) async {
|
|
|
|
+ await tester.pasteContent(
|
|
|
|
+ html:
|
|
|
|
+ '''<meta charset='utf-8'><h2><strong>User Installation</strong></h2>
|
|
|
|
+<ul>
|
|
|
|
+<li><a href="https://appflowy.gitbook.io/docs/essential-documentation/install-appflowy/installation-methods/mac-windows-linux-packages">Windows/Mac/Linux</a></li>
|
|
|
|
+<li><a href="https://appflowy.gitbook.io/docs/essential-documentation/install-appflowy/installation-methods/installing-with-docker">Docker</a></li>
|
|
|
|
+<li><a href="https://appflowy.gitbook.io/docs/essential-documentation/install-appflowy/installation-methods/from-source">Source</a></li>
|
|
|
|
+</ul>''',
|
|
|
|
+ (editorState) {
|
|
|
|
+ expect(editorState.document.root.children.length, 4);
|
|
|
|
+ final node1 = editorState.getNodeAtPath([0])!;
|
|
|
|
+ final node2 = editorState.getNodeAtPath([1])!;
|
|
|
|
+ final node3 = editorState.getNodeAtPath([2])!;
|
|
|
|
+ final node4 = editorState.getNodeAtPath([3])!;
|
|
|
|
+ expect(node1.delta!.toJson(), [
|
|
|
|
+ {
|
|
|
|
+ "insert": "User Installation",
|
|
|
|
+ "attributes": {"bold": true},
|
|
|
|
+ }
|
|
|
|
+ ]);
|
|
|
|
+ expect(node2.delta!.toJson(), [
|
|
|
|
+ {
|
|
|
|
+ "insert": "Windows/Mac/Linux",
|
|
|
|
+ "attributes": {
|
|
|
|
+ "href":
|
|
|
|
+ "https://appflowy.gitbook.io/docs/essential-documentation/install-appflowy/installation-methods/mac-windows-linux-packages",
|
|
|
|
+ },
|
|
|
|
+ }
|
|
|
|
+ ]);
|
|
|
|
+ expect(
|
|
|
|
+ node3.delta!.toJson(),
|
|
|
|
+ [
|
|
|
|
+ {
|
|
|
|
+ "insert": "Docker",
|
|
|
|
+ "attributes": {
|
|
|
|
+ "href":
|
|
|
|
+ "https://appflowy.gitbook.io/docs/essential-documentation/install-appflowy/installation-methods/installing-with-docker",
|
|
|
|
+ },
|
|
|
|
+ }
|
|
|
|
+ ],
|
|
|
|
+ );
|
|
|
|
+ expect(
|
|
|
|
+ node4.delta!.toJson(),
|
|
|
|
+ [
|
|
|
|
+ {
|
|
|
|
+ "insert": "Source",
|
|
|
|
+ "attributes": {
|
|
|
|
+ "href":
|
|
|
|
+ "https://appflowy.gitbook.io/docs/essential-documentation/install-appflowy/installation-methods/from-source",
|
|
|
|
+ },
|
|
|
|
+ }
|
|
|
|
+ ],
|
|
|
|
+ );
|
|
|
|
+ },
|
|
);
|
|
);
|
|
- await tester.pumpAndSettle();
|
|
|
|
-
|
|
|
|
- final editorState = tester.editor.getCurrentEditorState();
|
|
|
|
- expect(editorState.document.root.children.length, 4);
|
|
|
|
- for (var i = 0; i < lines; i++) {
|
|
|
|
- expect(
|
|
|
|
- editorState.getNodeAtPath([i])!.delta!.toPlainText(),
|
|
|
|
- 'line $i',
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ testWidgets('paste code from VSCode', (tester) async {
|
|
|
|
+ await tester.pasteContent(
|
|
|
|
+ html:
|
|
|
|
+ '''<meta charset='utf-8'><div style="color: #bbbbbb;background-color: #262335;font-family: Consolas, 'JetBrains Mono', monospace, 'cascadia code', Menlo, Monaco, 'Courier New', monospace;font-weight: normal;font-size: 14px;line-height: 21px;white-space: pre;"><div><span style="color: #fede5d;">void</span><span style="color: #ff7edb;"> </span><span style="color: #36f9f6;">main</span><span style="color: #ff7edb;">() {</span></div><div><span style="color: #ff7edb;"> </span><span style="color: #36f9f6;">runApp</span><span style="color: #ff7edb;">(</span><span style="color: #fede5d;">const</span><span style="color: #ff7edb;"> </span><span style="color: #fe4450;">MyApp</span><span style="color: #ff7edb;">());</span></div><div><span style="color: #ff7edb;">}</span></div></div>''',
|
|
|
|
+ (editorState) {
|
|
|
|
+ expect(editorState.document.root.children.length, 3);
|
|
|
|
+ final node1 = editorState.getNodeAtPath([0])!;
|
|
|
|
+ final node2 = editorState.getNodeAtPath([1])!;
|
|
|
|
+ final node3 = editorState.getNodeAtPath([2])!;
|
|
|
|
+ expect(node1.type, ParagraphBlockKeys.type);
|
|
|
|
+ expect(node2.type, ParagraphBlockKeys.type);
|
|
|
|
+ expect(node3.type, ParagraphBlockKeys.type);
|
|
|
|
+ expect(node1.delta!.toJson(), [
|
|
|
|
+ {
|
|
|
|
+ "insert": "void",
|
|
|
|
+ "attributes": {"font_color": "0xfffede5d"},
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ "insert": " ",
|
|
|
|
+ "attributes": {"font_color": "0xffff7edb"},
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ "insert": "main",
|
|
|
|
+ "attributes": {"font_color": "0xff36f9f6"},
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ "insert": "() {",
|
|
|
|
+ "attributes": {"font_color": "0xffff7edb"},
|
|
|
|
+ }
|
|
|
|
+ ]);
|
|
|
|
+ expect(node2.delta!.toJson(), [
|
|
|
|
+ {
|
|
|
|
+ "insert": " ",
|
|
|
|
+ "attributes": {"font_color": "0xffff7edb"},
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ "insert": "runApp",
|
|
|
|
+ "attributes": {"font_color": "0xff36f9f6"},
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ "insert": "(",
|
|
|
|
+ "attributes": {"font_color": "0xffff7edb"},
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ "insert": "const",
|
|
|
|
+ "attributes": {"font_color": "0xfffede5d"},
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ "insert": " ",
|
|
|
|
+ "attributes": {"font_color": "0xffff7edb"},
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ "insert": "MyApp",
|
|
|
|
+ "attributes": {"font_color": "0xfffe4450"},
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ "insert": "());",
|
|
|
|
+ "attributes": {"font_color": "0xffff7edb"},
|
|
|
|
+ }
|
|
|
|
+ ]);
|
|
|
|
+ expect(node3.delta!.toJson(), [
|
|
|
|
+ {
|
|
|
|
+ "insert": "}",
|
|
|
|
+ "attributes": {"font_color": "0xffff7edb"},
|
|
|
|
+ }
|
|
|
|
+ ]);
|
|
|
|
+ });
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
+
|
|
|
|
+ testWidgets('paste image(png) from memory', (tester) async {
|
|
|
|
+ final image = await rootBundle.load('assets/test/images/sample.png');
|
|
|
|
+ final bytes = image.buffer.asUint8List();
|
|
|
|
+ await tester.pasteContent(image: ('png', bytes), (editorState) {
|
|
|
|
+ expect(editorState.document.root.children.length, 2);
|
|
|
|
+ final node = editorState.getNodeAtPath([0])!;
|
|
|
|
+ expect(node.type, ImageBlockKeys.type);
|
|
|
|
+ expect(node.attributes[ImageBlockKeys.url], isNotNull);
|
|
|
|
+ });
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ testWidgets('paste image(jpeg) from memory', (tester) async {
|
|
|
|
+ final image = await rootBundle.load('assets/test/images/sample.jpeg');
|
|
|
|
+ final bytes = image.buffer.asUint8List();
|
|
|
|
+ await tester.pasteContent(image: ('jpeg', bytes), (editorState) {
|
|
|
|
+ expect(editorState.document.root.children.length, 2);
|
|
|
|
+ final node = editorState.getNodeAtPath([0])!;
|
|
|
|
+ expect(node.type, ImageBlockKeys.type);
|
|
|
|
+ expect(node.attributes[ImageBlockKeys.url], isNotNull);
|
|
|
|
+ });
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ testWidgets('paste image(gif) from memory', (tester) async {
|
|
|
|
+ // It's not supported yet.
|
|
|
|
+ // final image = await rootBundle.load('assets/test/images/sample.gif');
|
|
|
|
+ // final bytes = image.buffer.asUint8List();
|
|
|
|
+ // await tester.pasteContent(image: ('gif', bytes), (editorState) {
|
|
|
|
+ // expect(editorState.document.root.children.length, 2);
|
|
|
|
+ // final node = editorState.getNodeAtPath([0])!;
|
|
|
|
+ // expect(node.type, ImageBlockKeys.type);
|
|
|
|
+ // expect(node.attributes[ImageBlockKeys.url], isNotNull);
|
|
|
|
+ // });
|
|
|
|
+ });
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+extension on WidgetTester {
|
|
|
|
+ Future<void> pasteContent(
|
|
|
|
+ void Function(EditorState editorState) test, {
|
|
|
|
+ String? plainText,
|
|
|
|
+ String? html,
|
|
|
|
+ (String, Uint8List?)? image,
|
|
|
|
+ }) async {
|
|
|
|
+ await initializeAppFlowy();
|
|
|
|
+ await tapGoButton();
|
|
|
|
+
|
|
|
|
+ // create a new document
|
|
|
|
+ await createNewPageWithName();
|
|
|
|
+
|
|
|
|
+ // mock the clipboard
|
|
|
|
+ getIt<ClipboardService>().setData(
|
|
|
|
+ ClipboardServiceData(
|
|
|
|
+ plainText: plainText,
|
|
|
|
+ html: html,
|
|
|
|
+ image: image,
|
|
|
|
+ ),
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ // paste the text
|
|
|
|
+ await simulateKeyEvent(
|
|
|
|
+ LogicalKeyboardKey.keyV,
|
|
|
|
+ isControlPressed: Platform.isLinux || Platform.isWindows,
|
|
|
|
+ isMetaPressed: Platform.isMacOS,
|
|
|
|
+ );
|
|
|
|
+ await pumpAndSettle();
|
|
|
|
+
|
|
|
|
+ final editorState = editor.getCurrentEditorState();
|
|
|
|
+ test(editorState);
|
|
|
|
+ }
|
|
}
|
|
}
|