Skip to content

Commit

Permalink
Fix tests with out of date MockClipboard, share common one
Browse files Browse the repository at this point in the history
  • Loading branch information
justinmc committed Aug 4, 2021
1 parent cfc4a77 commit 97224a7
Show file tree
Hide file tree
Showing 11 changed files with 86 additions and 306 deletions.
17 changes: 1 addition & 16 deletions packages/flutter/test/cupertino/text_field_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,13 @@ import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';

import '../widgets/clipboard_utils.dart';
import '../rendering/mock_canvas.dart';
import '../widgets/semantics_tester.dart';

// On web, the context menu (aka toolbar) is provided by the browser.
final bool isContextMenuProvidedByPlatform = isBrowser;

class MockClipboard {
Object _clipboardData = <String, dynamic>{
'text': null,
};

Future<dynamic> handleMethodCall(MethodCall methodCall) async {
switch (methodCall.method) {
case 'Clipboard.getData':
return _clipboardData;
case 'Clipboard.setData':
_clipboardData = methodCall.arguments! as Object;
break;
}
}
}

class MockTextSelectionControls extends TextSelectionControls {
@override
Widget buildHandle(BuildContext context, TextSelectionHandleType type, double textLineHeight, [VoidCallback? onTap, double? startGlyphHeight, double? endGlyphHeight]) {
Expand Down
105 changes: 18 additions & 87 deletions packages/flutter/test/cupertino/text_selection_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,9 @@ import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';

import '../widgets/clipboard_utils.dart';
import '../widgets/editable_text_utils.dart' show textOffsetToPosition, findRenderEditable;

class MockClipboard {
Object _clipboardData = <String, dynamic>{
'text': null,
};

Future<dynamic> handleMethodCall(MethodCall methodCall) async {
switch (methodCall.method) {
case 'Clipboard.getData':
return _clipboardData;
case 'Clipboard.setData':
_clipboardData = methodCall.arguments! as Object;
break;
}
}
}

class _LongCupertinoLocalizationsDelegate extends LocalizationsDelegate<CupertinoLocalizations> {
const _LongCupertinoLocalizationsDelegate();

Expand Down Expand Up @@ -69,7 +54,6 @@ const _LongCupertinoLocalizations _longLocalizations = _LongCupertinoLocalizatio
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final MockClipboard mockClipboard = MockClipboard();
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);

// Returns true iff the button is visually enabled.
bool appearsEnabled(WidgetTester tester, String text) {
Expand All @@ -92,6 +76,23 @@ void main() {
}).toList();
}

setUp(() async {
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(
SystemChannels.platform,
mockClipboard.handleMethodCall,
);
// Fill the clipboard so that the Paste option is available in the text
// selection menu.
await Clipboard.setData(const ClipboardData(text: 'Clipboard data'));
});

tearDown(() {
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(
SystemChannels.platform,
null,
);
});

group('canSelectAll', () {
Widget createEditableText({
Key? key,
Expand Down Expand Up @@ -185,76 +186,6 @@ void main() {
});
});

// TODO(justinmc): https://github.com/flutter/flutter/issues/60145
testWidgets('Paste always appears regardless of clipboard content on iOS', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure',
);
await tester.pumpWidget(
CupertinoApp(
home: Column(
children: <Widget>[
CupertinoTextField(
controller: controller,
),
],
),
),
);

// Make sure the clipboard is empty to start.
await Clipboard.setData(const ClipboardData(text: ''));

// Double tap to select the first word.
const int index = 4;
await tester.tapAt(textOffsetToPosition(tester, index));
await tester.pump(const Duration(milliseconds: 50));
await tester.tapAt(textOffsetToPosition(tester, index));
await tester.pumpAndSettle();
expect(controller.selection.isCollapsed, isFalse);
expect(controller.selection.baseOffset, 0);
expect(controller.selection.extentOffset, 7);

// Paste is showing even though clipboard is empty.
expect(find.text('Paste'), findsOneWidget);
expect(find.text('Copy'), findsOneWidget);
expect(find.text('Cut'), findsOneWidget);
expect(find.descendant(
of: find.byType(Overlay),
matching: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_TextSelectionHandleOverlay'),
), findsNWidgets(2));

// Tap copy to add something to the clipboard and close the menu.
await tester.tapAt(tester.getCenter(find.text('Copy')));
await tester.pumpAndSettle();

// The menu is gone, but the handles are visible on the existing selection.
expect(find.text('Copy'), findsNothing);
expect(find.text('Cut'), findsNothing);
expect(find.text('Paste'), findsNothing);
expect(controller.selection.isCollapsed, isFalse);
expect(controller.selection.baseOffset, 0);
expect(controller.selection.extentOffset, 7);
expect(find.descendant(
of: find.byType(Overlay),
matching: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_TextSelectionHandleOverlay'),
), findsNWidgets(2));

// Double tap to show the menu again.
await tester.tapAt(textOffsetToPosition(tester, index));
await tester.pump(const Duration(milliseconds: 50));
await tester.tapAt(textOffsetToPosition(tester, index));
await tester.pumpAndSettle();

// Paste still shows.
expect(find.text('Paste'), findsOneWidget);
expect(find.text('Copy'), findsOneWidget);
expect(find.text('Cut'), findsOneWidget);
},
skip: isBrowser, // [intended] We do not use Flutter-rendered context menu on the Web.
variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS }),
);

group('Text selection menu overflow (iOS)', () {
testWidgets('All menu items show when they fit.', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController(text: 'abc def ghi');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';

import '../widgets/clipboard_utils.dart';

void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final MockClipboard mockClipboard = MockClipboard();
Expand Down Expand Up @@ -301,19 +303,3 @@ void main() {

});
}

class MockClipboard {
dynamic _clipboardData = <String, dynamic>{
'text': null,
};

Future<dynamic> handleMethodCall(MethodCall methodCall) async {
switch (methodCall.method) {
case 'Clipboard.getData':
return _clipboardData;
case 'Clipboard.setData':
_clipboardData = methodCall.arguments;
break;
}
}
}
17 changes: 1 addition & 16 deletions packages/flutter/test/material/search_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,9 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';

import '../widgets/clipboard_utils.dart';
import '../widgets/semantics_tester.dart';

class MockClipboard {
dynamic _clipboardData = <String, dynamic>{
'text': null,
};

Future<dynamic> handleMethodCall(MethodCall methodCall) async {
switch (methodCall.method) {
case 'Clipboard.getData':
return _clipboardData;
case 'Clipboard.setData':
_clipboardData = methodCall.arguments;
break;
}
}
}

void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final MockClipboard mockClipboard = MockClipboard();
Expand Down
39 changes: 15 additions & 24 deletions packages/flutter/test/material/text_field_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';

import '../widgets/clipboard_utils.dart';
import '../widgets/editable_text_utils.dart' show findRenderEditable, globalize, textOffsetToPosition;
import '../widgets/semantics_tester.dart';
import 'feedback_tester.dart';
Expand All @@ -31,22 +32,6 @@ final bool isContextMenuProvidedByPlatform = isBrowser;
// On web, key events in text fields are handled by the browser.
final bool areKeyEventsHandledByPlatform = isBrowser;

class MockClipboard {
Object _clipboardData = <String, dynamic>{
'text': null,
};

Future<dynamic> handleMethodCall(MethodCall methodCall) async {
switch (methodCall.method) {
case 'Clipboard.getData':
return _clipboardData;
case 'Clipboard.setData':
_clipboardData = methodCall.arguments as Object;
break;
}
}
}

class MaterialLocalizationsDelegate extends LocalizationsDelegate<MaterialLocalizations> {
@override
bool isSupported(Locale locale) => true;
Expand Down Expand Up @@ -9579,11 +9564,15 @@ void main() {
),
);

bool triedToReadClipboard = false;
bool calledGetData = false;
bool calledHasStrings = false;
tester.binding.defaultBinaryMessenger
.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
if (methodCall.method == 'Clipboard.getData') {
triedToReadClipboard = true;
calledGetData = true;
}
if (methodCall.method == 'Clipboard.hasStrings') {
calledHasStrings = true;
}
return null;
});
Expand All @@ -9596,14 +9585,16 @@ void main() {
await tester.tapAt(textfieldStart + const Offset(150.0, 9.0));
await tester.pump();

// getData is not called unless something is pasted. hasStrings is used to
// check the status of the clipboard.
expect(calledGetData, false);
if (kIsWeb) {
// The clipboard is not checked because it requires user permissions and
// web doesn't show a custom text selection menu.
expect(triedToReadClipboard, false);
// hasStrings is not checked because web doesn't show a custom text
// selection menu.
expect(calledHasStrings, false);
} else {
// The clipboard is checked in order to decide if the content can be
// pasted.
expect(triedToReadClipboard, true);
// hasStrings is checked in order to decide if the content can be pasted.
expect(calledHasStrings, true);
}
});

Expand Down
17 changes: 1 addition & 16 deletions packages/flutter/test/material/text_form_field_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,10 @@ import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';

import '../widgets/clipboard_utils.dart';
import '../rendering/mock_canvas.dart';
import '../widgets/editable_text_utils.dart';

class MockClipboard {
Object _clipboardData = <String, dynamic>{
'text': null,
};

Future<dynamic> handleMethodCall(MethodCall methodCall) async {
switch (methodCall.method) {
case 'Clipboard.getData':
return _clipboardData;
case 'Clipboard.setData':
_clipboardData = methodCall.arguments as Object;
break;
}
}
}

void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final MockClipboard mockClipboard = MockClipboard();
Expand Down
Loading

0 comments on commit 97224a7

Please sign in to comment.