scrollable_fling_test.dart 6.54 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
import 'package:flutter/gestures.dart' show DragStartBehavior;
6 7
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
8

9 10
const TextStyle testFont = TextStyle(
  color: Color(0xFF00FF00),
11 12 13
  fontFamily: 'Ahem',
);

14
Future<void> pumpTest(WidgetTester tester, TargetPlatform platform) async {
15 16 17
  await tester.pumpWidget(Container());
  await tester.pumpWidget(MaterialApp(
    theme: ThemeData(
18
      platform: platform,
19
    ),
20
    home: Container(
21
      color: const Color(0xFF111111),
22
      child: ListView.builder(
23
        dragStartBehavior: DragStartBehavior.down,
24
        itemBuilder: (BuildContext context, int index) {
25
          return Text('$index', style: testFont);
26 27
        },
      ),
28 29 30 31 32 33 34 35
    ),
  ));
}

const double dragOffset = 213.82;

void main() {
  testWidgets('Flings on different platforms', (WidgetTester tester) async {
36
    double getCurrentOffset() {
Adam Barth's avatar
Adam Barth committed
37
      return tester.state<ScrollableState>(find.byType(Scrollable)).position.pixels;
38 39
    }

40
    await pumpTest(tester, TargetPlatform.android);
41 42
    await tester.fling(find.byType(ListView), const Offset(0.0, -dragOffset), 1000.0);
    expect(getCurrentOffset(), dragOffset);
43
    await tester.pump(); // trigger fling
44
    expect(getCurrentOffset(), dragOffset);
45
    await tester.pump(const Duration(seconds: 5));
Dan Field's avatar
Dan Field committed
46
    final double androidResult = getCurrentOffset();
47 48 49 50
    // Regression test for https://github.com/flutter/flutter/issues/83632
    // Before changing these values, ensure the fling results in a distance that
    // makes sense. See issue for more context.
    expect(androidResult, greaterThan(394.0));
51
    expect(androidResult, lessThan(395.0));
52

53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
    await pumpTest(tester, TargetPlatform.linux);
    await tester.fling(find.byType(ListView), const Offset(0.0, -dragOffset), 1000.0);
    expect(getCurrentOffset(), dragOffset);
    await tester.pump(); // trigger fling
    expect(getCurrentOffset(), dragOffset);
    await tester.pump(const Duration(seconds: 5));
    final double linuxResult = getCurrentOffset();

    await pumpTest(tester, TargetPlatform.windows);
    await tester.fling(find.byType(ListView), const Offset(0.0, -dragOffset), 1000.0);
    expect(getCurrentOffset(), dragOffset);
    await tester.pump(); // trigger fling
    expect(getCurrentOffset(), dragOffset);
    await tester.pump(const Duration(seconds: 5));
    final double windowsResult = getCurrentOffset();

69
    await pumpTest(tester, TargetPlatform.iOS);
70
    await tester.fling(find.byType(ListView), const Offset(0.0, -dragOffset), 1000.0);
71 72
    // Scroll starts ease into the scroll on iOS.
    expect(getCurrentOffset(), moreOrLessEquals(210.71026666666666));
73
    await tester.pump(); // trigger fling
74
    expect(getCurrentOffset(), moreOrLessEquals(210.71026666666666));
75
    await tester.pump(const Duration(seconds: 5));
Dan Field's avatar
Dan Field committed
76
    final double iOSResult = getCurrentOffset();
77

Dan Field's avatar
Dan Field committed
78 79 80 81 82 83 84 85 86 87
    await pumpTest(tester, TargetPlatform.macOS);
    await tester.fling(find.byType(ListView), const Offset(0.0, -dragOffset), 1000.0);
    // Scroll starts ease into the scroll on iOS.
    expect(getCurrentOffset(), moreOrLessEquals(210.71026666666666));
    await tester.pump(); // trigger fling
    expect(getCurrentOffset(), moreOrLessEquals(210.71026666666666));
    await tester.pump(const Duration(seconds: 5));
    final double macOSResult = getCurrentOffset();

    expect(androidResult, lessThan(iOSResult)); // iOS is slipperier than Android
88 89
    expect(macOSResult, lessThan(iOSResult)); // iOS is slipperier than macOS
    expect(macOSResult, lessThan(androidResult)); // Android is slipperier than macOS
90
    expect(linuxResult, lessThan(iOSResult)); // iOS is slipperier than Linux
91
    expect(macOSResult, lessThan(linuxResult)); // Linux is slipperier than macOS
92
    expect(windowsResult, lessThan(iOSResult)); // iOS is slipperier than Windows
93
    expect(macOSResult, lessThan(windowsResult)); // Windows is slipperier than macOS
94 95 96 97
    expect(windowsResult, equals(androidResult));
    expect(windowsResult, equals(androidResult));
    expect(linuxResult, equals(androidResult));
    expect(linuxResult, equals(androidResult));
98
  });
99 100

  testWidgets('fling and tap to stop', (WidgetTester tester) async {
101
    final List<String> log = <String>[];
102
    await tester.pumpWidget(
103
      Directionality(
104
        textDirection: TextDirection.ltr,
105 106 107 108 109 110 111
        child: ListView(
          dragStartBehavior: DragStartBehavior.down,
          children: List<Widget>.generate(250, (int i) => GestureDetector(
            onTap: () { log.add('tap $i'); },
            child: Text('$i', style: testFont),
          )),
        ),
112 113
      ),
    );
114 115

    expect(log, equals(<String>[]));
Adam Barth's avatar
Adam Barth committed
116
    await tester.tap(find.byType(Scrollable));
117
    await tester.pump(const Duration(milliseconds: 50));
118
    expect(log, equals(<String>['tap 21']));
Adam Barth's avatar
Adam Barth committed
119
    await tester.fling(find.byType(Scrollable), const Offset(0.0, -200.0), 1000.0);
120
    await tester.pump(const Duration(milliseconds: 50));
121 122
    expect(log, equals(<String>['tap 21']));
    await tester.tap(find.byType(Scrollable)); // should stop the fling but not tap anything
123
    await tester.pump(const Duration(milliseconds: 50));
124
    expect(log, equals(<String>['tap 21']));
Adam Barth's avatar
Adam Barth committed
125
    await tester.tap(find.byType(Scrollable));
126
    await tester.pump(const Duration(milliseconds: 50));
127
    expect(log, equals(<String>['tap 21', 'tap 35']));
128
  });
129 130

  testWidgets('fling and wait and tap', (WidgetTester tester) async {
131
    final List<String> log = <String>[];
132
    await tester.pumpWidget(
133
      Directionality(
134
        textDirection: TextDirection.ltr,
135 136 137 138 139 140 141
        child: ListView(
          dragStartBehavior: DragStartBehavior.down,
          children: List<Widget>.generate(250, (int i) => GestureDetector(
            onTap: () { log.add('tap $i'); },
            child: Text('$i', style: testFont),
          )),
        ),
142 143
      ),
    );
144 145

    expect(log, equals(<String>[]));
Adam Barth's avatar
Adam Barth committed
146
    await tester.tap(find.byType(Scrollable));
147
    await tester.pump(const Duration(milliseconds: 50));
148
    expect(log, equals(<String>['tap 21']));
Adam Barth's avatar
Adam Barth committed
149
    await tester.fling(find.byType(Scrollable), const Offset(0.0, -200.0), 1000.0);
150
    await tester.pump(const Duration(milliseconds: 50));
151 152 153
    expect(log, equals(<String>['tap 21']));
    await tester.pump(const Duration(seconds: 50)); // long wait, so the fling will have ended at the end of it
    expect(log, equals(<String>['tap 21']));
Adam Barth's avatar
Adam Barth committed
154
    await tester.tap(find.byType(Scrollable));
155
    await tester.pump(const Duration(milliseconds: 50));
156
    expect(log, equals(<String>['tap 21', 'tap 48']));
157
  });
158
}