remember_scroll_position_test.dart 5.18 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
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
import 'package:meta/meta.dart';
Adam Barth's avatar
Adam Barth committed
8
import 'package:flutter_test/flutter_test.dart';
9
import 'package:flutter/material.dart';
Ian Hickson's avatar
Ian Hickson committed
10

11
ScrollController _controller = ScrollController(
12 13 14
  initialScrollOffset: 110.0,
);

15
class ThePositiveNumbers extends StatelessWidget {
16
  const ThePositiveNumbers({ @required this.from });
17
  final int from;
18
  @override
19
  Widget build(BuildContext context) {
20
    return ListView.builder(
21
      key: const PageStorageKey<String>('ThePositiveNumbers'),
22
      itemExtent: 100.0,
23
      controller: _controller,
24
      itemBuilder: (BuildContext context, int index) {
25
        return Text('${index + from}', key: ValueKey<int>(index));
26
      },
27
    );
Ian Hickson's avatar
Ian Hickson committed
28 29 30
  }
}

31
Future<void> performTest(WidgetTester tester, bool maintainState) async {
32
  final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
33
  await tester.pumpWidget(
34
    Directionality(
35
      textDirection: TextDirection.ltr,
36
      child: Navigator(
37 38 39
        key: navigatorKey,
        onGenerateRoute: (RouteSettings settings) {
          if (settings.name == '/') {
40
            return MaterialPageRoute<void>(
41
              settings: settings,
42
              builder: (_) => Container(child: const ThePositiveNumbers(from: 0)),
43 44 45
              maintainState: maintainState,
            );
          } else if (settings.name == '/second') {
46
            return MaterialPageRoute<void>(
47
              settings: settings,
48
              builder: (_) => Container(child: const ThePositiveNumbers(from: 10000)),
49 50 51 52
              maintainState: maintainState,
            );
          }
          return null;
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 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136

  // we're 600 pixels high, each item is 100 pixels high, scroll position is
  // 110.0, so we should have 7 items, 1..7.
  expect(find.text('0'), findsNothing);
  expect(find.text('1'), findsOneWidget);
  expect(find.text('2'), findsOneWidget);
  expect(find.text('3'), findsOneWidget);
  expect(find.text('4'), findsOneWidget);
  expect(find.text('5'), findsOneWidget);
  expect(find.text('6'), findsOneWidget);
  expect(find.text('7'), findsOneWidget);
  expect(find.text('8'), findsNothing);
  expect(find.text('10'), findsNothing);
  expect(find.text('100'), findsNothing);

  tester.state<ScrollableState>(find.byType(Scrollable)).position.jumpTo(1000.0);
  await tester.pump(const Duration(seconds: 1));

  // we're 600 pixels high, each item is 100 pixels high, scroll position is
  // 1000, so we should have exactly 6 items, 10..15.

  expect(find.text('0'), findsNothing);
  expect(find.text('1'), findsNothing);
  expect(find.text('8'), findsNothing);
  expect(find.text('9'), findsNothing);
  expect(find.text('10'), findsOneWidget);
  expect(find.text('11'), findsOneWidget);
  expect(find.text('12'), findsOneWidget);
  expect(find.text('13'), findsOneWidget);
  expect(find.text('14'), findsOneWidget);
  expect(find.text('15'), findsOneWidget);
  expect(find.text('16'), findsNothing);
  expect(find.text('100'), findsNothing);

  navigatorKey.currentState.pushNamed('/second');
  await tester.pump(); // navigating always takes two frames, one to start...
  await tester.pump(const Duration(seconds: 1)); // ...and one to end the transition

  // the second list is now visible, starting at 10001
  expect(find.text('0'), findsNothing);
  expect(find.text('1'), findsNothing);
  expect(find.text('10'), findsNothing);
  expect(find.text('11'), findsNothing);
  expect(find.text('10000'), findsNothing);
  expect(find.text('10001'), findsOneWidget);
  expect(find.text('10002'), findsOneWidget);
  expect(find.text('10003'), findsOneWidget);
  expect(find.text('10004'), findsOneWidget);
  expect(find.text('10005'), findsOneWidget);
  expect(find.text('10006'), findsOneWidget);
  expect(find.text('10007'), findsOneWidget);
  expect(find.text('10008'), findsNothing);
  expect(find.text('10010'), findsNothing);
  expect(find.text('10100'), findsNothing);

  navigatorKey.currentState.pop();
  await tester.pump(); // again, navigating always takes two frames

  // Ensure we don't clamp the scroll offset even during the navigation.
  // https://github.com/flutter/flutter/issues/4883
  final ScrollableState state = tester.state(find.byType(Scrollable).first);
  expect(state.position.pixels, equals(1000.0));

  await tester.pump(const Duration(seconds: 1));

  // we're 600 pixels high, each item is 100 pixels high, scroll position is
  // 1000, so we should have exactly 6 items, 10..15.

  expect(find.text('0'), findsNothing);
  expect(find.text('1'), findsNothing);
  expect(find.text('8'), findsNothing);
  expect(find.text('9'), findsNothing);
  expect(find.text('10'), findsOneWidget);
  expect(find.text('11'), findsOneWidget);
  expect(find.text('12'), findsOneWidget);
  expect(find.text('13'), findsOneWidget);
  expect(find.text('14'), findsOneWidget);
  expect(find.text('15'), findsOneWidget);
  expect(find.text('16'), findsNothing);
  expect(find.text('100'), findsNothing);
137
}
Adam Barth's avatar
Adam Barth committed
138

139 140
void main() {
  testWidgets('whether we remember our scroll position', (WidgetTester tester) async {
141 142
    await performTest(tester, true);
    await performTest(tester, false);
Ian Hickson's avatar
Ian Hickson committed
143 144
  });
}