Unverified Commit 2d9a075d authored by Kostia Sokolovskyi's avatar Kostia Sokolovskyi Committed by GitHub

Cover text_selection tests with leak tracking. (#137009)

parent db57d286
......@@ -364,7 +364,8 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin,
_readOnly = readOnly,
_forceLine = forceLine,
_clipBehavior = clipBehavior,
_hasFocus = hasFocus ?? false {
_hasFocus = hasFocus ?? false,
_disposeShowCursor = showCursor == null {
assert(!_showCursor.value || cursorColor != null);
_selectionPainter.highlightColor = selectionColor;
......@@ -405,6 +406,10 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin,
_selectionPainter.dispose();
_caretPainter.dispose();
_textPainter.dispose();
if (_disposeShowCursor) {
_showCursor.dispose();
_disposeShowCursor = false;
}
super.dispose();
}
......@@ -879,6 +884,8 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin,
_caretPainter.backgroundCursorColor = value;
}
bool _disposeShowCursor;
/// Whether to paint the cursor.
ValueNotifier<bool> get showCursor => _showCursor;
ValueNotifier<bool> _showCursor;
......@@ -889,6 +896,10 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin,
if (attached) {
_showCursor.removeListener(_showHideCursor);
}
if (_disposeShowCursor) {
_showCursor.dispose();
_disposeShowCursor = false;
}
_showCursor = value;
if (attached) {
_showHideCursor();
......
......@@ -8,6 +8,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
import 'clipboard_utils.dart';
import 'editable_text_utils.dart';
......@@ -88,18 +89,26 @@ void main() {
final TextSelectionGestureDetectorBuilder provider =
TextSelectionGestureDetectorBuilder(delegate: delegate);
final TextEditingController controller = TextEditingController();
addTearDown(controller.dispose);
final FocusNode focusNode = FocusNode();
addTearDown(focusNode.dispose);
await tester.pumpWidget(
MaterialApp(
home: provider.buildGestureDetector(
behavior: HitTestBehavior.translucent,
child: FakeEditableText(key: editableTextKey),
child: FakeEditableText(
key: editableTextKey,
controller: controller,
focusNode: focusNode,
),
),
),
);
}
testWidgets('a series of taps all call onTaps', (WidgetTester tester) async {
testWidgetsWithLeakTracking('a series of taps all call onTaps', (WidgetTester tester) async {
await pumpGestureDetector(tester);
await tester.tapAt(const Offset(200, 200));
await tester.pump(const Duration(milliseconds: 150));
......@@ -115,7 +124,7 @@ void main() {
expect(tapCount, 6);
});
testWidgets('in a series of rapid taps, onTapDown, onDoubleTapDown, and onTripleTapDown alternate', (WidgetTester tester) async {
testWidgetsWithLeakTracking('in a series of rapid taps, onTapDown, onDoubleTapDown, and onTripleTapDown alternate', (WidgetTester tester) async {
await pumpGestureDetector(tester);
await tester.tapAt(const Offset(200, 200));
await tester.pump(const Duration(milliseconds: 50));
......@@ -151,7 +160,7 @@ void main() {
expect(tapCount, 7);
});
testWidgets('quick tap-tap-hold is a double tap down', (WidgetTester tester) async {
testWidgetsWithLeakTracking('quick tap-tap-hold is a double tap down', (WidgetTester tester) async {
await pumpGestureDetector(tester);
await tester.tapAt(const Offset(200, 200));
await tester.pump(const Duration(milliseconds: 50));
......@@ -177,7 +186,7 @@ void main() {
expect(singleLongTapStartCount, 0);
});
testWidgets('a very quick swipe is ignored', (WidgetTester tester) async {
testWidgetsWithLeakTracking('a very quick swipe is ignored', (WidgetTester tester) async {
await pumpGestureDetector(tester);
final TestGesture gesture = await tester.startGesture(const Offset(200, 200));
await tester.pump(const Duration(milliseconds: 20));
......@@ -203,7 +212,7 @@ void main() {
expect(singleLongTapStartCount, 0);
});
testWidgets('a slower swipe has a tap down and a canceled tap', (WidgetTester tester) async {
testWidgetsWithLeakTracking('a slower swipe has a tap down and a canceled tap', (WidgetTester tester) async {
await pumpGestureDetector(tester);
final TestGesture gesture = await tester.startGesture(const Offset(200, 200));
await tester.pump(const Duration(milliseconds: 120));
......@@ -216,7 +225,7 @@ void main() {
expect(singleLongTapStartCount, 0);
});
testWidgets('a force press initiates a force press', (WidgetTester tester) async {
testWidgetsWithLeakTracking('a force press initiates a force press', (WidgetTester tester) async {
await pumpGestureDetector(tester);
final int pointerValue = tester.nextPointer;
......@@ -298,7 +307,7 @@ void main() {
expect(forcePressStartCount, 4);
});
testWidgets('a tap and then force press initiates a force press and not a double tap', (WidgetTester tester) async {
testWidgetsWithLeakTracking('a tap and then force press initiates a force press and not a double tap', (WidgetTester tester) async {
await pumpGestureDetector(tester);
final int pointerValue = tester.nextPointer;
......@@ -351,7 +360,7 @@ void main() {
expect(doubleTapDownCount, 0);
});
testWidgets('a long press from a touch device is recognized as a long single tap', (WidgetTester tester) async {
testWidgetsWithLeakTracking('a long press from a touch device is recognized as a long single tap', (WidgetTester tester) async {
await pumpGestureDetector(tester);
final int pointerValue = tester.nextPointer;
......@@ -368,7 +377,7 @@ void main() {
expect(singleLongTapStartCount, 1);
});
testWidgets('a long press from a mouse is just a tap', (WidgetTester tester) async {
testWidgetsWithLeakTracking('a long press from a mouse is just a tap', (WidgetTester tester) async {
await pumpGestureDetector(tester);
final int pointerValue = tester.nextPointer;
......@@ -386,7 +395,7 @@ void main() {
expect(singleLongTapStartCount, 0);
});
testWidgets('a touch drag is recognized for text selection', (WidgetTester tester) async {
testWidgetsWithLeakTracking('a touch drag is recognized for text selection', (WidgetTester tester) async {
await pumpGestureDetector(tester);
final int pointerValue = tester.nextPointer;
......@@ -408,7 +417,7 @@ void main() {
expect(dragEndCount, 1);
});
testWidgets('a mouse drag is recognized for text selection', (WidgetTester tester) async {
testWidgetsWithLeakTracking('a mouse drag is recognized for text selection', (WidgetTester tester) async {
await pumpGestureDetector(tester);
final int pointerValue = tester.nextPointer;
......@@ -433,7 +442,7 @@ void main() {
expect(dragEndCount, 1);
});
testWidgets('a slow mouse drag is still recognized for text selection', (WidgetTester tester) async {
testWidgetsWithLeakTracking('a slow mouse drag is still recognized for text selection', (WidgetTester tester) async {
await pumpGestureDetector(tester);
final int pointerValue = tester.nextPointer;
......@@ -458,7 +467,7 @@ void main() {
expect(dragEndCount, 1);
});
testWidgets('test TextSelectionGestureDetectorBuilder long press on Apple Platforms - focused renderEditable', (WidgetTester tester) async {
testWidgetsWithLeakTracking('test TextSelectionGestureDetectorBuilder long press on Apple Platforms - focused renderEditable', (WidgetTester tester) async {
await pumpTextSelectionGestureDetectorBuilder(tester);
final FakeEditableTextState state = tester.state(find.byType(FakeEditableText));
final FakeRenderEditable renderEditable = tester.renderObject(find.byType(FakeEditable));
......@@ -477,7 +486,7 @@ void main() {
expect(renderEditable.lastCause, SelectionChangedCause.longPress);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
testWidgets('test TextSelectionGestureDetectorBuilder long press on iOS - renderEditable not focused', (WidgetTester tester) async {
testWidgetsWithLeakTracking('test TextSelectionGestureDetectorBuilder long press on iOS - renderEditable not focused', (WidgetTester tester) async {
await pumpTextSelectionGestureDetectorBuilder(tester);
final FakeEditableTextState state = tester.state(find.byType(FakeEditableText));
final FakeRenderEditable renderEditable = tester.renderObject(find.byType(FakeEditable));
......@@ -495,7 +504,7 @@ void main() {
expect(renderEditable.lastCause, SelectionChangedCause.longPress);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS }));
testWidgets('test TextSelectionGestureDetectorBuilder long press on non-Apple Platforms', (WidgetTester tester) async {
testWidgetsWithLeakTracking('test TextSelectionGestureDetectorBuilder long press on non-Apple Platforms', (WidgetTester tester) async {
await pumpTextSelectionGestureDetectorBuilder(tester);
final TestGesture gesture = await tester.startGesture(
const Offset(200.0, 200.0),
......@@ -512,7 +521,7 @@ void main() {
expect(renderEditable.lastCause, SelectionChangedCause.longPress);
}, variant: TargetPlatformVariant.all(excluding: <TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
testWidgets('TextSelectionGestureDetectorBuilder right click Apple platforms', (WidgetTester tester) async {
testWidgetsWithLeakTracking('TextSelectionGestureDetectorBuilder right click Apple platforms', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/80119
await pumpTextSelectionGestureDetectorBuilder(tester);
......@@ -557,7 +566,7 @@ void main() {
variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }),
);
testWidgets('TextSelectionGestureDetectorBuilder right click non-Apple platforms', (WidgetTester tester) async {
testWidgetsWithLeakTracking('TextSelectionGestureDetectorBuilder right click non-Apple platforms', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/80119
await pumpTextSelectionGestureDetectorBuilder(tester);
......@@ -607,7 +616,7 @@ void main() {
variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.fuchsia, TargetPlatform.linux, TargetPlatform.windows }),
);
testWidgets('test TextSelectionGestureDetectorBuilder tap', (WidgetTester tester) async {
testWidgetsWithLeakTracking('test TextSelectionGestureDetectorBuilder tap', (WidgetTester tester) async {
await pumpTextSelectionGestureDetectorBuilder(tester);
final TestGesture gesture = await tester.startGesture(
const Offset(200.0, 200.0),
......@@ -634,7 +643,7 @@ void main() {
}
}, variant: TargetPlatformVariant.all());
testWidgets('test TextSelectionGestureDetectorBuilder toggles toolbar on single tap on previous selection iOS', (WidgetTester tester) async {
testWidgetsWithLeakTracking('test TextSelectionGestureDetectorBuilder toggles toolbar on single tap on previous selection iOS', (WidgetTester tester) async {
await pumpTextSelectionGestureDetectorBuilder(tester);
final FakeEditableTextState state = tester.state(find.byType(FakeEditableText));
......@@ -666,7 +675,7 @@ void main() {
}, variant: TargetPlatformVariant.all());
testWidgets('test TextSelectionGestureDetectorBuilder shows spell check toolbar on single tap on Android', (WidgetTester tester) async {
testWidgetsWithLeakTracking('test TextSelectionGestureDetectorBuilder shows spell check toolbar on single tap on Android', (WidgetTester tester) async {
await pumpTextSelectionGestureDetectorBuilder(tester);
final FakeEditableTextState state = tester.state(find.byType(FakeEditableText));
......@@ -686,7 +695,7 @@ void main() {
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android }));
testWidgets('test TextSelectionGestureDetectorBuilder shows spell check toolbar on single tap on iOS if word misspelled and text selection toolbar on additonal taps', (WidgetTester tester) async {
testWidgetsWithLeakTracking('test TextSelectionGestureDetectorBuilder shows spell check toolbar on single tap on iOS if word misspelled and text selection toolbar on additonal taps', (WidgetTester tester) async {
await pumpTextSelectionGestureDetectorBuilder(tester);
final FakeEditableTextState state = tester.state(find.byType(FakeEditableText));
final FakeRenderEditable renderEditable = tester.renderObject(find.byType(FakeEditable));
......@@ -727,7 +736,7 @@ void main() {
expect(state.toggleToolbarCalled, isTrue);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS }));
testWidgets('test TextSelectionGestureDetectorBuilder double tap', (WidgetTester tester) async {
testWidgetsWithLeakTracking('test TextSelectionGestureDetectorBuilder double tap', (WidgetTester tester) async {
await pumpTextSelectionGestureDetectorBuilder(tester);
final TestGesture gesture = await tester.startGesture(
const Offset(200.0, 200.0),
......@@ -747,7 +756,7 @@ void main() {
expect(renderEditable.lastCause, SelectionChangedCause.doubleTap);
});
testWidgets('test TextSelectionGestureDetectorBuilder forcePress enabled', (WidgetTester tester) async {
testWidgetsWithLeakTracking('test TextSelectionGestureDetectorBuilder forcePress enabled', (WidgetTester tester) async {
await pumpTextSelectionGestureDetectorBuilder(tester);
final TestGesture gesture = await tester.createGesture();
await gesture.downWithCustomEvent(
......@@ -774,7 +783,7 @@ void main() {
expect(renderEditable.selectWordsInRangeCalled, isTrue);
});
testWidgets('Mouse drag does not show handles nor toolbar', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Mouse drag does not show handles nor toolbar', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/69001
await tester.pumpWidget(
const MaterialApp(
......@@ -798,11 +807,12 @@ void main() {
expect(editableText.selectionOverlay!.toolbarIsVisible, isFalse);
});
testWidgets('Mouse drag selects and cannot drag cursor', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Mouse drag selects and cannot drag cursor', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/102928
final TextEditingController controller = TextEditingController(
text: 'I love flutter!',
);
addTearDown(controller.dispose);
final GlobalKey<EditableTextState> editableTextKey = GlobalKey<EditableTextState>();
final FakeTextSelectionGestureDetectorBuilderDelegate delegate = FakeTextSelectionGestureDetectorBuilderDelegate(
editableTextKey: editableTextKey,
......@@ -811,6 +821,8 @@ void main() {
);
final TextSelectionGestureDetectorBuilder provider =
TextSelectionGestureDetectorBuilder(delegate: delegate);
final FocusNode focusNode = FocusNode();
addTearDown(focusNode.dispose);
await tester.pumpWidget(
MaterialApp(
......@@ -819,7 +831,7 @@ void main() {
child: EditableText(
key: editableTextKey,
controller: controller,
focusNode: FocusNode(),
focusNode: focusNode,
backgroundCursorColor: Colors.white,
cursorColor: Colors.white,
style: const TextStyle(),
......@@ -861,11 +873,12 @@ void main() {
expect(controller.selection.extentOffset, 10);
});
testWidgets('Touch drag moves the cursor', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Touch drag moves the cursor', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/102928
final TextEditingController controller = TextEditingController(
text: 'I love flutter!',
);
addTearDown(controller.dispose);
final GlobalKey<EditableTextState> editableTextKey = GlobalKey<EditableTextState>();
final FakeTextSelectionGestureDetectorBuilderDelegate delegate = FakeTextSelectionGestureDetectorBuilderDelegate(
editableTextKey: editableTextKey,
......@@ -874,6 +887,8 @@ void main() {
);
final TextSelectionGestureDetectorBuilder provider =
TextSelectionGestureDetectorBuilder(delegate: delegate);
final FocusNode focusNode = FocusNode();
addTearDown(focusNode.dispose);
await tester.pumpWidget(
MaterialApp(
......@@ -882,7 +897,7 @@ void main() {
child: EditableText(
key: editableTextKey,
controller: controller,
focusNode: FocusNode(),
focusNode: focusNode,
backgroundCursorColor: Colors.white,
cursorColor: Colors.white,
style: const TextStyle(),
......@@ -917,11 +932,12 @@ void main() {
expect(controller.selection.baseOffset, 10);
});
testWidgets('Stylus drag moves the cursor', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Stylus drag moves the cursor', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/102928
final TextEditingController controller = TextEditingController(
text: 'I love flutter!',
);
addTearDown(controller.dispose);
final GlobalKey<EditableTextState> editableTextKey = GlobalKey<EditableTextState>();
final FakeTextSelectionGestureDetectorBuilderDelegate delegate = FakeTextSelectionGestureDetectorBuilderDelegate(
editableTextKey: editableTextKey,
......@@ -930,6 +946,8 @@ void main() {
);
final TextSelectionGestureDetectorBuilder provider =
TextSelectionGestureDetectorBuilder(delegate: delegate);
final FocusNode focusNode = FocusNode();
addTearDown(focusNode.dispose);
await tester.pumpWidget(
MaterialApp(
......@@ -938,7 +956,7 @@ void main() {
child: EditableText(
key: editableTextKey,
controller: controller,
focusNode: FocusNode(),
focusNode: focusNode,
backgroundCursorColor: Colors.white,
cursorColor: Colors.white,
style: const TextStyle(),
......@@ -973,11 +991,12 @@ void main() {
expect(controller.selection.baseOffset, 10);
});
testWidgets('Drag of unknown type moves the cursor', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Drag of unknown type moves the cursor', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/102928
final TextEditingController controller = TextEditingController(
text: 'I love flutter!',
);
addTearDown(controller.dispose);
final GlobalKey<EditableTextState> editableTextKey = GlobalKey<EditableTextState>();
final FakeTextSelectionGestureDetectorBuilderDelegate delegate = FakeTextSelectionGestureDetectorBuilderDelegate(
editableTextKey: editableTextKey,
......@@ -986,6 +1005,8 @@ void main() {
);
final TextSelectionGestureDetectorBuilder provider =
TextSelectionGestureDetectorBuilder(delegate: delegate);
final FocusNode focusNode = FocusNode();
addTearDown(focusNode.dispose);
await tester.pumpWidget(
MaterialApp(
......@@ -994,7 +1015,7 @@ void main() {
child: EditableText(
key: editableTextKey,
controller: controller,
focusNode: FocusNode(),
focusNode: focusNode,
backgroundCursorColor: Colors.white,
cursorColor: Colors.white,
style: const TextStyle(),
......@@ -1029,13 +1050,15 @@ void main() {
expect(controller.selection.baseOffset, 10);
});
testWidgets('test TextSelectionGestureDetectorBuilder drag with RenderEditable viewport offset change', (WidgetTester tester) async {
testWidgetsWithLeakTracking('test TextSelectionGestureDetectorBuilder drag with RenderEditable viewport offset change', (WidgetTester tester) async {
await pumpTextSelectionGestureDetectorBuilder(tester);
final FakeRenderEditable renderEditable = tester.renderObject(find.byType(FakeEditable));
// Reconfigure the RenderEditable for multi-line.
renderEditable.maxLines = null;
renderEditable.offset = ViewportOffset.fixed(20.0);
final ViewportOffset offset1 = ViewportOffset.fixed(20.0);
addTearDown(offset1.dispose);
renderEditable.offset = offset1;
renderEditable.layout(const BoxConstraints.tightFor(width: 400, height: 300.0));
await tester.pumpAndSettle();
......@@ -1053,7 +1076,9 @@ void main() {
expect(renderEditable.selectPositionAtTo, const Offset(300.0, 200.0));
// Move the viewport offset (scroll).
renderEditable.offset = ViewportOffset.fixed(150.0);
final ViewportOffset offset2 = ViewportOffset.fixed(150.0);
addTearDown(offset2.dispose);
renderEditable.offset = offset2;
renderEditable.layout(const BoxConstraints.tightFor(width: 400, height: 300.0));
await tester.pumpAndSettle();
......@@ -1066,7 +1091,7 @@ void main() {
expect(renderEditable.selectPositionAtTo, const Offset(300.0, 400.0));
});
testWidgets('test TextSelectionGestureDetectorBuilder selection disabled', (WidgetTester tester) async {
testWidgetsWithLeakTracking('test TextSelectionGestureDetectorBuilder selection disabled', (WidgetTester tester) async {
await pumpTextSelectionGestureDetectorBuilder(tester, selectionEnabled: false);
final TestGesture gesture = await tester.startGesture(
const Offset(200.0, 200.0),
......@@ -1082,7 +1107,7 @@ void main() {
expect(renderEditable.selectWordsInRangeCalled, isFalse);
});
testWidgets('test TextSelectionGestureDetectorBuilder mouse drag disabled', (WidgetTester tester) async {
testWidgetsWithLeakTracking('test TextSelectionGestureDetectorBuilder mouse drag disabled', (WidgetTester tester) async {
await pumpTextSelectionGestureDetectorBuilder(tester, selectionEnabled: false);
final TestGesture gesture = await tester.startGesture(
Offset.zero,
......@@ -1098,7 +1123,7 @@ void main() {
expect(renderEditable.selectPositionAtCalled, isFalse);
});
testWidgets('test TextSelectionGestureDetectorBuilder forcePress disabled', (WidgetTester tester) async {
testWidgetsWithLeakTracking('test TextSelectionGestureDetectorBuilder forcePress disabled', (WidgetTester tester) async {
await pumpTextSelectionGestureDetectorBuilder(tester, forcePressEnabled: false);
final TestGesture gesture = await tester.createGesture();
await gesture.downWithCustomEvent(
......@@ -1120,8 +1145,9 @@ void main() {
});
// Regression test for https://github.com/flutter/flutter/issues/37032.
testWidgets("selection handle's GestureDetector should not cover the entire screen", (WidgetTester tester) async {
testWidgetsWithLeakTracking("selection handle's GestureDetector should not cover the entire screen", (WidgetTester tester) async {
final TextEditingController controller = TextEditingController(text: 'a');
addTearDown(controller.dispose);
await tester.pumpWidget(
MaterialApp(
......@@ -1189,6 +1215,9 @@ void main() {
),
));
final FakeClipboardStatusNotifier clipboardStatus = FakeClipboardStatusNotifier();
addTearDown(clipboardStatus.dispose);
return SelectionOverlay(
context: tester.element(find.byKey(column)),
onSelectionHandleTapped: onSelectionHandleTapped,
......@@ -1204,7 +1233,7 @@ void main() {
onEndHandleDragStart: onEndDragStart,
onEndHandleDragUpdate: onEndDragUpdate,
onEndHandleDragEnd: onEndDragEnd,
clipboardStatus: FakeClipboardStatusNotifier(),
clipboardStatus: clipboardStatus,
selectionDelegate: FakeTextSelectionDelegate(),
selectionControls: selectionControls,
selectionEndpoints: const <TextSelectionPoint>[],
......@@ -1213,7 +1242,7 @@ void main() {
);
}
testWidgets('can show and hide handles', (WidgetTester tester) async {
testWidgetsWithLeakTracking('can show and hide handles', (WidgetTester tester) async {
final TextSelectionControlsSpy spy = TextSelectionControlsSpy();
final SelectionOverlay selectionOverlay = await pumpApp(
tester,
......@@ -1256,9 +1285,12 @@ void main() {
expect(find.byKey(spy.leftHandleKey), findsNothing);
expect(find.byKey(spy.rightHandleKey), findsNothing);
expect(find.byKey(spy.toolBarKey), findsNothing);
selectionOverlay.dispose();
await tester.pumpAndSettle();
});
testWidgets('only paints one collapsed handle', (WidgetTester tester) async {
testWidgetsWithLeakTracking('only paints one collapsed handle', (WidgetTester tester) async {
final TextSelectionControlsSpy spy = TextSelectionControlsSpy();
final SelectionOverlay selectionOverlay = await pumpApp(
tester,
......@@ -1276,9 +1308,12 @@ void main() {
expect(find.byKey(spy.leftHandleKey), findsNothing);
expect(find.byKey(spy.rightHandleKey), findsNothing);
expect(find.byKey(spy.collapsedHandleKey), findsOneWidget);
selectionOverlay.dispose();
await tester.pumpAndSettle();
});
testWidgets('can change handle parameter', (WidgetTester tester) async {
testWidgetsWithLeakTracking('can change handle parameter', (WidgetTester tester) async {
final TextSelectionControlsSpy spy = TextSelectionControlsSpy();
final SelectionOverlay selectionOverlay = await pumpApp(
tester,
......@@ -1310,9 +1345,12 @@ void main() {
rightHandle = tester.widget(find.byKey(spy.rightHandleKey)) as Text;
expect(leftHandle.data, 'height 13');
expect(rightHandle.data, 'height 12');
selectionOverlay.dispose();
await tester.pumpAndSettle();
});
testWidgets('can trigger selection handle onTap', (WidgetTester tester) async {
testWidgetsWithLeakTracking('can trigger selection handle onTap', (WidgetTester tester) async {
bool selectionHandleTapped = false;
void handleTapped() => selectionHandleTapped = true;
final TextSelectionControlsSpy spy = TextSelectionControlsSpy();
......@@ -1342,9 +1380,12 @@ void main() {
selectionHandleTapped = false;
await tester.tap(find.byKey(spy.rightHandleKey));
expect(selectionHandleTapped, isTrue);
selectionOverlay.dispose();
await tester.pumpAndSettle();
});
testWidgets('can trigger selection handle drag', (WidgetTester tester) async {
testWidgetsWithLeakTracking('can trigger selection handle drag', (WidgetTester tester) async {
DragStartDetails? startDragStartDetails;
DragUpdateDetails? startDragUpdateDetails;
DragEndDetails? startDragEndDetails;
......@@ -1413,9 +1454,12 @@ void main() {
await gesture2.up();
await tester.pump(const Duration(milliseconds: 20));
expect(endDragEndDetails, isNotNull);
selectionOverlay.dispose();
await tester.pumpAndSettle();
});
testWidgets('can show magnifier when no handles exist', (WidgetTester tester) async {
testWidgetsWithLeakTracking('can show magnifier when no handles exist', (WidgetTester tester) async {
final GlobalKey magnifierKey = GlobalKey();
final SelectionOverlay selectionOverlay = await pumpApp(
tester,
......@@ -1442,6 +1486,9 @@ void main() {
expect(tester.takeException(), isNull);
expect(find.byKey(magnifierKey), findsOneWidget);
selectionOverlay.dispose();
await tester.pumpAndSettle();
});
});
......@@ -1495,11 +1542,12 @@ void main() {
});
});
testWidgets('Mouse edge scrolling works in an outer scrollable', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Mouse edge scrolling works in an outer scrollable', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/102484
final TextEditingController controller = TextEditingController(
text: 'I love flutter!\n' * 8,
);
addTearDown(controller.dispose);
final GlobalKey<EditableTextState> editableTextKey = GlobalKey<EditableTextState>();
final FakeTextSelectionGestureDetectorBuilderDelegate delegate = FakeTextSelectionGestureDetectorBuilderDelegate(
editableTextKey: editableTextKey,
......@@ -1508,11 +1556,14 @@ void main() {
);
final ScrollController scrollController = ScrollController();
addTearDown(scrollController.dispose);
const double kLineHeight = 16.0;
final TextSelectionGestureDetectorBuilder provider =
TextSelectionGestureDetectorBuilder(
delegate: delegate,
);
final FocusNode focusNode = FocusNode();
addTearDown(focusNode.dispose);
await tester.pumpWidget(
MaterialApp(
......@@ -1527,7 +1578,7 @@ void main() {
child: EditableText(
key: editableTextKey,
controller: controller,
focusNode: FocusNode(),
focusNode: focusNode,
backgroundCursorColor: Colors.white,
cursorColor: Colors.white,
style: const TextStyle(),
......@@ -1572,11 +1623,12 @@ void main() {
expect(scrollController.position.pixels, scrollController.position.maxScrollExtent);
});
testWidgets('Mouse edge scrolling works with both an outer scrollable and scrolling in the EditableText', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Mouse edge scrolling works with both an outer scrollable and scrolling in the EditableText', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/102484
final TextEditingController controller = TextEditingController(
text: 'I love flutter!\n' * 8,
);
addTearDown(controller.dispose);
final GlobalKey<EditableTextState> editableTextKey = GlobalKey<EditableTextState>();
final FakeTextSelectionGestureDetectorBuilderDelegate delegate = FakeTextSelectionGestureDetectorBuilderDelegate(
editableTextKey: editableTextKey,
......@@ -1585,11 +1637,14 @@ void main() {
);
final ScrollController scrollController = ScrollController();
addTearDown(scrollController.dispose);
const double kLineHeight = 16.0;
final TextSelectionGestureDetectorBuilder provider =
TextSelectionGestureDetectorBuilder(
delegate: delegate,
);
final FocusNode focusNode = FocusNode();
addTearDown(focusNode.dispose);
await tester.pumpWidget(
MaterialApp(
......@@ -1604,7 +1659,7 @@ void main() {
child: EditableText(
key: editableTextKey,
controller: controller,
focusNode: FocusNode(),
focusNode: focusNode,
backgroundCursorColor: Colors.white,
cursorColor: Colors.white,
style: const TextStyle(),
......@@ -1668,9 +1723,11 @@ class FakeTextSelectionGestureDetectorBuilderDelegate implements TextSelectionGe
}
class FakeEditableText extends EditableText {
FakeEditableText({super.key}): super(
controller: TextEditingController(),
focusNode: FocusNode(),
FakeEditableText({
required super.controller,
required super.focusNode,
super.key,
}): super(
backgroundCursorColor: Colors.white,
cursorColor: Colors.white,
style: const TextStyle(),
......@@ -1738,7 +1795,13 @@ class FakeEditable extends LeafRenderObjectWidget {
}
class FakeRenderEditable extends RenderEditable {
FakeRenderEditable(EditableTextState delegate) : super(
FakeRenderEditable(EditableTextState delegate)
: this._(delegate, ViewportOffset.fixed(10.0));
FakeRenderEditable._(
EditableTextState delegate,
this._offset,
) : super(
text: const TextSpan(
style: TextStyle(height: 1.0, fontSize: 10.0),
text: 'placeholder',
......@@ -1749,7 +1812,7 @@ class FakeRenderEditable extends RenderEditable {
textAlign: TextAlign.start,
textDirection: TextDirection.ltr,
locale: const Locale('en', 'US'),
offset: ViewportOffset.fixed(10.0),
offset: _offset,
textSelectionDelegate: delegate,
selection: const TextSelection.collapsed(
offset: 0,
......@@ -1758,6 +1821,8 @@ class FakeRenderEditable extends RenderEditable {
SelectionChangedCause? lastCause;
ViewportOffset _offset;
bool selectWordsInRangeCalled = false;
@override
void selectWordsInRange({ required Offset from, Offset? to, required SelectionChangedCause cause }) {
......@@ -1804,6 +1869,12 @@ class FakeRenderEditable extends RenderEditable {
@override
bool hasFocus = false;
@override
void dispose() {
_offset.dispose();
super.dispose();
}
}
class TextSelectionControlsSpy extends TextSelectionControls {
......
......@@ -4,9 +4,10 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
void main() {
testWidgets('positions itself at anchorAbove if it fits', (WidgetTester tester) async {
testWidgetsWithLeakTracking('positions itself at anchorAbove if it fits', (WidgetTester tester) async {
late StateSetter setState;
const double height = 43.0;
const double anchorBelowY = 500.0;
......
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