ink_well_test.dart 7.28 KB
Newer Older
1 2 3 4 5
// Copyright 2016 The Chromium 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';
6
import 'package:flutter/rendering.dart';
7
import 'package:flutter_test/flutter_test.dart';
8
import 'package:flutter/gestures.dart';
9

10
import '../rendering/mock_canvas.dart';
11
import '../widgets/semantics_tester.dart';
12 13
import 'feedback_tester.dart';

14 15
void main() {
  testWidgets('InkWell gestures control test', (WidgetTester tester) async {
16
    final List<String> log = <String>[];
17

18
    await tester.pumpWidget(
19
      Directionality(
20
        textDirection: TextDirection.ltr,
21 22 23
        child: Material(
          child: Center(
            child: InkWell(
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
              onTap: () {
                log.add('tap');
              },
              onDoubleTap: () {
                log.add('double-tap');
              },
              onLongPress: () {
                log.add('long-press');
              },
              onTapDown: (TapDownDetails details) {
                log.add('tap-down');
              },
              onTapCancel: () {
                log.add('tap-cancel');
              },
            ),
          ),
41
        ),
42 43
      )
    );
44 45 46 47 48 49 50

    await tester.tap(find.byType(InkWell), pointer: 1);

    expect(log, isEmpty);

    await tester.pump(const Duration(seconds: 1));

51
    expect(log, equals(<String>['tap-down', 'tap']));
52 53 54
    log.clear();

    await tester.tap(find.byType(InkWell), pointer: 2);
55
    await tester.pump(const Duration(milliseconds: 100));
56 57
    await tester.tap(find.byType(InkWell), pointer: 3);

58
    expect(log, equals(<String>['double-tap']));
59 60 61 62
    log.clear();

    await tester.longPress(find.byType(InkWell), pointer: 4);

63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
    expect(log, equals(<String>['tap-down', 'tap-cancel', 'long-press']));

    log.clear();
    TestGesture gesture = await tester.startGesture(tester.getRect(find.byType(InkWell)).center);
    await tester.pump(const Duration(milliseconds: 100));
    expect(log, equals(<String>['tap-down']));
    await gesture.up();
    await tester.pump(const Duration(seconds: 1));

    log.clear();
    gesture = await tester.startGesture(tester.getRect(find.byType(InkWell)).center);
    await tester.pump(const Duration(milliseconds: 100));
    await gesture.moveBy(const Offset(0.0, 200.0));
    await gesture.cancel();
    expect(log, equals(<String>['tap-down', 'tap-cancel']));
78
  });
79 80 81

  testWidgets('long-press and tap on disabled should not throw', (WidgetTester tester) async {
    await tester.pumpWidget(const Material(
82 83 84 85 86
      child: Directionality(
        textDirection: TextDirection.ltr,
        child: Center(
          child: InkWell(),
        ),
87
      ),
88 89 90 91 92 93 94 95 96 97 98
    ));
    await tester.tap(find.byType(InkWell), pointer: 1);
    await tester.pump(const Duration(seconds: 1));
    await tester.longPress(find.byType(InkWell), pointer: 1);
    await tester.pump(const Duration(seconds: 1));
  });

  group('feedback', () {
    FeedbackTester feedback;

    setUp(() {
99
      feedback = FeedbackTester();
100 101 102 103 104 105 106
    });

    tearDown(() {
      feedback?.dispose();
    });

    testWidgets('enabled (default)', (WidgetTester tester) async {
107 108
      await tester.pumpWidget(Material(
        child: Directionality(
109
          textDirection: TextDirection.ltr,
110 111
          child: Center(
            child: InkWell(
112 113
              onTap: () { },
              onLongPress: () { },
114
            ),
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
          ),
        ),
      ));
      await tester.tap(find.byType(InkWell), pointer: 1);
      await tester.pump(const Duration(seconds: 1));
      expect(feedback.clickSoundCount, 1);
      expect(feedback.hapticCount, 0);

      await tester.tap(find.byType(InkWell), pointer: 1);
      await tester.pump(const Duration(seconds: 1));
      expect(feedback.clickSoundCount, 2);
      expect(feedback.hapticCount, 0);

      await tester.longPress(find.byType(InkWell), pointer: 1);
      await tester.pump(const Duration(seconds: 1));
      expect(feedback.clickSoundCount, 2);
      expect(feedback.hapticCount, 1);
    });

    testWidgets('disabled', (WidgetTester tester) async {
135 136
      await tester.pumpWidget(Material(
        child: Directionality(
137
          textDirection: TextDirection.ltr,
138 139
          child: Center(
            child: InkWell(
140 141
              onTap: () { },
              onLongPress: () { },
142 143
              enableFeedback: false,
            ),
144
          ),
145
        ),
146 147 148 149 150 151 152 153 154 155 156 157
      ));
      await tester.tap(find.byType(InkWell), pointer: 1);
      await tester.pump(const Duration(seconds: 1));
      expect(feedback.clickSoundCount, 0);
      expect(feedback.hapticCount, 0);

      await tester.longPress(find.byType(InkWell), pointer: 1);
      await tester.pump(const Duration(seconds: 1));
      expect(feedback.clickSoundCount, 0);
      expect(feedback.hapticCount, 0);
    });
  });
158 159

  testWidgets('splashing survives scrolling when keep-alive is enabled', (WidgetTester tester) async {
160
    Future<void> runTest(bool keepAlive) async {
161
      await tester.pumpWidget(
162
        Directionality(
163
          textDirection: TextDirection.ltr,
164 165 166 167
          child: Material(
            child: CompositedTransformFollower( // forces a layer, which makes the paints easier to separate out
              link: LayerLink(),
              child: ListView(
168
                addAutomaticKeepAlives: keepAlive,
169
                dragStartBehavior: DragStartBehavior.down,
170
                children: <Widget>[
171 172 173
                  Container(height: 500.0, child: InkWell(onTap: () { }, child: const Placeholder())),
                  Container(height: 500.0),
                  Container(height: 500.0),
174 175 176
                ],
              ),
            ),
177 178
          ),
        ),
179
      );
180
      expect(tester.renderObject<RenderProxyBox>(find.byType(PhysicalModel)).child, isNot(paints..circle()));
181 182 183
      await tester.tap(find.byType(InkWell));
      await tester.pump();
      await tester.pump(const Duration(milliseconds: 10));
184
      expect(tester.renderObject<RenderProxyBox>(find.byType(PhysicalModel)).child, paints..circle());
185 186 187 188 189
      await tester.drag(find.byType(ListView), const Offset(0.0, -1000.0));
      await tester.pump(const Duration(milliseconds: 10));
      await tester.drag(find.byType(ListView), const Offset(0.0, 1000.0));
      await tester.pump(const Duration(milliseconds: 10));
      expect(
190
        tester.renderObject<RenderProxyBox>(find.byType(PhysicalModel)).child,
191
        keepAlive ? (paints..circle()) : isNot(paints..circle()),
192 193 194 195 196
      );
    }
    await runTest(true);
    await runTest(false);
  });
197 198

  testWidgets('excludeFromSemantics', (WidgetTester tester) async {
199
    final SemanticsTester semantics = SemanticsTester(tester);
200

201
    await tester.pumpWidget(Directionality(
202
      textDirection: TextDirection.ltr,
203 204
      child: Material(
        child: InkWell(
205 206 207 208 209 210 211
          onTap: () { },
          child: const Text('Button'),
        ),
      ),
    ));
    expect(semantics, includesNodeWith(label: 'Button', actions: <SemanticsAction>[SemanticsAction.tap]));

212
    await tester.pumpWidget(Directionality(
213
      textDirection: TextDirection.ltr,
214 215
      child: Material(
        child: InkWell(
216 217 218 219 220 221 222 223 224 225
          onTap: () { },
          child: const Text('Button'),
          excludeFromSemantics: true,
        ),
      ),
    ));
    expect(semantics, isNot(includesNodeWith(label: 'Button', actions: <SemanticsAction>[SemanticsAction.tap])));

    semantics.dispose();
  });
226
}