scroll_events_test.dart 9.06 KB
Newer Older
1 2 3 4
// Copyright 2015 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.

5 6
import 'dart:async';

7 8
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/widgets.dart';
9
import 'package:meta/meta.dart';
10

11
Widget _buildScroller({ List<String> log }) {
12
  return NotificationListener<ScrollNotification>(
Adam Barth's avatar
Adam Barth committed
13
    onNotification: (ScrollNotification notification) {
14 15 16 17 18 19 20 21
      if (notification is ScrollStartNotification) {
        log.add('scroll-start');
      } else if (notification is ScrollUpdateNotification) {
        log.add('scroll-update');
      } else if (notification is ScrollEndNotification) {
        log.add('scroll-end');
      }
      return false;
22
    },
23 24
    child: SingleChildScrollView(
      child: Container(width: 1000.0, height: 1000.0),
25
    ),
26 27 28 29
  );
}

void main() {
30 31
  Completer<void> animateTo(WidgetTester tester, double newScrollOffset, { @required Duration duration }) {
    final Completer<void> completer = Completer<void>();
Adam Barth's avatar
Adam Barth committed
32
    final ScrollableState scrollable = tester.state(find.byType(Scrollable));
33
    scrollable.position.animateTo(newScrollOffset, duration: duration, curve: Curves.linear).whenComplete(completer.complete);
34 35 36
    return completer;
  }

37
  void jumpTo(WidgetTester tester, double newScrollOffset) {
Adam Barth's avatar
Adam Barth committed
38
    final ScrollableState scrollable = tester.state(find.byType(Scrollable));
39 40 41
    scrollable.position.jumpTo(newScrollOffset);
  }

42
  testWidgets('Scroll event drag', (WidgetTester tester) async {
43
    final List<String> log = <String>[];
44
    await tester.pumpWidget(_buildScroller(log: log));
45

46
    expect(log, equals(<String>[]));
47
    final TestGesture gesture = await tester.startGesture(const Offset(100.0, 100.0));
48
    expect(log, equals(<String>['scroll-start']));
49
    await tester.pump(const Duration(seconds: 1));
50
    expect(log, equals(<String>['scroll-start']));
51
    await gesture.moveBy(const Offset(-10.0, -10.0));
52
    expect(log, equals(<String>['scroll-start', 'scroll-update']));
53
    await tester.pump(const Duration(seconds: 1));
54
    expect(log, equals(<String>['scroll-start', 'scroll-update']));
55
    await gesture.up();
56
    expect(log, equals(<String>['scroll-start', 'scroll-update', 'scroll-end']));
57
    await tester.pump(const Duration(seconds: 1));
58
    expect(log, equals(<String>['scroll-start', 'scroll-update', 'scroll-end']));
59 60
  });

61
  testWidgets('Scroll animateTo', (WidgetTester tester) async {
62
    final List<String> log = <String>[];
63
    await tester.pumpWidget(_buildScroller(log: log));
64

65
    expect(log, equals(<String>[]));
66
    final Completer<void> completer = animateTo(tester, 100.0, duration: const Duration(seconds: 1));
67
    expect(completer.isCompleted, isFalse);
68
    expect(log, equals(<String>['scroll-start']));
69
    await tester.pump(const Duration(milliseconds: 100));
70
    expect(log, equals(<String>['scroll-start']));
71
    await tester.pump(const Duration(milliseconds: 100));
72
    expect(log, equals(<String>['scroll-start', 'scroll-update']));
73
    await tester.pump(const Duration(milliseconds: 1500));
74
    expect(log, equals(<String>['scroll-start', 'scroll-update', 'scroll-update', 'scroll-end']));
75
    expect(completer.isCompleted, isTrue);
76 77
  });

78
  testWidgets('Scroll jumpTo', (WidgetTester tester) async {
79
    final List<String> log = <String>[];
80
    await tester.pumpWidget(_buildScroller(log: log));
81

82
    expect(log, equals(<String>[]));
83 84
    jumpTo(tester, 100.0);
    expect(log, equals(<String>['scroll-start', 'scroll-update', 'scroll-end']));
85
    await tester.pump();
86
    expect(log, equals(<String>['scroll-start', 'scroll-update', 'scroll-end']));
87 88
  });

89
  testWidgets('Scroll jumpTo during animation', (WidgetTester tester) async {
90
    final List<String> log = <String>[];
91
    await tester.pumpWidget(_buildScroller(log: log));
92

93
    expect(log, equals(<String>[]));
94
    final Completer<void> completer = animateTo(tester, 100.0, duration: const Duration(seconds: 1));
95
    expect(completer.isCompleted, isFalse);
96
    expect(log, equals(<String>['scroll-start']));
97
    await tester.pump(const Duration(milliseconds: 100));
98
    expect(log, equals(<String>['scroll-start']));
99
    await tester.pump(const Duration(milliseconds: 100));
100
    expect(log, equals(<String>['scroll-start', 'scroll-update']));
101 102
    expect(completer.isCompleted, isFalse);

103
    jumpTo(tester, 100.0);
104
    expect(completer.isCompleted, isFalse);
105
    expect(log, equals(<String>['scroll-start', 'scroll-update', 'scroll-end', 'scroll-start', 'scroll-update', 'scroll-end']));
106
    await tester.pump(const Duration(milliseconds: 100));
107 108
    expect(log, equals(<String>['scroll-start', 'scroll-update', 'scroll-end', 'scroll-start', 'scroll-update', 'scroll-end']));
    expect(completer.isCompleted, isTrue);
109
    await tester.pump(const Duration(milliseconds: 1500));
110
    expect(log, equals(<String>['scroll-start', 'scroll-update', 'scroll-end', 'scroll-start', 'scroll-update', 'scroll-end']));
111
    expect(completer.isCompleted, isTrue);
112
  });
113

114
  testWidgets('Scroll scrollTo during animation', (WidgetTester tester) async {
115
    final List<String> log = <String>[];
116
    await tester.pumpWidget(_buildScroller(log: log));
117

118
    expect(log, equals(<String>[]));
119
    Completer<void> completer = animateTo(tester, 100.0, duration: const Duration(seconds: 1));
120
    expect(completer.isCompleted, isFalse);
121
    expect(log, equals(<String>['scroll-start']));
122
    await tester.pump(const Duration(milliseconds: 100));
123
    expect(log, equals(<String>['scroll-start']));
124
    await tester.pump(const Duration(milliseconds: 100));
125
    expect(log, equals(<String>['scroll-start', 'scroll-update']));
126 127
    expect(completer.isCompleted, isFalse);

128
    completer = animateTo(tester, 100.0, duration: const Duration(seconds: 1));
129
    expect(completer.isCompleted, isFalse);
130
    expect(log, equals(<String>['scroll-start', 'scroll-update']));
131
    await tester.pump(const Duration(milliseconds: 100));
132
    expect(log, equals(<String>['scroll-start', 'scroll-update']));
133
    await tester.pump(const Duration(milliseconds: 1500));
134
    expect(log, equals(<String>['scroll-start', 'scroll-update', 'scroll-update', 'scroll-end']));
135
    expect(completer.isCompleted, isTrue);
136 137
  });

138
  testWidgets('fling, fling generates two start/end pairs', (WidgetTester tester) async {
139
    final List<String> log = <String>[];
140
    await tester.pumpWidget(_buildScroller(log: log));
141

142
    // The ideal behavior here would be a single start/end pair, but for
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
    // simplicity of implementation we compromise here and accept two. Should
    // you find a way to make this work with just one without complicating the
    // API, feel free to change the expectation here.

    expect(log, equals(<String>[]));
    await tester.flingFrom(const Offset(100.0, 100.0), const Offset(-50.0, -50.0), 500.0);
    await tester.pump(const Duration(seconds: 1));
    log.removeWhere((String value) => value == 'scroll-update');
    expect(log, equals(<String>['scroll-start']));
    await tester.flingFrom(const Offset(100.0, 100.0), const Offset(-50.0, -50.0), 500.0);
    log.removeWhere((String value) => value == 'scroll-update');
    expect(log, equals(<String>['scroll-start', 'scroll-end', 'scroll-start']));
    await tester.pump(const Duration(seconds: 1));
    await tester.pump(const Duration(seconds: 1));
    log.removeWhere((String value) => value == 'scroll-update');
    expect(log, equals(<String>['scroll-start', 'scroll-end', 'scroll-start', 'scroll-end']));
  });

  testWidgets('fling, pause, fling generates two start/end pairs', (WidgetTester tester) async {
    final List<String> log = <String>[];
    await tester.pumpWidget(_buildScroller(log: log));

165
    expect(log, equals(<String>[]));
166
    await tester.flingFrom(const Offset(100.0, 100.0), const Offset(-50.0, -50.0), 500.0);
167
    await tester.pump(const Duration(seconds: 1));
168 169
    log.removeWhere((String value) => value == 'scroll-update');
    expect(log, equals(<String>['scroll-start']));
170
    await tester.pump(const Duration(minutes: 1));
171
    await tester.flingFrom(const Offset(100.0, 100.0), const Offset(-50.0, -50.0), 500.0);
172 173
    log.removeWhere((String value) => value == 'scroll-update');
    expect(log, equals(<String>['scroll-start', 'scroll-end', 'scroll-start']));
174 175
    await tester.pump(const Duration(seconds: 1));
    await tester.pump(const Duration(seconds: 1));
176 177
    log.removeWhere((String value) => value == 'scroll-update');
    expect(log, equals(<String>['scroll-start', 'scroll-end', 'scroll-start', 'scroll-end']));
178
  });
179

180
  testWidgets('fling up ends', (WidgetTester tester) async {
181
    final List<String> log = <String>[];
182
    await tester.pumpWidget(_buildScroller(log: log));
183

184
    expect(log, equals(<String>[]));
185
    await tester.flingFrom(const Offset(100.0, 100.0), const Offset(50.0, 50.0), 500.0);
186 187 188
    await tester.pump(const Duration(seconds: 1));
    await tester.pump(const Duration(seconds: 1));
    await tester.pump(const Duration(seconds: 1));
189 190 191
    expect(log.first, equals('scroll-start'));
    expect(log.last, equals('scroll-end'));
    log.removeWhere((String value) => value == 'scroll-update');
192
    expect(log.length, equals(2));
Adam Barth's avatar
Adam Barth committed
193
    expect(tester.state<ScrollableState>(find.byType(Scrollable)).position.pixels, equals(0.0));
194
  });
195
}