scrollable_dispose_test.dart 3.27 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 6
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
7 8 9 10 11 12 13
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/widgets.dart';

import 'test_widgets.dart';

void main() {
  testWidgets('simultaneously dispose a widget and end the scroll animation', (WidgetTester tester) async {
14
    await tester.pumpWidget(
15
      Directionality(
16
        textDirection: TextDirection.ltr,
17
        child: FlipWidget(
18
          left: ListView(children: List<Widget>.generate(250, (int i) => Text('$i'))),
19
          right: Container(),
20 21 22
        ),
      ),
    );
23

24
    await tester.fling(find.byType(ListView), const Offset(0.0, -200.0), 1000.0);
25 26
    await tester.pump();

27
    tester.state<FlipWidgetState>(find.byType(FlipWidget)).flip();
28
    await tester.pump(const Duration(hours: 5));
29
  });
30

Dan Field's avatar
Dan Field committed
31
  testWidgets('Disposing a (nested) Scrollable while holding in overscroll does not crash', (WidgetTester tester) async {
32 33 34
    // Regression test for https://github.com/flutter/flutter/issues/27707.

    final ScrollController controller = ScrollController();
35
    final Key outerContainer = GlobalKey();
36 37 38 39 40

    await tester.pumpWidget(
      MaterialApp(
        home: Center(
          child: Container(
41
            key: outerContainer,
42 43 44 45 46 47 48 49 50 51
            color: Colors.purple,
            width: 400.0,
            child: SingleChildScrollView(
              scrollDirection: Axis.horizontal,
              child: Container(
                width: 500.0,
                child: ListView.builder(
                  controller: controller,
                  itemBuilder: (BuildContext context, int index) {
                    return Container(
52
                      color: index.isEven ? Colors.red : Colors.green,
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
                      height: 200.0,
                      child: Text('Hello $index'),
                    );
                  },
                ),
              ),
            ),
          ),
        ),
      ),
    );

    // Go into overscroll.
    double lastScrollOffset;
    await tester.fling(find.text('Hello 0'), const Offset(0.0, 1000.0), 1000.0);
    await tester.pump(const Duration(milliseconds: 100));
    expect(lastScrollOffset = controller.offset, lessThan(0.0));

    // Reduce the overscroll a little, but don't let it go back to 0.0.
    await tester.pump(const Duration(milliseconds: 100));
    expect(controller.offset, greaterThan(lastScrollOffset));
    expect(controller.offset, lessThan(0.0));
    final double currentOffset = controller.offset;

    // Start a hold activity by putting one pointer down.
78
    await tester.startGesture(tester.getTopLeft(find.byKey(outerContainer)) + const Offset(50.0, 50.0));
79 80 81 82 83 84 85
    await tester.pumpAndSettle(); // This shouldn't change the scroll offset because of the down event above.
    expect(controller.offset, currentOffset);

    // Dispose the scrollables while the finger is still down, this should not crash.
    await tester.pumpWidget(
      MaterialApp(
        home: Container(),
86
      ),
87 88 89
    );
    await tester.pumpAndSettle();
    expect(controller.hasClients, isFalse);
Dan Field's avatar
Dan Field committed
90
  }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS,  TargetPlatform.macOS }));
91
}