page_selector_test.dart 10.6 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/material.dart';
6
import 'package:flutter_test/flutter_test.dart';
7

8
const Color kSelectedColor = Color(0xFF00FF00);
9
const Color kUnselectedColor = Colors.transparent;
10

11
Widget buildFrame(TabController tabController, { Color? color, Color? selectedColor, double indicatorSize = 12.0, BorderStyle? borderStyle }) {
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
  return Localizations(
    locale: const Locale('en', 'US'),
    delegates: const <LocalizationsDelegate<dynamic>>[
      DefaultMaterialLocalizations.delegate,
      DefaultWidgetsLocalizations.delegate,
    ],
    child: Directionality(
      textDirection: TextDirection.ltr,
      child: Theme(
        data: ThemeData(colorScheme: const ColorScheme.light().copyWith(secondary: kSelectedColor)),
        child: SizedBox.expand(
          child: Center(
            child: SizedBox(
              width: 400.0,
              height: 400.0,
              child: Column(
                children: <Widget>[
                  TabPageSelector(
30
                    controller: tabController,
31 32 33
                    color: color,
                    selectedColor: selectedColor,
                    indicatorSize: indicatorSize,
34
                    borderStyle: borderStyle,
35
                  ),
36 37 38 39 40 41 42 43 44 45 46 47
                  Flexible(
                    child: TabBarView(
                      controller: tabController,
                      children: const <Widget>[
                        Center(child: Text('0')),
                        Center(child: Text('1')),
                        Center(child: Text('2')),
                      ],
                    ),
                  ),
                ],
              ),
48
            ),
49 50 51 52 53 54 55 56 57 58 59
          ),
        ),
      ),
    ),
  );
}

List<Color> indicatorColors(WidgetTester tester) {
  final Iterable<TabPageSelectorIndicator> indicators = tester.widgetList(
    find.descendant(
      of: find.byType(TabPageSelector),
60
      matching: find.byType(TabPageSelectorIndicator),
61
    ),
62
  );
63
  return indicators.map<Color>((TabPageSelectorIndicator indicator) => indicator.backgroundColor).toList();
64 65 66
}

void main() {
67
  testWidgets('PageSelector responds correctly to setting the TabController index', (WidgetTester tester) async {
68
    final TabController tabController = TabController(
69 70 71
      vsync: const TestVSync(),
      length: 3,
    );
72
    addTearDown(tabController.dispose);
73 74 75
    await tester.pumpWidget(buildFrame(tabController));

    expect(tabController.index, 0);
76
    expect(indicatorColors(tester), const <Color>[kSelectedColor, kUnselectedColor, kUnselectedColor]);
77 78 79 80

    tabController.index = 1;
    await tester.pump();
    expect(tabController.index, 1);
81
    expect(indicatorColors(tester), const <Color>[kUnselectedColor, kSelectedColor, kUnselectedColor]);
82 83 84 85

    tabController.index = 2;
    await tester.pump();
    expect(tabController.index, 2);
86
    expect(indicatorColors(tester), const <Color>[kUnselectedColor, kUnselectedColor, kSelectedColor]);
87
  });
88

89
  testWidgets('PageSelector responds correctly to TabController.animateTo()', (WidgetTester tester) async {
90
    final TabController tabController = TabController(
91 92 93
      vsync: const TestVSync(),
      length: 3,
    );
94
    addTearDown(tabController.dispose);
95 96 97
    await tester.pumpWidget(buildFrame(tabController));

    expect(tabController.index, 0);
98
    expect(indicatorColors(tester), const <Color>[kSelectedColor, kUnselectedColor, kUnselectedColor]);
99 100 101 102

    tabController.animateTo(1, duration: const Duration(milliseconds: 200));
    await tester.pump();
    // Verify that indicator 0's color is becoming increasingly transparent,
103
    // and indicator 1's color is becoming increasingly opaque during the
104 105 106 107
    // 200ms animation. Indicator 2 remains transparent throughout.
    await tester.pump(const Duration(milliseconds: 10));
    List<Color> colors = indicatorColors(tester);
    expect(colors[0].alpha, greaterThan(colors[1].alpha));
108
    expect(colors[2], kUnselectedColor);
109 110 111
    await tester.pump(const Duration(milliseconds: 175));
    colors = indicatorColors(tester);
    expect(colors[0].alpha, lessThan(colors[1].alpha));
112
    expect(colors[2], kUnselectedColor);
113 114
    await tester.pumpAndSettle();
    expect(tabController.index, 1);
115
    expect(indicatorColors(tester), const <Color>[kUnselectedColor, kSelectedColor, kUnselectedColor]);
116 117 118 119 120 121 122

    tabController.animateTo(2, duration: const Duration(milliseconds: 200));
    await tester.pump();
    // Same animation test as above for indicators 1 and 2.
    await tester.pump(const Duration(milliseconds: 10));
    colors = indicatorColors(tester);
    expect(colors[1].alpha, greaterThan(colors[2].alpha));
123
    expect(colors[0], kUnselectedColor);
124 125 126
    await tester.pump(const Duration(milliseconds: 175));
    colors = indicatorColors(tester);
    expect(colors[1].alpha, lessThan(colors[2].alpha));
127
    expect(colors[0], kUnselectedColor);
128 129
    await tester.pumpAndSettle();
    expect(tabController.index, 2);
130
    expect(indicatorColors(tester), const <Color>[kUnselectedColor, kUnselectedColor, kSelectedColor]);
131
  });
132

133
  testWidgets('PageSelector responds correctly to TabBarView drags', (WidgetTester tester) async {
134
    final TabController tabController = TabController(
135 136 137 138
      vsync: const TestVSync(),
      initialIndex: 1,
      length: 3,
    );
139
    addTearDown(tabController.dispose);
140 141 142
    await tester.pumpWidget(buildFrame(tabController));

    expect(tabController.index, 1);
143
    expect(indicatorColors(tester), const <Color>[kUnselectedColor, kSelectedColor, kUnselectedColor]);
144 145 146 147 148 149 150 151 152

    final TestGesture gesture = await tester.startGesture(const Offset(200.0, 200.0));

    // Drag to the left moving the selection towards indicator 2. Indicator 2's
    // opacity should increase and Indicator 1's opacity should decrease.
    await gesture.moveBy(const Offset(-100.0, 0.0));
    await tester.pumpAndSettle();
    List<Color> colors = indicatorColors(tester);
    expect(colors[1].alpha, greaterThan(colors[2].alpha));
153
    expect(colors[0], kUnselectedColor);
154 155 156 157 158

    // Drag back to where we started.
    await gesture.moveBy(const Offset(100.0, 0.0));
    await tester.pumpAndSettle();
    colors = indicatorColors(tester);
159
    expect(indicatorColors(tester), const <Color>[kUnselectedColor, kSelectedColor, kUnselectedColor]);
160 161 162 163 164 165 166

    // Drag to the left moving the selection towards indicator 0. Indicator 0's
    // opacity should increase and Indicator 1's opacity should decrease.
    await gesture.moveBy(const Offset(100.0, 0.0));
    await tester.pumpAndSettle();
    colors = indicatorColors(tester);
    expect(colors[1].alpha, greaterThan(colors[0].alpha));
167
    expect(colors[2], kUnselectedColor);
168 169 170 171 172

    // Drag back to where we started.
    await gesture.moveBy(const Offset(-100.0, 0.0));
    await tester.pumpAndSettle();
    colors = indicatorColors(tester);
173
    expect(indicatorColors(tester), const <Color>[kUnselectedColor, kSelectedColor, kUnselectedColor]);
174 175 176 177 178

    // Completing the gesture doesn't change anything
    await gesture.up();
    await tester.pumpAndSettle();
    colors = indicatorColors(tester);
179
    expect(indicatorColors(tester), const <Color>[kUnselectedColor, kSelectedColor, kUnselectedColor]);
180 181 182 183

    // Fling to the left, selects indicator 2
    await tester.fling(find.byType(TabBarView), const Offset(-100.0, 0.0), 1000.0);
    await tester.pumpAndSettle();
184
    expect(indicatorColors(tester), const <Color>[kUnselectedColor, kUnselectedColor, kSelectedColor]);
185 186 187 188

    // Fling to the right, selects indicator 1
    await tester.fling(find.byType(TabBarView), const Offset(100.0, 0.0), 1000.0);
    await tester.pumpAndSettle();
189
    expect(indicatorColors(tester), const <Color>[kUnselectedColor, kSelectedColor, kUnselectedColor]);
190
  });
191

192
  testWidgets('PageSelector indicatorColors', (WidgetTester tester) async {
193 194
    const Color kRed = Color(0xFFFF0000);
    const Color kBlue = Color(0xFF0000FF);
195

196
    final TabController tabController = TabController(
197 198 199 200
      vsync: const TestVSync(),
      initialIndex: 1,
      length: 3,
    );
201
    addTearDown(tabController.dispose);
202 203 204 205 206 207 208 209
    await tester.pumpWidget(buildFrame(tabController, color: kRed, selectedColor: kBlue));

    expect(tabController.index, 1);
    expect(indicatorColors(tester), const <Color>[kRed, kBlue, kRed]);

    tabController.index = 0;
    await tester.pumpAndSettle();
    expect(indicatorColors(tester), const <Color>[kBlue, kRed, kRed]);
210
  });
211

212
  testWidgets('PageSelector indicatorSize', (WidgetTester tester) async {
213
    final TabController tabController = TabController(
214 215 216 217
      vsync: const TestVSync(),
      initialIndex: 1,
      length: 3,
    );
218
    addTearDown(tabController.dispose);
219 220 221 222 223 224 225 226
    await tester.pumpWidget(buildFrame(tabController, indicatorSize: 16.0));

    final Iterable<Element> indicatorElements = find.descendant(
      of: find.byType(TabPageSelector),
      matching: find.byType(TabPageSelectorIndicator),
    ).evaluate();

    // Indicators get an 8 pixel margin, 16 + 8 = 24.
227
    for (final Element indicatorElement in indicatorElements) {
228
      expect(indicatorElement.size, const Size(24.0, 24.0));
229
    }
230

231
    expect(tester.getSize(find.byType(TabPageSelector)).height, 24.0);
232 233
  });

234
  testWidgets('PageSelector circle border', (WidgetTester tester) async {
235 236 237 238 239
    final TabController tabController = TabController(
      vsync: const TestVSync(),
      initialIndex: 1,
      length: 3,
    );
240
    addTearDown(tabController.dispose);
241 242 243 244 245 246 247 248 249 250 251

    Iterable<TabPageSelectorIndicator> indicators;

    // Default border
    await tester.pumpWidget(buildFrame(tabController));
    indicators = tester.widgetList(
      find.descendant(
        of: find.byType(TabPageSelector),
        matching: find.byType(TabPageSelectorIndicator),
      ),
    );
252
    for (final TabPageSelectorIndicator indicator in indicators) {
253
      expect(indicator.borderStyle, BorderStyle.solid);
254
    }
255 256 257 258 259 260 261 262 263

    // No border
    await tester.pumpWidget(buildFrame(tabController, borderStyle: BorderStyle.none));
    indicators = tester.widgetList(
      find.descendant(
        of: find.byType(TabPageSelector),
        matching: find.byType(TabPageSelectorIndicator),
      ),
    );
264
    for (final TabPageSelectorIndicator indicator in indicators) {
265
      expect(indicator.borderStyle, BorderStyle.none);
266
    }
267 268 269 270 271 272 273 274 275

    // Solid border
    await tester.pumpWidget(buildFrame(tabController, borderStyle: BorderStyle.solid));
    indicators = tester.widgetList(
      find.descendant(
        of: find.byType(TabPageSelector),
        matching: find.byType(TabPageSelectorIndicator),
      ),
    );
276
    for (final TabPageSelectorIndicator indicator in indicators) {
277
      expect(indicator.borderStyle, BorderStyle.solid);
278
    }
279
  });
280
}