mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
This auto-formats all *.dart files in the repository outside of the `engine` subdirectory and enforces that these files stay formatted with a presubmit check. **Reviewers:** Please carefully review all the commits except for the one titled "formatted". The "formatted" commit was auto-generated by running `dev/tools/format.sh -a -f`. The other commits were hand-crafted to prepare the repo for the formatting change. I recommend reviewing the commits one-by-one via the "Commits" tab and avoiding Github's "Files changed" tab as it will likely slow down your browser because of the size of this PR. --------- Co-authored-by: Kate Lovett <katelovett@google.com> Co-authored-by: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com>
273 lines
7.8 KiB
Dart
273 lines
7.8 KiB
Dart
// 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/material.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
import 'clipboard_utils.dart';
|
|
import 'editable_text_utils.dart';
|
|
|
|
void main() {
|
|
final MockClipboard mockClipboard = MockClipboard();
|
|
TestWidgetsFlutterBinding.ensureInitialized().defaultBinaryMessenger.setMockMethodCallHandler(
|
|
SystemChannels.platform,
|
|
mockClipboard.handleMethodCall,
|
|
);
|
|
|
|
setUp(() async {
|
|
// Fill the clipboard so that the Paste option is available in the text
|
|
// selection menu.
|
|
await Clipboard.setData(const ClipboardData(text: 'Clipboard data'));
|
|
});
|
|
|
|
testWidgets('Hides and shows only a single menu', (WidgetTester tester) async {
|
|
final GlobalKey key1 = GlobalKey();
|
|
final GlobalKey key2 = GlobalKey();
|
|
late final BuildContext context;
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
body: Builder(
|
|
builder: (BuildContext localContext) {
|
|
context = localContext;
|
|
return const SizedBox.shrink();
|
|
},
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(find.byKey(key1), findsNothing);
|
|
expect(find.byKey(key2), findsNothing);
|
|
|
|
final ContextMenuController controller1 = ContextMenuController();
|
|
await tester.pump();
|
|
expect(find.byKey(key1), findsNothing);
|
|
expect(find.byKey(key2), findsNothing);
|
|
|
|
controller1.show(
|
|
context: context,
|
|
contextMenuBuilder: (BuildContext context) {
|
|
return Placeholder(key: key1);
|
|
},
|
|
);
|
|
await tester.pump();
|
|
|
|
expect(find.byKey(key1), findsOneWidget);
|
|
expect(find.byKey(key2), findsNothing);
|
|
|
|
// Showing the same thing again does nothing and is not an error.
|
|
controller1.show(
|
|
context: context,
|
|
contextMenuBuilder: (BuildContext context) {
|
|
return Placeholder(key: key1);
|
|
},
|
|
);
|
|
await tester.pump();
|
|
|
|
expect(tester.takeException(), null);
|
|
expect(find.byKey(key1), findsOneWidget);
|
|
expect(find.byKey(key2), findsNothing);
|
|
|
|
// Showing a new menu hides the first.
|
|
final ContextMenuController controller2 = ContextMenuController();
|
|
controller2.show(
|
|
context: context,
|
|
contextMenuBuilder: (BuildContext context) {
|
|
return Placeholder(key: key2);
|
|
},
|
|
);
|
|
await tester.pump();
|
|
|
|
expect(find.byKey(key1), findsNothing);
|
|
expect(find.byKey(key2), findsOneWidget);
|
|
|
|
controller2.remove();
|
|
await tester.pump();
|
|
|
|
expect(find.byKey(key1), findsNothing);
|
|
expect(find.byKey(key2), findsNothing);
|
|
});
|
|
|
|
testWidgets('A menu can be hidden and then reshown', (WidgetTester tester) async {
|
|
final GlobalKey key1 = GlobalKey();
|
|
late final BuildContext context;
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
body: Builder(
|
|
builder: (BuildContext localContext) {
|
|
context = localContext;
|
|
return const SizedBox.shrink();
|
|
},
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(find.byKey(key1), findsNothing);
|
|
|
|
final ContextMenuController controller = ContextMenuController();
|
|
addTearDown(controller.remove);
|
|
|
|
// Instantiating the controller does not shown it.
|
|
await tester.pump();
|
|
expect(find.byKey(key1), findsNothing);
|
|
|
|
controller.show(
|
|
context: context,
|
|
contextMenuBuilder: (BuildContext context) {
|
|
return Placeholder(key: key1);
|
|
},
|
|
);
|
|
await tester.pump();
|
|
|
|
expect(find.byKey(key1), findsOneWidget);
|
|
|
|
controller.remove();
|
|
await tester.pump();
|
|
|
|
expect(find.byKey(key1), findsNothing);
|
|
|
|
controller.show(
|
|
context: context,
|
|
contextMenuBuilder: (BuildContext context) {
|
|
return Placeholder(key: key1);
|
|
},
|
|
);
|
|
await tester.pump();
|
|
|
|
expect(find.byKey(key1), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('markNeedsBuild causes the builder to update', (WidgetTester tester) async {
|
|
int buildCount = 0;
|
|
late final BuildContext context;
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
body: Builder(
|
|
builder: (BuildContext localContext) {
|
|
context = localContext;
|
|
return const SizedBox.shrink();
|
|
},
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
final ContextMenuController controller = ContextMenuController();
|
|
controller.show(
|
|
context: context,
|
|
contextMenuBuilder: (BuildContext context) {
|
|
buildCount++;
|
|
return const Placeholder();
|
|
},
|
|
);
|
|
expect(buildCount, 0);
|
|
await tester.pump();
|
|
expect(buildCount, 1);
|
|
|
|
controller.markNeedsBuild();
|
|
expect(buildCount, 1);
|
|
await tester.pump();
|
|
expect(buildCount, 2);
|
|
|
|
controller.remove();
|
|
});
|
|
|
|
testWidgets(
|
|
'Calling show when a built-in widget is already showing its context menu hides the built-in menu',
|
|
(WidgetTester tester) async {
|
|
final GlobalKey builtInKey = GlobalKey();
|
|
final GlobalKey directKey = GlobalKey();
|
|
late final BuildContext context;
|
|
|
|
final TextEditingController textEditingController = TextEditingController();
|
|
addTearDown(textEditingController.dispose);
|
|
|
|
final FocusNode focusNode = FocusNode();
|
|
addTearDown(focusNode.dispose);
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
body: Builder(
|
|
builder: (BuildContext localContext) {
|
|
context = localContext;
|
|
return EditableText(
|
|
controller: textEditingController,
|
|
backgroundCursorColor: Colors.grey,
|
|
focusNode: focusNode,
|
|
style: const TextStyle(),
|
|
cursorColor: Colors.red,
|
|
selectionControls: materialTextSelectionHandleControls,
|
|
contextMenuBuilder: (BuildContext context, EditableTextState editableTextState) {
|
|
return Placeholder(key: builtInKey);
|
|
},
|
|
);
|
|
},
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(find.byKey(builtInKey), findsNothing);
|
|
expect(find.byKey(directKey), findsNothing);
|
|
|
|
final EditableTextState state = tester.state<EditableTextState>(find.byType(EditableText));
|
|
|
|
await tester.tapAt(textOffsetToPosition(tester, 0));
|
|
await tester.pump();
|
|
expect(state.showToolbar(), true);
|
|
await tester.pump();
|
|
|
|
expect(find.byKey(builtInKey), findsOneWidget);
|
|
expect(find.byKey(directKey), findsNothing);
|
|
|
|
final ContextMenuController controller = ContextMenuController();
|
|
controller.show(
|
|
context: context,
|
|
contextMenuBuilder: (BuildContext context) {
|
|
return Placeholder(key: directKey);
|
|
},
|
|
);
|
|
await tester.pump();
|
|
|
|
expect(find.byKey(builtInKey), findsNothing);
|
|
expect(find.byKey(directKey), findsOneWidget);
|
|
expect(controller.isShown, isTrue);
|
|
|
|
// And showing the built-in menu hides the directly shown menu.
|
|
expect(state.showToolbar(), isTrue);
|
|
await tester.pump();
|
|
|
|
expect(find.byKey(builtInKey), findsOneWidget);
|
|
expect(find.byKey(directKey), findsNothing);
|
|
expect(controller.isShown, isFalse);
|
|
|
|
// Calling remove on the hidden ContextMenuController does not hide the
|
|
// built-in menu.
|
|
controller.remove();
|
|
await tester.pump();
|
|
|
|
expect(find.byKey(builtInKey), findsOneWidget);
|
|
expect(find.byKey(directKey), findsNothing);
|
|
expect(controller.isShown, isFalse);
|
|
|
|
state.hideToolbar();
|
|
await tester.pump();
|
|
expect(find.byKey(builtInKey), findsNothing);
|
|
expect(find.byKey(directKey), findsNothing);
|
|
expect(controller.isShown, isFalse);
|
|
},
|
|
// [intended] no Flutter-drawn text selection toolbar on web.
|
|
skip: isContextMenuProvidedByPlatform,
|
|
);
|
|
}
|