list_view_misc_test.dart 7.39 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
Hixie's avatar
Hixie committed
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/widgets.dart';
6
import 'package:flutter_test/flutter_test.dart';
7
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
Hixie's avatar
Hixie committed
8

9
const Key blockKey = Key('test');
Hixie's avatar
Hixie committed
10 11

void main() {
12
  testWidgetsWithLeakTracking('Cannot scroll a non-overflowing block', (WidgetTester tester) async {
13
    await tester.pumpWidget(
14
      Directionality(
15
        textDirection: TextDirection.ltr,
16
        child: ListView(
17
          key: blockKey,
18 19
          children: const <Widget>[
            SizedBox(
20
              height: 200.0, // less than 600, the height of the test area
21
              child: Text('Hello'),
22 23 24 25
            ),
          ],
        ),
      ),
26 27
    );

28 29
    final Offset middleOfContainer = tester.getCenter(find.text('Hello'));
    final Offset target = tester.getCenter(find.byKey(blockKey));
30
    final TestGesture gesture = await tester.startGesture(target);
31
    await gesture.moveBy(const Offset(0.0, -10.0));
32

33
    await tester.pump(const Duration(milliseconds: 1));
34 35 36

    expect(tester.getCenter(find.text('Hello')) == middleOfContainer, isTrue);

37
    await gesture.up();
Hixie's avatar
Hixie committed
38 39
  });

40
  testWidgetsWithLeakTracking('Can scroll an overflowing block', (WidgetTester tester) async {
41
    await tester.pumpWidget(
42
      Directionality(
43
        textDirection: TextDirection.ltr,
44
        child: ListView(
45
          key: blockKey,
46 47
          children: const <Widget>[
            SizedBox(
48
              height: 2000.0, // more than 600, the height of the test area
49
              child: Text('Hello'),
50 51 52 53
            ),
          ],
        ),
      ),
54
    );
55

56 57 58
    final Offset middleOfContainer = tester.getCenter(find.text('Hello'));
    expect(middleOfContainer.dx, equals(400.0));
    expect(middleOfContainer.dy, equals(1000.0));
59

60
    final Offset target = tester.getCenter(find.byKey(blockKey));
61
    final TestGesture gesture = await tester.startGesture(target);
62
    await gesture.moveBy(const Offset(0.0, -10.0));
63

64
    await tester.pump(); // redo layout
65

66
    expect(tester.getCenter(find.text('Hello')), isNot(equals(middleOfContainer)));
67

68
    await gesture.up();
Hixie's avatar
Hixie committed
69
  });
70

71
  testWidgetsWithLeakTracking('ListView reverse', (WidgetTester tester) async {
72 73 74
    int first = 0;
    int second = 0;

75
    Widget buildBlock({ bool reverse = false }) {
76
      return Directionality(
77
        textDirection: TextDirection.ltr,
78 79
        child: ListView(
          key: UniqueKey(),
80 81
          reverse: reverse,
          children: <Widget>[
82
            GestureDetector(
83
              onTap: () { first += 1; },
84
              child: Container(
85 86
                height: 350.0, // more than half the height of the test area
                color: const Color(0xFF00FF00),
87
              ),
88
            ),
89
            GestureDetector(
90
              onTap: () { second += 1; },
91
              child: Container(
92 93 94 95 96 97
                height: 350.0, // more than half the height of the test area
                color: const Color(0xFF0000FF),
              ),
            ),
          ],
        ),
98 99
      );
    }
100

101
    await tester.pumpWidget(buildBlock(reverse: true));
102

103
    const Offset target = Offset(200.0, 200.0);
104
    await tester.tapAt(target);
105 106
    expect(first, equals(0));
    expect(second, equals(1));
107

108
    await tester.pumpWidget(buildBlock());
109

110
    await tester.tapAt(target);
111 112
    expect(first, equals(1));
    expect(second, equals(1));
113
  });
114

115
  testWidgetsWithLeakTracking('ListView controller', (WidgetTester tester) async {
116
    final ScrollController controller = ScrollController();
117
    addTearDown(controller.dispose);
118

119
    Widget buildBlock() {
120
      return Directionality(
121
        textDirection: TextDirection.ltr,
122
        child: ListView(
123
          controller: controller,
124
          children: const <Widget>[Text('A'), Text('B'), Text('C')],
125
        ),
126 127 128
      );
    }
    await tester.pumpWidget(buildBlock());
129
    expect(controller.offset, equals(0.0));
130
  });
131

132
  testWidgetsWithLeakTracking('SliverBlockChildListDelegate.estimateMaxScrollOffset hits end', (WidgetTester tester) async {
133 134 135 136 137 138
    final SliverChildListDelegate delegate = SliverChildListDelegate(<Widget>[
      Container(),
      Container(),
      Container(),
      Container(),
      Container(),
139 140
    ]);

141
    await tester.pumpWidget(
142
      Directionality(
143
        textDirection: TextDirection.ltr,
144
        child: CustomScrollView(
145
          slivers: <Widget>[
146
            SliverList(
147 148 149
              delegate: delegate,
            ),
          ],
150
        ),
151 152
      ),
    );
153

154
    final SliverMultiBoxAdaptorElement element = tester.element(find.byType(SliverList, skipOffstage: false));
155 156 157 158 159 160

    final double maxScrollOffset = element.estimateMaxScrollOffset(
      null,
      firstIndex: 3,
      lastIndex: 4,
      leadingScrollOffset: 25.0,
161
      trailingScrollOffset: 26.0,
162 163
    );
    expect(maxScrollOffset, equals(26.0));
164
  });
165

166
  testWidgetsWithLeakTracking('Resizing a ListView child restores scroll offset', (WidgetTester tester) async {
167
    // Regression test for https://github.com/flutter/flutter/issues/9221
168
    final AnimationController controller = AnimationController(
169 170 171
      vsync: const TestVSync(),
      duration: const Duration(milliseconds: 200),
    );
172
    addTearDown(controller.dispose);
173 174 175

    // The overall height of the frame is (as ever) 600
    Widget buildFrame() {
176
      return Directionality(
177
        textDirection: TextDirection.ltr,
178
        child: Column(
179
          children: <Widget>[
180
            Flexible(
181
              // The overall height of the ListView's contents is 500
182
              child: ListView(
183
                children: const <Widget>[
184
                  SizedBox(
185
                    height: 150.0,
186
                    child: Center(
187
                      child: Text('top'),
188
                    ),
189
                  ),
190
                  SizedBox(
191
                    height: 200.0,
192
                    child: Center(
193
                      child: Text('middle'),
194
                    ),
195
                  ),
196
                  SizedBox(
197
                    height: 150.0,
198
                    child: Center(
199
                      child: Text('bottom'),
200
                    ),
201
                  ),
202 203
                ],
              ),
204
            ),
205
            // If this widget's height is > 100 the ListView can scroll.
206
            SizeTransition(
207 208 209
              sizeFactor: controller.view,
              child: const SizedBox(
                height: 300.0,
210
                child: Text('keyboard'),
211
              ),
212
            ),
213 214
          ],
        ),
215 216 217 218 219 220
      );
    }

    await tester.pumpWidget(buildFrame());
    expect(find.text('top'), findsOneWidget);

221
    final ScrollPosition position = Scrollable.of(tester.element(find.text('middle'))).position;
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
    expect(position.viewportDimension, 600.0);
    expect(position.pixels, 0.0);

    // Animate the 'keyboard' height from 0 to 300
    controller.forward();
    await tester.pumpAndSettle();
    expect(position.viewportDimension, 300.0);

    // Scroll the ListView upwards
    position.jumpTo(200.0);
    await tester.pumpAndSettle();
    expect(position.pixels, 200.0);
    expect(find.text('top'), findsNothing);

    // Animate the 'keyboard' height back to 0. This causes the scroll
    // offset to return to 0.0
    controller.reverse();
    await tester.pumpAndSettle();
    expect(position.viewportDimension, 600.0);
    expect(position.pixels, 0.0);
    expect(find.text('top'), findsOneWidget);
  });
Hixie's avatar
Hixie committed
244
}