Ver Fonte

Tests for toolbar (#1006)

* fix: fix linux build

* Merge pull request #599 from AppFlowy-IO/refactor/grid_decode_cell_data

Refactor/grid decode cell data

* test: 🧪 tests for toolbar widget

* fix: removed multiText & replaced with single line

* refactor: cleaned up code & removed unused imports

* fix: fix some tests about the toolbar service

Co-authored-by: Nathan.fooo <[email protected]>
Co-authored-by: Lucas.Xu <[email protected]>
Sean Riley Hawkins há 2 anos atrás
pai
commit
1f9686dc66

+ 1 - 1
frontend/app_flowy/packages/appflowy_editor/lib/src/render/rich_text/rich_text_style.dart

@@ -49,6 +49,7 @@ class StyleKey {
     StyleKey.strikethrough,
     StyleKey.strikethrough,
     StyleKey.backgroundColor,
     StyleKey.backgroundColor,
     StyleKey.href,
     StyleKey.href,
+    StyleKey.code,
   ];
   ];
 
 
   static List<String> globalStyleKeys = [
   static List<String> globalStyleKeys = [
@@ -58,7 +59,6 @@ class StyleKey {
     StyleKey.bulletedList,
     StyleKey.bulletedList,
     StyleKey.numberList,
     StyleKey.numberList,
     StyleKey.quote,
     StyleKey.quote,
-    StyleKey.code,
   ];
   ];
 }
 }
 
 

+ 3 - 0
frontend/app_flowy/packages/appflowy_editor/test/infra/test_editor.dart

@@ -28,6 +28,9 @@ class EditorWidgetTester {
         home: Scaffold(
         home: Scaffold(
           body: AppFlowyEditor(
           body: AppFlowyEditor(
             editorState: _editorState,
             editorState: _editorState,
+            editorStyle: const EditorStyle(
+              padding: EdgeInsets.symmetric(vertical: 30),
+            ),
           ),
           ),
         ),
         ),
       ),
       ),

+ 331 - 0
frontend/app_flowy/packages/appflowy_editor/test/render/rich_text/toolbar_rich_text_test.dart

@@ -0,0 +1,331 @@
+import 'package:appflowy_editor/appflowy_editor.dart';
+import 'package:appflowy_editor/src/extensions/text_node_extensions.dart';
+import 'package:appflowy_editor/src/render/rich_text/rich_text_style.dart';
+import 'package:appflowy_editor/src/render/toolbar/toolbar_item_widget.dart';
+import 'package:appflowy_editor/src/render/toolbar/toolbar_widget.dart';
+import 'package:flutter_test/flutter_test.dart';
+import '../../infra/test_editor.dart';
+
+void main() async {
+  setUpAll(() {
+    TestWidgetsFlutterBinding.ensureInitialized();
+  });
+
+  const singleLineText = "One Line Of Text";
+
+  group('toolbar, heading', (() {
+    testWidgets('Select Text, Click toolbar and set style for h1 heading',
+        (tester) async {
+      final editor = tester.editor..insertTextNode(singleLineText);
+      await editor.startTesting();
+
+      final h1 = Selection(
+          start: Position(path: [0], offset: 0),
+          end: Position(path: [0], offset: singleLineText.length));
+
+      await editor.updateSelection(h1);
+
+      expect(find.byType(ToolbarWidget), findsOneWidget);
+
+      final h1Button = find.byWidgetPredicate((widget) {
+        if (widget is ToolbarItemWidget) {
+          return widget.item.id == 'appflowy.toolbar.h1';
+        }
+        return false;
+      });
+
+      expect(h1Button, findsOneWidget);
+      await tester.tap(h1Button);
+      await tester.pumpAndSettle();
+
+      final node = editor.nodeAtPath([0]) as TextNode;
+      expect(node.attributes.heading, 'h1');
+    });
+
+    testWidgets('Select Text, Click toolbar and set style for h2 heading',
+        (tester) async {
+      final editor = tester.editor..insertTextNode(singleLineText);
+      await editor.startTesting();
+
+      final h2 = Selection(
+          start: Position(path: [0], offset: 0),
+          end: Position(path: [0], offset: singleLineText.length));
+
+      await editor.updateSelection(h2);
+      expect(find.byType(ToolbarWidget), findsOneWidget);
+
+      final h2Button = find.byWidgetPredicate((widget) {
+        if (widget is ToolbarItemWidget) {
+          return widget.item.id == 'appflowy.toolbar.h2';
+        }
+        return false;
+      });
+      expect(h2Button, findsOneWidget);
+      await tester.tap(h2Button);
+      await tester.pumpAndSettle();
+      final node = editor.nodeAtPath([0]) as TextNode;
+      expect(node.attributes.heading, 'h2');
+    });
+
+    testWidgets('Select Text, Click toolbar and set style for h3 heading',
+        (tester) async {
+      final editor = tester.editor..insertTextNode(singleLineText);
+      await editor.startTesting();
+
+      final h3 = Selection(
+          start: Position(path: [0], offset: 0),
+          end: Position(path: [0], offset: singleLineText.length));
+
+      await editor.updateSelection(h3);
+      expect(find.byType(ToolbarWidget), findsOneWidget);
+
+      final h3Button = find.byWidgetPredicate((widget) {
+        if (widget is ToolbarItemWidget) {
+          return widget.item.id == 'appflowy.toolbar.h3';
+        }
+        return false;
+      });
+      expect(h3Button, findsOneWidget);
+      await tester.tap(h3Button);
+      await tester.pumpAndSettle();
+      final node = editor.nodeAtPath([0]) as TextNode;
+      expect(node.attributes.heading, 'h3');
+    });
+  }));
+
+  group('toolbar, underline', (() {
+    testWidgets('Select text, click toolbar and set style for underline',
+        (tester) async {
+      final editor = tester.editor..insertTextNode(singleLineText);
+      await editor.startTesting();
+
+      final underline = Selection(
+          start: Position(path: [0], offset: 0),
+          end: Position(path: [0], offset: singleLineText.length));
+
+      await editor.updateSelection(underline);
+      expect(find.byType(ToolbarWidget), findsOneWidget);
+      final underlineButton = find.byWidgetPredicate((widget) {
+        if (widget is ToolbarItemWidget) {
+          return widget.item.id == 'appflowy.toolbar.underline';
+        }
+        return false;
+      });
+
+      expect(underlineButton, findsOneWidget);
+      await tester.tap(underlineButton);
+      await tester.pumpAndSettle();
+      final node = editor.nodeAtPath([0]) as TextNode;
+      // expect(node.attributes.underline, true);
+      expect(node.allSatisfyUnderlineInSelection(underline), true);
+    });
+  }));
+
+  group('toolbar, bold', (() {
+    testWidgets('Select Text, Click Toolbar and set style for bold',
+        (tester) async {
+      final editor = tester.editor..insertTextNode(singleLineText);
+      await editor.startTesting();
+
+      final bold = Selection(
+          start: Position(path: [0], offset: 0),
+          end: Position(path: [0], offset: singleLineText.length));
+
+      await editor.updateSelection(bold);
+      expect(find.byType(ToolbarWidget), findsOneWidget);
+      final boldButton = find.byWidgetPredicate((widget) {
+        if (widget is ToolbarItemWidget) {
+          return widget.item.id == 'appflowy.toolbar.bold';
+        }
+        return false;
+      });
+
+      expect(boldButton, findsOneWidget);
+      await tester.tap(boldButton);
+      await tester.pumpAndSettle();
+      final node = editor.nodeAtPath([0]) as TextNode;
+      expect(node.allSatisfyBoldInSelection(bold), true);
+    });
+  }));
+
+  group('toolbar, italic', (() {
+    testWidgets('Select Text, Click Toolbar and set style for italic',
+        (tester) async {
+      final editor = tester.editor..insertTextNode(singleLineText);
+      await editor.startTesting();
+
+      final italic = Selection(
+          start: Position(path: [0], offset: 0),
+          end: Position(path: [0], offset: singleLineText.length));
+
+      await editor.updateSelection(italic);
+      expect(find.byType(ToolbarWidget), findsOneWidget);
+      final italicButton = find.byWidgetPredicate((widget) {
+        if (widget is ToolbarItemWidget) {
+          return widget.item.id == 'appflowy.toolbar.italic';
+        }
+        return false;
+      });
+
+      expect(italicButton, findsOneWidget);
+      await tester.tap(italicButton);
+      await tester.pumpAndSettle();
+      final node = editor.nodeAtPath([0]) as TextNode;
+      expect(node.allSatisfyItalicInSelection(italic), true);
+    });
+  }));
+
+  group('toolbar, strikethrough', (() {
+    testWidgets('Select Text, Click Toolbar and set style for strikethrough',
+        (tester) async {
+      final editor = tester.editor..insertTextNode(singleLineText);
+      await editor.startTesting();
+
+      final strikeThrough = Selection(
+          start: Position(path: [0], offset: 0),
+          end: Position(path: [0], offset: singleLineText.length));
+
+      await editor.updateSelection(strikeThrough);
+
+      expect(find.byType(ToolbarWidget), findsOneWidget);
+      final strikeThroughButton = find.byWidgetPredicate((widget) {
+        if (widget is ToolbarItemWidget) {
+          return widget.item.id == 'appflowy.toolbar.strikethrough';
+        }
+        return false;
+      });
+
+      expect(strikeThroughButton, findsOneWidget);
+      await tester.tap(strikeThroughButton);
+      await tester.pumpAndSettle();
+      final node = editor.nodeAtPath([0]) as TextNode;
+      expect(node.allSatisfyStrikethroughInSelection(strikeThrough), true);
+    });
+  }));
+
+  group('toolbar, code', (() {
+    testWidgets('Select Text, Click Toolbar and set style for code',
+        (tester) async {
+      final editor = tester.editor..insertTextNode(singleLineText);
+      await editor.startTesting();
+
+      final code = Selection(
+          start: Position(path: [0], offset: 0),
+          end: Position(path: [0], offset: singleLineText.length));
+
+      await editor.updateSelection(code);
+      expect(find.byType(ToolbarWidget), findsOneWidget);
+      final codeButton = find.byWidgetPredicate((widget) {
+        if (widget is ToolbarItemWidget) {
+          return widget.item.id == 'appflowy.toolbar.code';
+        }
+        return false;
+      });
+
+      expect(codeButton, findsOneWidget);
+      await tester.tap(codeButton);
+      await tester.pumpAndSettle();
+      final node = editor.nodeAtPath([0]) as TextNode;
+      expect(
+        node.allSatisfyInSelection(
+          code,
+          StyleKey.code,
+          (value) {
+            return value == true;
+          },
+        ),
+        true,
+      );
+    });
+  }));
+
+  group('toolbar, quote', (() {
+    testWidgets('Select Text, Click Toolbar and set style for quote',
+        (tester) async {
+      final editor = tester.editor..insertTextNode(singleLineText);
+      await editor.startTesting();
+
+      final quote = Selection(
+          start: Position(path: [0], offset: 0),
+          end: Position(path: [0], offset: singleLineText.length));
+
+      await editor.updateSelection(quote);
+      expect(find.byType(ToolbarWidget), findsOneWidget);
+      final quoteButton = find.byWidgetPredicate((widget) {
+        if (widget is ToolbarItemWidget) {
+          return widget.item.id == 'appflowy.toolbar.quote';
+        }
+        return false;
+      });
+      expect(quoteButton, findsOneWidget);
+      await tester.tap(quoteButton);
+      await tester.pumpAndSettle();
+      final node = editor.nodeAtPath([0]) as TextNode;
+      expect(node.subtype, 'quote');
+    });
+  }));
+
+  group('toolbar, bullet list', (() {
+    testWidgets('Select Text, Click Toolbar and set style for bullet',
+        (tester) async {
+      final editor = tester.editor..insertTextNode(singleLineText);
+      await editor.startTesting();
+
+      final bulletList = Selection(
+          start: Position(path: [0], offset: 0),
+          end: Position(path: [0], offset: singleLineText.length));
+
+      await editor.updateSelection(bulletList);
+      expect(find.byType(ToolbarWidget), findsOneWidget);
+      final bulletListButton = find.byWidgetPredicate((widget) {
+        if (widget is ToolbarItemWidget) {
+          return widget.item.id == 'appflowy.toolbar.bulleted_list';
+        }
+        return false;
+      });
+
+      expect(bulletListButton, findsOneWidget);
+      await tester.tap(bulletListButton);
+      await tester.pumpAndSettle();
+      final node = editor.nodeAtPath([0]) as TextNode;
+      expect(node.subtype, 'bulleted-list');
+    });
+  }));
+
+  group('toolbar, highlight', (() {
+    testWidgets('Select Text, Click Toolbar and set style for highlighted text',
+        (tester) async {
+      // FIXME: Use a const value instead of the magic string.
+      const blue = '0x6000BCF0';
+      final editor = tester.editor..insertTextNode(singleLineText);
+      await editor.startTesting();
+
+      final node = editor.nodeAtPath([0]) as TextNode;
+      final selection = Selection(
+          start: Position(path: [0], offset: 0),
+          end: Position(path: [0], offset: singleLineText.length));
+
+      await editor.updateSelection(selection);
+      expect(find.byType(ToolbarWidget), findsOneWidget);
+      final highlightButton = find.byWidgetPredicate((widget) {
+        if (widget is ToolbarItemWidget) {
+          return widget.item.id == 'appflowy.toolbar.highlight';
+        }
+        return false;
+      });
+      expect(highlightButton, findsOneWidget);
+      await tester.tap(highlightButton);
+      await tester.pumpAndSettle();
+      expect(
+        node.allSatisfyInSelection(
+          selection,
+          StyleKey.backgroundColor,
+          (value) {
+            return value == blue;
+          },
+        ),
+        true,
+      );
+    });
+  }));
+}

+ 10 - 2
frontend/app_flowy/packages/appflowy_editor/test/service/internal_key_event_handlers/page_up_down_handler_test.dart

@@ -40,7 +40,11 @@ void main() async {
         await editor.pressLogicKey(
         await editor.pressLogicKey(
           LogicalKeyboardKey.pageDown,
           LogicalKeyboardKey.pageDown,
         );
         );
-        currentOffsetY += onePageHeight!;
+        if (i == page) {
+          currentOffsetY = scrollService.maxScrollExtent;
+        } else {
+          currentOffsetY += onePageHeight!;
+        }
         final dy = scrollService.dy;
         final dy = scrollService.dy;
         expect(dy, currentOffsetY);
         expect(dy, currentOffsetY);
       }
       }
@@ -58,7 +62,11 @@ void main() async {
         await editor.pressLogicKey(
         await editor.pressLogicKey(
           LogicalKeyboardKey.pageUp,
           LogicalKeyboardKey.pageUp,
         );
         );
-        currentOffsetY -= onePageHeight!;
+        if (i == 1) {
+          currentOffsetY = scrollService.minScrollExtent;
+        } else {
+          currentOffsetY -= onePageHeight!;
+        }
         final dy = editor.editorState.service.scrollService?.dy;
         final dy = editor.editorState.service.scrollService?.dy;
         expect(dy, currentOffsetY);
         expect(dy, currentOffsetY);
       }
       }

+ 2 - 0
frontend/app_flowy/packages/appflowy_editor/test/service/toolbar_service_test.dart

@@ -83,6 +83,8 @@ void main() async {
             key = 'highlight';
             key = 'highlight';
           } else if (styleKey == StyleKey.href) {
           } else if (styleKey == StyleKey.href) {
             key = 'link';
             key = 'link';
+          } else {
+            continue;
           }
           }
           final itemWidget = _itemWidgetForId(tester, 'appflowy.toolbar.$key');
           final itemWidget = _itemWidgetForId(tester, 'appflowy.toolbar.$key');
           expect(itemWidget.isHighlight, expectedValue);
           expect(itemWidget.isHighlight, expectedValue);