Unverified Commit e070417a authored by Bruno Leroux's avatar Bruno Leroux Committed by GitHub

Add 'Share' button to the selection toolbar on Android (#139479)

## Description

This PR adds the 'Share' button to the text selection toolbar on Android.

## Related Issue

Fixes https://github.com/flutter/flutter/issues/138728

## Tests

Refactor a lot of existing tests in order to:
- make them more readable (avoid duplication by introducing helper functions, specify explictly check which buttons are expected).
- make them more accurate (check that expected buttons are visible instead of just checking the number of buttons).

For instance, previous tests contained sections such as:

```dart

      // Collapsed toolbar shows 3 buttons.
      expect(
        find.byType(CupertinoButton),
        isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(6) : findsNWidgets(3)
      );

```

Where the comment is obsolete, the two cases (6 widgets and 3 widgets) are not explicit (which buttons are expected?), and not accurate (will pass if the number of buttons is right but the buttons are the wrong ones).
parent c6741614
......@@ -226,7 +226,7 @@ class AdaptiveTextSelectionToolbar extends StatelessWidget {
case ContextMenuButtonType.searchWeb:
return localizations.searchWebButtonLabel;
case ContextMenuButtonType.share:
return localizations.searchWebButtonLabel;
return localizations.shareButtonLabel;
case ContextMenuButtonType.liveTextInput:
return localizations.scanTextButtonLabel;
case ContextMenuButtonType.custom:
......
......@@ -1882,6 +1882,10 @@ class EditableText extends StatefulWidget {
// If the paste button is enabled, don't render anything until the state
// of the clipboard is known, since it's used to determine if paste is
// shown.
// On Android, the share button is before the select all button.
final bool showShareBeforeSelectAll = defaultTargetPlatform == TargetPlatform.android;
resultButtonItem.addAll(<ContextMenuButtonItem>[
if (onCut != null)
ContextMenuButtonItem(
......@@ -1898,6 +1902,11 @@ class EditableText extends StatefulWidget {
onPressed: onPaste,
type: ContextMenuButtonType.paste,
),
if (onShare != null && showShareBeforeSelectAll)
ContextMenuButtonItem(
onPressed: onShare,
type: ContextMenuButtonType.share,
),
if (onSelectAll != null)
ContextMenuButtonItem(
onPressed: onSelectAll,
......@@ -1913,7 +1922,7 @@ class EditableText extends StatefulWidget {
onPressed: onSearchWeb,
type: ContextMenuButtonType.searchWeb,
),
if (onShare != null)
if (onShare != null && !showShareBeforeSelectAll)
ContextMenuButtonItem(
onPressed: onShare,
type: ContextMenuButtonType.share,
......@@ -2300,13 +2309,18 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
@override
bool get shareEnabled {
if (defaultTargetPlatform != TargetPlatform.iOS) {
return false;
switch (defaultTargetPlatform) {
case TargetPlatform.android:
case TargetPlatform.iOS:
return !widget.obscureText
&& !textEditingValue.selection.isCollapsed
&& textEditingValue.selection.textInside(textEditingValue.text).trim() != '';
case TargetPlatform.macOS:
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.windows:
return false;
}
return !widget.obscureText
&& !textEditingValue.selection.isCollapsed
&& textEditingValue.selection.textInside(textEditingValue.text).trim() != '';
}
@override
......@@ -2516,9 +2530,9 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
}
/// Launch the share interface for the current selection,
/// as in the "Share" edit menu button on iOS.
/// as in the "Share..." edit menu button on iOS.
///
/// Currently this is only implemented for iOS.
/// Currently this is only implemented for iOS and Android.
///
/// When 'obscureText' is true or the selection is empty,
/// this function will not do anything
......
......@@ -10,6 +10,7 @@ import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
import '../widgets/clipboard_utils.dart';
import '../widgets/live_text_utils.dart';
import '../widgets/text_selection_toolbar_utils.dart';
void main() {
final MockClipboard mockClipboard = MockClipboard();
......@@ -31,13 +32,6 @@ void main() {
);
});
Finder findOverflowNextButton() {
return find.byWidgetPredicate((Widget widget) =>
widget is CustomPaint &&
'${widget.painter?.runtimeType}' == '_RightCupertinoChevronPainter',
);
}
testWidgetsWithLeakTracking('Builds the right toolbar on each platform, including web, and shows buttonItems', (WidgetTester tester) async {
const String buttonText = 'Click me';
......@@ -188,27 +182,55 @@ void main() {
));
expect(find.byKey(key), findsOneWidget);
expect(find.text('Copy'), findsOneWidget);
expect(find.text('Cut'), findsOneWidget);
expect(find.text('Select All'), findsOneWidget);
expect(find.text('Paste'), findsOneWidget);
expect(find.text('Look Up'), findsOneWidget);
switch (defaultTargetPlatform) {
case TargetPlatform.android:
expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(6));
expect(find.text('Cut'), findsOneWidget);
expect(find.text('Copy'), findsOneWidget);
expect(find.text('Paste'), findsOneWidget);
expect(find.text('Select All'), findsOneWidget);
expect(find.text('Share...'), findsOneWidget);
expect(findCupertinoOverflowNextButton(), findsOneWidget);
await tapCupertinoOverflowNextButton(tester);
expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(4));
expect(findCupertinoOverflowBackButton(), findsOneWidget);
expect(find.text('Look Up'), findsOneWidget);
expect(find.text('Search Web'), findsOneWidget);
expect(findLiveTextButton(), findsOneWidget);
case TargetPlatform.fuchsia:
expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(6));
case TargetPlatform.iOS:
expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(6));
expect(findOverflowNextButton(), findsOneWidget);
await tester.tapAt(tester.getCenter(findOverflowNextButton()));
await tester.pumpAndSettle();
expect(find.text('Cut'), findsOneWidget);
expect(find.text('Copy'), findsOneWidget);
expect(find.text('Paste'), findsOneWidget);
expect(find.text('Select All'), findsOneWidget);
expect(find.text('Look Up'), findsOneWidget);
expect(findCupertinoOverflowNextButton(), findsOneWidget);
await tapCupertinoOverflowNextButton(tester);
expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(4));
expect(findCupertinoOverflowBackButton(), findsOneWidget);
expect(find.text('Search Web'), findsOneWidget);
expect(find.text('Share...'), findsOneWidget);
expect(findLiveTextButton(), findsOneWidget);
case TargetPlatform.macOS:
case TargetPlatform.linux:
case TargetPlatform.windows:
expect(find.byType(CupertinoDesktopTextSelectionToolbarButton), findsNWidgets(8));
expect(find.text('Cut'), findsOneWidget);
expect(find.text('Copy'), findsOneWidget);
expect(find.text('Paste'), findsOneWidget);
expect(find.text('Select All'), findsOneWidget);
expect(find.text('Share...'), findsOneWidget);
expect(find.text('Look Up'), findsOneWidget);
expect(find.text('Search Web'), findsOneWidget);
expect(findLiveTextButton(), findsOneWidget);
}
},
skip: kIsWeb, // [intended] on web the browser handles the context menu.
......
......@@ -11,6 +11,7 @@ import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
import '../widgets/clipboard_utils.dart';
import '../widgets/editable_text_utils.dart';
import '../widgets/live_text_utils.dart';
import '../widgets/text_selection_toolbar_utils.dart';
void main() {
final MockClipboard mockClipboard = MockClipboard();
......@@ -26,13 +27,6 @@ void main() {
await Clipboard.setData(const ClipboardData(text: 'Clipboard data'));
});
Finder findOverflowNextButton() {
return find.byWidgetPredicate((Widget widget) =>
widget is CustomPaint &&
'${widget.painter?.runtimeType}' == '_RightCupertinoChevronPainter',
);
}
testWidgetsWithLeakTracking('Builds the right toolbar on each platform, including web, and shows buttonItems', (WidgetTester tester) async {
const String buttonText = 'Click me';
......@@ -206,30 +200,74 @@ void main() {
);
expect(find.byKey(key), findsOneWidget);
expect(find.text('Copy'), findsOneWidget);
expect(find.text('Cut'), findsOneWidget);
expect(find.text('Paste'), findsOneWidget);
switch (defaultTargetPlatform) {
case TargetPlatform.android:
expect(find.text('Select all'), findsOneWidget);
expect(find.byType(TextSelectionToolbarTextButton), findsNWidgets(6));
case TargetPlatform.fuchsia:
expect(find.text('Cut'), findsOneWidget);
expect(find.text('Copy'), findsOneWidget);
expect(find.text('Paste'), findsOneWidget);
expect(find.text('Share'), findsOneWidget);
expect(find.text('Select all'), findsOneWidget);
expect(find.byType(TextSelectionToolbarTextButton), findsNWidgets(8));
expect(find.text('Look Up'), findsOneWidget);
expect(findMaterialOverflowNextButton(), findsOneWidget); // Material overflow buttons are not TextSelectionToolbarTextButton.
await tapMaterialOverflowNextButton(tester);
expect(find.byType(TextSelectionToolbarTextButton), findsNWidgets(2));
expect(find.text('Search Web'), findsOneWidget);
expect(findLiveTextButton(), findsOneWidget);
expect(findMaterialOverflowBackButton(), findsOneWidget); // Material overflow buttons are not TextSelectionToolbarTextButton.
case TargetPlatform.iOS:
expect(find.text('Select All'), findsOneWidget);
expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(6));
await tester.tapAt(tester.getCenter(findOverflowNextButton()));
await tester.pumpAndSettle();
expect(find.text('Cut'), findsOneWidget);
expect(find.text('Copy'), findsOneWidget);
expect(find.text('Paste'), findsOneWidget);
expect(find.text('Select All'), findsOneWidget);
expect(find.text('Look Up'), findsOneWidget);
expect(findCupertinoOverflowNextButton(), findsOneWidget);
await tapCupertinoOverflowNextButton(tester);
expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(4));
expect(findCupertinoOverflowBackButton(), findsOneWidget);
expect(find.text('Search Web'), findsOneWidget);
expect(find.text('Share...'), findsOneWidget);
expect(findLiveTextButton(), findsOneWidget);
case TargetPlatform.fuchsia:
expect(find.byType(TextSelectionToolbarTextButton), findsNWidgets(8));
expect(find.text('Cut'), findsOneWidget);
expect(find.text('Copy'), findsOneWidget);
expect(find.text('Paste'), findsOneWidget);
expect(find.text('Select all'), findsOneWidget);
expect(find.text('Look Up'), findsOneWidget);
expect(find.text('Search Web'), findsOneWidget);
expect(find.text('Share'), findsOneWidget);
case TargetPlatform.linux:
case TargetPlatform.windows:
expect(find.text('Select all'), findsOneWidget);
expect(find.byType(DesktopTextSelectionToolbarButton), findsNWidgets(8));
expect(find.text('Cut'), findsOneWidget);
expect(find.text('Copy'), findsOneWidget);
expect(find.text('Paste'), findsOneWidget);
expect(find.text('Select all'), findsOneWidget);
expect(find.text('Look Up'), findsOneWidget);
expect(find.text('Search Web'), findsOneWidget);
expect(find.text('Share'), findsOneWidget);
expect(findLiveTextButton(), findsOneWidget);
case TargetPlatform.macOS:
expect(find.text('Select All'), findsOneWidget);
expect(find.byType(CupertinoDesktopTextSelectionToolbarButton), findsNWidgets(8));
expect(find.text('Cut'), findsOneWidget);
expect(find.text('Copy'), findsOneWidget);
expect(find.text('Paste'), findsOneWidget);
expect(find.text('Select All'), findsOneWidget);
expect(find.text('Look Up'), findsOneWidget);
expect(find.text('Search Web'), findsOneWidget);
expect(find.text('Share...'), findsOneWidget);
expect(findLiveTextButton(), findsOneWidget);
}
},
skip: kIsWeb, // [intended] on web the browser handles the context menu.
......
......@@ -407,8 +407,9 @@ void main() {
expect(find.text('Cut'), findsNothing);
expect(find.text('Copy'), findsNothing);
expect(find.text('Paste'), findsNothing);
expect(find.text('Share'), findsNothing);
expect(find.text('Select all'), findsNothing);
expect(find.byType(IconButton), findsNothing);
expect(find.byType(IconButton), findsNothing); // 'More' button.
// Tap to place the cursor and tap again to show the menu without a
// selection.
......@@ -426,6 +427,7 @@ void main() {
expect(find.text('Cut'), findsNothing);
expect(find.text('Copy'), findsNothing);
expect(find.text('Paste'), findsOneWidget);
expect(find.text('Share'), findsNothing);
expect(find.text('Select all'), findsOneWidget);
expect(find.byType(IconButton), findsNothing);
......@@ -436,8 +438,9 @@ void main() {
expect(find.text('Cut'), findsOneWidget);
expect(find.text('Copy'), findsOneWidget);
expect(find.text('Paste'), findsOneWidget);
expect(find.text('Share'), findsNothing);
expect(find.text('Select all'), findsNothing);
expect(find.byType(IconButton), findsNothing);
expect(find.byType(IconButton), findsOneWidget); // 'More' button.
final Offset cutOffset = tester.getTopLeft(find.text('Cut'));
// Tap to clear the selection.
......@@ -447,37 +450,39 @@ void main() {
expect(find.text('Copy'), findsNothing);
expect(find.text('Paste'), findsNothing);
expect(find.text('Select all'), findsNothing);
expect(find.byType(IconButton), findsNothing);
expect(find.byType(IconButton), findsNothing); // 'More' button.
// Long press to show the menu.
await tester.longPressAt(textOffsetToPosition(tester, 1));
await tester.pumpAndSettle();
// The last button is missing, and a more button is shown.
// The last buttons (share and select all) are missing, and a more button is shown.
expect(find.text('Cut'), findsOneWidget);
expect(find.text('Copy'), findsOneWidget);
expect(find.text('Paste'), findsOneWidget);
expect(find.text('Share'), findsNothing);
expect(find.text('Select all'), findsNothing);
expect(find.byType(IconButton), findsOneWidget);
expect(find.byType(IconButton), findsOneWidget); // 'More' button.
// Tapping the button shows the overflow menu.
// Tapping the more button shows the overflow menu.
await tester.tap(find.byType(IconButton));
await tester.pumpAndSettle();
expect(find.text('Cut'), findsNothing);
expect(find.text('Copy'), findsNothing);
expect(find.text('Paste'), findsNothing);
expect(find.text('Share'), findsOneWidget);
expect(find.text('Select all'), findsOneWidget);
expect(find.byType(IconButton), findsOneWidget);
expect(find.byType(IconButton), findsOneWidget); // Back button.
// Tapping Select all changes the menu items so that there is no longer
// any overflow.
// Tapping 'Select all' closes the overflow menu.
await tester.tap(find.text('Select all'));
await tester.pumpAndSettle();
expect(find.text('Cut'), findsOneWidget);
expect(find.text('Copy'), findsOneWidget);
expect(find.text('Paste'), findsOneWidget);
expect(find.text('Share'), findsNothing);
expect(find.text('Select all'), findsNothing);
expect(find.byType(IconButton), findsNothing);
expect(find.byType(IconButton), findsOneWidget); // 'More' button.
final Offset newCutOffset = tester.getTopLeft(find.text('Cut'));
expect(newCutOffset, equals(cutOffset));
},
......
......@@ -2,8 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
/// A mock class to control the return result of Live Text input functions.
......@@ -34,7 +35,23 @@ class LiveTextInputTester {
}
/// A function to find the live text button.
Finder findLiveTextButton() => find.byWidgetPredicate((Widget widget) =>
widget is CustomPaint &&
'${widget.painter?.runtimeType}' == '_LiveTextIconPainter',
);
///
/// LiveText button is displayed either using a custom painter,
/// a Text with an empty label, or a Text with the 'Scan text' label.
Finder findLiveTextButton() {
final bool isMobile = defaultTargetPlatform == TargetPlatform.android ||
defaultTargetPlatform == TargetPlatform.fuchsia ||
defaultTargetPlatform == TargetPlatform.iOS;
if (isMobile) {
return find.byWidgetPredicate((Widget widget) {
return (widget is CustomPaint && '${widget.painter?.runtimeType}' == '_LiveTextIconPainter')
|| (widget is Text && widget.data == 'Scan text'); // Android and Fuchsia when inside a MaterialApp.
});
}
if (defaultTargetPlatform == TargetPlatform.macOS) {
return find.ancestor(of: find.text(''), matching: find.byType(CupertinoDesktopTextSelectionToolbarButton));
}
return find.byWidgetPredicate((Widget widget) {
return widget is Text && (widget.data == '' || widget.data == 'Scan text');
});
}
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/src/foundation/platform.dart';
import 'package:flutter_test/flutter_test.dart';
import '../widgets/editable_text_utils.dart';
Finder findCupertinoOverflowNextButton() {
return find.byWidgetPredicate((Widget widget) {
return widget is CustomPaint && '${widget.painter?.runtimeType}' == '_RightCupertinoChevronPainter';
});
}
Finder findCupertinoOverflowBackButton() {
return find.byWidgetPredicate((Widget widget) {
return widget is CustomPaint && '${widget.painter?.runtimeType}' == '_LeftCupertinoChevronPainter';
});
}
Future<void> tapCupertinoOverflowNextButton(WidgetTester tester) async{
await tester.tapAt(tester.getCenter(findCupertinoOverflowNextButton()));
await tester.pumpAndSettle();
}
void expectNoCupertinoToolbar() {
expect(find.byType(CupertinoButton), findsNothing);
}
// Check that the Cupertino text selection toolbars show the expected buttons
// when the content is partially selected.
void expectCupertinoToolbarForPartialSelection() {
if (isContextMenuProvidedByPlatform) {
expectNoCupertinoToolbar();
return;
}
switch (defaultTargetPlatform) {
case TargetPlatform.android:
expect(find.byType(CupertinoButton), findsNWidgets(5));
expect(find.text('Cut'), findsOneWidget);
expect(find.text('Copy'), findsOneWidget);
expect(find.text('Paste'), findsOneWidget);
expect(find.text('Share...'), findsOneWidget);
expect(find.text('Select All'), findsOneWidget);
case TargetPlatform.iOS:
expect(find.byType(CupertinoButton), findsNWidgets(6));
expect(find.text('Cut'), findsOneWidget);
expect(find.text('Copy'), findsOneWidget);
expect(find.text('Paste'), findsOneWidget);
expect(find.text('Share...'), findsOneWidget);
expect(find.text('Look Up'), findsOneWidget);
expect(find.text('Search Web'), findsOneWidget);
case TargetPlatform.macOS:
expect(find.byType(CupertinoButton), findsNWidgets(3));
expect(find.text('Cut'), findsOneWidget);
expect(find.text('Copy'), findsOneWidget);
expect(find.text('Paste'), findsOneWidget);
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.windows:
expect(find.byType(CupertinoButton), findsNWidgets(4));
expect(find.text('Cut'), findsOneWidget);
expect(find.text('Copy'), findsOneWidget);
expect(find.text('Paste'), findsOneWidget);
expect(find.text('Select All'), findsOneWidget);
}
}
// Check that the Cupertino text selection toolbar shows the expected buttons
// when the content is fully selected.
void expectCupertinoToolbarForFullSelection() {
if (isContextMenuProvidedByPlatform) {
expectNoCupertinoToolbar();
return;
}
switch (defaultTargetPlatform) {
case TargetPlatform.android:
expect(find.byType(CupertinoButton), findsNWidgets(4));
expect(find.text('Cut'), findsOneWidget);
expect(find.text('Copy'), findsOneWidget);
expect(find.text('Paste'), findsOneWidget);
expect(find.text('Share...'), findsOneWidget);
case TargetPlatform.iOS:
expect(find.byType(CupertinoButton), findsNWidgets(6));
expect(find.text('Cut'), findsOneWidget);
expect(find.text('Copy'), findsOneWidget);
expect(find.text('Paste'), findsOneWidget);
expect(find.text('Share...'), findsOneWidget);
expect(find.text('Look Up'), findsOneWidget);
expect(find.text('Search Web'), findsOneWidget);
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.macOS:
case TargetPlatform.windows:
expect(find.byType(CupertinoButton), findsNWidgets(3));
expect(find.text('Cut'), findsOneWidget);
expect(find.text('Copy'), findsOneWidget);
expect(find.text('Paste'), findsOneWidget);
}
}
// Check that the Cupertino text selection toolbar is correct for a collapsed selection.
void expectCupertinoToolbarForCollapsedSelection() {
if (isContextMenuProvidedByPlatform) {
expectNoCupertinoToolbar();
return;
}
switch (defaultTargetPlatform) {
case TargetPlatform.android:
expect(find.byType(CupertinoButton), findsNWidgets(4));
expect(find.text('Cut'), findsOneWidget);
expect(find.text('Copy'), findsOneWidget);
expect(find.text('Paste'), findsOneWidget);
expect(find.text('Share...'), findsOneWidget);
case TargetPlatform.iOS:
expect(find.byType(CupertinoButton), findsNWidgets(2));
expect(find.text('Paste'), findsOneWidget);
expect(find.text('Select All'), findsOneWidget);
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.windows:
case TargetPlatform.macOS:
expect(find.byType(CupertinoButton), findsNWidgets(1));
expect(find.text('Paste'), findsOneWidget);
}
}
void expectNoMaterialToolbar() {
expect(find.byType(TextButton), findsNothing);
}
// Check that the Material text selection toolbars show the expected buttons
// when the content is partially selected.
void expectMaterialToolbarForPartialSelection() {
if (isContextMenuProvidedByPlatform) {
expectNoMaterialToolbar();
return;
}
switch (defaultTargetPlatform) {
case TargetPlatform.android:
expect(find.byType(TextButton), findsNWidgets(5));
expect(find.text('Cut'), findsOneWidget);
expect(find.text('Copy'), findsOneWidget);
expect(find.text('Paste'), findsOneWidget);
expect(find.text('Share'), findsOneWidget);
expect(find.text('Select all'), findsOneWidget);
case TargetPlatform.iOS:
case TargetPlatform.macOS:
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.windows:
expect(find.byType(TextButton), findsNWidgets(4));
expect(find.text('Cut'), findsOneWidget);
expect(find.text('Copy'), findsOneWidget);
expect(find.text('Paste'), findsOneWidget);
expect(find.text('Select all'), findsOneWidget);
}
}
// Check that the Material text selection toolbar shows the expected buttons
// when the content is fully selected.
void expectMaterialToolbarForFullSelection() {
if (isContextMenuProvidedByPlatform) {
expectNoMaterialToolbar();
return;
}
switch (defaultTargetPlatform) {
case TargetPlatform.android:
expect(find.byType(TextButton), findsNWidgets(4));
expect(find.text('Cut'), findsOneWidget);
expect(find.text('Copy'), findsOneWidget);
expect(find.text('Paste'), findsOneWidget);
expect(find.text('Share'), findsOneWidget);
case TargetPlatform.iOS:
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.macOS:
case TargetPlatform.windows:
expect(find.byType(TextButton), findsNWidgets(3));
expect(find.text('Cut'), findsOneWidget);
expect(find.text('Copy'), findsOneWidget);
expect(find.text('Paste'), findsOneWidget);
}
}
Finder findMaterialOverflowNextButton() {
return find.byIcon(Icons.more_vert);
}
Finder findMaterialOverflowBackButton() {
return find.byIcon(Icons.arrow_back);
}
Future<void> tapMaterialOverflowNextButton(WidgetTester tester) async {
await tester.tapAt(tester.getCenter(findMaterialOverflowNextButton()));
await tester.pumpAndSettle();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment