editor_test_operations.dart 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. import 'dart:ui';
  2. import 'package:appflowy/generated/locale_keys.g.dart';
  3. import 'package:appflowy/plugins/document/presentation/editor_plugins/header/cover_editor.dart';
  4. import 'package:appflowy/plugins/document/presentation/editor_plugins/header/document_header_node_widget.dart';
  5. import 'package:appflowy/plugins/document/presentation/editor_plugins/header/emoji_icon_widget.dart';
  6. import 'package:appflowy/plugins/document/presentation/editor_plugins/header/emoji_popover.dart';
  7. import 'package:appflowy_editor/appflowy_editor.dart' hide Log;
  8. import 'package:easy_localization/easy_localization.dart';
  9. import 'package:flutter/services.dart';
  10. import 'package:flutter_test/flutter_test.dart';
  11. import 'ime.dart';
  12. import 'util.dart';
  13. extension EditorWidgetTester on WidgetTester {
  14. EditorOperations get editor => EditorOperations(this);
  15. }
  16. class EditorOperations {
  17. const EditorOperations(this.tester);
  18. final WidgetTester tester;
  19. EditorState getCurrentEditorState() {
  20. return tester
  21. .widget<AppFlowyEditor>(find.byType(AppFlowyEditor))
  22. .editorState;
  23. }
  24. /// Tap the line of editor at [index]
  25. Future<void> tapLineOfEditorAt(int index) async {
  26. final textBlocks = find.byType(FlowyRichText);
  27. index = index.clamp(0, textBlocks.evaluate().length - 1);
  28. await tester.tapAt(tester.getTopRight(textBlocks.at(index)));
  29. await tester.pumpAndSettle();
  30. }
  31. /// Hover on cover plugin button above the document
  32. Future<void> hoverOnCoverToolbar() async {
  33. final coverToolbar = find.byType(DocumentHeaderToolbar);
  34. await tester.startGesture(
  35. tester.getBottomLeft(coverToolbar).translate(5, -5),
  36. kind: PointerDeviceKind.mouse,
  37. );
  38. await tester.pumpAndSettle();
  39. }
  40. /// Taps on the 'Add Icon' button in the cover toolbar
  41. Future<void> tapAddIconButton() async {
  42. await tester.tapButtonWithName(
  43. LocaleKeys.document_plugins_cover_addIcon.tr(),
  44. );
  45. expect(find.byType(EmojiPopover), findsOneWidget);
  46. }
  47. /// Taps the 'Remove Icon' button in the cover toolbar and the icon popover
  48. Future<void> tapRemoveIconButton({bool isInPicker = false}) async {
  49. Finder button =
  50. find.text(LocaleKeys.document_plugins_cover_removeIcon.tr());
  51. if (isInPicker) {
  52. button = find.descendant(of: find.byType(EmojiPopover), matching: button);
  53. }
  54. await tester.tapButton(button);
  55. }
  56. /// Requires that the document must already have an icon. This opens the icon
  57. /// picker
  58. Future<void> tapOnIconWidget() async {
  59. final iconWidget = find.byType(EmojiIconWidget);
  60. await tester.tapButton(iconWidget);
  61. }
  62. Future<void> tapOnAddCover() async {
  63. await tester.tapButtonWithName(
  64. LocaleKeys.document_plugins_cover_addCover.tr(),
  65. );
  66. }
  67. Future<void> tapOnChangeCover() async {
  68. await tester.tapButtonWithName(
  69. LocaleKeys.document_plugins_cover_changeCover.tr(),
  70. );
  71. }
  72. Future<void> switchSolidColorBackground() async {
  73. final findPurpleButton = find.byWidgetPredicate(
  74. (widget) => widget is ColorItem && widget.option.colorHex == "ffe8e0ff",
  75. );
  76. await tester.tapButton(findPurpleButton);
  77. }
  78. Future<void> tapOnRemoveCover() async {
  79. await tester.tapButton(find.byType(DeleteCoverButton));
  80. }
  81. /// A cover must be present in the document to function properly since this
  82. /// catches all cover types collectively
  83. Future<void> hoverOnCover() async {
  84. final cover = find.byType(DocumentCover);
  85. await tester.startGesture(
  86. tester.getCenter(cover),
  87. kind: PointerDeviceKind.mouse,
  88. );
  89. await tester.pumpAndSettle();
  90. }
  91. Future<void> dismissCoverPicker() async {
  92. await tester.sendKeyEvent(LogicalKeyboardKey.escape);
  93. await tester.pumpAndSettle();
  94. }
  95. /// trigger the slash command (selection menu)
  96. Future<void> showSlashMenu() async {
  97. await tester.ime.insertCharacter('/');
  98. }
  99. /// trigger the slash command (selection menu)
  100. Future<void> showAtMenu() async {
  101. await tester.ime.insertCharacter('@');
  102. }
  103. /// Tap the slash menu item with [name]
  104. ///
  105. /// Must call [showSlashMenu] first.
  106. Future<void> tapSlashMenuItemWithName(String name) async {
  107. final slashMenuItem = find.text(name, findRichText: true);
  108. await tester.tapButton(slashMenuItem);
  109. }
  110. /// Tap the at menu item with [name]
  111. ///
  112. /// Must call [showAtMenu] first.
  113. Future<void> tapAtMenuItemWithName(String name) async {
  114. final atMenuItem = find.descendant(
  115. of: find.byType(SelectionMenuWidget),
  116. matching: find.text(name, findRichText: true),
  117. );
  118. await tester.tapButton(atMenuItem);
  119. }
  120. }