selection_area_test.dart 8.12 KB
Newer Older
1 2 3 4 5 6
// 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/cupertino.dart';
import 'package:flutter/foundation.dart';
7
import 'package:flutter/gestures.dart';
8
import 'package:flutter/material.dart';
9
import 'package:flutter/rendering.dart';
10 11
import 'package:flutter_test/flutter_test.dart';

12 13 14 15 16 17
Offset textOffsetToPosition(RenderParagraph paragraph, int offset) {
  const Rect caret = Rect.fromLTWH(0.0, 0.0, 2.0, 20.0);
  final Offset localOffset = paragraph.getOffsetForCaret(TextPosition(offset: offset), caret);
  return paragraph.localToGlobal(localOffset);
}

18 19 20 21 22 23 24 25 26 27 28 29
void main() {
  testWidgets('SelectionArea uses correct selection controls', (WidgetTester tester) async {
    await tester.pumpWidget(const MaterialApp(
      home: SelectionArea(
        child: Text('abc'),
      ),
    ));
    final SelectableRegion region = tester.widget<SelectableRegion>(find.byType(SelectableRegion));

    switch (defaultTargetPlatform) {
      case TargetPlatform.android:
      case TargetPlatform.fuchsia:
30
        expect(region.selectionControls, materialTextSelectionHandleControls);
31
      case TargetPlatform.iOS:
32
        expect(region.selectionControls, cupertinoTextSelectionHandleControls);
33 34
      case TargetPlatform.linux:
      case TargetPlatform.windows:
35
        expect(region.selectionControls, desktopTextSelectionHandleControls);
36
      case TargetPlatform.macOS:
37
        expect(region.selectionControls, cupertinoDesktopTextSelectionHandleControls);
38 39
    }
  }, variant: TargetPlatformVariant.all());
40

41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
  testWidgets('Does not crash when long pressing on padding after dragging', (WidgetTester tester) async {
    // Regression test for https://github.com/flutter/flutter/issues/123378
    await tester.pumpWidget(
      const MaterialApp(
        color: Color(0xFF2196F3),
        title: 'Demo',
        home: Scaffold(
          body: SelectionArea(
            child: Padding(
              padding: EdgeInsets.all(100.0),
              child: Text('Hello World'),
            ),
          ),
        ),
      ),
    );
    final TestGesture dragging = await tester.startGesture(const Offset(10, 10));
    addTearDown(dragging.removePointer);
    await tester.pump(const Duration(milliseconds: 500));
    await dragging.moveTo(const Offset(90, 90));
    await dragging.up();

    final TestGesture longpress = await tester.startGesture(const Offset(20,20));
    addTearDown(longpress.removePointer);
    await tester.pump(const Duration(milliseconds: 500));
    await longpress.up();

    expect(tester.takeException(), isNull);
  });


72 73 74 75 76 77 78 79 80
  testWidgets('builds the default context menu by default', (WidgetTester tester) async {
    await tester.pumpWidget(
      MaterialApp(
        home: SelectionArea(
          focusNode: FocusNode(),
          child: const Text('How are you?'),
        ),
      ),
    );
81
    await tester.pumpAndSettle();
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114

    expect(find.byType(AdaptiveTextSelectionToolbar), findsNothing);

    // Show the toolbar by longpressing.
    final RenderParagraph paragraph1 = tester.renderObject<RenderParagraph>(find.descendant(of: find.text('How are you?'), matching: find.byType(RichText)));
    final TestGesture gesture = await tester.startGesture(textOffsetToPosition(paragraph1, 6)); // at the 'r'
    addTearDown(gesture.removePointer);
    await tester.pump(const Duration(milliseconds: 500));
    // `are` is selected.
    expect(paragraph1.selections[0], const TextSelection(baseOffset: 4, extentOffset: 7));
    await tester.pumpAndSettle();

    expect(find.byType(AdaptiveTextSelectionToolbar), findsOneWidget);
  },
    skip: kIsWeb, // [intended]
  );

  testWidgets('builds a custom context menu if provided', (WidgetTester tester) async {
    final GlobalKey key = GlobalKey();
    await tester.pumpWidget(
      MaterialApp(
        home: SelectionArea(
          focusNode: FocusNode(),
          contextMenuBuilder: (
            BuildContext context,
            SelectableRegionState selectableRegionState,
          ) {
            return Placeholder(key: key);
          },
          child: const Text('How are you?'),
        ),
      ),
    );
115
    await tester.pumpAndSettle();
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134

    expect(find.byType(AdaptiveTextSelectionToolbar), findsNothing);
    expect(find.byKey(key), findsNothing);

    // Show the toolbar by longpressing.
    final RenderParagraph paragraph1 = tester.renderObject<RenderParagraph>(find.descendant(of: find.text('How are you?'), matching: find.byType(RichText)));
    final TestGesture gesture = await tester.startGesture(textOffsetToPosition(paragraph1, 6)); // at the 'r'
    addTearDown(gesture.removePointer);
    await tester.pump(const Duration(milliseconds: 500));
    // `are` is selected.
    expect(paragraph1.selections[0], const TextSelection(baseOffset: 4, extentOffset: 7));
    await tester.pumpAndSettle();

    expect(find.byType(AdaptiveTextSelectionToolbar), findsNothing);
    expect(find.byKey(key), findsOneWidget);
  },
    skip: kIsWeb, // [intended]
  );

135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
  testWidgets('onSelectionChange is called when the selection changes', (WidgetTester tester) async {
    SelectedContent? content;

    await tester.pumpWidget(MaterialApp(
      home: SelectionArea(
        child: const Text('How are you'),
        onSelectionChanged: (SelectedContent? selectedContent) => content = selectedContent,
      ),
    ));
    final RenderParagraph paragraph = tester.renderObject<RenderParagraph>(find.descendant(of: find.text('How are you'), matching: find.byType(RichText)));
    final TestGesture gesture = await tester.startGesture(textOffsetToPosition(paragraph, 4), kind: PointerDeviceKind.mouse);
    expect(content, isNull);
    addTearDown(gesture.removePointer);
    await tester.pump();

    await gesture.moveTo(textOffsetToPosition(paragraph, 7));
    await gesture.up();
    await tester.pump();
    expect(content, isNotNull);
    expect(content!.plainText, 'are');

    // Backwards selection.
    await gesture.down(textOffsetToPosition(paragraph, 3));
    expect(content, isNull);
    await gesture.moveTo(textOffsetToPosition(paragraph, 0));
    await gesture.up();
    await tester.pump();
    expect(content, isNotNull);
    expect(content!.plainText, 'How');
  });
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

  testWidgets('stopping drag of end handle will show the toolbar', (WidgetTester tester) async {
    // Regression test for https://github.com/flutter/flutter/issues/119314
    await tester.pumpWidget(
      MaterialApp(
        home: Scaffold(
          body: Padding(
            padding: const EdgeInsets.only(top: 64),
            child: Column(
              children: <Widget>[
                const Text('How are you?'),
                SelectionArea(
                  focusNode: FocusNode(),
                  child: const Text('Good, and you?'),
                ),
                const Text('Fine, thank you.'),
              ],
            ),
          ),
        ),
      ),
    );
187
    await tester.pumpAndSettle();
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
    final RenderParagraph paragraph2 = tester.renderObject<RenderParagraph>(find.descendant(of: find.text('Good, and you?'), matching: find.byType(RichText)));
    final TestGesture gesture = await tester.startGesture(textOffsetToPosition(paragraph2, 7)); // at the 'a'
    addTearDown(gesture.removePointer);
    await tester.pump(const Duration(milliseconds: 500));
    await gesture.up();
    final List<TextBox> boxes = paragraph2.getBoxesForSelection(paragraph2.selections[0]);
    expect(boxes.length, 1);
    // There is a selection now.
    // We check the presence of the copy button to make sure the selection toolbar
    // is showing.
    expect(find.text('Copy'), findsOneWidget);

    // This is the position of the selection handle displayed at the end.
    final Offset handlePos = paragraph2.localToGlobal(boxes[0].toRect().bottomRight);
    await gesture.down(handlePos);
    await gesture.moveTo(textOffsetToPosition(paragraph2, 11) + Offset(0, paragraph2.size.height / 2));
    await tester.pump();

    await gesture.up();
    await tester.pump();

    // After lifting the finger up, the selection toolbar should be showing again.
    expect(find.text('Copy'), findsOneWidget);
  },
    variant: TargetPlatformVariant.all(),
    skip: kIsWeb, // [intended]
  );
215
}