import 'dart:ui'; import 'package:appflowy_backend/log.dart'; import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/plugins/document/presentation/share/share_button.dart'; import 'package:appflowy/user/presentation/skip_log_in_screen.dart'; import 'package:appflowy/workspace/presentation/home/menu/app/header/add_button.dart'; import 'package:appflowy/workspace/presentation/home/menu/app/section/item.dart'; import 'package:appflowy/workspace/presentation/settings/widgets/settings_language_view.dart'; import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flowy_infra_ui/widget/buttons/primary_button.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'util.dart'; extension CommonOperations on WidgetTester { /// Get current file location of AppFlowy. Future currentFileLocation() async { return TestFolder.currentLocation(); } /// Tap the GetStart button on the launch page. Future tapGoButton() async { final goButton = find.byType(GoButton); await tapButton(goButton); } /// Tap the + button on the home page. Future tapAddButton() async { final addButton = find.byType(AddButton); await tapButton(addButton); } /// Tap the create document button. /// /// Must call [tapAddButton] first. Future tapCreateDocumentButton() async { await tapButtonWithName(LocaleKeys.document_menuName.tr()); } /// Tap the create grid button. /// /// Must call [tapAddButton] first. Future tapCreateGridButton() async { await tapButtonWithName(LocaleKeys.grid_menuName.tr()); } /// Tap the import button. /// /// Must call [tapAddButton] first. Future tapImportButton() async { await tapButtonWithName(LocaleKeys.moreAction_import.tr()); } /// Tap the import from text & markdown button. /// /// Must call [tapImportButton] first. Future tapTextAndMarkdownButton() async { await tapButtonWithName(LocaleKeys.importPanel_textAndMarkdown.tr()); } /// Tap the LanguageSelectorOnWelcomePage widget on the launch page. Future tapLanguageSelectorOnWelcomePage() async { final languageSelector = find.byType(LanguageSelectorOnWelcomePage); await tapButton(languageSelector); } /// Tap languageItem on LanguageItemsListView. /// /// [scrollDelta] is the distance to scroll the ListView. /// Default value is 100 /// /// If it is positive -> scroll down. /// /// If it is negative -> scroll up. Future tapLanguageItem({ required String languageCode, String? countryCode, double? scrollDelta, }) async { final languageItemsListView = find.descendant( of: find.byType(ListView), matching: find.byType(Scrollable), ); final languageItem = find.byWidgetPredicate( (widget) => widget is LanguageItem && widget.locale.languageCode == languageCode && widget.locale.countryCode == countryCode, ); // scroll the ListView until zHCNLanguageItem shows on the screen. await scrollUntilVisible( languageItem, scrollDelta ?? 100, scrollable: languageItemsListView, // maxHeight of LanguageItemsListView maxScrolls: 400, ); try { await tapButton(languageItem); } on FlutterError catch (e) { Log.warn('tapLanguageItem error: $e'); } } /// Hover on the widget. Future hoverOnWidget( Finder finder, { Offset? offset, Future Function()? onHover, }) async { try { final gesture = await createGesture(kind: PointerDeviceKind.mouse); await gesture.addPointer(location: Offset.zero); await pump(); await gesture.moveTo(offset ?? getCenter(finder)); await pumpAndSettle(); await onHover?.call(); await gesture.removePointer(); } catch (err) { Log.error('hoverOnWidget error: $err'); } } /// Hover on the page name. Future hoverOnPageName( String name, { Future Function()? onHover, bool useLast = true, }) async { if (useLast) { await hoverOnWidget(findPageName(name).last, onHover: onHover); } else { await hoverOnWidget(findPageName(name).first, onHover: onHover); } } /// open the page with given name. Future openPage(String name) async { await tapButton(findPageName(name)); } /// Tap the ... button beside the page name. /// /// Must call [hoverOnPageName] first. Future tapPageOptionButton() async { final optionButton = find.byType(ViewDisclosureButton); await tapButton(optionButton); } /// Tap the delete page button. Future tapDeletePageButton() async { await tapPageOptionButton(); await tapButtonWithName(ViewDisclosureAction.delete.name); } /// Tap the rename page button. Future tapRenamePageButton() async { await tapPageOptionButton(); await tapButtonWithName(ViewDisclosureAction.rename.name); } /// Rename the page. Future renamePage(String name) async { await tapRenamePageButton(); await enterText(find.byType(TextFormField), name); await tapOKButton(); } Future tapOKButton() async { final okButton = find.byWidgetPredicate( (widget) => widget is PrimaryTextButton && widget.label == LocaleKeys.button_OK.tr(), ); await tapButton(okButton); } /// Tap the restore button. /// /// the restore button will show after the current page is deleted. Future tapRestoreButton() async { final restoreButton = find.textContaining( LocaleKeys.deletePagePrompt_restore.tr(), ); await tapButton(restoreButton); } /// Tap the delete permanently button. /// /// the restore button will show after the current page is deleted. Future tapDeletePermanentlyButton() async { final restoreButton = find.textContaining( LocaleKeys.deletePagePrompt_deletePermanent.tr(), ); await tapButton(restoreButton); } /// Tap the share button above the document page. Future tapShareButton() async { final shareButton = find.byWidgetPredicate( (widget) => widget is DocumentShareButton, ); await tapButton(shareButton); } /// Tap the export markdown button /// /// Must call [tapShareButton] first. Future tapMarkdownButton() async { final markdownButton = find.textContaining( LocaleKeys.shareAction_markdown.tr(), ); await tapButton(markdownButton); } Future createNewPageWithName(ViewLayoutPB layout, String name) async { // create a new page await tapAddButton(); await tapButtonWithName(layout.menuName); await pumpAndSettle(); // hover on it and change it's name await hoverOnPageName( LocaleKeys.menuAppHeader_defaultNewPageName.tr(), onHover: () async { await renamePage(name); await pumpAndSettle(); }, ); await pumpAndSettle(); } } extension ViewLayoutPBTest on ViewLayoutPB { String get menuName { switch (this) { case ViewLayoutPB.Grid: return LocaleKeys.grid_menuName.tr(); case ViewLayoutPB.Board: return LocaleKeys.board_menuName.tr(); case ViewLayoutPB.Document: return LocaleKeys.document_menuName.tr(); case ViewLayoutPB.Calendar: return LocaleKeys.calendar_menuName.tr(); default: throw UnsupportedError('Unsupported layout: $this'); } } String get referencedMenuName { switch (this) { case ViewLayoutPB.Grid: return LocaleKeys.document_plugins_referencedGrid.tr(); case ViewLayoutPB.Board: return LocaleKeys.document_plugins_referencedBoard.tr(); case ViewLayoutPB.Calendar: return LocaleKeys.document_plugins_referencedCalendar.tr(); default: throw UnsupportedError('Unsupported layout: $this'); } } }