| // 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/rendering.dart'; |
| import 'package:flutter_api_samples/widgets/text_magnifier/text_magnifier.0.dart' |
| as example; |
| import 'package:flutter_test/flutter_test.dart'; |
| |
| List<TextSelectionPoint> _globalize( |
| Iterable<TextSelectionPoint> points, RenderBox box) { |
| return points.map<TextSelectionPoint>((TextSelectionPoint point) { |
| return TextSelectionPoint( |
| box.localToGlobal(point.point), |
| point.direction, |
| ); |
| }).toList(); |
| } |
| |
| RenderEditable _findRenderEditable<T extends State<StatefulWidget>>(WidgetTester tester) { |
| return (tester.state(find.byType(TextField)) |
| as TextSelectionGestureDetectorBuilderDelegate) |
| .editableTextKey |
| .currentState! |
| .renderEditable; |
| } |
| |
| Offset _textOffsetToPosition<T extends State<StatefulWidget>>(WidgetTester tester, int offset) { |
| final RenderEditable renderEditable = _findRenderEditable(tester); |
| |
| final List<TextSelectionPoint> endpoints = renderEditable |
| .getEndpointsForSelection( |
| TextSelection.collapsed(offset: offset), |
| ) |
| .map<TextSelectionPoint>((TextSelectionPoint point) => TextSelectionPoint( |
| renderEditable.localToGlobal(point.point), |
| point.direction, |
| )) |
| .toList(); |
| |
| return endpoints[0].point + const Offset(0.0, -2.0); |
| } |
| |
| void main() { |
| const Duration durationBetweenActions = Duration(milliseconds: 20); |
| const String defaultText = 'I am a magnifier, fear me!'; |
| |
| Future<void> showMagnifier(WidgetTester tester, String characterToTapOn) async { |
| final Offset tapOffset = _textOffsetToPosition(tester, defaultText.indexOf(characterToTapOn)); |
| |
| // Double tap 'Magnifier' word to show the selection handles. |
| final TestGesture testGesture = await tester.startGesture(tapOffset); |
| await tester.pump(durationBetweenActions); |
| await testGesture.up(); |
| await tester.pump(durationBetweenActions); |
| await testGesture.down(tapOffset); |
| await tester.pump(durationBetweenActions); |
| await testGesture.up(); |
| await tester.pumpAndSettle(); |
| |
| final TextSelection selection = tester |
| .firstWidget<TextField>(find.byType(TextField)) |
| .controller! |
| .selection; |
| |
| final RenderEditable renderEditable = _findRenderEditable(tester); |
| final List<TextSelectionPoint> endpoints = _globalize( |
| renderEditable.getEndpointsForSelection(selection), |
| renderEditable, |
| ); |
| |
| final Offset handlePos = endpoints.last.point + const Offset(10.0, 10.0); |
| |
| final TestGesture gesture = await tester.startGesture(handlePos); |
| |
| await gesture.moveTo( |
| _textOffsetToPosition( |
| tester, |
| defaultText.length - 2, |
| ), |
| ); |
| await tester.pump(); |
| } |
| |
| testWidgets('should show custom magnifier on drag', (WidgetTester tester) async { |
| await tester.pumpWidget(const example.TextMagnifierExampleApp(text: defaultText)); |
| |
| await showMagnifier(tester, 'e'); |
| expect(find.byType(example.CustomMagnifier), findsOneWidget); |
| |
| await expectLater( |
| find.byType(example.TextMagnifierExampleApp), |
| matchesGoldenFile('text_magnifier.0_test.png'), |
| ); |
| }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.android })); |
| |
| |
| for (final TextDirection textDirection in TextDirection.values) { |
| testWidgets('should show custom magnifier in $textDirection', (WidgetTester tester) async { |
| final String text = textDirection == TextDirection.rtl ? 'أثارت زر' : defaultText; |
| final String textToTapOn = textDirection == TextDirection.rtl ? 'ت' : 'e'; |
| |
| await tester.pumpWidget(example.TextMagnifierExampleApp(textDirection: textDirection, text: text)); |
| |
| await showMagnifier(tester, textToTapOn); |
| |
| expect(find.byType(example.CustomMagnifier), findsOneWidget); |
| }); |
| } |
| } |