blob: 3d2d0fed6193eb6a6d0ffe220698671d6b3d60f0 [file] [log] [blame]
// Copyright 2014 The Flutter Authors. All rights reserved.
// 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';
import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
const Color kSelectedColor = Color(0xFF00FF00);
const Color kUnselectedColor = Colors.transparent;
Widget buildFrame(TabController tabController, { Color? color, Color? selectedColor, double indicatorSize = 12.0, BorderStyle? borderStyle }) {
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(
controller: tabController,
color: color,
selectedColor: selectedColor,
indicatorSize: indicatorSize,
borderStyle: borderStyle,
),
Flexible(
child: TabBarView(
controller: tabController,
children: const <Widget>[
Center(child: Text('0')),
Center(child: Text('1')),
Center(child: Text('2')),
],
),
),
],
),
),
),
),
),
),
);
}
List<Color> indicatorColors(WidgetTester tester) {
final Iterable<TabPageSelectorIndicator> indicators = tester.widgetList(
find.descendant(
of: find.byType(TabPageSelector),
matching: find.byType(TabPageSelectorIndicator),
),
);
return indicators.map<Color>((TabPageSelectorIndicator indicator) => indicator.backgroundColor).toList();
}
void main() {
testWidgetsWithLeakTracking('PageSelector responds correctly to setting the TabController index', (WidgetTester tester) async {
final TabController tabController = TabController(
vsync: const TestVSync(),
length: 3,
);
await tester.pumpWidget(buildFrame(tabController));
expect(tabController.index, 0);
expect(indicatorColors(tester), const <Color>[kSelectedColor, kUnselectedColor, kUnselectedColor]);
tabController.index = 1;
await tester.pump();
expect(tabController.index, 1);
expect(indicatorColors(tester), const <Color>[kUnselectedColor, kSelectedColor, kUnselectedColor]);
tabController.index = 2;
await tester.pump();
expect(tabController.index, 2);
expect(indicatorColors(tester), const <Color>[kUnselectedColor, kUnselectedColor, kSelectedColor]);
});
testWidgetsWithLeakTracking('PageSelector responds correctly to TabController.animateTo()', (WidgetTester tester) async {
final TabController tabController = TabController(
vsync: const TestVSync(),
length: 3,
);
await tester.pumpWidget(buildFrame(tabController));
expect(tabController.index, 0);
expect(indicatorColors(tester), const <Color>[kSelectedColor, kUnselectedColor, kUnselectedColor]);
tabController.animateTo(1, duration: const Duration(milliseconds: 200));
await tester.pump();
// Verify that indicator 0's color is becoming increasingly transparent,
// and indicator 1's color is becoming increasingly opaque during the
// 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));
expect(colors[2], kUnselectedColor);
await tester.pump(const Duration(milliseconds: 175));
colors = indicatorColors(tester);
expect(colors[0].alpha, lessThan(colors[1].alpha));
expect(colors[2], kUnselectedColor);
await tester.pumpAndSettle();
expect(tabController.index, 1);
expect(indicatorColors(tester), const <Color>[kUnselectedColor, kSelectedColor, kUnselectedColor]);
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));
expect(colors[0], kUnselectedColor);
await tester.pump(const Duration(milliseconds: 175));
colors = indicatorColors(tester);
expect(colors[1].alpha, lessThan(colors[2].alpha));
expect(colors[0], kUnselectedColor);
await tester.pumpAndSettle();
expect(tabController.index, 2);
expect(indicatorColors(tester), const <Color>[kUnselectedColor, kUnselectedColor, kSelectedColor]);
});
testWidgetsWithLeakTracking('PageSelector responds correctly to TabBarView drags', (WidgetTester tester) async {
final TabController tabController = TabController(
vsync: const TestVSync(),
initialIndex: 1,
length: 3,
);
await tester.pumpWidget(buildFrame(tabController));
expect(tabController.index, 1);
expect(indicatorColors(tester), const <Color>[kUnselectedColor, kSelectedColor, kUnselectedColor]);
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));
expect(colors[0], kUnselectedColor);
// Drag back to where we started.
await gesture.moveBy(const Offset(100.0, 0.0));
await tester.pumpAndSettle();
colors = indicatorColors(tester);
expect(indicatorColors(tester), const <Color>[kUnselectedColor, kSelectedColor, kUnselectedColor]);
// 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));
expect(colors[2], kUnselectedColor);
// Drag back to where we started.
await gesture.moveBy(const Offset(-100.0, 0.0));
await tester.pumpAndSettle();
colors = indicatorColors(tester);
expect(indicatorColors(tester), const <Color>[kUnselectedColor, kSelectedColor, kUnselectedColor]);
// Completing the gesture doesn't change anything
await gesture.up();
await tester.pumpAndSettle();
colors = indicatorColors(tester);
expect(indicatorColors(tester), const <Color>[kUnselectedColor, kSelectedColor, kUnselectedColor]);
// Fling to the left, selects indicator 2
await tester.fling(find.byType(TabBarView), const Offset(-100.0, 0.0), 1000.0);
await tester.pumpAndSettle();
expect(indicatorColors(tester), const <Color>[kUnselectedColor, kUnselectedColor, kSelectedColor]);
// Fling to the right, selects indicator 1
await tester.fling(find.byType(TabBarView), const Offset(100.0, 0.0), 1000.0);
await tester.pumpAndSettle();
expect(indicatorColors(tester), const <Color>[kUnselectedColor, kSelectedColor, kUnselectedColor]);
});
testWidgetsWithLeakTracking('PageSelector indicatorColors', (WidgetTester tester) async {
const Color kRed = Color(0xFFFF0000);
const Color kBlue = Color(0xFF0000FF);
final TabController tabController = TabController(
vsync: const TestVSync(),
initialIndex: 1,
length: 3,
);
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]);
});
testWidgets('PageSelector indicatorSize', (WidgetTester tester) async {
final TabController tabController = TabController(
vsync: const TestVSync(),
initialIndex: 1,
length: 3,
);
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.
for (final Element indicatorElement in indicatorElements) {
expect(indicatorElement.size, const Size(24.0, 24.0));
}
expect(tester.getSize(find.byType(TabPageSelector)).height, 24.0);
});
testWidgetsWithLeakTracking('PageSelector circle border', (WidgetTester tester) async {
final TabController tabController = TabController(
vsync: const TestVSync(),
initialIndex: 1,
length: 3,
);
Iterable<TabPageSelectorIndicator> indicators;
// Default border
await tester.pumpWidget(buildFrame(tabController));
indicators = tester.widgetList(
find.descendant(
of: find.byType(TabPageSelector),
matching: find.byType(TabPageSelectorIndicator),
),
);
for (final TabPageSelectorIndicator indicator in indicators) {
expect(indicator.borderStyle, BorderStyle.solid);
}
// No border
await tester.pumpWidget(buildFrame(tabController, borderStyle: BorderStyle.none));
indicators = tester.widgetList(
find.descendant(
of: find.byType(TabPageSelector),
matching: find.byType(TabPageSelectorIndicator),
),
);
for (final TabPageSelectorIndicator indicator in indicators) {
expect(indicator.borderStyle, BorderStyle.none);
}
// Solid border
await tester.pumpWidget(buildFrame(tabController, borderStyle: BorderStyle.solid));
indicators = tester.widgetList(
find.descendant(
of: find.byType(TabPageSelector),
matching: find.byType(TabPageSelectorIndicator),
),
);
for (final TabPageSelectorIndicator indicator in indicators) {
expect(indicator.borderStyle, BorderStyle.solid);
}
});
}