blob: 845de0ff6e9f8d9381a1d966984975336f6b52a3 [file] [log] [blame]
// 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.
@Tags(<String>['reduced-test-set'])
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
final Offset basicOffset = Offset(CupertinoMagnifier.kDefaultSize.width / 2,
CupertinoMagnifier.kDefaultSize.height - CupertinoMagnifier.kMagnifierAboveFocalPoint);
const Rect reasonableTextField = Rect.fromLTRB(0, 100, 200, 200);
final MagnifierController magnifierController = MagnifierController();
// Make sure that your gesture in magnifierInfo is within the line in magnifierInfo,
// or else the magnifier status will stay hidden and this will not complete.
Future<void> showCupertinoMagnifier(
BuildContext context,
WidgetTester tester,
ValueNotifier<MagnifierInfo> magnifierInfo,
) async {
final Future<void> magnifierShown = magnifierController.show(
context: context,
builder: (_) => CupertinoTextMagnifier(
controller: magnifierController,
magnifierInfo: magnifierInfo,
));
WidgetsBinding.instance.scheduleFrame();
await tester.pumpAndSettle();
await magnifierShown;
}
tearDown(() async {
magnifierController.removeFromOverlay();
});
group('CupertinoTextEditingMagnifier', () {
group('position', () {
Offset getMagnifierPosition(WidgetTester tester) {
final AnimatedPositioned animatedPositioned =
tester.firstWidget(find.byType(AnimatedPositioned));
return Offset(
animatedPositioned.left ?? 0, animatedPositioned.top ?? 0);
}
testWidgets('should be at gesture position if does not violate any positioning rules', (WidgetTester tester) async {
final Key fakeTextFieldKey = UniqueKey();
final Key outerKey = UniqueKey();
await tester.pumpWidget(
Container(
key: outerKey,
color: const Color.fromARGB(255, 0, 255, 179),
child: MaterialApp(
home: Center(
child: Container(
key: fakeTextFieldKey,
width: 10,
height: 10,
color: Colors.red,
child: const Placeholder(),
),
),
),
),
);
final BuildContext context = tester.element(find.byType(Placeholder));
// Magnifier should be positioned directly over the red square.
final RenderBox tapPointRenderBox =
tester.firstRenderObject(find.byKey(fakeTextFieldKey)) as RenderBox;
final Rect fakeTextFieldRect =
tapPointRenderBox.localToGlobal(Offset.zero) & tapPointRenderBox.size;
final ValueNotifier<MagnifierInfo> magnifier =
ValueNotifier<MagnifierInfo>(
MagnifierInfo(
currentLineBoundaries: fakeTextFieldRect,
fieldBounds: fakeTextFieldRect,
caretRect: fakeTextFieldRect,
// The tap position is dragBelow units below the text field.
globalGesturePosition: fakeTextFieldRect.center,
),
);
await showCupertinoMagnifier(context, tester, magnifier);
// Should show two red squares; original, and one in the magnifier,
// directly ontop of one another.
await expectLater(
find.byKey(outerKey),
matchesGoldenFile('cupertino_magnifier.position.default.png'),
);
});
testWidgets('should never horizontally be outside of Screen Padding', (WidgetTester tester) async {
await tester.pumpWidget(
const MaterialApp(
color: Color.fromARGB(7, 0, 129, 90),
home: Placeholder(),
),
);
final BuildContext context = tester.firstElement(find.byType(Placeholder));
await showCupertinoMagnifier(
context,
tester,
ValueNotifier<MagnifierInfo>(
MagnifierInfo(
currentLineBoundaries: reasonableTextField,
fieldBounds: reasonableTextField,
caretRect: reasonableTextField,
// The tap position is far out of the right side of the app.
globalGesturePosition:
Offset(MediaQuery.of(context).size.width + 100, 0),
),
),
);
// Should be less than the right edge, since we have padding.
expect(getMagnifierPosition(tester).dx,
lessThan(MediaQuery.of(context).size.width));
});
testWidgets('should have some vertical drag', (WidgetTester tester) async {
final double dragPositionBelowTextField = reasonableTextField.center.dy + 30;
await tester.pumpWidget(
const MaterialApp(
color: Color.fromARGB(7, 0, 129, 90),
home: Placeholder(),
),
);
final BuildContext context =
tester.firstElement(find.byType(Placeholder));
await showCupertinoMagnifier(
context,
tester,
ValueNotifier<MagnifierInfo>(
MagnifierInfo(
currentLineBoundaries: reasonableTextField,
fieldBounds: reasonableTextField,
caretRect: reasonableTextField,
// The tap position is dragBelow units below the text field.
globalGesturePosition: Offset(
MediaQuery.of(context).size.width / 2,
dragPositionBelowTextField),
),
),
);
// The magnifier Y should be greater than the text field, since we "dragged" it down.
expect(getMagnifierPosition(tester).dy + basicOffset.dy,
greaterThan(reasonableTextField.center.dy));
expect(getMagnifierPosition(tester).dy + basicOffset.dy,
lessThan(dragPositionBelowTextField));
});
});
group('status', () {
testWidgets('should hide if gesture is far below the text field', (WidgetTester tester) async {
await tester.pumpWidget(
const MaterialApp(
color: Color.fromARGB(7, 0, 129, 90),
home: Placeholder(),
),
);
final BuildContext context =
tester.firstElement(find.byType(Placeholder));
final ValueNotifier<MagnifierInfo> magnifierinfo =
ValueNotifier<MagnifierInfo>(
MagnifierInfo(
currentLineBoundaries: reasonableTextField,
fieldBounds: reasonableTextField,
caretRect: reasonableTextField,
// The tap position is dragBelow units below the text field.
globalGesturePosition: Offset(
MediaQuery.of(context).size.width / 2, reasonableTextField.top),
),
);
// Show the magnifier initally, so that we get it in a not hidden state.
await showCupertinoMagnifier(context, tester, magnifierinfo);
// Move the gesture to one that should hide it.
magnifierinfo.value = MagnifierInfo(
currentLineBoundaries: reasonableTextField,
fieldBounds: reasonableTextField,
caretRect: reasonableTextField,
globalGesturePosition: magnifierinfo.value.globalGesturePosition + const Offset(0, 100),
);
await tester.pumpAndSettle();
expect(magnifierController.shown, false);
expect(magnifierController.overlayEntry, isNotNull);
});
testWidgets('should re-show if gesture moves back up',
(WidgetTester tester) async {
await tester.pumpWidget(
const MaterialApp(
color: Color.fromARGB(7, 0, 129, 90),
home: Placeholder(),
),
);
final BuildContext context =
tester.firstElement(find.byType(Placeholder));
final ValueNotifier<MagnifierInfo> magnifierInfo =
ValueNotifier<MagnifierInfo>(
MagnifierInfo(
currentLineBoundaries: reasonableTextField,
fieldBounds: reasonableTextField,
caretRect: reasonableTextField,
// The tap position is dragBelow units below the text field.
globalGesturePosition: Offset(MediaQuery.of(context).size.width / 2, reasonableTextField.top),
),
);
// Show the magnifier initally, so that we get it in a not hidden state.
await showCupertinoMagnifier(context, tester, magnifierInfo);
// Move the gesture to one that should hide it.
magnifierInfo.value = MagnifierInfo(
currentLineBoundaries: reasonableTextField,
fieldBounds: reasonableTextField,
caretRect: reasonableTextField,
globalGesturePosition:
magnifierInfo.value.globalGesturePosition + const Offset(0, 100));
await tester.pumpAndSettle();
expect(magnifierController.shown, false);
expect(magnifierController.overlayEntry, isNotNull);
// Return the gesture to one that shows it.
magnifierInfo.value = MagnifierInfo(
currentLineBoundaries: reasonableTextField,
fieldBounds: reasonableTextField,
caretRect: reasonableTextField,
globalGesturePosition: Offset(MediaQuery.of(context).size.width / 2,
reasonableTextField.top));
await tester.pumpAndSettle();
expect(magnifierController.shown, true);
expect(magnifierController.overlayEntry, isNotNull);
});
});
});
}