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

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';
8 9 10 11 12 13 14

// Assuming that the test container is 800x600. The height of the
// viewport's contents is 650.0, the top and bottom text children
// are 100 pixels high and top/left edge of both widgets are visible.
// The top of the bottom widget is at 550 (the top of the top widget
// is at 0). The top of the bottom widget is 500 when it has been
// scrolled completely into view.
15
Widget buildFrame(ScrollPhysics physics, { ScrollController? scrollController }) {
16 17
  return SingleChildScrollView(
    key: UniqueKey(),
18
    physics: physics,
19
    controller: scrollController,
20
    child: SizedBox(
21
      height: 650.0,
22
      child: Column(
23
        crossAxisAlignment: CrossAxisAlignment.start,
24
        textDirection: TextDirection.ltr,
25
        children: <Widget>[
26
          const SizedBox(height: 100.0, child: Text('top', textDirection: TextDirection.ltr)),
27
          Expanded(child: Container()),
28
          const SizedBox(height: 100.0, child: Text('bottom', textDirection: TextDirection.ltr)),
29 30 31
        ],
      ),
    ),
32 33 34 35
  );
}

void main() {
36
  testWidgetsWithLeakTracking('ClampingScrollPhysics', (WidgetTester tester) async {
37 38 39

    // Scroll the target text widget by offset and then return its origin
    // in global coordinates.
40
    Future<Offset> locationAfterScroll(String target, Offset offset) async {
41
      await tester.dragFrom(tester.getTopLeft(find.text(target)), offset);
42 43
      await tester.pump();
      final RenderBox textBox = tester.renderObject(find.text(target));
44
      final Offset widgetOrigin = textBox.localToGlobal(Offset.zero);
45
      await tester.pump(const Duration(seconds: 1)); // Allow overscroll to settle
46
      return Future<Offset>.value(widgetOrigin);
47 48
    }

49
    await tester.pumpWidget(buildFrame(const BouncingScrollPhysics()));
50 51
    Offset origin = await locationAfterScroll('top', const Offset(0.0, 400.0));
    expect(origin.dy, greaterThan(0.0));
52
    origin = await locationAfterScroll('bottom', const Offset(0.0, -400.0));
53
    expect(origin.dy, lessThan(500.0));
54 55


56
    await tester.pumpWidget(buildFrame(const ClampingScrollPhysics()));
57
    origin = await locationAfterScroll('top', const Offset(0.0, 400.0));
58
    expect(origin.dy, equals(0.0));
59
    origin = await locationAfterScroll('bottom', const Offset(0.0, -400.0));
60
    expect(origin.dy, equals(500.0));
61
  });
62

63
  testWidgetsWithLeakTracking('ClampingScrollPhysics affects ScrollPosition', (WidgetTester tester) async {
64

65
    // BouncingScrollPhysics
66

67
    await tester.pumpWidget(buildFrame(const BouncingScrollPhysics()));
Adam Barth's avatar
Adam Barth committed
68
    ScrollableState scrollable = tester.state(find.byType(Scrollable));
69

70
    await tester.dragFrom(tester.getTopLeft(find.text('top')), const Offset(0.0, 400.0));
71
    await tester.pump();
72
    expect(scrollable.position.pixels, lessThan(0.0));
73 74
    await tester.pump(const Duration(seconds: 1)); // Allow overscroll to settle

75
    await tester.dragFrom(tester.getTopLeft(find.text('bottom')), const Offset(0.0, -400.0));
76
    await tester.pump();
77
    expect(scrollable.position.pixels, greaterThan(0.0));
78 79
    await tester.pump(const Duration(seconds: 1)); // Allow overscroll to settle

80
    // ClampingScrollPhysics
81

82
    await tester.pumpWidget(buildFrame(const ClampingScrollPhysics()));
Adam Barth's avatar
Adam Barth committed
83
    scrollable = scrollable = tester.state(find.byType(Scrollable));
84

85
    await tester.dragFrom(tester.getTopLeft(find.text('top')), const Offset(0.0, 400.0));
86
    await tester.pump();
87
    expect(scrollable.position.pixels, equals(0.0));
88 89
    await tester.pump(const Duration(seconds: 1)); // Allow overscroll to settle

90
    await tester.dragFrom(tester.getTopLeft(find.text('bottom')), const Offset(0.0, -400.0));
91
    await tester.pump();
92
    expect(scrollable.position.pixels, equals(50.0));
93
  });
94

95
  testWidgetsWithLeakTracking('ClampingScrollPhysics handles out of bounds ScrollPosition', (WidgetTester tester) async {
96 97
    Future<void> testOutOfBounds(ScrollPhysics physics, double initialOffset, double expectedOffset) async {
      final ScrollController scrollController = ScrollController(initialScrollOffset: initialOffset);
98
      addTearDown(scrollController.dispose);
99 100 101 102 103 104 105 106 107 108 109
      await tester.pumpWidget(buildFrame(physics, scrollController: scrollController));
      final ScrollableState scrollable = tester.state(find.byType(Scrollable));

      expect(scrollable.position.pixels, equals(initialOffset));
      await tester.pump(const Duration(seconds: 1)); // Allow overscroll to settle
      expect(scrollable.position.pixels, equals(expectedOffset));
    }

    await testOutOfBounds(const ClampingScrollPhysics(), -400.0, 0.0);
    await testOutOfBounds(const ClampingScrollPhysics(), 800.0, 50.0);
  });
110
}