tabs_test.dart 8.75 KB
Newer Older
Hixie's avatar
Hixie 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.

Adam Barth's avatar
Adam Barth committed
5
import 'package:flutter_test/flutter_test.dart';
6 7 8
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';

Adam Barth's avatar
Adam Barth committed
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
class StateMarker extends StatefulWidget {
  StateMarker({ Key key, this.child }) : super(key: key);

  final Widget child;

  @override
  StateMarkerState createState() => new StateMarkerState();
}

class StateMarkerState extends State<StateMarker> {
  String marker;

  @override
  Widget build(BuildContext context) {
    if (config.child != null)
      return config.child;
    return new Container();
  }
}

Hans Muller's avatar
Hans Muller committed
29
Widget buildFrame({ List<String> tabs, String value, bool isScrollable: false, Key tabBarKey }) {
30
  return new Material(
31 32 33 34
    child: new TabBarSelection<String>(
      value: value,
      values: tabs,
      child: new TabBar<String>(
Hans Muller's avatar
Hans Muller committed
35
        key: tabBarKey,
36
        labels: new Map<String, TabLabel>.fromIterable(tabs, value: (String tab) => new TabLabel(text: tab)),
37 38
        isScrollable: isScrollable
      )
39
    )
40 41 42 43
  );
}

void main() {
44
  testWidgets('TabBar tap selects tab', (WidgetTester tester) async {
45 46
    List<String> tabs = <String>['A', 'B', 'C'];

47
    await tester.pumpWidget(buildFrame(tabs: tabs, value: 'C', isScrollable: false));
48 49 50 51 52 53 54 55 56 57 58 59 60
    TabBarSelectionState<String> selection = TabBarSelection.of(tester.element(find.text('A')));
    expect(selection, isNotNull);
    expect(selection.indexOf('A'), equals(0));
    expect(selection.indexOf('B'), equals(1));
    expect(selection.indexOf('C'), equals(2));
    expect(find.text('A'), findsOneWidget);
    expect(find.text('B'), findsOneWidget);
    expect(find.text('C'), findsOneWidget);
    expect(selection.index, equals(2));
    expect(selection.previousIndex, equals(2));
    expect(selection.value, equals('C'));
    expect(selection.previousValue, equals('C'));

61 62 63
    await tester.pumpWidget(buildFrame(tabs: tabs, value: 'C' ,isScrollable: false));
    await tester.tap(find.text('B'));
    await tester.pump();
64
    expect(selection.valueIsChanging, true);
65
    await tester.pump(const Duration(seconds: 1)); // finish the animation
66 67 68 69 70 71
    expect(selection.valueIsChanging, false);
    expect(selection.value, equals('B'));
    expect(selection.previousValue, equals('C'));
    expect(selection.index, equals(1));
    expect(selection.previousIndex, equals(2));

72 73 74 75
    await tester.pumpWidget(buildFrame(tabs: tabs, value: 'C', isScrollable: false));
    await tester.tap(find.text('C'));
    await tester.pump();
    await tester.pump(const Duration(seconds: 1));
76 77 78 79 80
    expect(selection.value, equals('C'));
    expect(selection.previousValue, equals('B'));
    expect(selection.index, equals(2));
    expect(selection.previousIndex, equals(1));

81 82 83 84
    await tester.pumpWidget(buildFrame(tabs: tabs, value: 'C', isScrollable: false));
    await tester.tap(find.text('A'));
    await tester.pump();
    await tester.pump(const Duration(seconds: 1));
85 86 87 88
    expect(selection.value, equals('A'));
    expect(selection.previousValue, equals('C'));
    expect(selection.index, equals(0));
    expect(selection.previousIndex, equals(2));
89 90
  });

91
  testWidgets('Scrollable TabBar tap selects tab', (WidgetTester tester) async {
92 93
    List<String> tabs = <String>['A', 'B', 'C'];

94
    await tester.pumpWidget(buildFrame(tabs: tabs, value: 'C', isScrollable: true));
95 96 97 98 99 100 101
    TabBarSelectionState<String> selection = TabBarSelection.of(tester.element(find.text('A')));
    expect(selection, isNotNull);
    expect(find.text('A'), findsOneWidget);
    expect(find.text('B'), findsOneWidget);
    expect(find.text('C'), findsOneWidget);
    expect(selection.value, equals('C'));

102 103 104
    await tester.pumpWidget(buildFrame(tabs: tabs, value: 'C', isScrollable: true));
    await tester.tap(find.text('B'));
    await tester.pump();
105 106
    expect(selection.value, equals('B'));

107 108 109
    await tester.pumpWidget(buildFrame(tabs: tabs, value: 'C', isScrollable: true));
    await tester.tap(find.text('C'));
    await tester.pump();
110 111
    expect(selection.value, equals('C'));

112 113 114
    await tester.pumpWidget(buildFrame(tabs: tabs, value: 'C', isScrollable: true));
    await tester.tap(find.text('A'));
    await tester.pump();
115
    expect(selection.value, equals('A'));
116
  });
Hans Muller's avatar
Hans Muller committed
117

118
  testWidgets('Scrollable TabBar tap centers selected tab', (WidgetTester tester) async {
119 120
    List<String> tabs = <String>['AAAAAA', 'BBBBBB', 'CCCCCC', 'DDDDDD', 'EEEEEE', 'FFFFFF', 'GGGGGG', 'HHHHHH', 'IIIIII', 'JJJJJJ', 'KKKKKK', 'LLLLLL'];
    Key tabBarKey = new Key('TabBar');
121
    await tester.pumpWidget(buildFrame(tabs: tabs, value: 'AAAAAA', isScrollable: true, tabBarKey: tabBarKey));
122 123 124 125 126 127 128 129
    TabBarSelectionState<String> selection = TabBarSelection.of(tester.element(find.text('AAAAAA')));
    expect(selection, isNotNull);
    expect(selection.value, equals('AAAAAA'));

    expect(tester.getSize(find.byKey(tabBarKey)).width, equals(800.0));
    // The center of the FFFFFF item is to the right of the TabBar's center
    expect(tester.getCenter(find.text('FFFFFF')).x, greaterThan(401.0));

130 131 132
    await tester.tap(find.text('FFFFFF'));
    await tester.pump();
    await tester.pump(const Duration(seconds: 1)); // finish the scroll animation
133 134 135
    expect(selection.value, equals('FFFFFF'));
    // The center of the FFFFFF item is now at the TabBar's center
    expect(tester.getCenter(find.text('FFFFFF')).x, closeTo(400.0, 1.0));
Hans Muller's avatar
Hans Muller committed
136 137 138
  });


139
  testWidgets('TabBar can be scrolled independent of the selection', (WidgetTester tester) async {
140 141
    List<String> tabs = <String>['AAAAAA', 'BBBBBB', 'CCCCCC', 'DDDDDD', 'EEEEEE', 'FFFFFF', 'GGGGGG', 'HHHHHH', 'IIIIII', 'JJJJJJ', 'KKKKKK', 'LLLLLL'];
    Key tabBarKey = new Key('TabBar');
142
    await tester.pumpWidget(buildFrame(tabs: tabs, value: 'AAAAAA', isScrollable: true, tabBarKey: tabBarKey));
143 144 145 146 147 148
    TabBarSelectionState<String> selection = TabBarSelection.of(tester.element(find.text('AAAAAA')));
    expect(selection, isNotNull);
    expect(selection.value, equals('AAAAAA'));

    // Fling-scroll the TabBar to the left
    expect(tester.getCenter(find.text('HHHHHH')).x, lessThan(700.0));
149 150 151
    await tester.fling(find.byKey(tabBarKey), const Offset(-20.0, 0.0), 1000.0);
    await tester.pump();
    await tester.pump(const Duration(seconds: 1)); // finish the scroll animation
152 153 154 155
    expect(tester.getCenter(find.text('HHHHHH')).x, lessThan(500.0));

    // Scrolling the TabBar doesn't change the selection
    expect(selection.value, equals('AAAAAA'));
Hans Muller's avatar
Hans Muller committed
156
  });
Adam Barth's avatar
Adam Barth committed
157

158
  testWidgets('TabView maintains state', (WidgetTester tester) async {
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
    List<String> tabs = <String>['AAAAAA', 'BBBBBB', 'CCCCCC', 'DDDDDD', 'EEEEEE'];
    String value = tabs[0];

    void onTabSelectionChanged(String newValue) {
      value = newValue;
    }

    Widget builder() {
      return new Material(
        child: new TabBarSelection<String>(
          value: value,
          values: tabs,
          onChanged: onTabSelectionChanged,
          child: new TabBarView<String>(
            children: tabs.map((String name) {
              return new StateMarker(
                child: new Text(name)
              );
            }).toList()
Adam Barth's avatar
Adam Barth committed
178
          )
179 180 181 182 183 184 185 186
        )
      );
    }

    StateMarkerState findStateMarkerState(String name) {
      return tester.state(find.widgetWithText(StateMarker, name));
    }

187 188 189 190
    await tester.pumpWidget(builder());
    TestGesture gesture = await tester.startGesture(tester.getCenter(find.text(tabs[0])));
    await gesture.moveBy(new Offset(-600.0, 0.0));
    await tester.pump();
191 192
    expect(value, equals(tabs[0]));
    findStateMarkerState(tabs[1]).marker = 'marked';
193 194 195
    await gesture.up();
    await tester.pump();
    await tester.pump(const Duration(seconds: 1));
196
    expect(value, equals(tabs[1]));
197
    await tester.pumpWidget(builder());
198 199 200 201
    expect(findStateMarkerState(tabs[1]).marker, equals('marked'));

    // Move to the third tab.

202 203 204 205
    gesture = await tester.startGesture(tester.getCenter(find.text(tabs[1])));
    await gesture.moveBy(new Offset(-600.0, 0.0));
    await gesture.up();
    await tester.pump();
206
    expect(findStateMarkerState(tabs[1]).marker, equals('marked'));
207
    await tester.pump(const Duration(seconds: 1));
208
    expect(value, equals(tabs[2]));
209
    await tester.pumpWidget(builder());
210 211 212 213 214 215 216

    // The state is now gone.

    expect(find.text(tabs[1]), findsNothing);

    // Move back to the second tab.

217 218 219
    gesture = await tester.startGesture(tester.getCenter(find.text(tabs[2])));
    await gesture.moveBy(new Offset(600.0, 0.0));
    await tester.pump();
220 221 222
    StateMarkerState markerState = findStateMarkerState(tabs[1]);
    expect(markerState.marker, isNull);
    markerState.marker = 'marked';
223 224 225
    await gesture.up();
    await tester.pump();
    await tester.pump(const Duration(seconds: 1));
226
    expect(value, equals(tabs[1]));
227
    await tester.pumpWidget(builder());
228
    expect(findStateMarkerState(tabs[1]).marker, equals('marked'));
Adam Barth's avatar
Adam Barth committed
229
  });
230
}